渲染模式

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

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

浏览器和服务器都可以解释 JavaScript 代码,将 Vue.js 组件转换为 HTML 元素。这一步称为 渲染。Nuxt 同时支持 通用客户端 渲染。这两种方法都有优点和缺点,我们将对此进行深入讨论。

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

通用渲染

这一步类似于传统的 服务器端渲染,由 PHP 或 Ruby 应用程序执行。当浏览器请求启用了通用渲染的 URL 时,Nuxt 在服务器环境中运行 JavaScript(Vue.js)代码,并返回一个完全渲染的 HTML 页面给浏览器。如果页面之前已经生成,Nuxt 还可以从缓存中返回完全渲染的 HTML 页面。用户立即获得应用程序的全部初始内容,与客户端渲染相反。

一旦 HTML 文档被下载,浏览器将解释此文档,Vue.js 将控制该文档。之前在服务器上运行的相同 JavaScript 代码 再次 在客户端(浏览器)中运行,在后台现在启用交互性(因此称为 通用渲染),通过将其监听器绑定到 HTML。这称为 水合。当水合完成后,页面可以享受动态界面和页面过渡等好处。

通用渲染允许 Nuxt 应用程序提供快速的页面加载时间,同时保留客户端渲染的好处。此外,由于内容已经在 HTML 文档中存在,爬虫可以无开销地对其进行索引。

用户可以在 HTML 文档加载时访问静态内容。水合随后允许页面的交互性

什么是服务器渲染,什么是客户端渲染?

在通用渲染模式下,询问 Vue 文件的哪些部分在服务器和/或客户端上运行是很正常的。

app.vue
<script setup lang="ts">
const counter = ref(0); // 在服务器和客户端环境中执行

const handleClick = () => {
  counter.value++; // 仅在客户端环境中执行
};
</script>

<template>
  <div>
    <p>计数: {{ counter }}</p>
    <button @click="handleClick">增加</button>
  </div>
</template>

在初始请求时,counter 引用在服务器中初始化,因为它是在 <p> 标签内渲染的。此时 handleClick 的内容不会执行。在浏览器中的水合过程中,counter 引用被重新初始化。handleClick 最终绑定到按钮;因此,可以合理推断 handleClick 的主体将始终在浏览器环境中运行。

中间件页面 在服务器和水合过程中在客户端中执行。插件 可以在服务器、客户端或两者上渲染。组件 也可以被强制仅在客户端运行。组合函数工具 的渲染根据它们的使用上下文。

服务器端渲染的好处:

  • 性能:用户可以立即访问页面的内容,因为浏览器比 JavaScript 生成的内容更快地显示静态内容。与此同时,Nuxt 在水合过程中保留了 Web 应用程序的交互性。
  • 搜索引擎优化:通用渲染将页面的整个 HTML 内容作为经典的服务器应用程序交付给浏览器。网络爬虫可以直接索引页面的内容,这使得通用渲染适合任何希望快速索引的内容。

服务器端渲染的缺点:

  • 开发限制:服务器和浏览器环境提供的 API 不相同,因此编写可以在双方无缝运行的代码可能会很棘手。幸运的是,Nuxt 提供了指导方针和特定变量来帮助您确定某段代码的执行位置。
  • 成本:必须运行一台服务器,以便动态渲染页面。这增加了每月的费用,就像任何传统服务器一样。然而,由于浏览器在客户端导航过程中接管,服务器调用的数量大大减少。通过利用 边缘侧渲染 可以减少成本。

通用渲染非常灵活,几乎可以适应任何用例,特别适合任何内容导向的网站:博客、营销网站、作品集、电商网站和市场

有关编写没有水合不匹配的 Vue 代码的更多示例,请参阅 Vue 文档
当导入依赖于浏览器 API 并且具有副作用的库时,请确保导入它的组件仅在客户端被调用。打包工具不会对包含副作用的模块的导入进行摇树优化。

客户端渲染

开箱即用,传统的 Vue.js 应用程序在浏览器(或 客户端)中进行渲染。然后,Vue.js 在浏览器下载和解析所有包含当前界面创建指令的 JavaScript 代码后生成 HTML 元素。

用户必须等待浏览器下载、解析并执行 JavaScript,才能看到页面的内容

客户端渲染的好处:

  • 开发速度:在完全在客户端工作时,我们不必担心代码的服务器兼容性,例如,使用仅限浏览器的 API,如 window 对象。
  • 成本更低:运行一台服务器会增加基础设施成本,因为您需要在支持 JavaScript 的平台上运行。我们可以在任何静态服务器上托管仅客户端的应用程序,使用 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 的文件,该屏幕将在您的应用程序水合之前呈现。
Read more in SPA 加载模板.
观看 Alexander Lichter 有关 使用 Nuxt 构建纯 SPA 的视频!

部署静态客户端渲染应用

如果您通过 nuxi generatenuxi build --prerender 命令将应用部署到 静态托管,那么默认情况下,Nuxt 将每个页面渲染为单独的静态 HTML 文件。

如果您通过 nuxi generatenuxi build --prerender 命令预渲染应用程序,则无法使用任何服务器端点,因为您的输出文件夹中不会包含服务器。如果需要服务器功能,请使用 nuxi build

如果您使用的是完全客户端渲染,则这可能是不必要的。您可能只需要一个 index.html 文件,另外还有 200.html404.html 备用文件,您可以告诉静态 Web 主机为所有请求提供这些文件。

为了实现这一点,我们可以改变路由的预渲染方式。只需将其添加到 您的钩子 中的 nuxt.config.ts

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

这将生成三个文件:

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

200.html404.html 可能对您使用的托管提供商有用。

跳过客户端备用生成

在预渲染客户端渲染应用时,Nuxt 默认将生成 index.html200.html404.html 文件。但是,如果您需要防止在构建中生成任何(或全部)这些文件,可以使用 Nitro'prerender:generate' 钩子。

nuxt.config.ts
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 路由的规则,更改渲染模式或根据路由分配缓存策略!

Nuxt 服务器将自动注册相应的中间件,并使用 Nitro 缓存层 包装路由与缓存处理程序。

nuxt.config.ts
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 路由上添加 CORS 头
    '/api/**': { cors: true },
    // 重定向旧的 URL
    '/old-page': { redirect: '/new-page' }
  }
})

路由规则

您可以使用的不同属性如下:

  • redirect: string - 定义服务器端重定向。
  • ssr: boolean - 禁用应用程序部分的 HTML 服务器端渲染,并使其仅在浏览器中渲染,设置为 ssr: false
  • cors: boolean - 自动添加 CORS 头,设置为 cors: true - 您可以通过 headers 覆盖自定义输出
  • headers: object - 为网站部分添加特定头信息,例如您的资产
  • swr: number | boolean - 为服务器响应添加缓存头,并在服务器或反向代理上缓存具有可配置的 TTL(生存时间)。Nitro 的 node-server 预设能够缓存完整响应。当 TTL 过期时,将发送缓存响应,同时在后台重新生成页面。如果使用 true,将添加一个没有 MaxAge 的 stale-while-revalidate 头。
  • isr: number | boolean - 行为与 swr 相同,除了我们可以在支持此功能的平台上将响应添加到 CDN 缓存(目前为 Netlify 或 Vercel)。如果使用 true,内容将在下次部署前在 CDN 中保留。
  • prerender: boolean - 在构建时预渲染路由,并将其作为静态资产包含在构建中
  • noScripts: boolean - 禁用网站部分的 Nuxt 脚本和 JS 资源提示的渲染。
  • appMiddleware: string | string[] | Record<string, boolean> - 允许您定义应或不应在应用程序的 Vue 应用部分内部的页面路径上运行的中间件(即不是 Nitro 路由的部分)

在可能的情况下,路由规则将自动应用于部署平台的本地规则,以获得最佳性能(目前支持 Netlify 和 Vercel)。

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

示例:

Nuxt Vercel ISR

一个在 Vercel 上部署的支持混合渲染的 Nuxt 应用示例。

边缘侧渲染

边缘侧渲染(ESR)是 Nuxt 中引入的强大功能,允许通过内容分发网络(CDN)的边缘服务器将业务逻辑靠近用户进行渲染。通过利用 ESR,您可以确保提高性能,降低延迟,从而提供增强的用户体验。

通过 ESR,渲染过程被推送到网络的“边缘”——CDN 的边缘服务器。请注意,ESR 更多的是一种部署目标而不是实际的渲染模式。

当请求页面时,代替前往原始服务器,它被最近的边缘服务器拦截。该服务器生成页面的 HTML 并将其发送回用户。此过程最小化了数据传输的物理距离,降低了延迟并更快加载页面

边缘侧渲染得益于 Nitro,这是驱动 Nuxt 的 服务器引擎。它提供对 Node.js、Deno、Cloudflare Workers 等的跨平台支持。

您可以利用 ESR 的当前平台有:

请注意,在使用具有路由规则的边缘侧渲染时可以使用 混合渲染

您可以浏览已在上述某些平台上部署的开源示例:

Nuxt Todos Edge

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

Atinotes

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