React Static 配置完全指南:深入static.config.js的每一项参数
【免费下载链接】react-static⚛️ 🚀 A progressive static site generator for React.项目地址: https://gitcode.com/gh_mirrors/re/react-static
static.config.js是 React Static(一个渐进式 React 静态站点生成器)的核心配置文件,掌控着路由构建、站点元数据、资源路径、构建性能与 HTML 文档骨架等全部关键行为。本指南以 docs/config.md 为主体,结合 packages/react-static 内的源码实现逐项拆解每一个配置项,帮助你理解每个参数背后的运行机制,并能在自己的项目中准确、安全地配置它们。
认识static.config.js:文件位置与加载机制
static.config.js位于项目根目录,是一个可选但强烈推荐的文件。如果不提供它,React Static 会以一组内置默认值运行;提供后,它必须default export一个对象,对象中可以包含下文中任意属性的子集。
从源码 getConfig.js 可以看到默认约定:
const DEFAULT_NAME_FOR_STATIC_CONFIG_FILE = 'static.config.js' const DEFAULT_ROUTES = [{ path: '/' }] const DEFAULT_ENTRY = 'index.js' const DEFAULT_EXTENSIONS = ['.js', '.jsx']也就是说,即使完全没有配置文件,React Static 也会默认生成一条指向/的路由、使用index.js作为入口,并支持.js/.jsx扩展名。
加载逻辑还支持两种额外的配置来源(getConfig.js):
- 通过
state.configPath显式指定的路径; package.json中的config字段指定的路径;- 以上都未提供时,回退到根目录下的
static.config.js。
开发模式下的热重载
该文件在开发模式下会被chokidar监听(getConfig.js):一旦你保存了static.config.js,React Static 会自动重新执行getRoutes,路由或路由数据的变更会即时热更新到浏览器,无需手动重启 dev server。如果不想反复编辑保存配置文件,文档还推荐直接调用rebuildRoutesAPI 来触发同样的重建流程——该 API 在 getRoutes.js 中被实现为一个可被覆盖的引用(rebuildRoutes.current)。
路由体系:getRoutes与route
getRoutes:异步生成全部路由
getRoutes是一个异步函数,应 resolve 出一个由 route 对象组成的数组。它通常在构建开始时被调用,用来拉取构建所有路由所需的动态数据。它接收一个参数对象,其中包含布尔值dev,用于区分当前是生产构建还是开发环境:
// static.config.js export default { getRoutes: async ({ dev }) => [...routes], }从源码角度看,实际的路由来源不止用户配置这一处。在 getRoutes.js 中,路由最终由「插件贡献的路由」与「用户getRoutes返回的路由」合并而成:
const pluginRoutes = await plugins.getRoutes([], state) const userRoutes = await state.config.getRoutes(state) const routes = [...pluginRoutes, ...userRoutes]合并后还会经过normalizeAllRoutes的递归扁平化处理。这里有两个值得注意的强制约束(getRoutes.js):
- 必须存在 index 路由:若构建结果中没有
path === '/'的路由,构建会直接报错; - 404 路由自动兜底:若没有任何 404 路由,React Static 会自动插入内置的 Default404 组件作为 404 页面。
route对象结构
路由对象代表站点中的一个唯一位置,是整个 React Static 站点的骨架。它支持以下属性:
| 属性 | 类型 | 说明 |
|---|---|---|
path | String | 该路由要匹配的 URL 路径,不含搜索参数与 hash 片段;相对于siteRoot + basePath,若是子路由则再相对于父路由的 path |
template | String | 渲染该路由所用组件的路径(相对于项目根目录或使用绝对路径) |
getData | async Function | 异步函数,resolve 出该路由渲染所需的任意数据对象;接收(resolvedRoute, { dev })两个参数 |
children | Array[Route] | 嵌套子路由。子路由的 path 会继承父路由的 path,因此无需在子路由里重复前缀 |
redirect | URL | 设置后执行等同于 301 的静态站内重定向(借助http-equivmeta 标签、canonical 等);该页面将只渲染执行重定向所需的最少内容 |
路由还可以携带其他属性供插件使用,这些属性会列在各插件的文档中。
getData的两个参数含义:
resolvedRoute: Object—— 当前正在处理的、已解析完成的路由对象;flags: Object{}—— 构建相关的标志与元信息对象,其中包含dev: Boolean,表示当前是开发构建还是生产构建。
一个覆盖了简单路由、带数据路由、动态子路由和 404 路由的完整示例:
// static.config.js export default { getRoutes: async ({ dev }) => [ // A simple route { path: 'about', template: 'src/containers/About', }, // A route with data { path: 'portfolio', template: 'src/containers/Portfolio', getData: async () => ({ portfolio, }), }, // A route with data and dynamically generated child routes { path: 'blog', template: 'src/containers/Blog', getData: async () => ({ posts, }), children: posts.map(post => ({ path: `post/${post.slug}`, template: 'src/containers/BlogPost', getData: async () => ({ post, }), })), }, // A 404 component { path: '404', template: 'src/containers/NotFound', }, ], }子路由的路径继承是如何实现的
「路径继承」并非黑魔法,而是由 getRoutes.js 中的normalizeRoute完成的:每个路由在被处理时,会取出父路由的path(默认/),通过pathJoin(parentPath, route.path)拼接后得到完整路径。这也是为什么子路由post/${post.slug}最终会变成blog/post/${post.slug}。
分页路由的实用工具
若你的博客或列表页需要分页,仓库还提供了一个非常实用的辅助函数 makePageRoutes。它会将数据按pageSize切片,第一页保持原始路径(不带页码),后续页自动生成${route.path}/${pageToken}/${i + 1}形式的路径,并通过decorate(page, pageNumber, totalPages)回调把每页数据注入路由。这是 docs/guides/pagination.md 中分页方案背后的底层实现。
getSiteData:全站共享数据
getSiteData与路由的getData非常相似,但它的结果通过useSiteDataHook、SiteData组件以及getSiteDataHOC 提供给全站使用。需要特别注意的是:虽然数据只加载一次,但它会被嵌入站点导出的每一个页面中,所以不宜在里面放置过大的数据。
// static.config.js export default { getSiteData: async ({ dev }) => ({ title: 'My Awesome Website', lastBuilt: Date.now(), }), }从 fetchSiteData.js 的源码可以看到,它就是简单地在构建/开发阶段执行一次state.config.getSiteData(state),把结果存入state.siteData。开发模式下,它还会通过 runDevServer.js 暴露的/__react-static__/siteData接口提供给客户端运行时,并在配置变更时重新拉取。
站点根与路径:siteRoot、basePath与assetsPath系列
这一组配置决定了站点的 URL 结构、静态资源加载位置,是 SEO 与部署正确性的关键。
siteRoot与stagingSiteRoot
siteRoot的格式为protocol://domain.com,强烈推荐配置,它支撑了 SEO 相关的诸多能力,目前已包括:
- 导出时自动生成
sitemap.xml; - 将静态渲染出的链接强制转换为绝对 URL。
使用注意:如果站点使用 HTTPS 提供服务,务必把https写进siteRoot。任何尾随斜杠(包括路径部分)都会被自动移除;如果站点部署在某个子路径下(例如 GitHub Pages),应改用basePath而非siteRoot。
// static.config.js export default { siteRoot: 'https://mysite.com', }stagingSiteRoot行为与siteRoot完全一致,但仅在带--staging构建标志时生效。
从 getConfig.js 的源码可以看到三套路径解析是分环境完成的:开发环境走devBasePath/devAssetsPath;staging 环境走stagingSiteRoot/stagingBasePath/stagingAssetsPath;生产环境走siteRoot/basePath/assetsPath。
basePath、stagingBasePath与devBasePath
当你要把站点托管在域名下的某个具体路由(例如 GitHub Pages 场景,或https://mysite.com/blog中的blog)时,就需要设置basePath。所有前导和尾随斜杠都会被自动移除。
// static.config.js export default { basePath: 'blog', }stagingBasePath与devBasePath分别对应--staging构建与 dev server 运行时的等价配置。最终拼接出的publicPath形如${siteRoot}/${basePath}/,并被注入到REACT_STATIC_PUBLIC_PATH环境变量供 webpack 使用(参见 webpack.config.dev.js)。
assetsPath、devAssetsPath与stagingAssetsPath
assetsPath决定打包后的 JS 与 CSS 从何处加载,适合把静态资源托管到外部 CDN 的场景:
// static.config.js export default { assetsPath: 'https://cdn.example.com/assets', }若assetsPath不是绝对 URL,源码会把它规范化为/${basePath}/${assetsPath}/并补全尾随斜杠(getConfig.js)。devAssetsPath与stagingAssetsPath分别覆盖 dev server 与--staging构建场景。
CSS 交付优化:extractCssChunks与inlineCss
extractCssChunks会用ExtractCssChunks替换默认的ExtractTextPlugin,从而按路由以及动态组件(基于react-universal-component)自动拆分 CSS 到独立文件,是 CSS 交付优化的基础能力。默认为false。
配合extractCssChunks在合适的位置做代码分割后,每个页面相关的 CSS 文件可以做到很小。此时开启inlineCss,可以把页面相关的 CSS 内联进 HTML,通过减少首屏渲染所需的请求数来加速应用。默认为false。
// static.config.js export default { extractCssChunks: true, inlineCss: true, }Document:自定义 HTML 文档外壳
Document是一个可选(同样推荐)的 React 组件,负责渲染网站的 HTML 外壳。适合放置以下内容:
- 全站自定义的
head/meta标签; - 全站统计脚本;
- 全站样式表。
Document接收的 Props
| Prop | 类型 | 说明 |
|---|---|---|
Html | ReactComponent | 必填,默认html标签的增强版 |
Head | ReactComponent | 必填,默认head标签的增强版 |
Body | ReactComponent | 必填,默认body标签的增强版 |
children | ReactComponent | 必填,站点主体内容(布局、路由等) |
state | Object | 当前导出状态 |
state对象包含:
routeInfo: Object—— 当前路由的全部信息,包括任何routeData;siteData: Object—— 通过本配置文件中的getSiteData解析出的数据;renderMeta: Object—— 渲染过程中由 hooks 或 transformers 设置的任意数据;inlineScripts: Object—— 由 React Static 添加的内联脚本的源码与 hash,例如:
{ "routeInfo": { "script": "script", "hash": "sha256-<base64-value>" } }这些 hash 可以直接用作 CSP 指令,从而让站点在不需要unsafe-inline的情况下正常工作。hash 的生成逻辑在 exportRoute.js:内联脚本window.__routeInfo = JSON.parse(...)会经 SHA-256 计算并加上sha256-前缀。
示例:
// static.config.js export default { Document: ({ Html, Head, Body, children, state: { siteData, renderMeta }, }) => ( <Html lang="en-US"> <Head> <meta charSet="UTF-8" /> <meta name="viewport" content="width=device-width, initial-scale=1" /> </Head> <Body>{children}</Body> </Html> ), }注意:既然static.config.js中使用了 JSX,就需要在文件顶部引入 React:import React from 'react'。
Document在渲染管线中的位置
在 exportRoute.js 中,页面 HTML 的生成顺序是:先用renderToString渲染应用主体(期间通过react-helmet收集 head 元数据),随后用renderToStaticMarkup把DocumentTemplate连同增强版的Html/Head/Body组件(实现在 HtmlWithMeta.js、HeadWithMeta.js、BodyWithMeta.js)一起渲染成完整 HTML 外壳。这也解释了为什么Html/Head/Body是增强版组件——它们会把react-helmet收集到的 meta 信息合并进标准标签。
devServer:开发服务器配置
devServer是一个对象,其中的选项会被透传给底层的webpack-dev-server实例。常用配置:
// static.config.js export default { // An optional object for customizing the options for the devServer: { port: 3000, host: '127.0.0.1', }, }也可以用来为本地开发开启 HTTPS:
// static.config.js export default { devServer: { // Enable HTTPS and provide certificates https: true, key: fs.readFileSync('/path/to/localhost.key'), cert: fs.readFileSync('/path/to/localhost.crt'), }, }从 getConfig.js 可以看到devServer的默认值是{ host: 'localhost', port: 3000 },用户的配置会覆盖默认值。而 runDevServer.js 展示了更细致的运行时行为:如果设定的端口被占用,React Static 会自动寻找可用端口,并在终端打印警示信息;https: true时启动日志中的协议也会相应变为https://(runDevServer.js)。开发服务器的 webpack 配置还默认注入了react-hot-loader、HMR 插件以及ExtractCssChunks(见 webpack.config.dev.js)。
entry与paths:入口与内部目录
entry
入口文件名,以字符串形式给出,相对于paths.src:
// static.config.js export default { entry: 'index.js', }默认值就是'index.js',从 getConfig.js 的DEFAULT_ENTRY常量可以印证。
paths
内部目录的对象,每个路径都相对于项目根目录,默认值如下:
// static.config.js export default { paths: { root: process.cwd(), // The root of your project. Don't change this unless you know what you're doing. src: 'src', // The source directory. Must include an index.js entry file. temp: 'tmp', // Temp output directory for build files not to be published. dist: 'dist', // The production output directory. devDist: 'tmp/dev-server', // The development scratch directory. public: 'public', // The public directory (files copied to dist during build) assets: 'dist', // The output directory for bundled JS and CSS buildArtifacts: 'artifacts', // The output directory for generated (internal) resources }, }在 getConfig.js 中,这些相对路径会被基于root解析为绝对路径并生成一组大写命名的内部常量(如SRC、DIST、TEMP、PUBLIC、ASSETS、ARTIFACTS等),后续的 webpack 配置与导出流程都依赖这些常量。注意源码中还包含一个文档未列出的默认值:plugins: 'plugins'(项目级插件目录)以及pages: 'src/pages'。
构建与客户端性能调优
outputFileRate
可选Int,表示构建过程中可同时写入磁盘的最大文件数(即并发写入上限),默认100:
// static.config.js export default { outputFileRate: 100, }这个值不仅作用于文件写入,还作为路由数据拉取的并发池大小被复用在 fetchRoutes.js 的poolAll(downloadTasks, Number(config.outputFileRate))中——即所有路由的getData请求也是按该速率并发执行的。
prefetchRate
可选Int,客户端预加载路由数据时的最大并发请求数:
// static.config.js export default { prefetchRate: 10, }默认值在源码中是5(getConfig.js),文档中的示例给出了调高到10的用法。该值最终通过REACT_STATIC_PREFETCH_RATE环境变量注入客户端运行时。
maxThreads
可选Number,导出站点页面时使用的最大线程数。默认值为Infinity,即使用机器上所有可用线程。
注意:该选项只影响把页面渲染成 HTML 文件的进程,不影响最初的打包(bundling)过程。
// static.config.js export default { maxThreads: 1, // Will only use one thread to export your site }exportRoutes.js 的实现印证了这一行为:当maxThreads <= 1时走单线程的exportRoutes.sync;否则以Math.min(CPU 核心数, maxThreads)为线程数,用child_process.fork派生多个 exportRoutes.threaded 子进程,并把路由按i % threads轮询分配给各子进程并行渲染。
minLoadTime
可选Number(毫秒),表示当模板、siteData或routeData不能立即就绪时,加载 spinner 至少展示的时长。如果你在激进地预加载,通常不会看到加载器;但一旦出现加载器,保持展示时间不至于闪烁会带来更好的体验。
// static.config.js export default { minLoadTime: 200, }默认值为200(毫秒,getConfig.js),并通过REACT_STATIC_MIN_LOAD_TIME环境变量传递给客户端。
disablePreload
设为true可禁用所有预加载。当前主要用于调试,但其内部机制未来很可能演化为按客户端条件(移动端、慢速网络等)决定是否预加载:
// static.config.js export default { disablePreload: true, }路由行为开关
disableDuplicateRoutesWarning
设为true可关闭构建期间对重复路由的告警:
// static.config.js export default { disableDuplicateRoutesWarning: true, }在 getRoutes.js 中可以看到重复路由的实际处理逻辑:React Static 会按 path 建立索引,若两条路由 path 相同,默认行为是**合并(Object.assign)**而非报错——除非路由带replace标记。
disableRoutePrefixing
设为true可禁用链接href值与浏览器历史记录中的config.basePath前缀注入。适合使用动态basePath(如/country/language/basePath)的场景:
// static.config.js export default { disableRoutePrefixing: true, }从 exportRoute.js 的源码看,默认情况下导出 HTML 时,React Static 会用正则把href="/..."/src="/..."改写为带publicPath(即siteRoot + basePath)的绝对形式;该选项关闭的就是这层改写(仅影响 href,src 的改写仍然执行)。
编译与调试选项
babelExcludes
React Static 会为「你自己的源码」和「外部依赖(node_modules)」分别运行 Babel。自己的源码可以用常规方式配置 Babel;而node_modules的 Babel 配置比较特殊,React Static 会尝试用一套最小化配置去编译它们,但偶尔有些模块会因此出问题(例如 mapbox-gl)。该选项允许你把某些模块排除在 Babel 编译之外:
// static.config.js export default { babelExcludes: [/mapbox-gl/], }这里接受的是 webpack module condition 格式(test规则),因此可以传正则、字符串或函数。
productionSourceMaps
设为true在生产构建中包含 source map,默认为false:
// static.config.js export default { productionSourceMaps: true, }silent
设为true可隐藏控制台中的'React Static: Templates Reloaded'消息,默认为false:
// static.config.js export default { silent: true, }已弃用的配置项
两个配置项已被标记为弃用,请勿在新项目中使用:
renderToElement:已弃用,请改用 Node API hookbeforeRenderToElement(见 docs/plugins/node-api.md);renderToHtml:将在未来版本中移除,请改用 Node API hookbeforeRenderToHtml。
exportRoute.js 的源码中也保留了对应的守卫逻辑:一旦检测到config.renderToElement或config.renderToHtml,会直接抛出弃用错误,提示改用beforeRenderToElement/beforeRenderToHtml/beforeHtmlToDocumenthooks。
配置文件的边界:Plugin API
配置文件并非 React Static 的全部自定义入口。许多能力需要通过插件系统才能实现,例如:
- Webpack 定制;
- 渲染管线的自定义与转换(React 组件、元素、
Document包装器等); - head 标签注入。
每个 React Static 项目都可以在项目根目录创建node.api.js或browser.api.js文件来本地使用插件 API,无需真正发布插件。从 getConfig.js 可以看到,项目根目录本身就会被作为一个插件目录加入plugins列表,这正是「本地插件」机制能够生效的原因。完整的插件能力说明见 docs/plugins/README.md、docs/plugins/node-api.md 与 docs/plugins/browser-api.md。
小结
static.config.js的每一项配置都有清晰的默认值与明确的适用场景:getRoutes/getSiteData定义了站点的数据与路由骨架;siteRoot/basePath/assetsPath系列决定了部署形态与 SEO 基础;Document与devServer负责 HTML 外壳与本地开发体验;outputFileRate/maxThreads/prefetchRate等则让你在构建与客户端性能之间取得平衡。结合 getConfig.js 中集中化的默认值与解析逻辑,你可以放心地只覆盖需要的字段,其余全部交由 React Static 的默认行为处理。
【免费下载链接】react-static⚛️ 🚀 A progressive static site generator for React.项目地址: https://gitcode.com/gh_mirrors/re/react-static
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考