预渲染允许您通过在构建时而不是在运行时渲染页面来加速静态内容的页面加载。预渲染通过 react-router.config.ts
中的 prerender
配置启用,并可根据 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;
如果您指定了 ssr:false
但没有 prerender
配置,React Router 将此称为SPA 模式。在 SPA 模式下,我们渲染一个能够为您的应用程序任何路径进行水合的单一 HTML 文件。它之所以能做到这一点,是因为它只将 root
路由渲染到 HTML 文件中,然后在水合过程中根据浏览器 URL 决定加载哪些子路由。这意味着您可以在根路由上使用 loader
,但不能在任何其他路由上使用,因为在浏览器中水合之前我们不知道要加载哪些路由。
如果您想用 ssr:false
预渲染路径,那些匹配的路由可以有 loader,因为我们会预渲染这些路径所有匹配的路由,而不仅仅是根路由。当设置 ssr:false
时,您不能在任何路由中包含 actions
或 headers
函数,因为没有运行时服务器来运行它们。
如果您想使用 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
函数,因为没有运行时服务器来运行它们ssr:false
且没有 prerender
配置(SPA 模式)时,只允许在根路由上使用 loader
ssr:false
且有 prerender
配置时,允许在任何由 prerender
路径匹配的路由上使用 loader
loader
,您需要确保父路由的 loaderData
可以在运行时正确确定,方法是loader
可以在构建时为每个子路由路径调用并渲染到一个 .data
文件中,或者clientLoader
,它可以在运行时为非预渲染的子路径调用