跳到主要内容

Prerendering

Nuxt 允许在构建时静态渲染某些页面,以改善特定的性能或 SEO 指标。

Nuxt 允许在构建时渲染应用中的选定页面。当请求这些页面时,Nuxt 会提供预构建的页面,而不是即时生成它们。

Nuxt 渲染模式·阅读更多

基于爬取的预渲染(Crawl-based Pre-rendering)

使用 nuxt generate 命令,借助 Nitro 爬虫来构建并预渲染你的应用。这个命令类似于将 nuxt buildnitro.static 选项设为 true,或者运行 nuxt build --prerender

它会构建你的站点,启动一个 Nuxt 实例,并默认预渲染根页面 / 以及你的站点中任何与之链接的页面、这些页面链接到的任何页面,依此类推。

npx nuxt generate

现在你可以将 .output/public 目录部署到任何静态托管服务,或者使用 npx serve .output/public 在本地预览。

静态构建和预渲染构建还会输出 200.html404.html 这两个 SPA 回退页面。请参阅 什么是 200.html 和 404.html?

Nitro 爬虫的工作方式:

  1. 加载你的应用根路由(/)的 HTML、你 ~/pages 目录中的任何非动态页面,以及 nitro.prerender.routes 数组中的任何其他路由。
  2. 将 HTML 和 _payload.json 保存到 ~/.output/public/ 目录,以便静态提供服务。
  3. 在 HTML 中查找所有锚点标签(<a href="...">)以导航到其他路由。
  4. 对找到的每个锚点标签重复步骤 1-3,直到没有更多锚点标签可爬取。

理解这一点很重要,因为未被可发现页面链接到的页面无法被自动预渲染。

阅读更多关于 nuxt generate 命令的内容。

选择性预渲染(Selective Pre-rendering)

你可以手动指定 Nitro 在构建期间会获取并预渲染的路由,或者忽略你不想预渲染的路由(例如 nuxt.config 文件中的 /dynamic):

nuxt.config.ts
// @errors: 2353
export default defineNuxtConfig({
  nitro: {
    prerender: {
      routes: ['/user/1', '/user/2'],
      ignore: ['/dynamic'],
    },
  },
})

你可以将其与 crawlLinks 选项结合,以预渲染爬虫无法发现的一组路由,例如你的 /sitemap.xml/robots.txt

nuxt.config.ts
// @errors: 2353
export default defineNuxtConfig({
  nitro: {
    prerender: {
      crawlLinks: true,
      routes: ['/sitemap.xml', '/robots.txt'],
    },
  },
})

nitro.prerender 设为 true 类似于将 nitro.prerender.crawlLinks 设为 true

在 Nitro 文档中阅读更多关于预渲染的内容。

最后,你也可以使用 routeRules 手动配置。

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    // 将 prerender 设为 true 以配置为预渲染
    '/rss.xml': { prerender: true },
    // 将其设为 false 以配置为跳过预渲染
    '/this-DOES-NOT-get-prerendered': { prerender: false },
    // 只要从另一个页面链接到,/blog 下的所有内容都会被预渲染
    '/blog/**': { prerender: true },
  },
})

阅读更多关于 Nitro 的 routeRules 配置。

作为一种简写,你也可以在页面文件中使用 defineRouteRules 来配置。

此特性是实验性的,要使用它,你必须在 nuxt.config 中启用 experimental.inlineRouteRules 选项。

app/pages/index.vue
<script setup>
// 或者在页面级别设置
defineRouteRules({
  prerender: true,
})
</script>

<template>
  <div>
    <h1>Homepage</h1>
    <p>在构建时预渲染</p>
  </div>
</template>

它会被转换为:

nuxt.config.ts
export default defineNuxtConfig({
  routeRules: {
    '/': { prerender: true },
  },
})

Payload 提取(Payload Extraction)

当 Nuxt 在服务端渲染页面时,它会将你的数据获取结果(useAsyncDatauseFetch)以及应用状态(useState)序列化到一个 payload 中,以便客户端无需重新获取即可完成 hydration。启用 payload 提取后,Nuxt 还会将该 payload 写入到路由 HTML 同级的 _payload.json 文件中:

  • 预渲染的路由会在构建时生成它们的 payload 文件。
  • 使用 ISR 或 SWR 缓存 的路由会在该路由首次渲染时生成它们的 payload 文件,即使在混合(非静态)站点上也是如此。

在客户端导航期间,Nuxt 会获取目标路由的 _payload.json 文件,并复用提取的数据,而不是在浏览器中再次运行数据获取。

你可以通过 experimental.payloadExtraction 选项来控制此行为:

  • 'client' - payload 在初始渲染时内联在 HTML 中,并为客户端导航提取到 _payload.json 文件。首次加载没有额外的网络请求。
  • true - payload 被提取到单独的 _payload.json 文件中,用于初始渲染和客户端导航。HTML 更小,且 payload 文件可以被 CDN 缓存,代价是首次加载多一次请求。
  • false - 禁用 payload 提取。payload 始终内联在 HTML 中,不会生成 _payload.json 文件。

默认值为 true,或者在设置了 compatibilityVersion: 5 时为 'client'。当设置了 ssr: false 时,它会被强制设为 false

nuxt.config.ts
export default defineNuxtConfig({
  experimental: {
    payloadExtraction: 'client',
  },
})

需要注意的几个实际后果:

  • 在完全静态的站点上,客户端导航会复用构建时捕获的数据,因此数据可能在下一次重建之前都是过期的。
  • 对于 ISR/SWR 路由,CDN 可以将 payload 文件与 HTML 一起缓存,从而提升缓存路由的客户端导航性能。像 pages/[...slug].vue 这样的动态路由可以通过 glob 模式(如 '/**': { isr: true })选择加入。
  • payload 使用 devalue 序列化,因此自定义类型(例如类实例)需要带有自定义 reducer 和 reviver 的 payload 插件才能在往返中存活。
Payload reducer 与 reviver·

运行时预渲染配置(Runtime Prerender Configuration)

prerenderRoutes

你可以在 Nuxt 上下文 中的运行时使用它,为 Nitro 添加更多要预渲染的路由。

app/pages/index.vue
<script setup>
prerenderRoutes(['/some/other/url'])
prerenderRoutes('/api/content/article/my-article')
</script>

<template>
  <div>
    <h1>这将在预渲染时注册其他路由以供预渲染</h1>
  </div>
</template>
prerenderRoutes·

prerender:routes Nuxt 钩子

这会在预渲染之前被调用,以注册额外的路由。

nuxt.config.ts
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 钩子

这会在预渲染期间针对每个路由被调用。你可以用它来对每个被预渲染的路由进行细粒度处理。

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    hooks: {
      'prerender:generate' (route) {
        if (route.route?.includes('private')) {
          route.skip = true
        }
      },
    },
  },
})