预渲染
在本页

预渲染

预渲染允许您通过在构建时而不是运行时渲染页面来加速静态内容的页面加载速度。预渲染通过 react-router.config.ts 中的 prerender 配置启用,并且可以根据 ssr 配置值以两种方式使用

  • 与运行时 SSR 服务器 `ssr:true`(默认值)一起使用
  • 部署到带有 `ssr:false` 的静态文件服务器

使用 ssr:true 预渲染

配置

prerender 选项添加到您的配置,有三种签名

import type { Config } from "@react-router/dev/config";

export default {
  // Can be omitted - defaults to true
  ssr: true,

  // all static paths (no dynamic segments like "/post/:slug")
  prerender: true,

  // specific paths
  prerender: ["/", "/blog", "/blog/popular-post"],

  // async function for dependencies like a CMS
  async prerender({ getStaticPaths }) {
    let posts = await fakeGetPostsFromCMS();
    return [
      "/",
      "/blog",
      ...posts.map((post) => post.href),
    ];
  },
} satisfies Config;

数据加载和预渲染

预渲染没有额外的应用程序 API。正在预渲染的路由使用与服务器渲染相同的路由 loader 函数

export async function loader({ request, params }) {
  let post = await getPost(params.slug);
  return post;
}

export function Post({ loaderData }) {
  return <div>{loaderData.title}</div>;
}

构建会创建一个 `new Request()` 并在您的应用程序中运行它,就像服务器一样,而不是请求到达已部署服务器上的路由。

当服务器渲染时,对未预渲染路径的请求将像往常一样进行服务器渲染。

静态文件输出

渲染结果将写入您的 `build/client` 目录。您会注意到每个路径有两个文件

  • [url].html 用于初始文档请求的 HTML 文件
  • [url].data 用于客户端导航浏览器请求的文件

构建的输出将指示预渲染了哪些文件

> react-router build
vite v5.2.11 building for production...
...
vite v5.2.11 building SSR bundle for production...
...
Prerender: Generated build/client/index.html
Prerender: Generated build/client/blog.data
Prerender: Generated build/client/blog/index.html
Prerender: Generated build/client/blog/my-first-post.data
Prerender: Generated build/client/blog/my-first-post/index.html
...

在开发期间,预渲染不会将渲染结果保存到 public 目录,这仅在 `react-router build` 时发生。

使用 ssr:false 预渲染

以上示例假设您正在部署运行时服务器,但正在预渲染一些静态页面,以便更快地为它们提供服务并避免访问服务器。

要禁用运行时 SSR 并配置从静态文件服务器提供预渲染,您可以设置 `ssr:false` 配置标志

import type { Config } from "@react-router/dev/config";

export default {
  ssr: false, // disable runtime server rendering
  prerender: true, // pre-render all static routes
} satisfies Config;

如果您在没有 `prerender` 配置的情况下指定 `ssr:false`,React Router 将其称为 SPA 模式。在 SPA 模式下,我们渲染一个能够为任何应用程序路径进行水合的单个 HTML 文件。它可以做到这一点,因为它仅将 `root` 路由渲染到 HTML 文件中,然后根据浏览器 URL 在水合期间确定要加载哪些子路由。这意味着您可以在根路由上使用 `loader`,但不能在任何其他路由上使用,因为我们不知道在浏览器中水合之前要加载哪些路由。

如果您想使用 `ssr:false` 预渲染路径,则匹配的路由可以具有 loader,因为我们将预渲染这些路径的所有匹配路由,而不仅仅是根路由。当设置 `ssr:false` 时,您不能在任何路由中包含 `actions` 或 `headers` 函数,因为将没有运行时服务器来运行它们。

使用 SPA 回退预渲染

如果您想要 `ssr:false` 但不想预渲染所有路由 - 这也没问题!您可能在某些路径中需要预渲染的性能/SEO 优势,但在其他页面中 SPA 也可以。

您也可以使用配置选项的组合来做到这一点 - 只需将您的 `prerender` 配置限制为您想要预渲染的路径,React Router 还将输出一个“SPA 回退”HTML 文件,该文件可以用于水合任何其他路径(使用与 SPA 模式 相同的方法)。

这将写入以下路径之一

  • build/client/index.html - 如果 `/` 路径未预渲染
  • build/client/__spa-fallback.html - 如果 `/` 路径已预渲染
import type { Config } from "@react-router/dev/config";

export default {
  ssr: false,

  // SPA fallback will be written to build/client/index.html
  prerender: ["/about-us"],

  // SPA fallback will be written to build/client/__spa-fallback.html
  prerender: ["/", "/about-us"],
} satisfies Config;

您可以配置您的部署服务器,以便为任何其他情况会返回 404 的路径提供此文件。某些主机默认会这样做,但其他主机则不会。例如,主机可能支持 `_redirects` 文件来执行此操作

# If you did not pre-render the `/` route
/*    /index.html   200

# If you pre-rendered the `/` route
/*    /__spa-fallback.html   200

如果您在应用程序的有效路由上收到 404 错误,则很可能需要配置您的主机。

这是另一个关于如何使用 `sirv-cli` 工具执行此操作的示例

# If you did not pre-render the `/` route
sirv-cli build/client --single index.html

# If you pre-rendered the `/` route
sirv-cli build/client --single __spa-fallback.html

无效导出

当使用 `ssr:false` 进行预渲染时,如果您有无效的导出,React Router 将在构建时报错,以帮助防止一些容易被忽视的错误。

  • 所有路由中都禁止使用 `headers`/`action` 函数,因为将没有运行时服务器来运行它们
  • 当在没有 `prerender` 配置的情况下使用 `ssr:false`(SPA 模式)时,仅允许在根路由上使用 `loader`
  • 当使用带有 `prerender` 配置的 `ssr:false` 时,允许在 `prerender` 路径匹配的任何路由上使用 `loader`
    • 如果您在具有子路由的预渲染路由上使用 `loader`,您需要确保父 `loaderData` 可以在运行时正确确定,通过以下任一方式
      • 预渲染所有子路由,以便可以在构建时为每个子路由路径调用父 `loader` 并将其渲染到 `.data` 文件中,或者
      • 在父级上使用 `clientLoader`,可以在运行时为非预渲染的子路径调用它
文档和示例 CC 4.0