Nuxt 3 已于 31 July 2026 结束生命周期
此版本将不再接收错误修复或安全补丁。 升级到 Nuxt 4 或获取 HeroDevs 提供的延长支持

渲染模式

了解 Nuxt 中可用的不同渲染模式。

Maschinelle Übersetzung ·0 % geprüft

Nuxt 支持不同的渲染模式,包括通用渲染、客户端渲染,还提供了混合渲染和在 CDN 边缘服务器上渲染应用的可能性。

浏览器和服务器都可以解释 JavaScript 代码,将 Vue.js 组件转化为 HTML 元素。这个步骤称为 渲染。Nuxt 支持 通用 和 客户端 渲染,这两种方法各有优缺点,我们将在下文进行介绍。

默认情况下,Nuxt 使用通用渲染来提供更好的用户体验和性能,并优化搜索引擎索引,但你可以通过一行配置切换渲染模式。

通用渲染

这一步类似于传统的由 PHP 或 Ruby 应用执行的 服务器端渲染。当浏览器请求开启了通用渲染的 URL 时,Nuxt 会在服务器环境中运行 JavaScript(Vue.js)代码,并返回一个完整渲染好的 HTML 页面给浏览器。Nuxt 也可能从缓存中返回预先生成的完整 HTML 页。用户会立即获得应用初始内容的全部,相较于客户端渲染更快。

HTML 文档下载完毕后,浏览器会解析它,然后 Vue.js 会接管该文档。之前服务器端运行的相同 JavaScript 代码现在重新在客户端(浏览器)后台执行,使页面启用交互性(这就是 通用渲染)并将监听器绑定到 HTML 元素。这一步称为 激活(Hydration)。激活完成后,页面即可享有动态界面和页面过渡等优势。

通用渲染允许 Nuxt 应用实现快速页面加载,同时保留客户端渲染的好处。此外,由于内容已经存在于 HTML 文档中,爬虫可以无需额外开销直接索引内容。

哪些部分是服务器渲染,哪些是客户端渲染?

在通用渲染模式下,常有人会问 Vue 文件的哪些部分在服务器和/或客户端执行。

app.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 的 ref 因为在 <p> 标签内渲染而在服务器中初始化,handleClick 中的代码则不会被执行。浏览器激活阶段时,counter ref 会重新初始化,handleClick 函数最终绑定到按钮上。因此可以合理推断,handleClick 的主体始终在浏览器环境运行。

中间件和页面会在服务器运行,并在客户端激活期间运行。插件可以在服务器端、客户端或两端渲染。组件也可以被强制仅在客户端运行。组合式函数和工具函数则根据其使用上下文进行渲染。

服务器端渲染的优点:

  • 性能:用户可以立即访问页面内容,因为浏览器可以比 JavaScript 生成内容更快地显示静态内容。同时,Nuxt 在激活过程中保持了 web 应用的交互性。
  • 搜索引擎优化(SEO):通用渲染将页面完整 HTML 内容像经典服务器应用一样交付给浏览器。网络爬虫能直接索引页面内容,这使通用渲染成为希望快速被索引内容的理想选择。

服务器端渲染的缺点:

  • **开发限制:**服务器和浏览器环境提供的 API 并不相同,因此编写能在两端无缝运行的代码可能颇具挑战。幸运的是,Nuxt 提供了指南和特定变量,帮助你确定代码在哪一端执行。
  • **成本:**需要运行服务器才能即时渲染页面。这会像任何传统服务器一样产生每月费用。不过,由于客户端导航时浏览器会接管,通用渲染大幅减少了服务器调用次数。利用边缘渲染可以降低成本。

通用渲染非常灵活,几乎适用于所有应用场景,特别适合内容导向型网站:博客、营销网站、作品集、电商及市场平台。

想了解更多关于编写避免激活不匹配的 Vue 代码示例,请参阅 Vue 文档。
当导入依赖浏览器 API 且具有副作用的库时,确保导入该库的组件仅在客户端调用。打包器不会对带有副作用的模块导入进行摇树优化。

客户端渲染

传统的 Vue.js 应用默认在浏览器(即客户端)中渲染。浏览器下载并解析包含当前界面构造指令的所有 JavaScript 代码后,Vue.js 才开始生成 HTML 元素。

客户端渲染的优点:

  • 开发速度:完全客户端开发时,无需担心代码的服务器兼容性问题,例如可以直接使用只运行在浏览器的 API,如 window 对象。
  • 成本较低:不需要运行服务器增加基础设施成本。客户端应用可以托管在任何静态服务器,只需提供 HTML、CSS 和 JavaScript 文件。
  • 脱机可用:代码完全运行在浏览器,断网时仍然可以正常工作。

客户端渲染的缺点:

  • 性能:用户必须等待浏览器下载、解析和执行 JavaScript 文件。下载依赖网络状况,解析和执行受用户设备影响,这可能增加等待时间,影响用户体验。
  • 搜索引擎优化:客户端渲染内容的索引和更新速度比服务器渲染 HTML 慢。搜索引擎爬虫通常不会等待页面完全渲染后再进行索引,因此页面内容显示和更新会延迟。

客户端渲染适合交互性强且不需索引或用户频繁访问的Web 应用。可利用浏览器缓存跳过后续访问的下载阶段,例如 SaaS、后台管理系统或在线游戏。

可在 nuxt.config.ts 中通过设置启用仅客户端渲染:

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
})
如果使用 ssr: false,还应在 ~/app/spa-loading-template.html 放置一个 HTML 文件,其中包含你想用于渲染加载屏幕的 HTML。在应用激活之前,都会显示该加载屏幕。
Weitere Informationen findest du unter SPA 加载模板.

部署静态客户端渲染应用

如果使用 nuxt generate 或 nuxt build --prerender 命令将应用部署到静态托管,Nuxt 默认会将每个页面渲染为单独的静态 HTML 文件。

若用 nuxt generate 或 nuxt build --prerender 命令预渲染应用,则无法使用任何服务器端点,因为输出目录不会包含服务器代码。如需服务器功能,请使用 nuxt build。

纯客户端渲染时,通常只需一个 index.html 文件,再加上 200.html 和 404.html 作为回退文件,静态网站托管服务可针对所有请求返回它们。

为此,我们可以更改路由的预渲染方式。只需将以下内容添加到 nuxt.config.ts 中的钩子:

export default defineNuxtConfig({
  hooks: {
    'prerender:routes' ({ routes }) {
      routes.clear() // 不生成路由(除了默认路由)
    },
  },
})

这样将生成三个文件:

  • index.html
  • 200.html
  • 404.html

根据你使用的托管商,200.html 和 404.html 可能会有用。

跳过客户端回退页面生成

预渲染客户端渲染应用时,Nuxt 默认会生成 index.html、200.html 和 404.html 文件。不过,如果你需要阻止构建时生成其中任意或全部文件,可以使用 Nitro 的 'prerender:generate' 钩子。

// @errors: 2353 7006
export default defineNuxtConfig({
  ssr: false,
  nitro: {
    hooks: {
      'prerender:generate' (route) {
        const routesToSkip = ['/index.html', '/200.html', '/404.html']
        if (routesToSkip.includes(route.route)) {
          route.skip = true
        }
      },
    },
  },
})

混合渲染

混合渲染允许针对不同路由使用不同的缓存策略,借助 路由规则 决定服务器如何响应特定 URL 的请求。

过去,Nuxt 应用的每个路由/页面服务器必须使用统一的渲染模式——通用或客户端渲染。在某些场景下,有些页面可以在构建时生成,而其它页面需客户端渲染。例如,一个内容网站包含管理后台,每个内容页应静态生成一次,但管理后台页面由于需要注册,更像动态应用。

Nuxt 支持路由规则和混合渲染。通过路由规则可以为某组路由定义规则,改变渲染模式或指定缓存策略!

Nuxt 服务器会自动注册对应的中间件,并利用 Nitro 缓存层包裹路由的缓存处理。

export default defineNuxtConfig({
  routeRules: {
    // 首页于构建时预渲染
    '/': { prerender: true },
    // 产品页面按需生成,后台重新校验,缓存直到 API 响应变化
    '/products': { swr: true },
    // 产品详情页按需生成,后台重新校验,缓存 1 小时(3600 秒)
    '/products/**': { swr: 3600 },
    // 博客首页按需生成,后台重新校验,CDN 缓存 1 小时(3600 秒)
    '/blog': { isr: 3600 },
    // 博客文章页按需生成一次,直到下一次部署,CDN 缓存
    '/blog/**': { isr: true },
    // 管理后台仅客户端渲染
    '/admin/**': { ssr: false },
    // API 路由加上跨域请求头
    '/api/**': { cors: true },
    // 旧页面重定向
    '/old-page': { redirect: '/new-page' }
  }
})

路由规则

可用属性如下:

  • redirect: string - 定义服务器端重定向。
  • ssr: boolean - 禁用部分应用区域的服务器端渲染,仅在浏览器渲染(ssr: false)。
  • cors: boolean - 自动添加 CORS 请求头(cors: true),可用 headers 自定义。
  • headers: object - 为应用区域添加自定义请求头,例如静态资源。
  • swr: number | boolean - 添加缓存响应头,在服务器或反向代理端缓存一段 TTL(存活时间)。Nitro 的 node-server 预设支持完整响应缓存。TTL 过期后,将返回缓存内容,同时后台重新生成。当为 true 时,添加 stale-while-revalidate 头且无 MaxAge。
  • isr: number | boolean - 与 swr 功能类似,同时支持 CDN 缓存(目前仅 Netlify 和 Vercel)。为 true 时,内容在 CDN 中缓存直到下一次部署。
  • prerender: boolean - 在构建时预渲染路由,包含为静态资源。
  • noScripts: boolean - 禁止渲染 Nuxt 脚本和 JS 资源提示。
  • appMiddleware: string | string[] | Record<string, boolean> - 指定哪些中间件应在 Vue 应用部分运行(不包括 Nitro 路由)。
使用 isr 或 swr 的路由也会在 HTML 旁边生成 _payload.json 文件。客户端导航会加载这些缓存的 payload,而不是重新获取数据。使用 glob 模式为动态路由配置,例如 pages/[...slug].vue:'/**': { isr: true }。

尽可能情况下,路由规则会自动应用到部署平台的原生规则,以获得最佳性能(目前支持 Netlify 和 Vercel)。

请注意,使用 nuxt generate 时无法使用混合渲染。

示例:

Nuxt Vercel ISR

Nuxt 应用混合渲染部署于 Vercel 示例。

边缘渲染

边缘渲染(Edge-Side Rendering,ESR)是 Nuxt 中引入的强大特性,使你的 Nuxt 应用可通过内容分发网络(CDN)边缘服务器更靠近用户进行渲染。借助 ESR,可以提升性能并减少延迟,提供更优体验。

ESR 将渲染过程推送到网络“边缘”——CDN 的边缘服务器。请注意,ESR 更像是一个部署目标,而非真正的渲染模式。

当对某页面发出请求时,最近的边缘服务器会拦截请求,生成该页面的 HTML 并返回给用户。此过程缩短了数据实际传输距离,降低延迟并更快加载页面。

借助 Nitro(为 Nuxt 提供支持的服务器引擎),即可实现边缘渲染。它支持跨平台运行于 Node.js、Deno、Cloudflare Workers 等环境。

当前支持可运用 ESR 的平台包括:

请注意,使用边缘渲染时,可结合路由规则启用混合渲染。

以下开源示例项目部署在上述部分平台:

Nuxt Todos Edge

一款具有用户认证、SSR 和 SQLite 的待办事项应用。

Atinotes

基于 Cloudflare KV 的可编辑网站,使用通用渲染。