用途
本技能用于在构建或调试 Nuxt 4 应用时提供模式指导,覆盖服务端渲染(SSR)、混合渲染、路由规则以及页面级数据获取等场景。
何时启用
- 服务端 HTML 与客户端状态之间出现水合不匹配(hydration mismatch)
- 需要做路由级渲染决策,例如 prerender、SWR、ISR 或仅客户端渲染区块
- 围绕懒加载、懒水合或 payload 体积进行性能优化
- 使用 useFetch、useAsyncData 或 $fetch 进行页面或组件数据获取
- 与路由参数、中间件或 SSR/客户端差异相关的 Nuxt 路由问题
水合安全
- 保持首次渲染的确定性。不要把 Date.now()、Math.random()、仅浏览器可用的 API 或存储读取直接放入 SSR 渲染的模板状态中。
- 当服务端无法产出相同标记时,将仅浏览器逻辑放到 onMounted()、import.meta.client、ClientOnly 或 .client.vue 组件之后。
- 使用 Nuxt 的 useRoute() 组合式函数,而不是来自 vue-router 的那个。
- 不要用 route.fullPath 驱动 SSR 渲染的标记。URL 片段(fragment)仅存在于客户端,可能造成水合不匹配。
- 把 ssr: false 视为真正仅浏览器区域的逃生舱,而不是水合不匹配的默认修复手段。
数据获取
- 在页面和组件中优先使用 await useFetch() 进行 SSR 安全的 API 读取。它会把服务端获取的数据转发到 Nuxt payload 中,避免水合时二次请求。
- 当 fetcher 不是简单的 $fetch() 调用、需要自定义 key,或需要组合多个异步来源时,使用 useAsyncData()。
- 为 useAsyncData() 提供稳定的 key,以便缓存复用和可预测的刷新行为。
- 保持 useAsyncData() 处理函数无副作用。它们可能在 SSR 和水合期间运行。
- 使用 $fetch() 处理用户触发的写入或仅客户端操作,而不是应从 SSR 水合的顶层页面数据。
- 对不应阻塞导航的非关键数据,使用 lazy: true、useLazyFetch() 或 useLazyAsyncData(),并在 UI 中处理 status === 'pending'。
- 仅对 SEO 或首屏不需要的数据使用 server: false。
- 用 pick 裁剪 payload 体积;当不需要深层响应式时,优先使用更浅的 payload。
示例代码:
const route = useRoute()
const { data: article, status, error, refresh } = await useAsyncData(
() => `article:${route.params.slug}`,
() => $fetch(`/api/articles/${route.params.slug}`),
)
const { data: comments } = await useFetch(`/api/articles/${route.params.slug}/comments`, {
lazy: true,
server: false,
})
路由规则
优先在 nuxt.config.ts 中使用 routeRules 定义渲染与缓存策略:
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/products/**': { swr: 3600 },
'/blog/**': { isr: true },
'/admin/**': { ssr: false },
'/api/**': { cache: { maxAge: 60 * 60 } },
},
})
- prerender:构建时生成静态 HTML
- swr:提供缓存内容并在后台重新验证
- isr:在支持的平台上进行增量静态再生成
- ssr: false:客户端渲染路由
- cache 或 redirect:Nitro 层级的响应行为
按路由分组选择路由规则,而不是全局统一。营销页、商品目录、仪表盘和 API 通常需要不同策略。
懒加载与性能
- Nuxt 已按路由对页面进行代码分割。在微优化组件拆分之前,先确保路由边界合理。
- 使用 Lazy 前缀动态导入非关键组件。
- 用 v-if 条件渲染懒加载组件,使 chunk 在 UI 真正需要时才加载。
- 对首屏以下或非关键的交互式 UI 使用懒水合。
示例代码:
<template>
<LazyRecommendations v-if="showRecommendations" />
<LazyProductGallery hydrate-on-visible />
</template>
- 自定义策略可使用 defineLazyHydrationComponent() 配合可见性或空闲策略。
- Nuxt 懒水合作用于单文件组件。向懒水合组件传入新 props 会立即触发水合。
- 使用 NuxtLink 进行内部导航,以便 Nuxt 预取路由组件和生成的 payload。
检查清单
- 首次 SSR 渲染与水合后的客户端渲染产出相同标记
- 页面数据使用 useFetch 或 useAsyncData,而不是顶层 $fetch
- 非关键数据为懒加载,并有明确的加载 UI
- 路由规则与页面的 SEO 和新鲜度要求匹配
- 重型交互孤岛(island)采用懒加载或懒水合