Skip to content

第9章:服务端渲染(SSR)与静态站点生成(SSG)

1. SSR 与 SSG 核心概念(区别与适用场景)

1.1 服务端渲染 (SSR)

概念:服务端渲染是指在服务器端生成 HTML 内容,然后将完整的 HTML 页面发送给客户端。

工作流程

  1. 客户端发送请求到服务器
  2. 服务器获取数据并渲染页面
  3. 服务器将完整的 HTML 页面发送给客户端
  4. 客户端接收 HTML 并进行 hydration(激活)

优势

  • 更好的 SEO:搜索引擎可以直接索引完整的 HTML 内容
  • 更快的首屏加载:客户端无需等待 JavaScript 加载和执行即可看到内容
  • 更好的用户体验:首屏加载速度快,用户可以更快看到内容

适用场景

  • 内容需要 SEO 的网站,如企业官网、博客、电商网站等
  • 首屏加载速度要求高的应用
  • 有大量静态内容的网站

1.2 静态站点生成 (SSG)

概念:静态站点生成是指在构建时生成静态 HTML 文件,然后将这些静态文件部署到服务器。

工作流程

  1. 在构建时,服务器获取数据并渲染页面
  2. 生成静态 HTML 文件
  3. 将静态文件部署到服务器
  4. 客户端请求时,直接返回静态 HTML 文件

优势

  • 极致的性能:静态文件加载速度极快
  • 低成本部署:可以部署到任何静态文件服务器,如 GitHub Pages、Netlify 等
  • 更好的安全性:静态站点没有服务端逻辑,减少了安全风险
  • 更好的可扩展性:可以轻松应对高流量

适用场景

  • 内容相对静态的网站,如博客、文档网站、企业官网等
  • 对性能要求极高的网站
  • 需要低成本部署的项目

1.3 客户端渲染 (CSR)

概念:客户端渲染是指在客户端使用 JavaScript 生成 HTML 内容。

工作流程

  1. 客户端发送请求到服务器
  2. 服务器返回空白 HTML 和 JavaScript 文件
  3. 客户端加载 JavaScript 文件
  4. 客户端执行 JavaScript,获取数据并渲染页面

优势

  • 开发效率高:无需考虑服务端渲染的复杂性
  • 交互性强:适合复杂的单页应用
  • 前后端分离:前端和后端可以独立开发

适用场景

  • 交互性强的单页应用,如管理系统、社交应用等
  • 不需要 SEO 的内部应用
  • 对首屏加载速度要求不高的应用

2. 服务端渲染数据获取(asyncData 与 useAsyncData 服务端执行逻辑)

2.1 useAsyncData

基本用法

vue
<template>
  <div>
    <h1>Posts</h1>
    <div v-if="pending">Loading...</div>
    <div v-else-if="error">Error: {{ error.message }}</div>
    <div v-else>
      <ul>
        <li v-for="post in posts" :key="post.id">
          {{ post.title }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
const { data: posts, pending, error } = useAsyncData('posts', () => {
  return $fetch('/api/posts')
})
</script>

服务端执行逻辑

  • 在服务端渲染时,useAsyncData 会在服务端执行,获取数据并渲染页面
  • 数据会被序列化并传递给客户端
  • 客户端会使用这些数据进行 hydration,避免重复获取数据

选项

vue
<template>
  <div>
    <h1>Posts</h1>
    <!-- 内容 -->
  </div>
</template>

<script setup>
const { data: posts, pending, error, refresh } = useAsyncData('posts', () => {
  return $fetch('/api/posts')
}, {
  server: true, // 在服务端获取数据
  lazy: false, // 非懒加载
  refreshInterval: 10000, // 每10秒刷新一次
  initialCache: false, // 不使用初始缓存
  watch: [/* 依赖项 */] // 依赖项变化时重新获取数据
})
</script>

2.2 useFetch

基本用法

vue
<template>
  <div>
    <h1>Posts</h1>
    <div v-if="pending">Loading...</div>
    <div v-else-if="error">Error: {{ error.message }}</div>
    <div v-else>
      <ul>
        <li v-for="post in data" :key="post.id">
          {{ post.title }}
        </li>
      </ul>
    </div>
  </div>
</template>

<script setup>
const { data, pending, error } = useFetch('/api/posts')
</script>

服务端执行逻辑

  • useAsyncData 类似,useFetch 也会在服务端执行,获取数据并渲染页面
  • 数据会被序列化并传递给客户端
  • 客户端会使用这些数据进行 hydration

3. 静态站点生成(nuxt generate 命令,部署静态资源)

3.1 基本用法

生成静态站点

bash
# 使用 npm
npm run generate

# 使用 pnpm
pnpm generate

# 使用 yarn
yarn generate

生成的文件

  • 生成的静态文件会放在 dist 目录中
  • 每个路由都会生成对应的 HTML 文件
  • 静态资源会被优化和压缩

3.2 配置静态站点生成

nuxt.config.ts 中配置

typescript
export default defineNuxtConfig({
  generate: {
    routes: [
      '/',
      '/about',
      '/contact',
      '/posts/1',
      '/posts/2'
    ] // 静态生成的路由
  }
})

3.3 动态路由的静态生成

使用 useAsyncData 获取动态路由数据

vue
<!-- pages/posts/[id].vue -->
<template>
  <div>
    <h1>{{ post.title }}</h1>
    <p>{{ post.body }}</p>
  </div>
</template>

<script setup>
const route = useRoute()
const { data: post } = useAsyncData(`post-${route.params.id}`, () => {
  return $fetch(`/api/posts/${route.params.id}`)
})
</script>

配置动态路由

typescript
export default defineNuxtConfig({
  generate: {
    async routes() {
      const { data: posts } = await $fetch('/api/posts')
      return posts.map(post => `/posts/${post.id}`)
    }
  }
})

3.4 部署静态站点

部署到 GitHub Pages

  1. 生成静态站点

    bash
    npm run generate
  2. 创建 GitHub 仓库:创建一个新的 GitHub 仓库

  3. 部署

    • 手动部署:将 dist 目录中的文件上传到 GitHub Pages
    • 使用 GitHub Actions:配置 CI/CD 自动部署

部署到 Netlify

  1. 连接 GitHub 仓库:在 Netlify 中连接你的 GitHub 仓库

  2. 配置构建命令

    • 构建命令:npm run generate
    • 发布目录:dist
  3. 部署:Netlify 会自动构建和部署你的静态站点

4. 混合渲染模式(部分页面 SSR、部分页面 CSR)

4.1 路由规则配置

nuxt.config.ts 中配置

typescript
export default defineNuxtConfig({
  routeRules: {
    // 静态生成
    '/': {
      static: true
    },
    '/about': {
      static: true
    },
    // 服务端渲染
    '/api/**': {
      ssr: true
    },
    // 客户端渲染
    '/admin/**': {
      ssr: false
    }
  }
})

4.2 页面级配置

在页面组件中配置

vue
<!-- pages/admin/index.vue -->
<template>
  <div>
    <h1>Admin Panel</h1>
    <!-- 内容 -->
  </div>
</template>

<script setup>
// 客户端渲染
</script>

<script>
export default {
  ssr: false // 禁用服务端渲染
}
</script>

5. 服务端配置(环境变量、运行环境区分)

5.1 环境变量配置

创建 .env 文件

txt
# .env
NUXT_PUBLIC_API_BASE=https://api.example.com
NUXT_API_KEY=secret_key

nuxt.config.ts 中配置

typescript
export default defineNuxtConfig({
  runtimeConfig: {
    public: {
      apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
    },
    apiKey: process.env.NUXT_API_KEY
  }
})

使用环境变量

vue
<template>
  <div>
    <h1>API Base: {{ config.public.apiBase }}</h1>
  </div>
</template>

<script setup>
const config = useRuntimeConfig()
</script>

5.2 运行环境区分

环境变量文件

  • .env:默认环境变量
  • .env.development:开发环境变量
  • .env.production:生产环境变量

使用环境变量

typescript
// composables/useApi.ts
const baseURL = process.env.NODE_ENV === 'production' 
  ? process.env.NUXT_PUBLIC_API_BASE 
  : '/api'

在组件中区分环境

vue
<template>
  <div>
    <h1>Environment: {{ environment }}</h1>
  </div>
</template>

<script setup>
const environment = process.env.NODE_ENV
</script>

小结

本章介绍了 Nuxt.js 的服务端渲染 (SSR) 与静态站点生成 (SSG),包括它们的核心概念、区别与适用场景,以及如何在 Nuxt.js 中实现服务端渲染和静态站点生成。通过本章的学习,你应该已经掌握了如何根据项目需求选择合适的渲染模式,以及如何配置和使用这些渲染模式。

在接下来的章节中,我们将学习 Nuxt.js 的生态集成、基础实战项目等内容,帮助你更深入地理解和使用 Nuxt.js。

© 2026 编程马·菜鸟教程 版权所有