渲染模式
了解 Nuxt 提供的不同渲染模式。
Nuxt 支持不同的渲染模式,通用渲染、客户端渲染,还提供混合渲染和在CDN 边缘服务器上渲染应用的可能性。
浏览器和服务器都可以解释 JavaScript 代码,将 Vue.js 组件转换为 HTML 元素。这个步骤称为渲染。Nuxt 支持通用和客户端渲染。我们将介绍这两种方法的优缺点。
默认情况下,Nuxt 使用通用渲染来提供更好的用户体验、性能并优化搜索引擎索引,但你可以在一行配置中切换渲染模式。
通用渲染
这个步骤类似于 PHP 或 Ruby 应用程序执行的传统服务器端渲染。当浏览器请求启用通用渲染的 URL 时,Nuxt 在服务器环境中运行 JavaScript (Vue.js) 代码,并向浏览器返回一个完全渲染的 HTML 页面。如果页面是预先生成的,Nuxt 也可能从缓存中返回一个完全渲染的 HTML 页面。用户立即获得应用程序的初始内容,而不是客户端渲染。
一旦下载了 HTML 文档,浏览器就会解释它,Vue.js 接管文档。在服务器上运行的相同 JavaScript 代码现在在客户端(浏览器)后台再次运行,启用交互性(因此称为通用渲染),通过将其监听器绑定到 HTML。这称为Hydration。当 Hydration 完成后,页面可以享受动态界面和页面过渡等好处。
通用渲染允许 Nuxt 应用程序在保留客户端渲染优势的同时提供快速的页面加载时间。此外,由于内容已经存在于 HTML 文档中,爬虫可以在没有开销的情况下对其进行索引。
什么是服务器渲染的,什么是客户端渲染的?
在通用渲染模式下,通常会问 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
的内容在这里从未执行。在浏览器中的 Hydration 过程中,counter
ref 被重新初始化。handleClick
最终绑定到按钮;因此可以合理地推断 handleClick
的主体将始终在浏览器环境中运行。
中间件和页面在服务器和客户端的 Hydration 过程中运行。插件可以在服务器或客户端或两者上渲染。组件也可以强制仅在客户端运行。组合函数和实用程序根据其使用的上下文进行渲染。
服务器端渲染的好处:
-
性能:用户可以立即访问页面的内容,因为浏览器可以比 JavaScript 生成的内容更快地显示静态内容。同时,Nuxt 在 Hydration 过程中保留了 Web 应用程序的交互性。
-
搜索引擎优化:通用渲染将页面的整个 HTML 内容传递给浏览器,类似于经典的服务器应用程序。Web 爬虫可以直接索引页面的内容,这使得通用渲染成为任何希望快速索引内容的理想选择。
服务器端渲染的缺点:
-
开发限制:服务器和浏览器环境不提供相同的 API,编写可以在两端无缝运行的代码可能很棘手。幸运的是,Nuxt 提供了指南和特定变量来帮助你确定代码的执行位置。
-
成本:需要运行服务器以动态渲染页面。这增加了每月的成本,就像任何传统服务器一样。然而,由于通用渲染在客户端导航时由浏览器接管,服务器调用大大减少。通过利用边缘渲染可以实现成本降低。
通用渲染非常灵活,几乎适用于任何用例,特别适合任何内容导向的网站:博客、营销网站、作品集、电子商务网站和市场。
有关编写没有 Hydration 不匹配的 Vue 代码的更多示例,请参见Vue 文档。
当导入依赖于浏览器 API 并具有副作用的库时,请确保导入它的组件仅在客户端调用。打包器不会对包含副作用的模块的导入进行树摇。
客户端渲染
开箱即用,传统的 Vue.js 应用程序在浏览器(或客户端)中渲染。然后,Vue.js 在浏览器下载并解析包含创建当前界面指令的所有 JavaScript 代码后生成 HTML 元素。
客户端渲染的好处:
-
开发速度:当完全在客户端工作时,我们不必担心代码的服务器兼容性,例如使用
window
对象等仅限浏览器的 API。 -
更便宜:运行服务器增加了基础设施成本,因为你需要在支持 JavaScript 的平台上运行。我们可以在任何带有 HTML、CSS 和 JavaScript 文件的静态服务器上托管仅客户端应用程序。
-
离线:由于代码完全在浏览器中运行,它可以在没有互联网的情况下正常工作。
客户端渲染的缺点:
-
性能:用户必须等待浏览器下载、解析和运行 JavaScript 文件。根据网络下载部分和用户设备的解析和执行,这可能需要一些时间并影响用户体验。
-
搜索引擎优化:通过客户端渲染传递的内容的索引和更新比服务器渲染的 HTML 文档需要更多时间。这与我们讨论的性能缺点有关,因为
搜索引擎爬虫
不会等待界面在第一次尝试索引页面时完全渲染。使用纯客户端渲染,你的内容需要更多时间才能在搜索结果页面中显示和更新。
客户端渲染是一个很好的选择,适用于不需要索引(SEO
)或用户频繁访问的高度交互的Web 应用程序。它可以利用浏览器缓存跳过后续访问时的下载阶段,例如SaaS、后台应用程序或在线游戏。
你可以在 nuxt.config.ts
中启用仅客户端渲染:
export default defineNuxtConfig({
ssr: false,
});
如果你确实使用
ssr: false
,你还应该在~/app/spa-loading-template.html
中放置一个 HTML 文件,其中包含一些 HTML,你希望在应用程序 Hydration 之前用于渲染加载屏幕。
观看 Alexander Lichter 关于使用 Nuxt 构建纯 SPA的视频。
部署静态客户端渲染应用
如果你使用 nuxi generate
或 nuxi build --prerender
命令将应用部署到静态托管,则默认情况下,Nuxt 会将每个页面渲染为单独的静态 HTML 文件。
如果你仅使用纯客户端渲染,这可能是不必要的。你可能只需要一个 index.html
文件,加上 200.html
和 404.html
备用文件,你可以告诉你的静态 Web 主机为所有请求提供这些文件。
为了实现这一点,我们可以更改路由的预渲染方式。只需将此添加到你的 nuxt.config.ts
中的钩子:
export default defineNuxtConfig({
hooks: {
'prerender:routes'({ routes }) {
routes.clear(); // 不生成任何路由(除默认值外)
},
},
});
这将生成三个文件:
-
index.html
-
200.html
-
404.html
200.html
和 404.html
可能对你使用的托管提供商有用。
混合渲染
混合渲染允许使用路由规则为每个路由设置不同的缓存规则,并决定服务器如何响应给定 URL 的新请求。
以前,Nuxt 应用程序和服务器的每个路由/页面必须使用相同的渲染模式,通用或客户端。在各种情况下,一些页面可以在构建时生成,而其他页面应该在客户端渲染。例如,想象一个带有管理部分的内容网站。每个内容页面应该主要是静态的并且只生成一次,但管理部分需要注册并且更像是一个动态应用程序。
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 路由上添加 cors 头
'/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
- 在构建时预渲染路由,并将其作为静态资产包含在构建中 -
experimentalNoScripts: boolean
- 禁用 Nuxt 脚本和 JS 资源提示的渲染,适用于你网站的部分。 -
appMiddleware: string | string[] | Record<string, boolean>
- 允许你定义中间件,应该或不应该在 Vue 应用程序部分的页面路径内运行(即,不是你的 Nitro 路由)
在可能的情况下,路由规则将自动应用于部署平台的本机规则,以实现最佳性能(目前支持 Netlify 和 Vercel)。
请注意,使用
nuxt generate
时不支持混合渲染。
示例:
在 Vercel 上部署的带有混合渲染的 Nuxt 应用程序示例。
边缘渲染
边缘渲染(ESR)是 Nuxt 引入的一个强大功能,允许通过内容分发网络(CDN)的边缘服务器更接近用户地渲染你的 Nuxt 应用程序。通过利用 ESR,你可以确保提高性能和减少延迟,从而提供增强的用户体验。
使用 ESR,渲染过程被推送到网络的“边缘”——CDN 的边缘服务器。请注意,ESR 更像是一个部署目标,而不是实际的渲染模式。
当请求页面时,不是直接到原始服务器,而是被最近的边缘服务器拦截。这个服务器生成页面的 HTML 并将其发送回用户。这个过程最小化了数据传输的物理距离,减少了延迟并加快了页面加载。
边缘渲染得益于 Nitro,这是 Nuxt 3 的服务器引擎。它提供了对 Node.js、Deno、Cloudflare Workers 等的跨平台支持。
目前可以利用 ESR 的平台有:
-
Cloudflare Pages 使用 git 集成和
nuxt build
命令进行零配置 -
Vercel Edge Functions 使用
nuxt build
命令和NITRO_PRESET=vercel-edge
环境变量 -
Netlify Edge Functions 使用
nuxt build
命令和NITRO_PRESET=netlify-edge
环境变量
请注意,使用边缘渲染时可以使用混合渲染和路由规则。
你可以探索在上述平台上部署的开源示例:
翻译日期: 2024-10-12
, 截止日期,文档为最新。