预渲染
Nuxt 允许将应用中的部分页面在构建时渲染。Nuxt 在请求这些页面时会提供预构建好的页面,而不是在运行时动态生成它们。
基于爬虫的预渲染
使用 nuxt generate 命令 来构建并使用 Nitro 爬虫预渲染你的应用。该命令类似于将 nitro.static 选项设置为 true 的 nuxt build,或运行 nuxt build --prerender。
这会构建你的网站,启动一个 nuxt 实例,并且默认会预渲染根页面 /,以及该页面链接的任何站点页面、这些页面所链接的页面,依此类推。
npx nuxt generate
yarn nuxt generate
pnpm nuxt generate
bun x nuxt generate
deno x nuxt generate
你现在可以将 .output/public 目录部署到任意静态托管服务,或使用 npx serve .output/public 在本地预览。
静态和预渲染构建也会输出 200.html 和 404.html 作为 SPA 回退页面。请参阅 什么是 200.html 和 404.html?。
Nitro 爬虫的工作方式:
- 加载你应用根路由(
/)、~/pages目录中的所有非动态页面,以及nitro.prerender.routes数组中的其他所有路由的 HTML。 - 将 HTML 和
_payload.json保存到~/.output/public/目录,以便静态提供。 - 在 HTML 中查找所有锚点标签(
<a href="...">)以导航到其他路由。 - 对找到的每个锚点标签重复步骤 1-3,直到没有更多锚点标签可供爬取。
理解这一点很重要,因为未被任何可发现页面链接的页面无法被自动预渲染。
选择性预渲染
你可以在 nuxt.config 文件中手动指定 Nitro 在构建期间会抓取并预渲染的路由,或忽略你不想预渲染的路由,例如 /dynamic:
// @errors: 2353
export default defineNuxtConfig({
nitro: {
prerender: {
routes: ['/user/1', '/user/2'],
ignore: ['/dynamic'],
},
},
})
你可以将此与 crawlLinks 选项结合使用,以预渲染爬虫无法发现的一组路由,例如你的 /sitemap.xml 或 /robots.txt:
// @errors: 2353
export default defineNuxtConfig({
nitro: {
prerender: {
crawlLinks: true,
routes: ['/sitemap.xml', '/robots.txt'],
},
},
})
将 nitro.prerender 设置为 true 与将 nitro.prerender.crawlLinks 设置为 true 类似。
最后,你也可以使用 routeRules 手动配置此行为。
export default defineNuxtConfig({
routeRules: {
// 将 prerender 设为 true 以配置为预渲染
'/rss.xml': { prerender: true },
// 将其设为 false 以配置为跳过预渲染
'/this-DOES-NOT-get-prerendered': { prerender: false },
// /blog 下的所有内容都会被预渲染,只要它
// 从另一个页面被链接到
'/blog/**': { prerender: true },
},
})
作为简写,你也可以在页面文件中使用 defineRouteRules 来配置此项。
<script setup>
// 或在页面级别设置
defineRouteRules({
prerender: true,
})
</script>
<template>
<div>
<h1>首页</h1>
<p>在构建时预渲染</p>
</div>
</template>
这将被转换为:
export default defineNuxtConfig({
routeRules: {
'/': { prerender: true },
},
})
负载提取
当 Nuxt 在服务器上渲染页面时,它会将你的数据获取(useAsyncData 和 useFetch)以及应用状态(useState)的结果序列化为一个负载,这样客户端就可以在不重新获取数据的情况下完成 hydration。启用负载提取后,Nuxt 还会将此负载写入与路由 HTML 并列的 _payload.json 文件中:
- 预渲染路由会在构建时生成其负载文件。
- 使用 ISR 或 SWR 缓存 的路由会在路由首次渲染时生成其负载文件,即使是在混合(非静态)站点上也是如此。
在客户端导航期间,Nuxt 会为目标路由获取 _payload.json 文件,并复用提取出的数据,而不是在浏览器中再次执行数据获取。
你可以通过 experimental.payloadExtraction 选项来控制此行为:
'client'- 首次渲染时,负载内联在 HTML 中,并在客户端导航时提取到_payload.json文件中。首次加载不会有额外的网络请求。true- 对于首次渲染和客户端导航,负载都会提取到单独的_payload.json文件中。HTML 更小,负载文件可以被 CDN 缓存,但首次加载会多一次请求。false- 禁用负载提取。负载始终内联在 HTML 中,不会生成_payload.json文件。
默认值为 true;当设置了 compatibilityVersion: 5 时,默认值为 'client'。当设置 ssr: false 时,它会被强制设为 false。
export default defineNuxtConfig({
experimental: {
payloadExtraction: 'client',
},
})
需要注意的一些实际影响:
- 在完全静态站点上,客户端导航会复用构建时捕获的数据,因此在下一次重建之前,数据可能会过期。
- 对于 ISR/SWR 路由,CDN 可以在 HTML 旁边缓存负载文件,从而提升缓存路由的客户端导航性能。像
pages/[...slug].vue这样的动态路由可以通过诸如'/**': { isr: true }这样的 glob 模式来启用。 - 负载使用 devalue 序列化,因此自定义类型(例如类实例)需要带有自定义 reducer 和 reviver 的负载插件,才能在往返过程中保持不变。
运行时预渲染配置
prerenderRoutes
你可以在运行时于 Nuxt 上下文 中使用此方法,为 Nitro 添加更多需要预渲染的路由。
<script setup>
prerenderRoutes(['/some/other/url'])
prerenderRoutes('/api/content/article/my-article')
</script>
<template>
<div>
<h1>这将在预渲染时为预渲染注册其他路由</h1>
</div>
</template>
prerender:routes Nuxt hook
这个钩子在预渲染之前被调用,用于注册额外的路由。
export default defineNuxtConfig({
hooks: {
async 'prerender:routes' (ctx) {
const { pages } = await fetch('https://api.some-cms.com/pages').then(
res => res.json(),
)
for (const page of pages) {
ctx.routes.add(`/${page.name}`)
}
},
},
})
prerender:generate Nitro hook
该钩子在预渲染过程中对每个路由分别调用。你可以用它对每个被预渲染的路由进行更精细的处理。
export default defineNuxtConfig({
nitro: {
hooks: {
'prerender:generate' (route) {
if (route.route?.includes('private')) {
route.skip = true
}
},
},
},
})