2024 字
10 分钟
Nuxt 4 的渲染模式

渲染模式总览#

Nuxt 4 支持通用渲染、客户端渲染、混合渲染和边缘渲染。渲染指浏览器和服务器解析 JavaScript 代码,把 Vue 组件转换成 HTML 元素。

这四种模式的区别在于 HTML 在哪台机器上生成,以及能不能按路由分别选择。

通用渲染#

通用渲染(universal rendering)和 PHP、Ruby 应用的服务器端渲染类似:Nuxt 在服务器环境里执行 Vue.js 代码,把渲染完成的 HTML 返回给浏览器。

页面如果已经预先生成,Nuxt 也可能直接从缓存返回 HTML。用户马上就能拿到应用的完整初始内容,不必等 JavaScript 跑完。

HTML 文档下载完成后,浏览器解析它,Vue.js 接着接管。同一份 JavaScript 代码在浏览器里初始化应用,把事件监听器绑定到 HTML 上,页面恢复可交互,这个过程叫水合(hydration)。

水合完成后,页面还能使用动态界面和页面过渡。

服务器和客户端各跑一部分#

通用渲染下,同一个 Vue 文件里的不同部分会分别在服务器和客户端执行。

<script setup lang="ts">
const counter = ref(0) // 服务器和客户端都会执行
const handleClick = () => {
counter.value++ // 只在客户端执行
}
</script>
<template>
<div>
<p>Count: {{ counter }}</p>
<button @click="handleClick">Increment</button>
</div>
</template>

首次请求这个组件时,counter 要在模板里渲染,而 counter 这个 ref 是在服务器端的 Node.js 环境里初始化的。

handleClick 的函数体在服务端永远不会执行,和客户端才有的 DOM、BOM 一样。

浏览器执行水合时,counter 会被重新初始化,handleClick 最终绑定到按钮上,之后它的函数体始终在浏览器里运行。

不同渲染模式下,Nuxt 目录里各部分代码的执行环境不同。

  • 水合过程中,中间件(middlewares)和页面(pages)在服务器和客户端上都运行。
  • 插件(plugins)可以只在服务器运行、只在客户端运行,或者两边都运行。
  • 组件(components)可以用 <ClientOnly> 包裹,强制只在客户端渲染。
  • 可组合项(composables)和工具函数(utilities)按使用位置决定运行环境。

优势#

浏览器显示静态内容比显示 JavaScript 生成的内容快,用户能立即看到页面内容,水合过程又保留了 Web 应用的交互性。

通用渲染把页面的完整 HTML 内容像传统服务器应用那样发给浏览器,网络爬虫可以直接索引页面内容,适合需要被快速索引的页面。

缺点#

服务器和浏览器提供的 API 不同,写一份两边都能直接运行的代码并不容易。

按需渲染页面要求服务器持续运行,每月都要付费,和传统服务器一样。客户端导航能减少服务器请求,改用边缘渲染也能降低成本。

客户端渲染#

客户端渲染(client-side rendering,CSR)指在浏览器里用 JavaScript 生成 HTML 内容。原生 Vue SPA 默认就是这样:浏览器必须先下载并执行完所有 JS,才能生成页面 HTML 展示内容。

优势#

开发时不区分服务器和客户端环境,可以直接使用 window 这类只有浏览器才有的 API。

纯客户端应用可以托管在任何静态服务器上,只需要 HTML、CSS 和 JavaScript 文件,不需要为常驻服务器付出基础设施成本。

代码完全在浏览器里运行,断网后也能继续工作。

缺点#

用户必须等浏览器下载、解析并执行完所有需要的 JavaScript 文件,等待时间取决于网络状况和用户设备。

搜索引擎爬虫不会等界面渲染完成再索引,客户端渲染交付的内容因此要更久才会出现在搜索结果里。

客户端渲染适合不需要索引,或者用户频繁交互的 Web 应用。

混合渲染#

混合渲染(hybrid rendering)用路由规则(route rules)给不同路由单独配置缓存策略,同时规定服务器收到某个 URL 的新请求时怎么响应。

旧版 Nuxt 里整个应用只能统一选一种渲染模式:要么全部服务端渲染,要么全部客户端渲染。内容类网站很难两全,内容页面适合静态生成,后台管理模块需要登录权限,更像动态 SPA。

Nuxt 现在内置了路由规则和混合渲染。路由规则能批量匹配路由,单独改匹配到的路由的渲染模式,或者给它们配置专属缓存策略。Nuxt 会自动注册对应的中间件,依托 Nitro 服务缓存层,给匹配到的路由包一层缓存处理。

在 nuxt.config.ts 里配置:

export default defineNuxtConfig({
routeRules: {
// 首页:构建时提前预渲染(静态生成)
'/': { prerender: true },
// 产品列表页:按需生成,后台自动刷新,API 数据变化前一直缓存
'/products': { swr: true },
// 产品详情页:按需生成,后台自动刷新,缓存 1 小时(3600 秒)
'/products/**': { swr: 3600 },
// 博客列表页:按需生成,后台自动刷新,在 CDN 上缓存 1 小时
'/blog': { isr: 3600 },
// 博客文章页:构建或部署时生成一次,下次部署前一直缓存在 CDN
'/blog/**': { isr: true },
// 管理后台:只在客户端渲染(关闭 SSR,纯 SPA 模式)
'/admin/**': { ssr: false },
// API 路由:自动添加跨域 CORS 响应头
'/api/**': { cors: true },
// 旧页面:自动重定向到新页面
'/old-page': { redirect: '/new-page' },
},
})

九个键的作用如下。

键类型作用
redirectstring定义服务端重定向,把请求路由跳转到指定地址
ssrboolean关闭部分页面的服务端 HTML 渲染;设为 false 后,这些页面只在浏览器里渲染
corsboolean设为 true 会自动添加跨域资源共享(CORS)响应头,跨域参数可以用 headers 覆盖
headersobject为指定页面或资源(静态资源、接口)添加自定义 HTTP 响应头
swrnumber 或 boolean给服务端响应加缓存头,在服务端或反向代理里缓存完整响应,TTL 可配。缓存过期后先返回旧缓存,同时在后台重新生成。设为 true 时只加 stale-while-revalidate 头,不设过期时间
isrnumber 或 boolean作用和 swr 一致,区别是把响应缓存到受支持平台(Netlify、Vercel)的 CDN 上。设为 true 时内容一直缓存在 CDN,直到下次项目部署才更新
prerenderboolean构建阶段提前渲染路由,把生成的页面作为静态资源打包进构建产物
noScriptsboolean禁用指定页面的 Nuxt 脚本和 JS 资源预加载提示,页面只保留静态 HTML
appMiddlewarestring、string[] 或 Record<string, boolean>为 Vue 应用内的页面路径(不是 Nitro 服务端路由)指定需要或不需要执行的应用中间件

边缘渲染#

边缘渲染(edge-side rendering,ESR)把 Nuxt 应用放到 CDN 的边缘服务器上渲染。渲染地点离用户更近,延迟更低。

用户请求页面时,请求不会直接发到源服务器,而是由最近的边缘服务器拦截处理。边缘服务器直接生成页面 HTML 并返回,数据传输的物理距离短,页面加载更快。

ESR 能实现,靠的是驱动 Nuxt 的服务引擎 Nitro。Nitro 跨平台,可以运行在 Node.js、Deno、Cloudflare Workers 等环境里。

目前支持 ESR 的平台有三个。

  • Cloudflare Pages:通过 Git 集成和 nuxt build 命令,零配置直接启用
  • Vercel:使用 nuxt build 命令,并配置环境变量 NITRO_PRESET=vercel-edge
  • Netlify:使用 nuxt build 命令,并配置环境变量 NITRO_PRESET=netlify-edge

第 19 篇,共 19 篇本文属于系列

Nuxt 4 的渲染模式
https://www.choria.top/posts/nuxt-ssr/
作者
乔瑞雅·克林威尔
发布于
2026-03-27
许可协议
CC BY-NC-SA 4.0

分享文章

生成精美分享图或复制链接,与更多人分享本文。

继续阅读

沿着主题读

基于共同的标签与分类

换条路线

从其他文章中稳定抽取

最后更新于 ,距今已过 226 天

部分内容可能已过时