Skip to content

在 EdgeOne 上做 CMS

目标:整站一个域名、功能有机结合、统一管理(装了哪些插件、什么显示什么不显示、 访问数据、SEO)。形态是 CMS + 插件,但不跑在 VPS 上,跑在 EdgeOne 边缘。


一、先说清楚缺了什么

@magireco/kernel浏览器那一半。它管交互:点一下唤起 ADV、点一下显示精灵。

CMS 还需要边缘那一半——路由、服务端渲染、SEO 元信息。原因很硬:

2,400 多个页面(725 篇剧情 + 241 个角色 + 1,404 条记忆结晶)的内容如果只在 浏览器里由插件渲染,爬虫看到的是空壳。Google 勉强能跑 JS,百度基本不行—— 而中文资料站的主要流量来源恰恰是百度。

所以插件要有两半,由同一个插件 id 绑在一起:

插件 adv-player
 ├─ 边缘半边(@magireco/site)  路由 /story/:id、SSR、meta、sitemap 条目
 └─ 浏览器半边(@magireco/kernel)能力 adv.play、surface 挂载、进度回流

后台一个开关同时管住两边——这是「统一管理」在代码上的落点:

关掉 adv-player结果
边缘/story/:id 返回 404(reason: 'plugin-disabled'),且不进 sitemap
浏览器剧本行上的播放按钮消失,剧本照常可读

两半各写一套开关,迟早出现「后台显示关着,页面还在」这种查不出来的状态。 本包的 site.test.ts 里有一个测试专门钉这件事。


二、EdgeOne 上的落点

CMS 部件落在哪备注
内容页静态导出(现状)见 §二·五:静态导出读不到 KV
动态行为 / 后台 / 下架兜底Pages FunctionsKV 仅在边缘函数内可用
站点配置(插件开关、导航、SEO)KV后台写、边缘读
下架清单Blob(强一致模式)见下节,不能放 KV
资源字节Blob 或 COS + CDN20 GiB 量级
权威内容(交叉表、策略、契约)git人工核对过的判断,需要 review 与历史
后台鉴权会话KV短 TTL
访问统计Functions 写 KVEdgeOne 官方有 PV 计数模板
缓存失效cacheTags + 主动 purge见第四节

🔴 KV 是最终一致的,最长 60 秒

官方文档写明:KV 采用中心存储 + 边缘缓存,其它边缘节点最长 60 秒才看到新值

对导航、SEO 文案、插件开关,这没问题——晚一分钟生效无所谓。

只有一件事不能等:下架。 版权方来函时那 60 秒是实打实的暴露窗口。 所以 TakedownList 单独一份、单独一条读取路径,走 Blob 的强一致模式, 代价是需要判定下架的请求多一次强一致读。

这不是洁癖:同类项目里已经出现过因为这种压力而退役公开站的先例, 仓库里有一份 TAKEDOWN.md。下架能力是这个站的必备件,不是可选件。

其它已知限额

KV 单值25 MB
KV 键名512 字节
KV 账号总容量1 GB(免费额度)
KV 命名空间10 个/账号
list() 分页默认 256 条
KV 可用范围仅边缘函数内

这些数字取自 EdgeOne Pages 官方文档页。开工前仍需在控制台复核一次—— 见 docs/CONSTRAINTS.md


二·五、🔴 静态导出与 KV 不兼容——这条要先解决

apps/station 现在是 Next.js 静态导出next buildout/,CI 已在看着)。 而官方文档写明 KV「仅支持在边缘函数内使用」

两件事放一起就是一个硬矛盾:

静态导出的页面在构建时就定型了,请求到来时没有任何代码在跑, 因此读不到 KV。后台改一个插件开关,静态页面不会知道。

三条出路,各有代价:

做法开关生效速度SEO代价
A纯静态:配置在构建期烘焙一次重建+部署(分钟级)✅ 真 HTML后台变成「生成一个配置提交并触发构建」,不是即时开关
B全部改 Functions/SSR秒级(KV 60 秒最终一致)放弃静态导出;每请求都要算,成本与冷启动
C混合(建议)见下多几个活动部件

建议走 C,分工如下

内容交付方式配置从哪来
2,400 个内容页(角色/剧情/记忆结晶)静态导出构建期烘焙。它们的内容本来就来自交叉表与清单,本就该构建期定型
插件开关、导航、SEO 文案静态页 + 构建期烘焙;后台改动触发重建KV 存的是「下次构建要用的值」
浏览器侧的能力门禁客户端启动时向一个 Function 端点拉当前配置KV,秒级
下架EdgeOne 规则引擎按路径 404/跳转 + 缓存 purgeBlob 强一致
后台、鉴权、统计FunctionsKV

为什么下架不能靠重建

静态页已经在边缘缓存里了,重建要几分钟。收到通知时的正确动作是 立刻让那条路径不可达——那只能由请求路径上的东西做,也就是 EdgeOne 的规则引擎或一个前置 Function,配合缓存 purge。

packages/siteTakedownListisTakenDown() 因此有两个消费者: 构建期(把下架的页排除出 sitemap 与产物)与请求期(规则/Function 兜住漏网的缓存副本)。 两处都要,缺一个都有窗口。

这条的落地顺序

先确认 EdgeOne 的缓存 purge 是否支持按 tag(待验证项 3)。 只支持按 URL 的话,rev: 标签方案要换成版本化路径(如 /_v7/character/1001 再由规则重写),那会改变整个 URL 设计——必须在铺开内容页之前定下来


三、内容模型:不要做内容编辑器

这个站的内容 95% 是生成的,不是编辑出来的

交叉表(git)+ 资源清单(Blob)

        │ 边缘插件的 render()

   角色页 / 剧情页 / 记忆结晶页   ← 2,400+ 个,没有一个是人写的

真正需要人编辑的只有四类,全都是配置而不是内容:

  1. 站点设置(站名、导航、SEO 模板)
  2. 插件开关
  3. 个别页面的 SEO 覆盖(overrides['/character/1001'] = { title, description }
  4. 下架清单

所以 SiteConfig 里没有 posts / pages 这类表。内容是管道产物,配置才是内容管理。 这省掉了 CMS 里最重最容易做歪的一块(编辑器、草稿、版本、发布流)。

要发公告或写「关于」页怎么办?——那是一个插件pages 插件, 内容放 git 的 Markdown,构建时进 Blob),不是往核心里加一张表。


四、缓存失效才是真正的难点

边缘 CMS 的坑不在渲染,在改了东西之后旧页面还在

本包的做法:每个渲染结果带 cacheTags

ts
cacheTags: ['mr:scenario/310241', 'rev:7']
  • mr:scenario/310241 —— 内容标签。这篇剧情更新/下架时按此 purge。
  • rev:7 —— 配置版本号,每次后台保存自增。改了任何设置, 所有旧页面的标签集就整体失效,不必逐页记住谁受影响。

第二条是关键。没有它,「改了标题模板,为什么只有一半页面变了」会成为常驻问题。


五、SEO 的具体做法

要素由谁产出
<title> / descriptionresolveMeta():页面标题套 titleTemplate,覆盖项优先
canonicalcanonicalOrigin + 路径,防止同内容多路径
robots三层叠加,见下
JSON-LD插件在 meta.jsonld 里给,</ 已转义防脚本提前闭合
sitemap.xmlsite.sitemap():枚举开着的插件 × 可索引 × 未下架
robots.txtsite.robots():全站关索引时不再递 sitemap

索引默认是 selective,不是 all

ts
indexing: 'all' | 'none' | 'selective'   // 默认 selective

默认只索引显式登记的路径前缀。反过来(默认全收)意味着任何人加一条路由 都会顺带把它推给搜索引擎,而没人会在加路由时想到这件事

'none' 是总闸:收到通知时一键收缩整站可见面,页面级 index 也盖不过它。

一个必须由你决定的取舍

把 725 篇剧情正文做进索引,SEO 收益很大——但那是版权方的文本, 索引得越全,被发现得越快。这类公开站退役过不止一次。

方案默认的姿态是保守的(selective + 空前缀 = 什么都不索引), 把决定权留给你。要放开哪些前缀,是你的判断,不是我的。


六、后台

后台不是「一个面板」,是三件具体的事:

页面干什么后端
/admin/plugins插件开关、看每个插件提供什么能力、哪些 ref kind 没有提供者(缺口视图)KV
/admin/content下架开关、资源线路健康、清单版本Blob 强一致 + KV
/admin/seo索引模式、允许前缀、单页覆盖、sitemap 预览KV
/admin/analyticsPV/UV、热门页面KV 计数

「缺口视图」几乎免费:内核已有 plugins / providersFor / can, 列出哪些能力没人提供就是几十行。

鉴权:EdgeOne Functions + KV 会话。robots.txtDisallow: /admin/, 且后台路由一律 noindex——两道都要,因为 Disallow 只是请求,不是强制。


七、落地顺序

做什么前提
1一个 Pages Functions 入口 + Site 接上 KV 配置,跑通 /character/:id 的 SSR域名
2sitemap.xml / robots.txt / cacheTags purge步 1
3/admin/plugins + 鉴权,验证「一个开关两边都生效」步 1
4下架链路(Blob 强一致 + purge),在放开索引之前做完步 2
5资源搬迁到 Blob/COS,插件真正接上独立于 1–4
6PV 统计与热门页步 1

步 4 必须在放开索引之前。 先把内容推给搜索引擎、再去建下架能力, 顺序反了就是给自己挖坑。


待验证项

  1. Pages Functions 的 CPU 时间 / 内存 / 请求体上限(决定 SSR 能做多重)。
  2. Blob 强一致读的延迟与配额(下架链路的关键路径)。
  3. EdgeOne 的缓存 purge API 是否支持按 tag,还是只能按 URL / 前缀。 只能按 URL 的话,第四节的 rev: 标签方案要改成版本化路径。
  4. ICP 备案(国内加速必须)。

GPLv3。素材版权归各自的版权方所有,本站与本仓库不含任何素材。