渲染模式
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 文件的哪些部分在通用渲染模式下在服务器和/或客户端上运行是很正常的。
<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 应用程序的交互性。
- 搜索引擎优化:通用渲染将页面的整个 HTML 内容作为经典服务器应用程序交付给浏览器。Web 爬虫可以直接索引页面的内容,这使得通用渲染成为任何想要快速索引的内容的绝佳选择。
服务器端渲染的缺点:
- 开发约束:服务器和浏览器环境不提供相同的 API,编写可以在两侧无缝运行的代码可能会很棘手。幸运的是,Nuxt 提供了指南和特定变量来帮助您确定代码在哪里执行。
- 成本:需要运行服务器才能动态渲染页面。这像任何传统服务器一样增加了每月成本。但是,由于通用渲染,服务器调用大大减少,浏览器接管客户端导航。
通用渲染非常通用,几乎可以适应任何用例,特别适合任何以内容为导向的网站:博客、营销网站、作品集、电子商务网站和市场。
客户端渲染
开箱即用的传统 Vue.js 应用程序在浏览器(或客户端)中渲染。然后,在浏览器下载并解析所有包含创建当前界面指令的 JavaScript 代码后,Vue.js 生成 HTML 元素。
客户端渲染的好处:
- 开发速度:当完全在客户端工作时,我们不必担心代码的服务器兼容性,例如,使用仅浏览器的 API,如
window对象。 - 更便宜:运行服务器增加了基础设施成本,因为您需要在支持 JavaScript 的平台上运行。我们可以在任何带有 HTML、CSS 和 JavaScript 文件的静态服务器上托管仅客户端的应用程序。
- 离线:因为代码完全在浏览器中运行,所以在互联网不可用时它可以很好地继续工作。
客户端渲染的缺点:
- 性能:用户必须等待浏览器下载、解析和运行 JavaScript 文件。根据网络对下载部分的影响以及用户的设备对解析和执行的影响,这可能需要一些时间并影响用户体验。
- 搜索引擎优化:索引和更新通过客户端渲染交付的内容比服务器渲染的 HTML 文档需要更多时间。这与我们讨论的性能缺点有关,因为搜索引擎爬虫不会在第一次尝试索引页面时等待界面完全渲染。您的内容将需要更多时间在搜索结果页面中显示和更新。
客户端渲染是那些不需要索引或用户经常访问的重交互Web 应用程序的好选择。它可以利用浏览器缓存在后续访问时跳过下载阶段,例如SaaS、后台办公室应用程序或在线游戏。
您可以在 nuxt.config.ts 中使用 Nuxt 启用仅客户端渲染:
export default defineNuxtConfig({
ssr: false,
})
ssr: false,您还应该在 ~/spa-loading-template.html 中放置一个 HTML 文件,其中包含一些您希望用于呈现加载屏幕的 HTML,该加载屏幕将在应用程序水合之前呈现。部署静态客户端渲染应用程序
如果您使用 nuxt generate 或 nuxt build --prerender 命令将应用程序部署到静态托管,那么默认情况下,Nuxt 会将每个页面渲染为单独的静态 HTML 文件。
nuxt generate 或 nuxt build --prerender 命令预渲染应用程序,那么您将无法使用任何服务器端点,因为输出文件夹中不会包含服务器。如果您需要服务器功能,请改用 nuxt build。如果您使用纯客户端渲染,那么这可能是不必要的。您可能只需要一个 index.html 文件,加上 200.html 和 404.html 回退文件,您可以告诉您的静态 Web 主机为所有请求提供这些文件。
为了实现这一点,我们可以更改路由的预渲染方式。只需将其添加到 nuxt.config.ts 中的您的钩子:
export default defineNuxtConfig({
hooks: {
'prerender:routes' ({ routes }) {
routes.clear() // 不生成任何路由(除了默认路由)
},
},
})
这将生成三个文件:
index.html200.html404.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 路由定义规则,根据路由更改渲染模式或分配缓存策略!
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 },
// 重定向旧 URL
'/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,则添加没有 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 路由)
isr 或 swr 的路由还会在 HTML 旁边生成 _payload.json 文件。客户端导航加载这些缓存的负载,而不是重新获取数据。使用全局模式配置动态路由,如 pages/[...slug].vue:'/**': { isr: true }。如果可能,路由规则将自动应用于部署平台的原生规则以获得最佳性能(目前支持 Netlify 和 Vercel)。
示例:
::
边缘渲染
边缘渲染(ESR)是 Nuxt 中引入的强大功能,它允许通过内容交付网络(CDN)的边缘服务器在更靠近用户的地方渲染 Nuxt 应用程序。通过利用 ESR,您可以确保提高性能并减少延迟,从而提供增强的用户体验。
使用 ESR,渲染过程被推送到网络的"边缘" - CDN 的边缘服务器。请注意,ESR 更多是一个部署目标,而不是实际的渲染模式。
当请求页面时,而不是一直到达原始服务器,它会被最近的边缘服务器拦截。此服务器为页面生成 HTML 并将其发送回用户。此过程最大限度地减少了数据必须传输的物理距离,减少延迟并更快地加载页面。
边缘渲染之所以可能,归功于 Nitro,它为 Node.js、Deno、Cloudflare Workers 等提供跨平台支持。
您目前可以利用 ESR 的平台有:
- Cloudflare Pages,使用 git 集成和
nuxt build命令零配置 - Vercel Cloud,使用
nuxt build命令和NITRO_PRESET=vercel-edge环境变量 - Netlify Edge Functions,使用
nuxt build命令和NITRO_PRESET=netlify-edge环境变量
请注意,当使用边缘渲染时,可以使用混合渲染配合路由规则。