Vue.js: SSR/SSG 与 Nuxt
最后更新:2026-08-26
SSR(服务端渲染)和 SSG(静态生成)是 Vue 应用的进阶部署方式——比 CSR(客户端渲染)首屏更快、SEO 更好。Nuxt 3 是 Vue 3 的 SSR 框架,提供了开箱即用的路由、状态管理、SEO 优化。
理解 CSR/SSR/SSG 三种渲染模式能让你根据场景选择正确的部署方式。本课帮你建立 SSR/SSG 知识体系。
1. 你将学到
- CSR vs SSR vs SSG 三大渲染模式对比
- 5 大 SSR 适用场景
- Nuxt 3 完整目录结构
- Nuxt 3 组合式 API(useState / useFetch / useAsyncData)
- Nuxt 自动导入 + 文件路由
- Nuxt 模块生态(@nuxtjs/tailwindcss 等)
- 5 个常见错误
2. 一个 Vue SPA 的"首屏 5 秒"尴尬
(1) 痛点:CSR 首屏慢 + SEO 抓不到内容
Alice 的 Vue SPA 遇到了问题:
TEXT
📖 仅展示
传统 Vue SPA(CSR):
1. 浏览器请求 → 返回空 HTML(<div id="app"></div>)
2. 下载 JS(500KB)
3. 执行 JS(Vue 启动)
4. 渲染内容
5. 用户看到内容
首屏时间:3-5 秒
SEO:Google 抓不到内容(spa 内容是 JS 渲染的)
产品经理 Charlie:
"Alice,我们的 Google 排名很差。需要服务端渲染 HTML,让搜索引擎能索引内容。还要更快的首屏。"
(2) Nuxt 3 SSR 解法
TEXT
📖 仅展示
Nuxt 3 SSR:
1. 浏览器请求 → 服务端渲染完整 HTML
2. 返回带内容的 HTML(首屏 0.5 秒)
3. 下载 JS(hydration 所需)
4. 客户端"激活"(接管交互)
首屏时间:0.5 秒
SEO:✅ 完美(HTML 包含内容)
JS
// server/api/products.js(Nuxt 3 自动路由)
export default defineEventHandler(async (event) => {
return await $fetch('https://api.example.com/products')
})
VUE
<!-- pages/products.vue(自动路由) -->
<template>
<div>
<ProductCard v-for="product in products" :key="product.id" :product="product" />
</div>
</template>
<script setup lang="ts">
// useFetch 在服务端预取数据
const { data: products } = await useFetch('/api/products')
</script>
(3) 收益
迁移到 Nuxt 3 SSR 后:
- 首屏时间:3-5s → 0.5s(-90%)
- SEO 评分:60 → 95(+35)
- Google 收录:0 页 → 全部 5,000 SKU 页面(+∞)
- 社交分享:0 卡片 → 完整预览(Open Graph)
3. CSR vs SSR vs SSG
(1) 3 大渲染模式
| 模式 | 渲染时机 | 首屏 | SEO | 服务器压力 |
|---|---|---|---|---|
| CSR(客户端渲染) | 浏览器 | 慢(3-5s) | ❌ 差 | 低 |
| SSR(服务端渲染) | 每次请求 | 中(0.5-1s) | ✅ 好 | 高 |
| SSG(静态生成) | 构建时 | **快(0.1-0.5s) | ✅ 完美 | 最低 |
(2) 5 大 SSR 适用场景
| 场景 | 推荐模式 |
|---|---|
| 内容站(博客 / 文档 / 营销页) | SSG(最快 + SEO 完美) |
| 电商商品详情(5,000 SKU) | SSR(实时数据 + SEO) |
| SaaS 后台(登录后) | CSR(不需要 SEO) |
| 社交平台(动态内容) | SSR(实时 + SEO) |
| 个人博客(少量内容) | SSG(最简单) |
(3) 5 大 SSG 优势 vs SSR
| SSG 优势 | SSR 优势 |
|---|---|
| 速度最快(CDN 直出) | 实时数据(每次请求) |
| 服务器压力最低 | 登录状态个性化 |
| 无限扩展(CDN) | 适合动态内容 |
| 构建后无需服务器 | 适合交互式应用 |
| Netlify / Vercel 免费托管 | Node.js 服务器 |
4. Nuxt 3 基础
(1) 创建项目
BASH
npx nuxi@latest init my-nuxt-app
cd my-nuxt-app
npm install
npm run dev # 默认 http://localhost:3000
(2) 完整目录结构
TEXT
📖 仅展示
my-nuxt-app/
├── assets/ # 资源(图片、字体)
│ └── css/
│ └── main.css
├── components/ # 公共组件
│ ├── AppHeader.vue
│ └── AppFooter.vue
│ └── product/
│ └── ProductCard.vue # 嵌套目录自动注册
├── composables/ # 组合式函数
│ └── useAuth.ts
├── layouts/ # 布局
│ ├── default.vue # 默认布局
│ └── admin.vue # 后台布局
├── middleware/ # 路由中间件
│ └── auth.ts
├── pages/ # 文件路由(自动生成)
│ ├── index.vue # /
│ ├── about.vue # /about
│ ├── products/
│ │ ├── index.vue # /products
│ │ └── [id].vue # /products/:id
│ └── admin/
│ └── index.vue # /admin
├── plugins/ # Nuxt 插件
│ └── pinia.ts
├── public/ # 静态资源
├── server/ # 服务端代码
│ ├── api/ # API 路由(自动注册)
│ │ └── products.ts # /api/products
│ └── middleware/ # 服务端中间件
├── stores/ # Pinia stores
├── app.vue # 根组件
├── nuxt.config.ts # Nuxt 配置
└── package.json
(3) 文件路由(自动)
TEXT
📖 仅展示
pages/index.vue → /
pages/about.vue → /about
pages/products/index.vue → /products
pages/products/[id].vue → /products/:id
pages/admin/index.vue → /admin
无需配置路由表,文件即路由。
5. Nuxt 3 核心 API
(1) useFetch:服务端数据预取
VUE
<script setup lang="ts">
// useFetch 在 SSR 时服务端执行,CSR 时客户端执行
const { data, pending, error, refresh } = await useFetch('/api/products')
// 5 大返回值
// data: 响应数据
// pending: 加载中
// error: 错误信息
// refresh: 重新获取方法
// status: 状态码
</script>
(2) useAsyncData:通用异步数据
VUE
<script setup lang="ts">
const { data } = await useAsyncData('products', () =>
$fetch('/api/products')
)
// 选项:缓存、依赖、转换
const { data: users } = await useAsyncData(
'users',
() => $fetch('/api/users'),
{
cache: 'force-cache', // 强制缓存
default: () => [] // 默认值
}
)
</script>
(3) useState:跨组件 SSR 友好的状态
VUE
<script setup lang="ts">
// useState 替代 ref(SSR 友好)
const cart = useState('cart', () => ({ items: [], total: 0 }))
// 修改
cart.value.items.push(product)
</script>
(4) 5 大其他 composables
TS
// 1. useFetch:服务端数据预取
const { data } = await useFetch('/api/products')
// 2. useAsyncData:通用异步
const { data } = await useAsyncData('key', fetcher)
// 3. useState:全局状态(SSR 友好)
const user = useState('user', () => null)
// 4. useRoute:当前路由
const route = useRoute()
// 5. useRuntimeConfig:运行时配置
const config = useRuntimeConfig()
6. Nuxt 3 核心配置
(1) nuxt.config.ts
TS
export default defineNuxtConfig({
// 1. 模块
modules: [
'@nuxtjs/tailwindcss',
'@pinia/nuxt',
'@vueuse/nuxt'
],
// 2. CSS
css: ['~/assets/css/main.css'],
// 3. 运行时配置
runtimeConfig: {
apiSecret: 'xxx', // 服务端
public: {
apiBase: 'https://api.example.com' // 客户端
}
},
// 4. 渲染模式
ssr: true, // 启用 SSR
// 5. 应用配置
app: {
head: {
title: 'My App',
meta: [
{ name: 'description', content: 'My app description' }
]
}
}
})
(2) 自动导入(无需 import)
VUE
<script setup lang="ts">
// ✅ Nuxt 自动导入:
// - Vue 3 API(ref, computed, watch)
// - Nuxt 3 composables(useFetch, useState)
// - 组件(components/ 目录)
// - utils/ 目录
const count = ref(0)
const { data } = await useFetch('/api/products')
</script>
(3) SEO 自动优化
VUE
<script setup lang="ts">
useHead({
title: 'iPhone 15 Pro - My Shop',
meta: [
{ name: 'description', content: 'Buy iPhone 15 Pro at best price' },
{ property: 'og:title', content: 'iPhone 15 Pro' },
{ property: 'og:image', content: '/iphone.jpg' }
]
})
</script>
7. 完整示例:5 大 Nuxt 场景
▶ 示例:Nuxt 完整目录结构(⚠️ 需 Vite + Nuxt)
⚠️ Nuxt 3 是基于 Vite 的 SSR 框架,必须在 Node 服务端运行,CDN 不可用。展示核心结构:
TEXT
📖 仅展示
my-nuxt-app/
├── pages/ # 文件路由(自动生成)
├── components/ # 自动注册组件
├── composables/ # 自动导入
├── server/api/ # API 路由(服务端)
├── server/middleware/
├── middleware/ # 客户端中间件
├── plugins/ # Nuxt 插件
├── layouts/ # 布局
└── nuxt.config.ts # Nuxt 配置
▶ 示例:5 大核心 API(Nuxt 自动导入)
| API | 用途 |
|---|---|
useFetch |
服务端数据预取(SSR 友好) |
useAsyncData |
通用异步数据获取 |
useState |
全局状态(SSR 友好,自动序列化) |
useRoute |
当前路由信息 |
useRuntimeConfig |
运行时配置 |
▶ 示例:5 大 Nuxt 模块
TS
// nuxt.config.ts
export default defineNuxtConfig({
modules: [
'@nuxtjs/tailwindcss', // Tailwind CSS 集成
'@pinia/nuxt', // Pinia 状态管理
'@vueuse/nuxt', // VueUse 工具集
'@nuxt/image', // 图片优化
'nuxt-icon' // 图标系统
]
})
▶ 示例:5 大使用场景
| 场景 | Nuxt 方案 |
|---|---|
| 内容站 | SSG(nuxi generate) |
| 电商 | SSR(默认) |
| 后台 | CSR(ssr: false) |
| 全栈 | Nuxt + server/api |
| 静态博客 | SSG + Markdown |
▶ 示例:5 个常见错误速查
| 错误 | 现象 | 解决 |
|---|---|---|
| useFetch 数据不显示 | 没 await | 改成 const { data } = await ... |
| SSR 水合失败 | 数据不一致 | useState 替代 ref |
| 路由不工作 | 文件路径错 | 放 pages/ 目录 |
| 模块安装失败 | 名字错 | 检查 modules 拼写 |
| SEO 抓不到 | ssr: false | 启用 SSR |
❓ 常见问题
Q CSR / SSR / SSG 选哪个?
A 内容站(博客/文档)→ SSG。电商/社交 → SSR。后台/SaaS → CSR。Nuxt 3 三种都支持。
Q Nuxt 3 需要 Node 多少?
A Node 18+(2023-10 起)。Nuxt 2 还支持 Node 16。
Q useFetch vs useAsyncData?
A useFetch 是 useAsyncData 的语法糖(专门处理 fetch)。大多数情况 useFetch 就够。
Q Nuxt 3 vs Nuxt 2?
A Nuxt 3(2022-11)支持 Vue 3 + Vite + TypeScript 一等公民。Nuxt 2 仅维护。
Q SSG 怎么构建?
A
npx nuxi generate 生成 .output/public/ 目录,部署到 Netlify / Vercel / Cloudflare Pages。Q SSR 服务器压力大怎么办?
A 用 Nitro 服务器(Nuxt 内置)部署到 Vercel Edge / Cloudflare Workers / Node 集群。或降级到 SSG。
📖 小节
- CSR / SSR / SSG 三大渲染模式:CSR(3-5s 首屏)/ SSR(0.5-1s)/ SSG(0.1-0.5s)
- 5 大 SSR 适用场景:电商 / 社交 / 实时数据 / 登录状态 / 动态内容
- Nuxt 3 是 Vue 3 官方 SSR 框架
- 文件路由:pages/ 目录即路由
- 5 大核心 API:useFetch / useAsyncData / useState / useRoute / useRuntimeConfig
- 自动导入:Vue API + Nuxt composables + 组件 + utils
- Nuxt 模块生态:200+ 官方/社区模块
- SEO 自动优化:useHead 动态设置
📝 作业
-
基础题(难度⭐) 创建一个 Nuxt 3 项目:
- 3 个页面(Home / About / Contact)
- 1 个 API(/api/hello)
- 顶部导航 + 底部布局
-
进阶题(难度⭐⭐) 实现 Nuxt 3 SSR 完整功能:
- 5 个页面(首页 / 商品列表 / 详情 / 购物车 / 登录)
- server/api 路由(/api/products)
- useFetch 服务端预取
- useHead 动态 SEO
- Pinia 状态管理
-
挑战题(难度⭐⭐⭐) 实现完整的"企业级 Nuxt 3"项目:
- 10+ 页面(电商 + 后台 + 认证)
- 5 大 API 路由
- 3 种渲染模式(SSR / SSG / CSR 混合)
- SEO 优化(结构化数据 + Open Graph + sitemap)
- 性能优化(图片懒加载 / 代码分割 / CDN)
- 部署到 Vercel Edge
- 完整的 TypeScript 类型