SSG:避免动态路由页面 SSG 意外降级为 SSR
在 Next.js 项目中实现 SSG(Static Site Generation)时,使用了 generateStaticParams,动态路由页面也一定会在构建阶段生成静态页面。
如果页面中混入了依赖请求上下文的逻辑,例如错误地在 SSG 页面中使用了 @supabase/ssr 的 createServerClient,那么原本应该静态生成的页面,可能会悄悄退化为动态渲染(SSR / 按需渲染),最终导致:
- 构建时没有真正输出静态页面
- 页面预取(prefetch)返回 404
- SEO 和首屏性能受到影响
generateStaticParams看起来写了,但实际上没有生效
1. 问题现象
最开始发现的问题是:
动态路由页面在客户端进行 prefetch 时返回了 404。
例如课程页和课时页虽然使用了动态路由,但在页面跳转前预加载资源时,发现并没有命中已生成的静态页面,这通常意味着这些页面并没有在构建阶段正确输出。
后来尝试临时添加:
export const dynamic = "force-static";
发现页面行为开始接近预期。
这说明问题并不在 generateStaticParams 本身,而是页面中的某些逻辑影响了渲染模式,导致原本应该走 SSG 的页面,被 Next.js 判定成了动态页面。
2. 根本原因
继续回溯后发现,问题出在页面的数据查询客户端上。
这是因为 createServerClient 的设计初衷是为了处理基于 Cookie 的身份验证(SSR 场景),它依赖于 Next.js 的 cookies() 函数。但在 SSG 模式下(即执行 next build 时),这些函数不可用。
对于 SSG 页面,应该直接使用原生 @supabase/supabase-js 提供的 createClient。这个客户端不依赖于请求上下文(Cookies),非常适合在构建阶段获取公共数据。
操作: 创建 /lib/supabase/static.ts 之后在SSG页面中使用静态客户端
3. 验证是否生效
-
运行
pnpm build时观察构建输出● /[courseSlug] │ ├ /raytonx-learn-from-zero │ └ /supabase-fundamentals ├ ● /[courseSlug]/lessons/[lessonSlug] │ ├ /supabase-fundamentals/lessons/why-supabase │ ├ /raytonx-learn-from-zero/lessons/raytonx-learn-start-up │ ├ /raytonx-learn-from-zero/lessons/email-auth-nextjs-supabase │ └ [+6 more paths] -
部署后,观察 prefetech 是否正常