Appearance
第9章:服务端渲染(SSR)与静态站点生成(SSG)
1. SSR 与 SSG 核心概念(区别与适用场景)
1.1 服务端渲染 (SSR)
概念:服务端渲染是指在服务器端生成 HTML 内容,然后将完整的 HTML 页面发送给客户端。
工作流程:
- 客户端发送请求到服务器
- 服务器获取数据并渲染页面
- 服务器将完整的 HTML 页面发送给客户端
- 客户端接收 HTML 并进行 hydration(激活)
优势:
- 更好的 SEO:搜索引擎可以直接索引完整的 HTML 内容
- 更快的首屏加载:客户端无需等待 JavaScript 加载和执行即可看到内容
- 更好的用户体验:首屏加载速度快,用户可以更快看到内容
适用场景:
- 内容需要 SEO 的网站,如企业官网、博客、电商网站等
- 首屏加载速度要求高的应用
- 有大量静态内容的网站
1.2 静态站点生成 (SSG)
概念:静态站点生成是指在构建时生成静态 HTML 文件,然后将这些静态文件部署到服务器。
工作流程:
- 在构建时,服务器获取数据并渲染页面
- 生成静态 HTML 文件
- 将静态文件部署到服务器
- 客户端请求时,直接返回静态 HTML 文件
优势:
- 极致的性能:静态文件加载速度极快
- 低成本部署:可以部署到任何静态文件服务器,如 GitHub Pages、Netlify 等
- 更好的安全性:静态站点没有服务端逻辑,减少了安全风险
- 更好的可扩展性:可以轻松应对高流量
适用场景:
- 内容相对静态的网站,如博客、文档网站、企业官网等
- 对性能要求极高的网站
- 需要低成本部署的项目
1.3 客户端渲染 (CSR)
概念:客户端渲染是指在客户端使用 JavaScript 生成 HTML 内容。
工作流程:
- 客户端发送请求到服务器
- 服务器返回空白 HTML 和 JavaScript 文件
- 客户端加载 JavaScript 文件
- 客户端执行 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:
生成静态站点:
bashnpm run generate创建 GitHub 仓库:创建一个新的 GitHub 仓库
部署:
- 手动部署:将
dist目录中的文件上传到 GitHub Pages - 使用 GitHub Actions:配置 CI/CD 自动部署
- 手动部署:将
部署到 Netlify:
连接 GitHub 仓库:在 Netlify 中连接你的 GitHub 仓库
配置构建命令:
- 构建命令:
npm run generate - 发布目录:
dist
- 构建命令:
部署: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。
