关键要点
- React Router v7.5.0支持通过Vite插件的prerender配置实现SSG(静态站点生成),适合静态部署。
- 建议设置ssr: false以确保运行时无服务器渲染,并通过prerender指定需要生成的静态路径。
- 构建时会生成HTML和数据文件,可部署到Netlify或GitHub Pages等静态服务器。
- 对于动态路由,需要在prerender函数中明确列出所有路径,例如从CMS获取。
概述
React Router v7.5.0的发布带来了对静态站点生成(SSG)的增强支持,特别是在Vite插件中引入了prerender配置。这一功能允许开发者在构建时生成静态HTML和数据文件,适合部署到静态文件服务器(如Netlify、GitHub Pages或Vercel),从而提高性能和SEO效果。以下是基于最新版本的详细SSG方案,包括配置、实现步骤和注意事项。
React Router v7.5.0于2025年4月4日发布,但对SSG的支持在v7.0.0中已引入,并延续到v7.5.0。生成的文件可以静态服务,适合不需要运行时服务器渲染的场景。我个人使用体验感觉优于Nextjs。
准备工作
首先,确保安装了必要的依赖:
shell
npm install [email protected] @react-router/[email protected] @react-router/[email protected]
# 或使用pnpm
pnpm add [email protected] @react-router/[email protected] @react-router/[email protected]
项目结构设置
一个典型的使用React Router 7.5的SSG项目结构如下:
shell
/src
/components
/pages
entry.client.tsx # 客户端入口
root.tsx # 根组件
routes.ts # 路由配置
i18n.ts # 国际化配置(可选)
/public
# 静态资源
react-router.config.ts # React Router配置
配置Vite插件
首先,确保你的项目使用Vite构建,并安装必要的依赖。配置vite.config.ts文件,启用reactRouter插件,并设置ssr: false以禁用运行时的服务器渲染。
ts
import {defineConfig} from 'vite'
import tailwindcss from '@tailwindcss/vite'
import {reactRouter} from "@react-router/dev/vite";
// https://vite.dev/config/
export default defineConfig({
plugins: [reactRouter(), tailwindcss()],
})
配置react-router.config.ts文件,prerender选项用于指定需要预渲染的路径,例如:
- 如果路径是静态的,可以直接列出:prerender: ["/", "/about"]。
- 对于动态路由(如/product/:slug),可以使用异步函数从CMS或API获取所有可能的路径
ts
export default {
appDirectory: "src",
ssr: false,
async prerender({getStaticPaths}) {
// getStaticPaths() 函数返回全部路由
console.log("prerender", ...getStaticPaths())
// 示例:从CMS获取动态路径
const slugs = await fetchSlugsFromCMS(); // 假设的函数,根据实际情况实现
return [
...getStaticPaths(), // 获取静态路径
...slugs.map(slug => `/product/${slug}`), // 添加动态路径
];
},
} satisfies Config;
设置路由配置
在src/routes.ts
中定义您的路由:
ts
import {
type RouteConfig,
route, index,
} from "@react-router/dev/routes";
export default [
// * matches all URLs, the ? makes it optional so it will match / as well
index("./pages/HomePage.tsx"),
route("/success", "./pages/PaymentSuccess.tsx"),
route("/cancel", "./pages/PaymentCancel.tsx"),
route("*?", "catchall.tsx"),
] satisfies RouteConfig;
在src/catchall.tsx
中定义未预渲染的页面,当上面配置的路由匹配不到时在路由到下面的单页面组件继续路由:
ts
import {Route, Routes} from "react-router";
export default function Component() {
return <div className="min-h-screen bg-slate-900 text-white relative overflow-hidden">
<Routes>
<Route path="/retry-payment/:videoId" element={<RetryPayment />} />
<Route path="/terms" element={<TermsOfService />} />
<Route path="/privacy" element={<PrivacyPolicy />} />
</Routes>
</div>
}
创建根组件
在src/root.tsx
中创建根组件:
ts
import {Links, Meta, Outlet, Scripts, ScrollRestoration,} from "react-router";
import Header from "./components/Header";
import Footer from "./components/Footer";
export function Layout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="en">
<head>
<meta charSet="UTF-8"/>
<link rel="icon" type="image/svg+xml" href="/ico.png"/>
<meta name="viewport" content="width=device-width, initial-scale=1.0"/>
<title>VTFox - AI Audio and Video Content Recognition Tool</title>
<Meta/>
<Links/>
</head>
<body>
<Header/>
{children}
<Footer/>
<ScrollRestoration/>
<Scripts/>
</body>
</html>
);
}
export default function Root() {
return <Outlet/>;
}
客户端入口文件
在src/entry.client.tsx
中设置客户端入口:
ts
import ReactDOM from 'react-dom/client'
import './index.css'
import './i18n'
import {HydratedRouter} from "react-router/dom";
import {StrictMode} from "react";
ReactDOM.hydrateRoot(
document,
<StrictMode>
<HydratedRouter />
</StrictMode>
);
开发和构建命令
在package.json
中添加以下脚本:
json
{
"scripts": {
"dev": "react-router dev",
"build": "react-router build",
"preview": "react-router preview"
}
}
运行npm run build后,Vite会生成静态文件到build/client目录,包括每个预渲染路径的.html和.data文件。这些文件可以直接部署到静态服务器,如Netlify或GitHub Pages。
构建过程会生成build/client目录,包含:
-
url\].html:每个预渲染路径的渲染HTML文件。
例如,预渲染路径/会生成build/client/index.html和build/client/index.data。
部署与SPA回退
将build/client目录上传到静态文件服务器:
-
Netlify:上传目录,并创建_redirects文件以处理SPA回退:
bash/* /index.html 200
-
GitHub Pages:上传目录,确保404页面重定向到index.html,可能需要额外的配置。
对于ssr: false
模式,如果未预渲染的路径被访问,应用会回退到SPA模式,使用客户端JavaScript处理导航。回退文件为:
- 如果预渲染/,到build/client/index.html。
- 如果未预渲染了/,回退到build/client/__spa-fallback.html。
这样,未预渲染的路径会回退到客户端处理。
数据加载和SEO
在路由定义中,使用loader函数预取数据,确保静态文件包含必要内容。这对SEO很重要,因为搜索引擎可以直接爬取生成的HTML。此外,记得使用管理元标签,如和。
对比与选择
React Router v7.5.0的SSG方案类似于Next.js的getStaticProps,但通过Vite插件集成,更加轻量且灵活。以下是与传统SSG框架的对比:
特性 | React Router v7.5.0 SSG | Next.jsgetStaticProps |
---|---|---|
配置方式 | Vite插件prerender配置 | 文件系统路由+getStaticProps |
动态路径支持 | 通过prerender异步函数 | 通过getStaticPaths |
部署方式 | 静态文件服务器 | 静态导出或SSR服务器 |
灵活性 | 高(适合已有React Router项目) | 高(内置支持更全面) |
对于已有React Router项目的开发者,v7.5.0的SSG方案更自然;对于新项目,Next.js可能提供更开箱即用的体验。
官方文档建议,未来版本可能进一步增强框架模式(Framework Mode),支持更多SSG和SSR混合场景。
结论
React Router v7.5.0通过Vite插件的prerender配置提供了强大的SSG支持,适合需要静态部署的场景。通过设置ssr: false和配置prerender,开发者可以轻松生成静态文件,部署到静态服务器,并确保SEO和性能优化。对于动态路由,需通过异步函数明确列出所有路径,确保构建时生成完整内容。