Skip to content

渲染模式

Nuxt 支持多种渲染模式,可以根据不同页面的需求灵活选择。理解渲染模式是理解 Nuxt 的关键——它直接决定了你的网站在 SEO、性能、用户体验上的表现。

为什么要关心渲染模式?

不同的渲染模式,用户体验完全不同:

你遇到的问题可能是渲染模式选错了
搜索引擎搜不到我的网站用了 CSR,爬虫看不到内容
用户打开页面看到白屏很久没用 SSR,JS 要先下载完才能显示
后台管理系统不需要 SEO不需要 SSR,用 CSR 更轻量
服务器压力太大可能需要 SSG 或缓存策略

一句话总结

渲染模式决定了"页面内容在哪里生成"——在服务器上(SSR)、在浏览器里(CSR)、还是构建时就生成好(SSG)。

通用渲染(SSR)

默认模式,页面在服务端渲染为 HTML,发送到客户端后再进行 Hydration。

工作流程

text
1. 用户请求 → 2. 服务端渲染 HTML → 3. 发送 HTML 到浏览器

4. 页面显示 ← 5. Hydration(激活交互)

逐步理解

  1. 用户请求:用户在浏览器输入 URL 或点击链接
  2. 服务端渲染:Nuxt 在服务器上执行 Vue 组件,生成完整的 HTML
  3. 发送 HTML:服务器把 HTML + JS + 数据(payload)发送给浏览器
  4. 页面显示:浏览器收到 HTML 后立即显示(用户已经能看到内容了)
  5. Hydration:浏览器下载 JS 后,把静态 HTML "激活"为可交互的 Vue 应用

为什么叫"Hydration"(水合)?

就像干海绵吸水后变得有弹性——静态 HTML(干海绵)加上 JavaScript(水),页面就变得可交互了。

优势

  • 更快的首屏加载:用户看到 HTML 就有内容,不用等 JS
  • 更好的 SEO:搜索引擎爬虫能抓取完整内容(不是空 HTML)
  • 更好的无障碍支持:屏幕阅读器能读到内容
  • 低性能设备也能快速显示:渲染在服务器完成,不消耗用户设备性能

配置

ts
// nuxt.config.ts(默认就是 SSR,不写也行)
export default defineNuxtConfig({
  ssr: true,
})

大多数项目用 SSR 就对了

它是 Nuxt 的默认模式,也是 Nuxt 存在的意义——如果没有 SSR 需求,用 Vue 就够了。

客户端渲染(CSR)

页面仅在浏览器中渲染,服务端返回空 HTML。

工作流程

text
1. 用户请求 → 2. 服务器返回空 HTML + JS → 3. 浏览器下载 JS

4. 页面空白 ← 等待 JS 执行 ← 5. JS 执行完毕,页面渲染

CSR 的问题

  • 用户在 JS 加载完之前看到的是空白页面
  • 搜索引擎爬虫看到的也是空白页面(虽然 Google 爬虫能执行 JS,但效果不如 SSR)
  • 低端设备(手机)上 JS 执行可能很慢

适用场景

  • 不需要 SEO 的应用(后台管理系统)
  • 重交互的应用(在线编辑器、游戏)

配置方式

全局禁用 SSR:

ts
export default defineNuxtConfig({
  ssr: false,
})

特定路由禁用 SSR:

ts
export default defineNuxtConfig({
  routeRules: {
    '/admin/**': { ssr: false },      // 管理后台用 CSR
    '/dashboard/**': { ssr: false },   // 仪表盘用 CSR
  },
})

最佳实践

不要全局禁用 SSR,只对不需要 SEO 的路由禁用。这样首页、博客等需要 SEO 的页面仍然是 SSR。

混合渲染

不同路由使用不同渲染策略,通过 routeRules 配置:

ts
export default defineNuxtConfig({
  routeRules: {
    // 首页:SSR + 缓存 1 小时(SWR)
    '/': { swr: 3600 },

    // 博客列表:SSR + 缓存 1 小时
    '/blog/**': { swr: 3600 },

    // 博客文章:ISR,60秒后重新验证
    '/blog/**': { isr: 60 },

    // 管理后台:纯 CSR
    '/admin/**': { ssr: false },

    // API:允许跨域
    '/api/**': { cors: true },

    // 旧页面:重定向
    '/old-page': { redirect: '/new-page' },

    // 静态预渲染
    '/about': { prerender: true },
  },
})

混合渲染是 Nuxt 的核心优势

——你不需要为整个网站选择一种渲染模式,不同页面可以用不同的策略。

routeRules 选项详解

选项类型说明典型用途
ssrboolean是否启用 SSR后台页面设 false
swrnumber | booleanStale-While-Revalidate 缓存秒数内容不常变的页面
isrnumber | booleanIncremental Static Regeneration博客文章等定时更新的内容
prerenderboolean构建时预渲染关于页等不变的内容
redirectstring重定向目标旧 URL 迁移到新 URL
corsboolean启用 CORSAPI 跨域访问
headersobject自定义响应头安全头、缓存策略

SWR vs ISR 的区别

特性SWRISR
全称Stale-While-RevalidateIncremental Static Regeneration
工作方式先返回缓存,后台更新等缓存过期后重新生成
用户体验总是能快速看到内容过期后可能短暂等待
适合需要快速响应的页面可以容忍短暂过期的页面

简单记忆

SWR = "先给旧的,再更新";ISR = "过期了就重新生成"。

静态站点生成(SSG)

构建时生成所有页面的静态 HTML:

bash
npx nuxt generate

SSG 和 SSR 的区别

特性SSRSSG
何时生成 HTML每次用户请求时构建时一次性生成
内容更新实时需要重新构建
服务器需要 Node.js 服务器不需要,纯静态文件
部署需要服务器任何静态托管(GitHub Pages 等)
适合内容经常变化的网站内容不常变化的网站

SSG 的最大优势

不需要服务器!你可以把生成的静态文件放到 GitHub Pages、Cloudflare Pages 等免费托管平台上。

ts
export default defineNuxtConfig({
  // 可以配合 routeRules 做部分预渲染
  routeRules: {
    '/api/**': { cors: true },
  },
})

边缘渲染(ESR)

在边缘节点(CDN)上运行服务端渲染:

ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare-pages',  // 或 'vercel-edge'
  },
})

什么是"边缘"?

传统架构中,你的服务器在某个固定位置(如美国)。亚洲用户访问时,请求要跨越太平洋,延迟很高。"边缘"指的是全球分布的 CDN 节点——用户访问时,由离他最近的节点处理,速度更快。

部署方式服务器位置延迟
传统服务器固定位置(如美国)亚洲用户可能 200ms+
边缘渲染全球节点通常 < 50ms

支持的边缘预设:

  • cloudflare-pages
  • vercel-edge
  • netlify-edge
  • deno-deploy

渲染模式对比

特性SSRCSRSSG混合
首屏速度最快按需
SEO✅ 优秀❌ 差✅ 优秀按需
动态内容
服务器负载
部署难度需要服务器需要服务器纯静态按需
适用场景通用后台博客/官网全场景

渲染模式选择指南

text
需要 SEO?
├── 是 → 内容变化频繁?
│   ├── 是 → SSR 或混合渲染(SWR/ISR 缓存)
│   └── 否 → SSG(nuxt generate,最简单最便宜)
└── 否 → 重交互?
    ├── 是 → CSR(ssr: false)
    └── 否 → SSR(默认就好)

独立开发者建议

  • 博客/官网 → SSG(免费部署,不需要服务器)
  • 全栈应用 → SSR(需要数据库、用户系统等)
  • 管理后台 → 混合渲染(公开页面 SSR,后台 CSR)
  • 不确定 → 先用默认 SSR,后面再调整

常见问题

Hydration 不匹配警告

text
[Vue warn]: Hydration mismatch

这意味着服务端渲染的 HTML 和客户端渲染的结果不一致。常见原因:

  • 在模板中使用了 Date.now()Math.random()
  • 在服务端和客户端有不同的条件判断
  • 使用了浏览器 API(如 window.innerWidth

解决方案:把这些代码放在 onMounted 中或用 <ClientOnly> 包裹。

SSG 构建很慢

如果页面很多(如几千篇文章),nuxt generate 会很慢。解决方案:

  1. 使用 ISR 代替全量 SSG
  2. 使用 routeRules 只预渲染关键页面
  3. 使用增量生成(只生成变化的页面)

基于 Nuxt 4 官方文档整理编写