From 47ff8528c3f0495abc08b6dab93686b8312f0a89 Mon Sep 17 00:00:00 2001
From: Mrx <18278715334@163.com>
Date: Sat, 28 Feb 2026 17:41:25 +0800
Subject: [PATCH] f
---
public/seo-templates/agent.html | 80 +++++++++++
public/seo-templates/example.html | 80 +++++++++++
public/seo-templates/help-guide.html | 80 +++++++++++
public/seo-templates/help.html | 80 +++++++++++
public/seo-templates/index.html | 80 +++++++++++
public/seo-templates/service.html | 80 +++++++++++
server/crawler-detector.js | 170 ++++++++++++++++++++++++
server/generate-seo-templates.cjs | 191 +++++++++++++++++++++++++++
server/middleware.js | 170 ++++++++++++++++++++++++
server/package.json | 27 ++++
10 files changed, 1038 insertions(+)
create mode 100644 public/seo-templates/agent.html
create mode 100644 public/seo-templates/example.html
create mode 100644 public/seo-templates/help-guide.html
create mode 100644 public/seo-templates/help.html
create mode 100644 public/seo-templates/index.html
create mode 100644 public/seo-templates/service.html
create mode 100644 server/crawler-detector.js
create mode 100644 server/generate-seo-templates.cjs
create mode 100644 server/middleware.js
create mode 100644 server/package.json
diff --git a/public/seo-templates/agent.html b/public/seo-templates/agent.html
new file mode 100644
index 0000000..f19cbec
--- /dev/null
+++ b/public/seo-templates/agent.html
@@ -0,0 +1,80 @@
+
+
+
+
+
天远助手代理 - 免费开通代理权限 | 大数据风险报告代理
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
天远助手代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/example.html b/public/seo-templates/example.html
new file mode 100644
index 0000000..157ccdc
--- /dev/null
+++ b/public/seo-templates/example.html
@@ -0,0 +1,80 @@
+
+
+
+
+
示例报告 - 天远助手报告展示 | 大数据风险报告样例
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
天远助手示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/help-guide.html b/public/seo-templates/help-guide.html
new file mode 100644
index 0000000..4f52bb3
--- /dev/null
+++ b/public/seo-templates/help-guide.html
@@ -0,0 +1,80 @@
+
+
+
+
+
使用指南 - 天远助手操作教程 | 功能说明
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
天远助手详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/help.html b/public/seo-templates/help.html
new file mode 100644
index 0000000..eddace1
--- /dev/null
+++ b/public/seo-templates/help.html
@@ -0,0 +1,80 @@
+
+
+
+
+
帮助中心 - 天远助手使用指南 | 常见问题解答
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
天远助手帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/index.html b/public/seo-templates/index.html
new file mode 100644
index 0000000..87a83da
--- /dev/null
+++ b/public/seo-templates/index.html
@@ -0,0 +1,80 @@
+
+
+
+
+
天远助手|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+
\ No newline at end of file
diff --git a/public/seo-templates/service.html b/public/seo-templates/service.html
new file mode 100644
index 0000000..cad8cc0
--- /dev/null
+++ b/public/seo-templates/service.html
@@ -0,0 +1,80 @@
+
+
+
+
+
客服中心 - 天远助手在线客服 | 技术支持
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
天远助手客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+
\ No newline at end of file
diff --git a/server/crawler-detector.js b/server/crawler-detector.js
new file mode 100644
index 0000000..b49fec1
--- /dev/null
+++ b/server/crawler-detector.js
@@ -0,0 +1,170 @@
+/**
+ * 爬虫检测模块
+ * 用于识别搜索引擎爬虫和社交媒体爬虫
+ */
+
+class CrawlerDetector {
+ constructor() {
+ // 常见搜索引擎爬虫User-Agent列表
+ this.crawlerPatterns = [
+ // 百度爬虫
+ 'baiduspider',
+ 'baiduspider-mobile',
+ 'baiduspider-image',
+ 'baiduspider-video',
+ 'baiduspider-news',
+ 'baiduboxapp',
+
+ // Google爬虫
+ 'googlebot',
+ 'googlebot-image',
+ 'googlebot-news',
+ 'googlebot-mobile',
+ 'googlebot-video',
+ 'google-web-snippet',
+
+ // 360搜索
+ '360spider',
+ 'soha-agent',
+ 'haosouspider',
+
+ // 搜狗搜索
+ 'sogou spider',
+ 'sogou news spider',
+ 'sogou orion spider',
+ 'sogou-blog',
+
+ // 必应
+ 'bingbot',
+ 'msnbot',
+
+ // 雅虎
+ 'slurp',
+
+ // 搜搜
+ 'sosospider',
+ 'sosoimagespider',
+
+ // 有道
+ 'youdaobot',
+ 'yodaobot',
+
+ // 头条搜索
+ 'bytedance-spider',
+ 'toutiaospider',
+
+ // 社交媒体爬虫
+ 'facebookexternalhit',
+ 'facebookcatalog',
+ 'twitterbot',
+ 'linkedinbot',
+ 'whatsapp',
+ 'telegrambot',
+ 'viber',
+ 'line',
+
+ // 其他常见爬虫
+ 'applebot',
+ 'semrushbot',
+ 'ahrefsbot',
+ 'mj12bot',
+ 'dotbot',
+ 'crawler',
+ 'spider',
+ 'bot'
+ ]
+
+ // 需要检测的头部字段
+ this.crawlerHeaders = ['x-bot', 'x-crawler', 'x-forwarded-for']
+ }
+
+ /**
+ * 检测请求是否来自爬虫
+ * @param {Object} req - HTTP请求对象
+ * @returns {Boolean} 是否为爬虫
+ */
+ isCrawler(req) {
+ const userAgent = req.headers['user-agent']?.toLowerCase() || ''
+ const headers = req.headers
+
+ // 1. 通过User-Agent检测
+ if (this.checkUserAgent(userAgent)) {
+ console.log(`[CrawlerDetector] 检测到爬虫 UA: ${userAgent}`)
+ return true
+ }
+
+ // 2. 通过特定头部检测
+ if (this.checkHeaders(headers)) {
+ console.log(`[CrawlerDetector] 检测到爬虫 Headers`)
+ return true
+ }
+
+ // 3. 通过IP地址检测(可选)
+ // if (this.checkIP(req.connection.remoteAddress)) {
+ // return true
+ // }
+
+ return false
+ }
+
+ /**
+ * 检查User-Agent
+ * @param {String} userAgent
+ * @returns {Boolean}
+ */
+ checkUserAgent(userAgent) {
+ if (!userAgent) return false
+
+ return this.crawlerPatterns.some(pattern => {
+ return userAgent.includes(pattern.toLowerCase())
+ })
+ }
+
+ /**
+ * 检查请求头
+ * @param {Object} headers
+ * @returns {Boolean}
+ */
+ checkHeaders(headers) {
+ for (const header of this.crawlerHeaders) {
+ const headerValue = headers[header]?.toLowerCase()
+ if (headerValue && (headerValue.includes('bot') || headerValue.includes('crawler'))) {
+ return true
+ }
+ }
+ return false
+ }
+
+ /**
+ * 检查IP地址是否为已知爬虫IP
+ * @param {String} ip
+ * @returns {Boolean}
+ */
+ checkIP(ip) {
+ // 这里可以添加已知爬虫IP段的检测
+ // 需要定期更新爬虫IP列表
+ return false
+ }
+
+ /**
+ * 获取爬虫类型
+ * @param {String} userAgent
+ * @returns {String} 爬虫类型
+ */
+ getCrawlerType(userAgent) {
+ const ua = userAgent.toLowerCase()
+
+ if (ua.includes('baiduspider')) return 'baidu'
+ if (ua.includes('googlebot')) return 'google'
+ if (ua.includes('bingbot') || ua.includes('msnbot')) return 'bing'
+ if (ua.includes('360spider')) return '360'
+ if (ua.includes('sogou spider')) return 'sogou'
+ if (ua.includes('facebookexternalhit')) return 'facebook'
+ if (ua.includes('twitterbot')) return 'twitter'
+ if (ua.includes('linkedinbot')) return 'linkedin'
+
+ return 'unknown'
+ }
+}
+
+module.exports = CrawlerDetector
diff --git a/server/generate-seo-templates.cjs b/server/generate-seo-templates.cjs
new file mode 100644
index 0000000..5a81854
--- /dev/null
+++ b/server/generate-seo-templates.cjs
@@ -0,0 +1,191 @@
+/**
+ * SEO模板生成器
+ * 根据 useSEO.js 的页面配置自动生成静态 HTML 模板,供爬虫访问时返回
+ * 配置与 src/composables/useSEO.js 保持一致
+ *
+ * 多站点:通过环境变量 SEO_BASE_URL 指定 canonical/og:url 域名后生成
+ * 例:SEO_BASE_URL=https://www.tianyuandb.com node generate-seo-templates.cjs
+ */
+
+const fs = require('fs')
+const path = require('path')
+
+const BASE_URL = process.env.SEO_BASE_URL || 'https://www.zhinengcha.cn'
+
+// 页面 SEO 配置(与 useSEO.js 的 routeConfigs 保持一致)
+const pageSEOConfigs = {
+ 'index.html': {
+ title: '天远助手|大数据风险报告查询与代理平台,支持个人和企业多场景风控应用',
+ description: '天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。',
+ keywords: '大数据风险报告查询、大数据风险评估、大数据分析报告、个人大数据风险查询、小微企业风险、贷前风险背调、代理管理平台、免费开通代理、风险管控平台、信用风险分析、企业风险报告、贷前信用审核、失信人名单查询、被执行人信息、信用黑名单查询',
+ url: BASE_URL
+ },
+ 'agent.html': {
+ title: '天远助手代理 - 免费开通代理权限 | 大数据风险报告代理',
+ description: '天远助手代理平台,免费开通代理权限,享受大数据风险报告查询服务代理收益。专业的大数据风险报告、婚姻查询、个人信用评估等服务的代理合作。',
+ keywords: '天远助手代理, 免费代理, 大数据风险报告代理, 代理权限, 代理收益',
+ url: `${BASE_URL}/agent`
+ },
+ 'help.html': {
+ title: '帮助中心 - 天远助手使用指南 | 常见问题解答',
+ description: '天远助手帮助中心,提供详细的使用指南、常见问题解答、操作教程等,帮助用户更好地使用大数据风险报告查询服务。',
+ keywords: '天远助手帮助, 使用指南, 常见问题, 操作教程, 客服支持',
+ url: `${BASE_URL}/help`
+ },
+ 'help-guide.html': {
+ title: '使用指南 - 天远助手操作教程 | 功能说明',
+ description: '天远助手详细使用指南,包含各功能模块的操作教程、功能说明、注意事项等,让用户快速上手使用。',
+ keywords: '使用指南, 操作教程, 功能说明, 快速上手, 天远助手教程',
+ url: `${BASE_URL}/help/guide`
+ },
+ 'example.html': {
+ title: '示例报告 - 天远助手报告展示 | 大数据风险报告样例',
+ description: '天远助手示例报告展示,包含大数据风险报告、婚姻状况查询、个人信用评估等服务的报告样例,让用户了解报告内容和格式。',
+ keywords: '示例报告, 报告展示, 报告样例, 大数据风险报告, 婚姻查询报告',
+ url: `${BASE_URL}/example`
+ },
+ 'service.html': {
+ title: '客服中心 - 天远助手在线客服 | 技术支持',
+ description: '天远助手客服中心,提供在线客服支持、技术咨询、问题反馈等服务,确保用户获得及时有效的帮助。',
+ keywords: '客服中心, 在线客服, 技术支持, 问题反馈, 天远助手客服',
+ url: `${BASE_URL}/service`
+ }
+}
+
+/**
+ * 规范化文案:统一为中文标点,避免乱码
+ */
+function normalizeText(str) {
+ if (typeof str !== 'string') return str
+ return str
+ .replace(/\uFFFD/g, '')
+ .replace(/。/g, '。')
+ .replace(/、/g, '、')
+}
+
+/**
+ * 转义 HTML 属性值
+ */
+function escapeAttr(str) {
+ if (typeof str !== 'string') return ''
+ return str
+ .replace(/&/g, '&')
+ .replace(/"/g, '"')
+ .replace(//g, '>')
+}
+
+/**
+ * 生成单页 HTML 模板
+ */
+function generateHTMLTemplate(config) {
+ const title = normalizeText(config.title)
+ const description = normalizeText(config.description)
+ const keywords = normalizeText(config.keywords)
+ const structuredData = {
+ '@context': 'https://schema.org',
+ '@type': 'WebPage',
+ name: title,
+ description: description,
+ url: config.url,
+ mainEntity: {
+ '@type': 'Organization',
+ name: '天远助手',
+ url: 'https://www.zhinengcha.cn/',
+ description: '专业大数据风险报告查询与代理平台,支持个人和企业多场景风控应用'
+ }
+ }
+
+ return `
+
+
+
+
${escapeAttr(title)}
+
+
正在跳转到完整版网站...
+
如果浏览器没有自动跳转,请 点击这里
+
+
${escapeAttr(description)}
+
+ 关于天远助手
+ 天远助手,专业大数据风险报告查询与代理平台,支持个人信用查询、小微企业风控、贷前风险背调等多场景报告应用,免费开通代理权限,助力高效识别信用与风险。
+
+
+ 核心服务
+
+ - 大数据风险报告查询
+ - 个人信用查询服务
+ - 小微企业风控
+ - 贷前风险背调
+ - 代理管理平台
+ - 风险管控服务
+
+
+
+
+`
+}
+
+function main() {
+ const outputDir = path.join(__dirname, '../public/seo-templates')
+
+ if (!fs.existsSync(outputDir)) {
+ fs.mkdirSync(outputDir, { recursive: true })
+ console.log(`✓ 创建模板目录: ${outputDir}`)
+ }
+
+ let successCount = 0
+ Object.entries(pageSEOConfigs).forEach(([filename, config]) => {
+ const htmlContent = generateHTMLTemplate(config)
+ const filePath = path.join(outputDir, filename)
+ fs.writeFileSync(filePath, htmlContent, 'utf-8')
+ console.log(`✓ 生成模板: ${filename}`)
+ successCount++
+ })
+
+ console.log(`\n✓ 成功生成 ${successCount} 个 SEO 模板文件`)
+ console.log(`📁 模板目录: ${outputDir}`)
+ console.log(`💡 配置与 useSEO.js 一致,当前域名: ${BASE_URL}`)
+}
+
+main()
diff --git a/server/middleware.js b/server/middleware.js
new file mode 100644
index 0000000..aa9f2d8
--- /dev/null
+++ b/server/middleware.js
@@ -0,0 +1,170 @@
+/**
+ * SEO中间件
+ * 用于在Node.js服务器中检测爬虫并返回静态HTML
+ */
+
+const fs = require('fs')
+const path = require('path')
+const CrawlerDetector = require('./crawler-detector')
+
+class SEOMiddleware {
+ constructor(options = {}) {
+ this.detector = new CrawlerDetector()
+ this.templateDir = options.templateDir || path.join(__dirname, '../public/seo-templates')
+ this.defaultTemplate = options.defaultTemplate || 'index.html'
+ this.fallbackToSPA = options.fallbackToSPA !== false
+ this.debug = options.debug || false
+
+ // 路由到模板的映射(与 useSEO.js 的 routeConfigs 保持一致)
+ this.routeTemplateMap = {
+ '/': 'index.html',
+ '/agent': 'agent.html',
+ '/help/guide': 'help-guide.html',
+ '/help': 'help.html',
+ '/example': 'example.html',
+ '/service': 'service.html'
+ }
+
+ // 初始化模板缓存
+ this.templateCache = new Map()
+ this.cacheTemplates()
+ }
+
+ /**
+ * 缓存所有模板文件
+ */
+ cacheTemplates() {
+ try {
+ if (!fs.existsSync(this.templateDir)) {
+ console.warn(`[SEOMiddleware] 模板目录不存在: ${this.templateDir}`)
+ return
+ }
+
+ const files = fs.readdirSync(this.templateDir)
+ files.forEach(file => {
+ const filePath = path.join(this.templateDir, file)
+ if (fs.statSync(filePath).isFile()) {
+ this.templateCache.set(file, fs.readFileSync(filePath, 'utf-8'))
+ if (this.debug) {
+ console.log(`[SEOMiddleware] 已缓存模板: ${file}`)
+ }
+ }
+ })
+
+ console.log(`[SEOMiddleware] 已缓存 ${this.templateCache.size} 个模板文件`)
+ } catch (error) {
+ console.error('[SEOMiddleware] 缓存模板失败:', error)
+ }
+ }
+
+ /**
+ * 获取对应的模板文件名
+ * @param {String} path - 请求路径
+ * @returns {String} 模板文件名
+ */
+ getTemplatePath(requestPath) {
+ // 完全匹配
+ if (this.routeTemplateMap[requestPath]) {
+ return this.routeTemplateMap[requestPath]
+ }
+
+ // 模糊匹配(处理动态路由)
+ const matchedKey = Object.keys(this.routeTemplateMap).find(route => {
+ return requestPath.startsWith(route)
+ })
+
+ return matchedKey ? this.routeTemplateMap[matchedKey] : this.defaultTemplate
+ }
+
+ /**
+ * 获取模板内容
+ * @param {String} templateName - 模板文件名
+ * @returns {String|null} 模板内容
+ */
+ getTemplate(templateName) {
+ // 首先尝试缓存
+ let content = this.templateCache.get(templateName)
+
+ // 如果缓存中没有,尝试从磁盘读取
+ if (!content) {
+ try {
+ const filePath = path.join(this.templateDir, templateName)
+ if (fs.existsSync(filePath)) {
+ content = fs.readFileSync(filePath, 'utf-8')
+ this.templateCache.set(templateName, content)
+ }
+ } catch (error) {
+ console.error(`[SEOMiddleware] 读取模板失败: ${templateName}`, error)
+ }
+ }
+
+ return content || null
+ }
+
+ /**
+ * Express中间件
+ */
+ express() {
+ return (req, res, next) => {
+ // 检测是否为爬虫
+ if (this.detector.isCrawler(req)) {
+ const templateName = this.getTemplatePath(req.path)
+ const template = this.getTemplate(templateName)
+
+ if (template) {
+ // 设置响应头
+ res.setHeader('Content-Type', 'text/html; charset=utf-8')
+ res.setHeader('X-SEOMiddleware', 'prerendered')
+
+ // 返回静态HTML
+ if (this.debug) {
+ console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${req.path}`)
+ }
+
+ return res.send(template)
+ }
+ }
+
+ // 不是爬虫或模板不存在,继续处理SPA
+ next()
+ }
+ }
+
+ /**
+ * Koa中间件
+ */
+ koa() {
+ return async (ctx, next) => {
+ // 检测是否为爬虫
+ if (this.detector.isCrawler(ctx.req)) {
+ const templateName = this.getTemplatePath(ctx.path)
+ const template = this.getTemplate(templateName)
+
+ if (template) {
+ ctx.type = 'text/html; charset=utf-8'
+ ctx.set('X-SEOMiddleware', 'prerendered')
+
+ if (this.debug) {
+ console.log(`[SEOMiddleware] 返回SEO模板: ${templateName} for ${ctx.path}`)
+ }
+
+ ctx.body = template
+ return
+ }
+ }
+
+ await next()
+ }
+ }
+
+ /**
+ * 重新加载模板缓存
+ */
+ reloadCache() {
+ this.templateCache.clear()
+ this.cacheTemplates()
+ console.log('[SEOMiddleware] 模板缓存已重新加载')
+ }
+}
+
+module.exports = SEOMiddleware
diff --git a/server/package.json b/server/package.json
new file mode 100644
index 0000000..dbb7c3e
--- /dev/null
+++ b/server/package.json
@@ -0,0 +1,27 @@
+{
+ "name": "tydata-seo-server",
+ "version": "1.0.0",
+ "description": "SPA SEO 优化 - 爬虫检测与静态 HTML 回退,与 useSEO.js 同步",
+ "main": "server-example-express.js",
+ "scripts": {
+ "start": "node server-example-express.js",
+ "dev": "node server-example-express.js",
+ "generate": "node generate-seo-templates.cjs",
+ "test": "node test-seo.js",
+ "test:crawler": "node test-crawler-detection.js"
+ },
+ "keywords": [
+ "seo",
+ "crawler",
+ "spa",
+ "prerender"
+ ],
+ "license": "MIT",
+ "dependencies": {
+ "express": "^4.18.2",
+ "compression": "^1.7.4"
+ },
+ "devDependencies": {
+ "nodemon": "^3.0.1"
+ }
+}