Nuxt4阶段五:渲染模式与性能优化
学习目标 :理解 SSR / SSG / SPA / 混合渲染,会用
routeRules,掌握 SEO 与常见性能优化。预计时间 :约 1 周
前置 :完成阶段四,有可访问的页面与 API。
本阶段产出:博客首页预渲染、后台 SPA、文章 ISR/缓存策略,并补齐 SEO。
1. 为什么渲染模式很重要?
同一套 Vue 代码,可以在不同时机生成 HTML:
| 模式 | 谁生成 HTML | 典型场景 |
|---|---|---|
| SSR | 每个请求在服务器渲染 | 个性化、频繁更新、需 SEO |
| SSG | 构建时生成静态 HTML | 文档、营销页、博客列表 |
| SPA | 浏览器里渲染(几乎空壳 HTML) | 后台、强交互工具 |
| 混合 | 按路由组合以上策略 | 真实生产项目的默认选择 |
| ISR | 静态生成 + 定时/按需再生 | 文章页「准静态」 |
Nuxt 默认是 SSR。精通 Nuxt = 会按路由选对策略。
2. 全局开关(了解即可)
ts
// nuxt.config.ts
export default defineNuxtConfig({
// 整站关闭 SSR → 纯 SPA(一般不推荐整站这么干)
ssr: false,
})
更推荐:保持 ssr: true,用 routeRules 精细控制。
3. routeRules:混合渲染核心
ts
// nuxt.config.ts
export default defineNuxtConfig({
routeRules: {
// 首页构建时预渲染(SSG)
'/': { prerender: true },
// 关于页预渲染
'/about': { prerender: true },
// 博客列表:ISR,每 60 秒可重新验证(平台支持时)
'/blog': { isr: 60 },
// 博客详情:ISR 一小时
'/blog/**': { isr: 3600 },
// 后台:纯客户端
'/admin/**': { ssr: false },
// API:可加 CORS、缓存头等
'/api/**': { cors: true },
// 某页强制 SSR(显式)
'/todos': { ssr: true },
},
})
常用规则字段:
| 字段 | 含义 |
|---|---|
prerender: true |
构建时生成静态页 |
ssr: false |
该路由客户端渲染 |
| `isr: number | true` |
| `swr: number | true` |
redirect |
重定向 |
headers |
自定义响应头 |
cors |
CORS 快捷配置 |
不同部署平台对
isr/swr支持程度不同(Vercel/Netlify 等更完整)。本地pnpm preview行为也可能与线上略有差异,以目标平台文档为准。
4. 预渲染与静态生成
4.1 开发时怎么验证?
bash
pnpm build
pnpm preview
构建日志里会看到 prerender 的路由。输出在 .output/。
4.2 只生成静态站
bash
pnpm generate
适合完全静态托管(GitHub Pages、对象存储+CDN)。动态 server/api 在纯静态托管中不可用,需改用外部 API 或 BaaS。
4.3 爬取动态路由
若文章是 /blog/1、/blog/2,可在配置里告诉爬虫:
ts
export default defineNuxtConfig({
nitro: {
prerender: {
crawlLinks: true,
routes: ['/blog/1', '/blog/2'],
},
},
})
或构建前从 API 拉 ID 列表写入 routes(阶段八实战会用到)。
5. SEO:让搜索引擎看懂你的页
5.1 useSeoMeta / useHead
ts
// 文章页
const { data: post } = await useFetch(() => `/api/posts/${id.value}`)
useSeoMeta({
title: () => post.value?.title ?? '文章',
description: () => post.value?.excerpt ?? '',
ogTitle: () => post.value?.title,
ogDescription: () => post.value?.excerpt,
ogImage: 'https://example.com/og.png',
twitterCard: 'summary_large_image',
})
useHead({
htmlAttrs: { lang: 'zh-CN' },
link: [{ rel: 'canonical', href: `https://example.com/blog/${id.value}` }],
})
5.2 标题模板
nuxt.config.ts 或 app.vue:
ts
useHead({
titleTemplate: (title) => (title ? `${title} · MyBlog` : 'MyBlog'),
})
5.3 为什么 SSR/SSG 对 SEO 重要?
爬虫拿到的是服务器已经填好内容的 HTML,而不是空白壳 + 等 JS。后台 /admin 可以 ssr: false,公开内容页尽量 SSR 或 prerender。
5.4 robots 与 sitemap(了解)
可用模块如 @nuxtjs/sitemap、手动 public/robots.txt。阶段八项目再集成。
6. 性能优化清单
6.1 图片:@nuxt/image
bash
pnpm add @nuxt/image
ts
export default defineNuxtConfig({
modules: ['@nuxt/image'],
})
html
<NuxtImg
src="/hero.jpg"
width="800"
height="400"
format="webp"
loading="lazy"
alt="封面"
/>
自动处理尺寸、懒加载、现代格式(视 provider 配置)。
6.2 组件懒加载
html
<LazyAdminHeavyChart v-if="tab === 'stats'" />
6.3 数据层优化(呼应阶段三)
- 稳定、语义化的
key - 列表与详情分开缓存
- 非首屏用
lazy: true - 避免在父、子组件重复打不同 key 的同一接口
6.4 Payload 与客户端体积
Nuxt 会把 SSR 数据嵌入 payload,避免客户端重复请求。检查:
- 不要在 payload 里塞巨无无关数据
- 大列表考虑分页
- 分析包体积:
nuxi analyze(若版本支持)或打包分析工具
6.5 字体与 CSS
- 避免一次性引入巨大 UI 库全量样式
- 关键 CSS 放
assets,注意 scoped - 字体用
font-display: swap,或@nuxt/fonts等方案
6.6 路由级性能直觉
text
营销首页、关于我们 → prerender
博客文章 → prerender 或 isr
用户仪表盘、编辑器 → ssr: false 或保持 SSR 但勿缓存隐私数据
API → 适当 Cache-Control(公开数据)
7. 实战练习:给博客骨架套上策略
在现有项目 nuxt.config.ts 写入类似:
ts
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
'/about': { prerender: true },
'/blog': { swr: 60 },
'/blog/**': { swr: 3600 },
'/admin/**': { ssr: false },
'/todos': { ssr: true },
'/login': { ssr: true },
},
})
然后:
- 给首页、关于、文章页补全
useSeoMeta - 加一张
public图片并用<NuxtImg>(或先用普通img) pnpm build && pnpm preview,分别打开/、/blog/1、/admin- 用浏览器「查看网页源代码」:
/源码里应能看到首页标题文字(预渲染/SSR)/admin源码可能几乎没有业务内容(SPA)
8. 客户端与服务端代码边界
ts
if (import.meta.server) {
// 仅服务端
}
if (import.meta.client) {
// 仅客户端
}
错误示例:在 setup 顶层直接 window.localStorage → SSR 报错。应:
ts
onMounted(() => {
localStorage.setItem('x', '1')
})
或:
ts
const data = import.meta.client ? localStorage.getItem('x') : null
9. Loading 与错误页(体验也是性能)
app/error.vue:
html
<script setup lang="ts">
import type { NuxtError } from '#app'
const props = defineProps<{ error: NuxtError }>()
const handleClear = () => clearError({ redirect: '/' })
</script>
<template>
<div>
<h1>{{ error.statusCode }}</h1>
<p>{{ error.statusMessage || error.message }}</p>
<button @click="handleClear">回首页</button>
</div>
</template>
页面级可用 <NuxtLoadingIndicator /> 显示导航进度。
10. 本阶段验收清单
- 能用自己的话解释 SSR / SSG / SPA / ISR 区别
- 配置了至少 3 种不同的
routeRules - 公开页写了
useSeoMeta(title + description) -
pnpm build && pnpm preview成功 - 用「查看源代码」对比过公开页与 admin 页
- (加分)接入
@nuxt/image - (加分)为动态文章配置
nitro.prerender.routes或crawlLinks
11. 常见坑
把整站 ssr: false 然后抱怨 SEO 差
公开内容请开 SSR 或 prerender。
隐私页用了长时间 ISR/SWR
用户仪表盘、购物车不要缓存成「别人的数据」。
本地觉得 ISR 没生效
部分策略依赖托管平台;以平台文档 + 响应头为准。
预渲染时请求了需鉴权的 API
构建环境没有用户 Cookie,预渲染失败或拿到空数据------公开数据才适合 prerender。
12. 阶段总结
你已经掌握:
- 混合渲染与
routeRules - 构建预览与 SEO 基础
- 图片懒加载、payload、客户端边界等性能要点
下一篇:阶段六 ------ 模块生态、路由中间件、插件、TypeScript、测试与错误处理。