Umi.js preload_helper.js 自动生成机制:路由预加载是怎么落地的
【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi
在 Umi 项目里跑一次生产构建(umi build),你会发现产物目录比源码目录多出一个小文件——preload_helper.js。它不属于你手写的任何源码,却会被注入到 HTML 头部,在首屏加载时提前把目标路由的 JS 和 CSS 拉进浏览器缓存。理解 Umi.js 这套 preload_helper.js 生成机制,能帮你判断首屏为什么快、以及怎样按项目需要调整预加载范围。
现象:构建产物里为什么会多出 preload_helper.js
先说结论:这个文件只在生产构建阶段生成,由 Umi 的预置包动态写出,而不是构建工具的固定产物。它的作用很单一——在页面真正导航之前,把用户即将访问路由对应的分块资源提前下载。
你可以把它想成一份"资源清单脚本"。普通 SPA 里,路由切换后才触发React.lazy的import,资源请求才发出;而preload_helper.js提前一步,在 HTML 解析阶段就根据当前location.pathname去猜用户要去哪个路由,并用浏览器原生机制把对应资源拉下来,省掉一次"导航后才开始下载"的等待。
生成流程:从 Webpack 统计信息到 dist 文件
生成逻辑集中在 packages/preset-umi/src/features/routePreloadOnLoad/ 目录,核心是routePreloadOnLoad.ts和utils.ts两个文件。整个过程挂在构建完成的钩子上,分三步:
- 收集分块。构建结束后读取 bundler 的统计信息(Webpack 的
stats.toJson(),或 Mako 的编译结果),遍历所有非入口 chunk,只挑出.js和.css文件,并记录它们各自属于哪个路由模块。 - 建立路由到文件的映射。拿到应用的路由树后,对每条路由向上回溯其父级路由,把沿途所有路由文件关联到的分块索引合并去重,得到"路由路径 → 资源索引列表"的映射。路径排序借用了类似 React Router 6 的路由打分算法,静态段权重高于动态段。
- 写入文件。把映射序列化进一个模板脚本,模板存放在 packages/preset-umi/templates/routePreloadOnLoad/preloadRouteFilesScp.js,随后写到输出目录(
dist/)。
生产模式下文件内容还会经 Terser 压缩;如果项目开启了文件名哈希(hash配置),生成的文件名会带上一段内容摘要,保证缓存正确失效。最后,框架在 HTML 头部注入对preload_helper.js的<script>引用,脚本随首屏一起执行。
运行时:preload_helper.js 如何挑选资源
文件本身很小,刻意避免了高级语法,防止压缩器再插入额外的辅助函数。它的运行逻辑(见 packages/preset-umi/src/client/preloadRouteFilesScp.ts)大致是:
- 先取
location.pathname,剥掉base前缀得到路由路径,前缀不匹配则直接退出; - 在映射表里先查静态路由,查不到再逐条用正则匹配动态路由(
/:id转成/[^/]+,/*转成/.+); - 命中后按资源类型生成标签:JS 插入带
async的<script>,CSS 插入<link rel="preload" as="style">,并给标签加上带包名和 chunk id 的data-属性,方便后续调试定位。
让它生效:生效条件与关键配置
preload_helper.js不是无条件生成的,enableBy里有四个前提,缺一个都不会产出文件:项目package.json必须有name(它被用作 HTML 属性的前缀),未开启vite模式,未开启mpa多页模式,且routeLoader.moduleType为esm。
也就是说,这个机制专为"单页 + ESM 懒加载路由"的设计服务。和它相关的可用配置项主要有:
- routeLoader:控制路由组件的加载方式,
esm走React.lazy(() => import(...)),是预加载生效的前提; - routePrefetch:另一条预加载链路,默认
false,可设'none' | 'intent' | 'render' | 'viewport',配合defaultPrefetchTimeout使用; - hash / publicPath / base / runtimePublicPath:分别影响生成文件名、资源 URL 前缀和运行时路径解析。
与 routePrefetch 的分工,以及怎么验证
需要区分两件事。preload_helper.js属于构建期能力:基于统计信息,针对"用户当前所在的 URL 会跳向哪个路由"做一次性预取,只关心静态或动态路由的 URL 形态。而routePrefetch是运行时能力,挂在Link组件上,按用户交互意图触发——intent在鼠标悬停/焦点时预取,render在元素进入视口时预取,viewport持续监测视口。两者互补:前者兜底首屏,后者响应交互。
验证是否生效,最直接的办法是生产构建后查看dist/里是否出现preload_helper.js(或带哈希后缀的版本),并打开页面用 DevTools 的 Network 面板观察导航发生前是否已有对应 chunk 的请求。若没生成文件,优先回查上面四条enableBy条件;若资源 404,多半是publicPath或runtimePublicPath与实际部署路径不一致,可对照 docs/docs/ 下config文档中publicPath、runtimePublicPath两节核对配置。
下一步建议
想进一步定制,可以从 packages/preset-umi/src/features/routePreloadOnLoad/routePreloadOnLoad.ts 入手,理解映射表结构后按需扩展匹配规则;运行时行为则集中在client/preloadRouteFilesScp.ts。完整的routeLoader、routePrefetch语义见 docs/docs/ 的配置文档,路由分块与懒加载的示例可参考 examples/ 目录下的mpa、with-react-19等工程。
【免费下载链接】umiA framework in react community ✨项目地址: https://gitcode.com/GitHub_Trending/um/umi
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考