渲染模式

了解 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 文档中,爬虫可以直接索引,而无需额外开销。

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

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

app/app.vue
<script setup lang="ts">
const counter = ref(0) // executes in server and client environments

const handleClick = () => {
  counter.value++ // executes only in a client environment
}
</script>

<template>
  <div>
    <p>Count: {{ counter }}</p>
    <button @click="handleClick">
      Increment
    </button>
  </div>
</template>

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

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

服务器端渲染的优势

  • 性能:用户可以立即访问页面内容,因为浏览器显示静态内容的速度远快于 JavaScript 生成的内容。同时,Nuxt 在激活过程中保留了 Web 应用程序的交互性。
  • 搜索引擎优化:通用渲染像经典服务器应用程序一样,将页面的整个 HTML 内容传递给浏览器。网络爬虫可以直接索引页面内容,这使得通用渲染成为任何您想要快速索引的内容的绝佳选择。

服务器端渲染的缺点

  • 开发限制: 服务器和浏览器环境不提供相同的 API,编写可以在两端无缝运行的代码可能很棘手。幸运的是,Nuxt 提供了指南和特定变量来帮助您确定一段代码的执行位置。
  • 成本: 服务器需要运行才能动态渲染页面。这增加了与任何传统服务器相同的每月成本。然而,由于通用渲染和浏览器在客户端导航时接管,服务器调用大大减少。通过利用边缘侧渲染可以降低成本。

通用渲染非常通用,几乎适用于所有用例,尤其适用于任何面向内容的网站:博客、营销网站、作品集、电子商务网站和市场。

有关在没有激活不匹配的情况下编写 Vue 代码的更多示例,请参见Vue 文档.
当导入依赖于浏览器 API 并具有副作用的库时,请确保导入它的组件仅在客户端调用。打包工具不会对包含副作用的模块的导入进行 treeshake。

客户端渲染

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

客户端渲染的优势

  • 开发速度:当完全在客户端工作时,我们无需担心代码的服务器兼容性,例如,通过使用仅限浏览器的 API,如 window 对象。
  • 更便宜: 运行服务器会增加基础设施成本,因为您需要在支持 JavaScript 的平台上运行。我们可以将纯客户端应用程序托管在任何带有 HTML、CSS 和 JavaScript 文件的静态服务器上。
  • 离线: 由于代码完全在浏览器中运行,因此在互联网不可用时,它也能正常工作。

客户端渲染的缺点

  • 性能:用户必须等待浏览器下载、解析并运行 JavaScript 文件。根据下载的网络和解析与执行的用户设备,这可能需要一些时间并影响用户体验。
  • 搜索引擎优化:通过客户端渲染交付内容的索引和更新比服务器渲染的 HTML 文档花费更多时间。这与我们讨论的性能缺陷有关,因为搜索引擎爬虫在第一次尝试索引页面时不会等待界面完全渲染。使用纯客户端渲染,您的内容需要更长时间才能在搜索结果页面中显示和更新。

客户端渲染是需要大量交互的Web 应用程序的不错选择,这些应用程序不需要索引或用户经常访问。它可以利用浏览器缓存来跳过后续访问的下载阶段,例如 SaaS、后台应用程序或在线游戏

您可以在 nuxt.config.ts 中为 Nuxt 启用纯客户端渲染。

nuxt.config.ts
export default defineNuxtConfig({
  ssr: false,
})
如果您确实使用 ssr: false,您还应该在 ~/spa-loading-template.html 中放置一个 HTML 文件,其中包含您希望用于渲染加载屏幕的 HTML,该屏幕将在您的应用程序激活之前渲染。
SPA 加载模板中阅读更多内容。

部署静态客户端渲染应用程序

如果您使用 nuxt generatenuxt build --prerender 命令将您的应用程序部署到静态主机,那么默认情况下,Nuxt 会将每个页面渲染为单独的静态 HTML 文件。

如果您使用 nuxt generatenuxt build --prerender 命令预渲染您的应用程序,那么您将无法使用任何服务器端点,因为您的输出文件夹中不包含服务器。如果您需要服务器功能,请改用 nuxt build

如果您纯粹使用客户端渲染,那么这可能是不必要的。您可能只需要一个 index.html 文件,以及 200.html404.html 回退文件,您可以告诉您的静态 Web 主机为所有请求提供这些文件。

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

nuxt.config.ts
export default defineNuxtConfig({
  hooks: {
    'prerender:routes' ({ routes }) {
      routes.clear() // Do not generate any routes (except the defaults)
    },
  },
})

这将生成三个文件

  • 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: {
    // Homepage pre-rendered at build time
    '/': { prerender: true },
    // Products page generated on demand, revalidates in background, cached until API response changes
    '/products': { swr: true },
    // Product pages generated on demand, revalidates in background, cached for 1 hour (3600 seconds)
    '/products/**': { swr: 3600 },
    // Blog posts page generated on demand, revalidates in background, cached on CDN for 1 hour (3600 seconds)
    '/blog': { isr: 3600 },
    // Blog post page generated on demand once until next deployment, cached on CDN
    '/blog/**': { isr: true },
    // Admin dashboard renders only on client-side
    '/admin/**': { ssr: false },
    // Add cors headers on API routes
    '/api/**': { cors: true },
    // Redirects legacy urls
    '/old-page': { redirect: '/new-page' },
  },
})

路由规则

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

  • redirect: string - 定义服务器端重定向。
  • ssr: boolean - 禁用应用程序某些部分的 HTML 服务器端渲染,并使用 ssr: false 使它们仅在浏览器中渲染
  • cors: boolean - 使用 cors: true 自动添加 CORS 标头 - 您可以通过使用 headers 覆盖来自定义输出
  • headers: object - 为您网站的某些部分添加特定的标头 - 例如,您的资产
  • swr: number | boolean - 将缓存标头添加到服务器响应,并在服务器或反向代理上缓存它,缓存时间可配置(TTL)。Nitro 的 node-server 预设能够缓存完整响应。当 TTL 过期时,将发送缓存的响应,同时页面将在后台重新生成。如果使用 true,则会添加 stale-while-revalidate 标头,但不带 MaxAge。
  • isr: number | boolean - 行为与 swr 相同,不同之处在于我们可以在支持此功能的平台(目前是 Netlify 或 Vercel)上将响应添加到 CDN 缓存中。如果使用 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) 的边缘服务器将 Nuxt 应用程序渲染到更靠近用户的位置。通过利用 ESR,您可以确保提高性能并减少延迟,从而提供增强的用户体验。

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

当请求页面时,它不会一路发送到原始服务器,而是被最近的边缘服务器拦截。此服务器生成页面的 HTML 并将其发送回用户。此过程将数据传输的物理距离最小化,从而减少延迟并更快地加载页面

边缘侧渲染之所以可能,得益于Nitro,为 Nuxt 提供动力的服务器引擎。它为 Node.js、Deno、Cloudflare Workers 等提供跨平台支持。

您可以利用 ESR 的当前平台是

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

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

Nuxt Todos Edge

一个带有用户身份验证、SSR 和 SQLite 的待办事项应用程序。

Atinotes

一个基于 Cloudflare KV 的可编辑网站,支持通用渲染。