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. 你将学到


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. 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。

📖 小节


📝 作业

  1. 基础题(难度⭐) 创建一个 Nuxt 3 项目:

    • 3 个页面(Home / About / Contact)
    • 1 个 API(/api/hello)
    • 顶部导航 + 底部布局
  2. 进阶题(难度⭐⭐) 实现 Nuxt 3 SSR 完整功能:

    • 5 个页面(首页 / 商品列表 / 详情 / 购物车 / 登录)
    • server/api 路由(/api/products)
    • useFetch 服务端预取
    • useHead 动态 SEO
    • Pinia 状态管理
  3. 挑战题(难度⭐⭐⭐) 实现完整的"企业级 Nuxt 3"项目:

    1. 10+ 页面(电商 + 后台 + 认证)
    2. 5 大 API 路由
    3. 3 种渲染模式(SSR / SSG / CSR 混合)
    4. SEO 优化(结构化数据 + Open Graph + sitemap)
    5. 性能优化(图片懒加载 / 代码分割 / CDN)
    6. 部署到 Vercel Edge
    7. 完整的 TypeScript 类型
Web-Tutorial.com

Web-Tutorial 技术团队

由多位开发者共同维护的编程教程平台。每篇教程由对应领域的开发者编写和审核,确保内容准确可靠。如发现任何问题,欢迎向我们反馈。

100%

🙏 帮我们做得更好

我们是刚上线的编程教程站,几个人的小团队,精力有限。页面虽经检查,难免还有疏漏——链接失效、排版错乱、内容有误、语言生硬……

如果您发现了,麻烦告诉我们,我们会在收到反馈后第一时间进行修复,再次感谢您的光临 🙏