一款契合 Next.js 而非与之对抗的无头 CMS
草稿模式、ISR、App Router 与渲染层。当你把无头 CMS 接入 Next.js 时,真正要紧的是什么——以及它出错的三种方式。
在这个话题上,Google 的自动补全格外一致地反映了人们的诉求。出现频率最高的三条建议是:
best headless cms for next jsfree headless cms for nextjsnextjs headless cms open source
免费、开源,且专为 Next.js 而生。本文讨论的是:当你有了这样一份候选清单之后,真正拉开差距的是什么——因为关键的区别不在于 SDK,而在于请求到达时内容到底身处何处。
两种架构,以及区分它们的那一个问题
在你的应用内部。 Payload 运行在 Next.js 应用本身之中。你会得到一个完全跳过 HTTP 的本地 API、配置即代码,以及单次部署。对于单个产品来说,这是极佳的开发体验。
代价是耦合:CMS 与网站共享同一次部署、同一个运行时、同一个扩缩容单元。公共站点上的流量高峰,也就是你的编辑们正在使用的那个系统上的高峰;而更换前端框架也不再只是一个前端项目。
在你的应用旁边。 Strapi、Directus、Sanity、corpusctl。CMS 是一个独立的服务。你通过网络获取内容,这意味着你现在要自己承担一个缓存决策。
而这个缓存决策,就是整个集成的全部:
当访客请求一个页面时,内容来自何处——又允许它有多陈旧?
本文其余的一切,都由你对这个问题的回答推导而来。
团队回答它的三种方式
每次请求都拉取。 简单且正确,但你的 CMS 如今就处在每一次页面加载的关键路径上。它的延迟就是你的 TTFB,它的宕机就是你的宕机。对管理后台来说没问题,对营销站点来说则是错的。
带时间窗口的 ISR。 revalidate: 60,内容至多陈旧一分钟。这行得通,但它意味着编辑在发布后要盯着时钟,而且每一次窗口到期都是一次要有人买单的缓存未命中。
预先构建,从缓存供给。 内容在发布时渲染完成,并作为静态产物供给。这是最快也最省钱的——只要有某个环节在内容变更时负责失效处理。
大多数团队从第一种起步,当账单或延迟开始刺痛时转向第二种,最终通过把按需重新验证接到 webhook 上而抵达第三种。
失效难题,以及如何从根本上绕开它
第三种是对的,而它的难点在于缓存失效:页面是某次计算的一份副本,而这次计算随时可能改变。
corpusctl 不是去管理这个问题,而是通过让地址本身不可变来消除它。
发布会触发构建流水线:内容经过校验、渲染,并写入对象存储中的一个哈希寻址文件,随后刷新清单(manifest)。客户端在本地把 slug 解析到某个清单分片,再从 nginx 边缘缓存中获取那个地址。
由于地址是一个内容哈希: