渲染模式
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 文件的哪些部分在服务器和/或客户端上运行是很正常的。
<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
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
,您还应该在 ~/app/spa-loading-template.html
中放置一个 HTML 文件,其中包含您想要用于渲染加载屏幕的 HTML,该加载屏幕将在您的应用程序水合之前渲染。部署静态客户端渲染应用程序
如果您使用 nuxi generate
或 nuxi build --prerender
命令将您的应用程序部署到 静态托管,那么默认情况下,Nuxt 会将每个页面渲染为单独的静态 HTML 文件。
nuxi generate
或 nuxi build --prerender
命令预渲染您的应用程序,那么您将无法使用任何服务器端点,因为您的输出文件夹中不会包含任何服务器。如果您需要服务器功能,请改用 nuxi build
。如果您完全使用客户端渲染,则这可能是没有必要的。您可能只需要一个 index.html
文件,以及 200.html
和 404.html
回退文件,您可以告知您的静态 Web 主机为所有请求提供这些文件。
为了实现这一点,我们可以更改路由预渲染的方式。只需将此添加到您的 nuxt.config.ts
文件中的 hooks 中。
export default defineNuxtConfig({
hooks: {
'prerender:routes' ({ routes }) {
routes.clear() // Do not generate any routes (except the defaults)
}
},
})
这将生成三个文件
index.html
200.html
404.html
200.html
和 404.html
文件可能对您正在使用的主机提供商很有用。
跳过客户端回退生成
当预渲染客户端渲染的应用程序时,Nuxt 默认会生成 index.html
、200.html
和 404.html
文件。但是,如果您需要阻止在构建中生成任何(或所有)这些文件,您可以使用来自 Nitro 的 'prerender:generate'
hook。
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: {
// 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
时,混合渲染不可用。示例
边缘端渲染
边缘端渲染 (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
环境变量
请注意,当将边缘端渲染与路由规则一起使用时,可以使用 混合渲染 。
您可以探索部署在上面提到的一些平台上的开源示例