预渲染
本页内容

预渲染

预渲染允许您通过在构建时而非运行时渲染页面来加速静态内容的页面加载。可以通过 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
...

在开发过程中,预渲染不会将渲染结果保存到公共目录,这仅在运行 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 文件,该文件能够对您应用的任何路径进行 hydration。它之所以能做到这一点,是因为它只将 root 路由渲染到 HTML 文件中,然后在 hydration 期间根据浏览器 URL 确定要加载哪些子路由。这意味着您可以在 root 路由上使用 loader,但不能在任何其他路由上使用,因为直到浏览器进行 hydration 时我们才知道要加载哪些路由。

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

带 SPA 回退的预渲染

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

您也可以通过组合配置选项来实现这一点 - 只需将您的 prerender 配置限制在您想要预渲染的路径上,React Router 也会输出一个“SPA 回退”HTML 文件,该文件可以用于 hydrate 其他任何路径(使用与 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 函数,因为没有运行时服务器来运行它们。
  • 当使用 ssr:false 且没有 prerender 配置(SPA 模式)时,只允许在 root 路由上使用 loader
  • 当使用 ssr:false 且有 prerender 配置时,允许在由 prerender 路径匹配的任何路由上使用 loader
    • 如果您在具有子路由的预渲染路由上使用 loader,则需要确保父级 loaderData 可以在运行时正确确定,方法是:
      • 预渲染所有子路由,以便在构建时为每个子路由路径调用父级 loader 并将其渲染到 .data 文件中,或者
      • 在父级上使用 clientLoader,以便在运行时为未预渲染的子路径调用。
文档与示例 CC 4.0