渲染模式
Nuxt 支持不同的渲染模式:通用渲染、客户端渲染,但也提供 hybrid-rendering 以及在 CDN 边缘服务器 上渲染应用的可能性。
¥Nuxt supports different rendering modes, universal rendering, client-side rendering but also offers hybrid-rendering and the possibility to render your application on CDN Edge Servers.
浏览器和服务器都可以解释 JavaScript 代码,将 Vue.js 组件转换为 HTML 元素。此步骤称为渲染。Nuxt 同时支持通用渲染和客户端渲染。这两种方法各有优缺点,我们将分别介绍。
¥Both the browser and server can interpret JavaScript code to turn Vue.js components into HTML elements. This step is called rendering. Nuxt supports both universal and client-side rendering. The two approaches have benefits and downsides that we will cover.
默认情况下,Nuxt 使用通用渲染来提供更好的用户体验、性能并优化搜索引擎索引,但你可以在 一行配置 中切换渲染模式。
¥By default, Nuxt uses universal rendering to provide better user experience, performance and to optimize search engine indexing, but you can switch rendering modes in one line of configuration.
通用渲染
¥Universal Rendering
此步骤类似于 PHP 或 Ruby 应用执行的传统服务器端渲染。当浏览器请求启用了通用渲染的 URL 时,Nuxt 会在服务器环境中运行 JavaScript(Vue.js)代码,并向浏览器返回完全渲染的 HTML 页面。如果页面是预先生成的,Nuxt 还可以从缓存中返回完全渲染的 HTML 页面。与客户端渲染不同,用户可以立即获得应用的完整初始内容。
¥This step is similar to traditional server-side rendering performed by PHP or Ruby applications. When the browser requests a URL with universal rendering enabled, Nuxt runs the JavaScript (Vue.js) code in a server environment and returns a fully rendered HTML page to the browser. Nuxt may also return a fully rendered HTML page from a cache if the page was generated in advance. Users immediately get the entirety of the initial content of the application, contrary to client-side rendering.
HTML 文档下载完成后,浏览器会对其进行解释,然后 Vue.js 会控制该文档。曾经在服务器上运行的 JavaScript 代码现在在客户端(浏览器)的后台再次运行,通过将其监听器绑定到 HTML,实现了交互性(因此实现了通用渲染)。这称为 Hydration。Hylation 完成后,页面可以享受动态界面和页面转换等功能。
¥Once the HTML document has been downloaded, the browser interprets this and Vue.js takes control of the document. The same JavaScript code that once ran on the server runs on the client (browser) again in the background now enabling interactivity (hence Universal rendering) by binding its listeners to the HTML. This is called Hydration. When hydration is complete, the page can enjoy benefits such as dynamic interfaces and page transitions.
通用渲染使 Nuxt 应用能够提供快速的页面加载时间,同时保留客户端渲染的优势。生成 并将其写入项目 buildDir。
¥Universal rendering allows a Nuxt application to provide quick page load times while preserving the benefits of client-side rendering. Furthermore, as the content is already present in the HTML document, crawlers can index it without overhead.
什么是服务器渲染,什么是客户端渲染?
¥What's server-rendered and what's client-rendered?
询问 Vue 文件的哪些部分在通用渲染模式下在服务器和/或客户端上运行是正常的。
¥It is normal to ask which parts of a Vue file runs on the server and/or the client in universal rendering mode.
<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 的内容永远不会在此处执行。在浏览器中进行 hydration 时,counter 引用会被重新初始化。handleClick 最终将自身绑定到按钮;因此,可以合理推断 handleClick 的主体将始终在浏览器环境中运行。
¥On the initial request, the counter ref is initialized in the server since it is rendered inside the <p> tag. The contents of handleClick is never executed here. During hydration in the browser, the counter ref is re-initialized. The handleClick finally binds itself to the button; Therefore it is reasonable to deduce that the body of handleClick will always run in a browser environment.
中间件 和 pages 在水合 (hydration) 期间在服务器和客户端运行。插件 可以在服务器或客户端或两者上渲染。组件 也可以强制仅在客户端运行。可组合函数 和 utilities 根据其使用上下文进行渲染。
¥Middlewares and pages run in the server and on the client during hydration. Plugins can be rendered on the server or client or both. Components can be forced to run on the client only as well. Composables and utilities are rendered based on the context of their usage.
服务器端渲染的优势:
¥Benefits of server-side rendering:
- 性能:用户可以立即访问页面内容,因为浏览器显示静态内容的速度比 JavaScript 生成的内容快得多。同时,Nuxt 在 hydration 过程中保留了 Web 应用的交互性。
- 搜索引擎优化:通用渲染将页面的完整 HTML 内容像经典服务器应用一样呈现给浏览器。网络爬虫可以直接索引页面内容,这使得通用渲染成为你想要快速索引任何内容的绝佳选择。
服务器端渲染的缺点:
¥Downsides of server-side rendering:
- 开发限制:服务器和浏览器环境提供的 API 并不相同,编写能够在两端无缝运行的代码可能比较棘手。Nuxt 4 中不再支持以下四个实验性功能:
- 成本:需要运行服务器才能动态渲染页面。与任何传统服务器一样,这会增加月度成本。然而,由于浏览器接管了客户端导航的通用渲染,服务器调用次数大大减少。利用 edge-side-rendering 可以降低成本。
通用渲染功能非常灵活,几乎适用于任何用例,尤其适用于任何以内容为导向的网站:博客、营销网站、作品集、电商网站和市场。
¥Universal rendering is very versatile and can fit almost any use case, and is especially appropriate for any content-oriented websites: blogs, marketing websites, portfolios, e-commerce sites, and marketplaces.
客户端渲染
¥Client-Side Rendering
开箱即用,传统的 Vue.js 应用会在浏览器(或客户端)中渲染。然后,在浏览器下载并解析所有包含创建当前界面指令的 JavaScript 代码后,Vue.js 会生成 HTML 元素。
¥Out of the box, a traditional Vue.js application is rendered in the browser (or client). Then, Vue.js generates HTML elements after the browser downloads and parses all the JavaScript code containing the instructions to create the current interface.
客户端渲染的优势:
¥Benefits of client-side rendering:
- 开发速度:当完全在客户端工作时,我们不必担心代码的服务器兼容性,例如,通过使用像
window对象这样的仅限浏览器的 API。 - 更便宜:运行服务器会增加基础设施成本,因为你需要在支持 JavaScript 的平台上运行。我们可以在任何静态服务器上托管仅客户端的应用,其中包含 HTML、CSS 和 JavaScript 文件。
- 离线:由于代码完全在浏览器中运行,因此即使互联网不可用,它也可以很好地继续工作。
客户端渲染的缺点:
¥Downsides of client-side rendering:
- 性能:用户必须等待浏览器下载、解析并运行 JavaScript 文件。根据下载部分的网络情况以及解析和执行部分的用户设备,这可能需要一些时间并影响用户体验。
- 搜索引擎优化:与服务器端渲染的 HTML 文档相比,索引和更新通过客户端渲染的内容需要更多时间。这与我们讨论的性能缺陷有关,因为搜索引擎爬虫在第一次尝试索引页面时不会等待界面完全渲染。如果使用纯客户端渲染,你的内容在搜索结果页面中显示和更新将需要更多时间。
对于不需要索引或用户访问频繁的、交互性很强的 Web 应用来说,客户端渲染是一个不错的选择。它可以利用浏览器缓存,在后续访问中跳过下载阶段,例如 SaaS、后台应用或在线游戏。
¥Client-side rendering is a good choice for heavily interactive web applications that don't need indexing or whose users visit frequently. It can leverage browser caching to skip the download phase on subsequent visits, such as SaaS, back-office applications, or online games.
你可以在 nuxt.config.ts 中启用 Nuxt 的客户端渲染:
¥You can enable client-side only rendering with Nuxt in your nuxt.config.ts:
export default defineNuxtConfig({
ssr: false
})
ssr: false,你还应该在 ~/app/spa-loading-template.html 中放置一个 HTML 文件,其中包含一些你想要用来渲染加载屏幕的 HTML,这些 HTML 将在你的应用完成 hydrated 之前一直渲染。:read-more{title="SPA Loading Template" to="/docs/api/configuration/nuxt-config#spaloadingtemplate"}部署静态客户端渲染应用
¥Deploying a Static Client-Rendered App
如果你使用 nuxi generate 或 nuxi build --prerender 命令将应用部署到 静态托管,那么默认情况下,Nuxt 会将每个页面渲染为单独的静态 HTML 文件。
¥If you deploy your app to static hosting with the nuxi generate or nuxi build --prerender commands, then by default, Nuxt will render every page as a separate static HTML file.
nuxi generate 或 nuxi build --prerender 命令预渲染你的应用,那么你将无法使用任何服务器端点,因为你的输出文件夹中不会包含任何服务器。如果你需要服务器功能,请改用 nuxi build。¥If you prerender your app with the nuxi generate or nuxi build --prerender commands, then you will not be able to use any server endpoints as no server will be included in your output folder. If you need server functionality, use nuxi build instead.如果你使用纯客户端渲染,那么这可能没有必要。你可能只需要一个 index.html 文件,以及 200.html 和 404.html 后备文件,你可以告诉你的静态 Web 主机为所有请求提供服务。
¥If you are using purely client-side rendering, then this might be unnecessary. You might only need a single index.html file, plus 200.html and 404.html fallbacks, which you can tell your static web host to serve up for all requests.
为了实现这一点,我们可以更改路由的预渲染方式。只需将此添加到你的 nuxt.config.ts 中的 你的钩子 即可:
¥In order to achieve this we can change how the routes are prerendered. Just add this to your hooks in your nuxt.config.ts:
export default defineNuxtConfig({
hooks: {
'prerender:routes' ({ routes }) {
routes.clear() // Do not generate any routes (except the defaults)
}
},
})
这将生成三个文件:
¥This will produce three files:
index.html200.html404.html
200.html 和 404.html 可能对你使用的托管服务提供商有用。
¥The 200.html and 404.html might be useful for the hosting provider you are using.
跳过客户端回退生成
¥Skipping Client Fallback Generation
在预渲染客户端渲染的应用时,Nuxt 默认会生成 index.html、200.html 和 404.html 文件。但是,如果你需要阻止在构建过程中生成任何(或所有)这些文件,你可以使用 Nitro 中的 'prerender:generate' 钩子。
¥When prerendering a client-rendered app, Nuxt will generate index.html, 200.html and 404.html files by default. However, if you need to prevent any (or all) of these files from being generated in your build, you can use the 'prerender:generate' hook from Nitro.
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
}
}
}
}
})
混合渲染
¥Hybrid Rendering
混合渲染允许使用路由规则为每个路由设置不同的缓存规则,并决定服务器应如何响应给定 URL 上的新请求。
¥Hybrid rendering allows different caching rules per route using Route Rules and decides how the server should respond to a new request on a given URL.
之前,Nuxt 应用和服务器的每个路由/页面都必须使用相同的渲染模式(通用或客户端)。在各种情况下,某些页面可以在构建时生成,而其他页面则应在客户端渲染。例如,设想一个包含管理部分的内容网站。每个内容页面都应该是静态的,并且只生成一次,但管理部分需要注册,并且行为更像一个动态应用。
¥Previously every route/page of a Nuxt application and server must use the same rendering mode, universal or client-side. In various cases, some pages could be generated at build time, while others should be client-side rendered. For example, think of a content website with an admin section. Every content page should be primarily static and generated once, but the admin section requires registration and behaves more like a dynamic application.
Nuxt 包含路由规则和混合渲染支持。使用路由规则,你可以为一组 nuxt 路由定义规则、更改渲染模式或根据路由分配缓存策略!
¥Nuxt includes route rules and hybrid rendering support. Using route rules you can define rules for a group of nuxt routes, change rendering mode or assign a cache strategy based on route!
Nuxt 服务器将使用 Nitro 缓存层 自动注册相应的中间件,并使用缓存处理程序封装路由。
¥Nuxt server will automatically register corresponding middleware and wrap routes with cache handlers using Nitro caching layer.
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' }
}
})
路由规则
¥Route Rules
你可以使用以下不同属性:
¥The different properties you can use are the following:
redirect: stringlang=ts} - 定义服务器端重定向。ssr: booleanlang=ts} - 禁用应用部分 HTML 的服务器端渲染,使其仅在浏览器中使用ssr: false进行渲染。cors: booleanlang=ts} - 使用cors: true自动添加 cors 标头 - 你可以通过使用headers覆盖来自定义输出。headers: objectlang=ts} - 为网站的各个部分添加特定的标头 - 例如,你的资源swr: number | booleanlang=ts} - 向服务器响应添加缓存标头,并将其缓存在服务器或反向代理上,以实现可配置的 TTL(生存时间)。Nitro 的node-server预设能够缓存完整响应。TTL 过期后,将发送缓存的响应,同时页面将在后台重新生成。如果设置为 true,则会添加不包含 MaxAge 的stale-while-revalidate标头。isr: number | booleanlang=ts} - 除了我们可以在支持此功能的平台(目前为 Netlify 或 Vercel)上将响应添加到 CDN 缓存之外,其行为与swr相同。如果使用了true,内容将保留到下次在 CDN 内部署。prerender: booleanlang=ts} - 在构建时预渲染路由,并将其作为静态资源包含在构建中。noScripts: booleanlang=ts} - 禁用 Nuxt 脚本和 JS 资源提示的渲染。appMiddleware: string | string[] | Record<string, boolean>lang=ts} - 允许你定义在应用的 Vue 应用部分(即非 Nitro 路由)中应该或不应该为页面路径运行的中间件。
为了获得最佳性能,路由规则将尽可能自动应用于部署平台的原生规则(目前支持 Netlify 和 Vercel)。
¥Whenever possible, route rules will be automatically applied to the deployment platform's native rules for optimal performances (Netlify and Vercel are currently supported).
nuxt generate 时,混合渲染不可用。示例:
¥Examples:
边缘渲染
¥Edge-Side Rendering
边缘渲染 (ESR) 是 Nuxt 中引入的一项强大功能,它允许通过内容分发网络 (CDN) 的边缘服务器将 Nuxt 应用的渲染更贴近用户。利用 ESR,你可以确保提升性能并减少延迟,从而提供更佳的用户体验。
¥Edge-Side Rendering (ESR) is a powerful feature introduced in Nuxt that allows the rendering of your Nuxt application closer to your users via edge servers of a Content Delivery Network (CDN). By leveraging ESR, you can ensure improved performance and reduced latency, thereby providing an enhanced user experience.
使用 ESR,渲染过程被推送到网络的 'edge' 目录。 - CDN 的边缘服务器。请注意,ESR 更像是一个部署目标,而非实际的渲染模式。
¥With ESR, the rendering process is pushed to the 'edge' of the network - the CDN's edge servers. Note that ESR is more a deployment target than an actual rendering mode.
当发出页面请求时,它不会被直接发送到原始服务器,而是会被最近的边缘服务器拦截。此服务器生成页面的 HTML 并将其返回给用户。此过程最大限度地减少了数据传输的物理距离,从而减少了延迟并加快了页面加载速度。
¥When a request for a page is made, instead of going all the way to the original server, it's intercepted by the nearest edge server. This server generates the HTML for the page and sends it back to the user. This process minimizes the physical distance the data has to travel, reducing latency and loading the page faster.
得益于 Nitro(即 Nuxt 的 服务器引擎),边缘渲染成为可能。它为 Node.js、Deno、Cloudflare Workers 等提供跨平台支持。
¥Edge-side rendering is possible thanks to Nitro, the server engine that powers Nuxt. It offers cross-platform support for Node.js, Deno, Cloudflare Workers, and more.
目前,你可以使用 ESR 的平台包括:
¥The current platforms where you can leverage ESR are:
- 使用 git 集成和
nuxt build命令的零配置 Cloudflare 页面 - Vercel Edge 函数 使用
nuxt build命令和NITRO_PRESET=vercel-edge环境变量 - Netlify Edge 函数 使用
nuxt build命令和NITRO_PRESET=netlify-edge环境变量
请注意,在路由规则中使用边缘渲染时,可以使用混合渲染。
¥Note that Hybrid Rendering can be used when using Edge-Side Rendering with route rules.
你可以浏览部署在上述某些平台上的开源示例:
¥You can explore open source examples deployed on some of the platform mentioned above: