# 预渲染 > 在构建时渲染路由,并将其作为静态资源提供 启用预渲染后,Nitro 会在构建期间获取指定路由,并将响应写入 `.output/public` 目录。预渲染的路由随后会作为静态文件提供。请求时不会进行服务器渲染,因此这些路由速度快、可缓存,并且可以部署到任意静态托管服务或 CDN。 预渲染适用于内容不会随请求变化的路由:落地页、文档、博客文章,或输出内容固定的 JSON 端点。动态路由仍然可以继续由服务器提供,并且你可以在同一个应用中自由混合预渲染路由和服务器渲染路由。 ## 预渲染路由 ### `prerender.routes` 配置 使用 `prerender.routes` 选项列出要预渲染的路由: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ prerender: { routes: ["/", "/about", "/api/content.json"], }, }); ``` HTML 响应会作为 `index.html` 文件写入子文件夹中(`/about` 会生成 `about/index.html`),而其他响应会保留其路径(`/api/content.json` 会生成 `api/content.json`)。请参阅 [`autoSubfolderIndex`](#options) 以更改此行为。 ### `prerender` 路由规则 或者,使用 `prerender` [路由规则](/docs/routing#route-rules)将路由标记为预渲染: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ routeRules: { "/about": { prerender: true }, }, }); ``` ::warning 路由规则只会将**完全匹配的路径**添加到预渲染列表中。像 `"/blog/**": { prerender: true }` 这样的通配符模式**不会**自动展开,因为 Nitro 无法知道哪些路由与该模式匹配。要预渲染一组动态路由,请使用[链接爬取](#crawling-links)或 [`prerender:routes` hook](#hooks)。 :: ## 爬取链接 除了(或作为补充)列出每个路由之外,还可以启用 `crawlLinks`,让 Nitro 通过跟随预渲染 HTML 页面中的链接来发现路由: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ prerender: { crawlLinks: true, routes: ["/"], }, }); ``` 爬虫会从每个预渲染 HTML 页面中提取 `href` 属性,并将发现的路由加入预渲染队列。外部链接、哈希链接,以及指向带扩展名文件的链接(`.json` 除外)都会被跳过。相对链接会根据其所在页面进行解析。 如果启用了 `crawlLinks` 且未指定路由,爬取会从 `/` 开始。 ::tip 处理程序可以通过将 `x-nitro-prerender` 响应标头设置为以逗号分隔的路径列表,来为预渲染添加其他路由。即使禁用了 `crawlLinks`,此功能仍然有效。 :: ## 忽略路由 使用 `prerender.ignore` 跳过路由。每个条目可以是字符串前缀、正则表达式,或接收路径的函数: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ prerender: { crawlLinks: true, ignore: [ "/admin", // Ignore routes starting with /admin /\/preview$/, // Ignore routes ending with /preview (path) => path.includes("draft"), // Ignore routes containing "draft" ], }, }); ``` 你也可以使用 `prerender: false` 路由规则排除路由。与启用预渲染不同,通配符模式**可以**用于排除,因为它们会针对每个候选路由进行匹配: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ routeRules: { "/dynamic/**": { prerender: false }, }, }); ``` ### 公共资源 由带有基础 URL 前缀的[公共资源](/docs/assets)提供的路由始终会被跳过。此外,你可以设置 `prerender.ignoreUnprefixedPublicAssets: true`,跳过已经由不带前缀的公共资源提供的路由,从而避免输出中出现重复文件: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ prerender: { crawlLinks: true, ignoreUnprefixedPublicAssets: true, }, }); ``` ## 选项 | 选项 | 默认值 | 描述 | |--------|---------|-------------| | `failOnError` | `false` | 当路由无法预渲染时使构建失败。适用于 CI。 | | `retry` | `3` | 失败路由的重试次数。传入 `Infinity` 可无限重试。 | | `retryDelay` | `500` | 每次重试之间的延迟时间,单位为毫秒。 | | `concurrency` | `1` | 并行预渲染的最大路由数。 | | `interval` | `0` | 预渲染请求之间的延迟时间,单位为毫秒。 | | `autoSubfolderIndex` | `true` | 将 HTML 路由写入子文件夹索引文件。 | ::note `retry` 和 `retryDelay` 选项可以在配置中接受,但当前的 v3 预渲染器尚未应用它们。 :: `concurrency` 和 `interval` 选项控制预渲染速度。提高 `concurrency` 可以加快大型网站的速度,或者添加 `interval`,以避免路由调用外部 API 时触发速率限制。 `autoSubfolderIndex` 控制 HTML 文件写入 `.output/public` 的方式: ```bash # autoSubfolderIndex: true (default) /about -> .output/public/about/index.html # autoSubfolderIndex: false /about -> .output/public/about.html ``` 当你的托管服务提供商不允许配置尾部斜杠行为时,将其设置为 `false`。 ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ prerender: { crawlLinks: true, failOnError: true, concurrency: 8, autoSubfolderIndex: false, }, }); ``` ## Hooks 对于高级用例,你可以在构建时接入预渲染生命周期。这些 hooks 可供[模块](/docs/modules)和 `hooks` 配置选项使用: | Hook | 描述 | |------|-------------| | `prerender:routes` | 使用初始的路由 `Set` 调用,在预渲染开始前添加或移除条目。 | | `prerender:config` | 使用用于预渲染的内部 Nitro 实例配置调用。 | | `prerender:generate` | 在写入每个路由的文件之前调用,用于检查或修改路由对象(`route.contents`、`route.fileName`……),或设置 `route.skip = true`。 | | `prerender:route` | 每个路由生成后调用。 | | `prerender:done` | 预渲染完成后调用一次,并传入已预渲染和失败路由的列表。 | 一个常见用例是在运行时动态注册路由,例如从 CMS 或数据库中注册: ```ts [nitro.config.ts] import { defineConfig } from "nitro"; export default defineConfig({ modules: [ (nitro) => { nitro.hooks.hook("prerender:routes", async (routes) => { const posts = await fetch("https://api.example.com/posts").then((res) => res.json()); for (const post of posts) { routes.add(`/blog/${post.slug}`); } }); }, ], }); ``` ## 静态托管 要发布一个不包含服务器包的完全预渲染网站,请使用 `static`、`github_pages` 或 `gitlab_pages` 等静态预设。这些预设会跳过服务器构建、启用 `crawlLinks`,并且只输出 `public` 目录,可直接上传到任意静态托管服务。详情请参阅[部署文档](/deploy)以及 [GitHub Pages](/deploy/providers/github-pages) 等提供商的文档。 ::note `static: true` 配置选项只会禁用服务器构建;它本身不会启用预渲染。直接使用该选项而不是静态预设时,请配置 `prerender` 选项(通常为 `crawlLinks: true`)来生成页面。 ::