第一棒不只有"请求来了现跑"一种跑法。本节讲三种变奏:构建期把页面提前跑完(SSG)、缓存后按间隔再生(ISR 与 SWR)、以及用 routeRules 给全站逐页配棒(混合渲染)。它把 1.2 的选型表落成可执行的配置,并为第 9 章的部署决策提供依据。
nuxt generate 触发静态生成:Nuxt 从首页出发做爬取,把能发现的路由逐个渲染成 HTML 文件,连同静态资源一起产出。部署时不需要 Node 服务器,任何静态托管都能跑。
页面清单有两个来源:
// nuxt.config.ts export default defineNuxtConfig({ // 来源一:routeRules 显式声明要预渲染的路径 routeRules: { '/': { prerender: true }, '/about': { prerender: true }, }, // 来源二:nitro.prerender.additionalRoutes 补充爬虫发现不了的路径 nitro: { prerender: { additionalRoutes: ['/products/1', '/products/2'], // 动态路由要手工报备 crawlLinks: true, // 从已发现页面沿链接继续爬(默认开) }, }, })
动态路由是 SSG 的经典坑:products/[id].vue 有无数可能的 id,爬虫无从枚举,必须通过 additionalRoutes、sitemap 或一个返回路径清单的数据源显式报备。构建日志里会列出每个预渲染页面的状态,看到 503 或超时通常是页面在构建期请求了不可达的接口。
纯 SSG 的死穴是内容更新要重新构建。两条折中路:
routeRules: { // 商品页:SWR,缓存十分钟内直接回,过期后台再生 '/products/**': { swr: 600 }, // 文档页:ISR,每小时再生一次 '/docs/**': { isr: 3600 }, }
两者的微妙差别在于触发方式:swr 依赖 Nitro 内置缓存(可配 Redis 等存储后端,多实例部署时共享缓存),isr 则面向支持该语义的托管平台。中小项目多数场景用 swr 即可,其缓存行为完全在你的应用内可控。

在实验项目里加一个时间页面,肉眼观察缓存:
<!-- pages/now.vue --> <script setup> // 服务端渲染时生成的时间戳,用来判断这版 HTML 是何时产的 const { data } = await useFetch('/api/now') </script> <template> <div> <p>服务器认为现在是:{{ data.now }}</p> <p>刷新几次,看这个时间多久变一次</p> </div> </template>
// server/api/now.get.ts:返回服务器当前时间 export default defineEventHandler(() => ({ now: new Date().toISOString() }))
配置 /now: { swr: 10 } 后反复刷新:十秒内时间不变(命中缓存),过十秒先返回旧值、下一次刷新变成新值(后台再生完成)。把规则改成 ssr: true(默认),每次刷新时间都变。这个五分钟实验胜过十页文档。
预渲染跑完别急着发布,先验收产物。打开 .output/public,核对三件事:预期的 HTML 文件都在(对照 additionalRoutes 与爬虫清单,缺页通常是构建期接口失败,日志里搜错误);HTML 内容正确(抽查两三个页面,动态路由的参数渲染进了正文而不是空壳);内部链接可达(页面里的站内链接对应的目标文件存在,死链会同时伤用户与爬虫)。
回滚预案同样重要:静态产物的好处是版本即目录,保留前几版的产物(构建号命名),出问题时 CDN 或静态服务器切回旧目录即可,秒级完成。这比 SSR 应用的回滚(重新部署进程)轻得多——静态形态的运维红利,一半在发布、一半在回滚。
ISR/SWR 的回滚有个额外注意点:缓存里可能存着"坏版本"的页面,切回旧代码后要把缓存一并清掉,否则用户继续看到坏内容而你以为已经修好了。Nitro 的 storage 按命名空间组织,清理时按业务前缀批量删,别全量清缓存(会把无害的热缓存也干掉,流量洪峰直接砸到源站)。
⚠️ 常见坑:给带查询参数的页面配 swr。默认缓存键不含 query,
/search?kw=a与/search?kw=b可能命中同一份缓存,用户搜 A 看到 B 的结果。此类页面要么保持 SSR,要么在缓存键里显式纳入 query。
💡 关键直觉:routeRules 是"渲染模式的路由表"——先列全站路由清单,逐条问 1.2 的三问(谁渲染/何时/数据何时取),答案写进这张表,渲染架构就定稿了。