Nuxt.js 服务端渲染:SSR、SSG 与模块生态
Nuxt.js 服务端渲染:SSR、SSG 与模块生态
什么是 Nuxt.js 及其渲染模式
Nuxt.js 是一个基于 Vue.js 的渐进式框架,专为构建现代 Web 应用而设计。它内置了对服务端渲染(SSR)的支持,同时提供静态站点生成(SSG)和多种混合渲染模式,让你能根据项目需求灵活选择渲染策略。
Nuxt.js 的核心渲染模式包括:
- SPA(单页应用):仅在客户端渲染,没有服务端预先输出 HTML。
- SSR(服务端渲染):每次请求时在服务端生成完整的 HTML 页面,提高首屏加载速度和 SEO 表现。
- SSG(静态站点生成):在构建时预渲染所有页面,输出静态 HTML 文件,适合内容不变的站点。
- ISR(增量静态再生):在 SSG 基础上支持按需重新生成单个页面,兼顾静态优势与内容更新。
Nuxt 通过 nuxt.config.ts 中的 ssr 选项和 target 选项控制渲染模式,现代 Nuxt 3 则更统一地通过模块与路由规则实现。
快速上手 SSR 项目
创建项目并启用 SSR
使用推荐方式快速初始化一个 Nuxt 3 项目:
npx nuxi@latest init my-nuxt-app
cd my-nuxt-app
默认情况下,Nuxt 3 的 SSR 是开启的。打开 nuxt.config.ts,确认配置:
// nuxt.config.ts
export default defineNuxtConfig({
ssr: true, // 默认即为 true,表示启用服务端渲染
})
此时运行 npm run dev,应用将在服务端渲染模式下工作。查看页面源代码,你会看到完整的 HTML 内容,而不仅仅是空白的 <div id="__nuxt"></div>。
创建第一个 SSR 页面
在 pages 目录下创建 index.vue:
<template>
<div>
<h1>Nuxt SSR 示例</h1>
<p>当前服务器时间:{{ serverTime }}</p>
<p>当前客户端时间:{{ clientTime }}</p>
</div>
</template>
<script setup>
// 服务端执行
const serverTime = ref(new Date().toISOString())
// 客户端执行,通过 onMounted 确保仅在浏览器中更新
const clientTime = ref('')
onMounted(() => {
clientTime.value = new Date().toISOString()
})
</script>
通过这段代码可以直观感受 SSR 与客户端激活的区别:serverTime 在服务端渲染时确定,随后在客户端激活时保持不变(除非手动更新),而 clientTime 只在客户端挂载后设置。
使用 useAsyncData 获取数据
在 SSR 模式下,数据获取需要同时考虑服务端和客户端。Nuxt 提供 useAsyncData 和 useFetch 等组合式函数来处理异步数据:
<script setup>
const { data: posts } = await useAsyncData('posts', () =>
$fetch('https://jsonplaceholder.typicode.com/posts')
)
</script>
useAsyncData 会在服务端预取数据,并将结果序列化传递到客户端,避免重复请求。它的第一个参数是唯一键,用于缓存和 hydrate。更简洁的方式是使用 useFetch:
<script setup>
const { data: posts } = await useFetch('/api/posts')
</script>
深入理解服务端渲染(SSR)
SSR 工作流程
- 请求到达:用户通过浏览器请求一个页面。
- 服务端渲染:Nuxt 在 Node.js 环境中执行 Vue 组件,生成 HTML 字符串,并将组件状态(如
useAsyncData的数据)序列化后嵌入到<script>标签中。 - 返回完整 HTML:客户端收到包含实际内容的 HTML,可以立即展示首屏。
- 客户端激活(Hydration):浏览器加载 JavaScript 后,Vue 会接管静态 HTML,将其变为可交互的响应式应用。这一过程会复用已有的 DOM,并附着事件监听器。
这种模式的优势是:首屏加载快速,对搜索引擎友好,同时保留了 Vue 的响应式交互能力。
处理仅在客户端运行的代码
由于 SSR 阶段没有浏览器 API(如 window、document),你需要妥善处理仅限客户端的代码:
- 使用
process.client判断:if (process.client) { // 仅在浏览器执行 } - 利用
<ClientOnly>组件:<ClientOnly> <SomeBrowserOnlyComponent /> </ClientOnly> - 在
onMounted中执行:所有onMounted钩子只会在客户端运行。
错误处理与中间件
Nuxt 提供了全局错误处理页面 error.vue,以及路由中间件(middleware)来做权限验证或重定向。中间件支持服务端或客户端执行,通过 defineNuxtRouteMiddleware 定义:
// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
if (!isAuthenticated()) {
return navigateTo('/login')
}
})
在 SSR 场景下,中间件会在服务端首次运行时被调用,可以控制页面的初始渲染。
静态站点生成(SSG)
启用完全静态生成
如果项目的所有内容在构建时就已经确定,你可以配置为完全静态生成模式:
在 nuxt.config.ts 中设置:
export default defineNuxtConfig({
ssr: true,
nitro: {
prerender: {
routes: ['/', '/about'], // 手动指定需要预渲染的路由
crawlLinks: true // 自动爬取页面内的链接并预渲染
}
}
})
构建时运行:
npx nuxi generate
这将在 .output/public 目录下生成静态 HTML 文件,可以部署到任何静态托管服务(如 Netlify、Vercel、Cloudflare Pages)。
混合渲染:按路由选择模式
Nuxt 支持在同一项目内对不同路由使用不同渲染策略。可以使用 routeRules 精细控制:
export default defineNuxtConfig({
routeRules: {
// 首页使用 SSR
'/': { ssr: true },
// 博客文章使用 SSG,在构建时生成
'/blog/**': { static: true },
// 管理后台完全使用客户端渲染(SPA)
'/admin/**': { ssr: false },
// 特定动态路由使用 ISR,60 秒后重新验证
'/products/**': { isr: 60 }
}
})
这种混合模式让你能在一个应用内同时享受 SSR 的实时性、SSG 的高性能和 SPA 的交互体验。
Nuxt 模块生态:快速增强 SSR 能力
Nuxt 拥有丰富的模块系统,可以零配置集成各种功能,同时完美适配 SSR 环境。
常用核心模块
-
@nuxt/image:优化图片加载,支持自动格式转换、响应式尺寸和懒加载。在 SSR 中自动生成占位符并优化图片路径。 安装:npm install @nuxt/imageexport default defineNuxtConfig({ modules: ['@nuxt/image'] }) -
@nuxtjs/i18n:国际化解决方案,支持 SSR 下的多语言路由和翻译加载。 安装:npm install @nuxtjs/i18nexport default defineNuxtConfig({ modules: ['@nuxtjs/i18n'], i18n: { locales: ['en', 'zh'], defaultLocale: 'en' } }) -
@nuxtjs/tailwindcss:集成 Tailwind CSS,在 SSR 构建时生成最小化样式。npx nuxi module add tailwindcss -
@nuxtjs/color-mode:轻松实现暗黑模式切换,且兼容 SSR(避免闪烁)。npx nuxi module add color-mode
SEO 优化模块
@nuxtjs/seo(Nuxt 3):一站式 SEO 包,包含@nuxtjs/html-validator、@nuxtjs/sitemap等。@nuxtjs/robots:生成robots.txt。nuxt-simple-sitemap:自动生成站点地图。
这些模块大多在 SSR/SSG 场景下自动生成必要的元标记和文件,确保搜索引擎能正确抓取和索引。
内容管理模块
@nuxt/content:基于文件的 CMS,可将 Markdown、YAML、CSV 等作为内容源。它天然支持 SSR 和 SSG,能配合查询 API 在构建时或请求时获取内容。
安装:
npx nuxi module add content
使用示例:
<script setup>
const { data: articles } = await useAsyncData('articles', () =>
queryContent('/blog').find()
)
</script>
在 SSG 模式下,Nuxt 爬虫会自动发现内容路由并预渲染。
部署 SSR 应用
SSR 应用需要 Node.js 服务器环境。Nuxt 3 使用 Nitro 作为服务引擎,可以将应用部署到多种平台:
- Node.js 服务器:构建后运行
node .output/server/index.mjs - 无服务器函数:Vercel、Netlify Functions、AWS Lambda 等
- 边缘计算:Cloudflare Workers、Deno Deploy
生产构建命令:
npm run build
配置文件中的预设会影响部署方式。例如,部署到 Vercel 时,你几乎不需要额外配置,Vercel 会自动识别 Nuxt 项目并使用正确的预设。
常见问题与调试
避免内存泄漏
在 SSR 中,服务器实例会处理多个请求,务必避免使用全局单例状态。将具有状态的变量定义在 setup 函数或组合式函数内部,而不是模块顶层。
环境变量
Nuxt 中使用 useRuntimeConfig() 访问运行时配置,它可以安全地暴露给客户端或仅限服务端:
export default defineNuxtConfig({
runtimeConfig: {
// 只能服务端访问的密钥
apiSecret: '',
// 可暴露给客户端
public: {
apiBase: '/api'
}
}
})
调试服务端代码
可以使用 console.log 输出到终端,Nuxt 开发模式下服务端代码会显示在 Nuxt 命令行窗口。也可以使用 Node.js 调试器或 nuxt dev --inspect。
总结
Nuxt.js 通过内置的 SSR、SSG 和灵活的混合渲染策略,让服务端渲染不再是复杂难题。配合强大的模块生态,你可以快速集成 SEO、图片优化、内容管理和国际化等功能。无论是构建内容型网站还是复杂交互应用,Nuxt 都能提供适合的渲染模式组合,平衡性能、开发体验和 SEO 需求。