解释文档站点如何在保持 CMS 编辑模式功能的同时实现快速的静态页面加载
本指南解释了文档站点如何在保持 CMS 编辑模式功能的同时实现快速的静态页面加载。
我们为同一份内容使用两条路由:
app/
├── [...slug]/page.tsx # 生产环境:force-static(快速)
└── preview/[...slug]/page.tsx # 编辑模式:force-dynamic(读取 searchParams)
一个代理中间件会透明地重写编辑模式请求:
用户请求:/en/headless/quickstart?edit_mode=true
↓
代理检测到 ?edit_mode=true
↓
内部重写为:/preview/en/headless/quickstart?edit_mode=true
↓
动态路由会携带编辑包装进行渲染
用户永远不会在其 URL 中看到 /preview —— 这只是一次内部重写。
// app/[...slug]/page.tsx
export const dynamic = 'force-static';
export const revalidate = 60;
export default async function Page({ params }) {
// 无 searchParams —— 页面完全静态
return <
// app/preview/[...slug]/page.tsx
export const dynamic = 'force-dynamic';
export default async function PreviewPage({ params, searchParams }) {
// searchParams 可用,可检测 edit_mode
return <ParametricRoutePage params={params}
?edit_mode=true// src/proxy.ts
export const proxy = async (request: NextRequest) => {
const { pathname, searchParams } = request.nextUrl;
const editMode = searchParams.get('edit_mode');
| 场景 | 响应时间 | 渲染 |
|---|---|---|
| 生产页面(缓存命中) | ~50-100ms | 来自 CDN 的静态内容 |
| 生产页面(缓存过期) | ~50-100ms + 后台刷新 | 静态,然后 ISR |
| 编辑模式 | ~500-1500ms | 动态 SSR |
revalidate = 60 设置启用了 ISR。这并不意味着页面每隔 60 秒重新计算。
ISR 使用 stale-while-revalidate 模式:
请求到来:
→ 缓存页面是否小于 60 秒?→ 从缓存提供(即时)
→ 缓存页面是否超过 60 秒?→ 提供过期缓存(即时)
+ 在后台重新验证供下一次请求使用
没有请求 = 永不重新计算。
示例:
60 秒窗口只是安全保障。理想情况下,我们会在 CMS 内容变更时通过 Webhook 触发按需重新验证。
| 使用场景 | URL | 使用的路由 |
|---|---|---|
| 正常浏览 | /en/headless/quickstart | 静态 |
| CMS 模板构建器 | /en/headless/quickstart?edit_mode=true | 预览(通过重写) |
| AI 区块预览 | /en/headless/quickstart?ai_preview=1 | 预览(通过重写) |
这种简单方法(没有 force-static,也没有预览路由)虽然可行,但速度很慢:
// 简单方法 —— 可用,但每个请求约 1-2 秒
export default async function Page({ params, searchParams }) {
return <ParametricRoutePage params={params} searchParams={searchParams} />;
}
这会在每次请求时进行动态渲染。对于拥有大量页面的文档站点来说,这意味着:
双路由架构让我们兼得两者:为读者提供静态速度,为编辑者提供动态功能。