link rel="preload" 对动态 import() 产生的 chunk 无效,因浏览器仅在 HTML 解析阶段识别静态 href,而动态路径运行时才确定,且 preload 下载结果与 import() 请求上下文隔离、缓存不复用。

link rel="preload" 对大型 JS bundle 分片(如 Webpack 的 chunk、Vite 的 dynamic import() 产物)基本无效——浏览器无法静态识别动态导入路径,preload 声明不会触发下载,写了也白写。
为什么 preload 无法预加载动态 import() 产生的 chunk
浏览器在 HTML 解析阶段扫描 link rel="preload",只认静态 href 字符串。而 import('./feature.js') 这类调用的路径在运行时才确定,打包工具生成的 chunk 名(如 feature.abc123.js)也无法被 HTML 静态声明覆盖。
- 常见错误:在 HTML 中硬写
<link rel="preload" href="feature.abc123.js" as="script">→ 构建后 hash 变更,路径失效,404 - 即使路径侥幸匹配,浏览器也不会把 preload 下载结果关联到后续
import()创建的 fetch 请求 —— 它们属于不同请求上下文,缓存不复用 - Chrome DevTools Network 面板中,该资源的 Initiator 显示为
script(不是parser),证明 preload 没起作用
真正有效的分片预加载方案:prefetch + preload 组合
对「用户即将进入但尚未触发」的路由或功能模块,应使用 rel="prefetch";仅对「当前页首屏立即需要」的入口脚本(如 main.js 或 SSR hydration 所需的 app.js)才用 rel="preload"。
-
rel="preload" as="script"适合:紧随 HTML 后执行的主应用入口(<script src="app.js" type="module"></script>) -
rel="prefetch" as="script"适合:用户点击“设置”按钮后才会加载的settings.chunk.js,浏览器会在空闲时低优先级拉取 - 不要在首页 preload 所有路由 chunk —— 会抢占带宽,拖慢首屏,Lighthouse 评分暴跌
- Vite / Next.js 等框架自动生成的
<link rel="prefetch">已足够,无需手动补写
运行时条件预加载:用 JS 主动创建 preload link(慎用)
当必须基于用户行为提前加载某个已知路径的分片(例如 A/B 实验分支脚本、设备检测后的高清图逻辑),可用 JS 动态插入,但必须满足两个硬条件:
立即学习“前端免费学习笔记(深入)”;
- 插入时机极早:在
DOMContentLoaded前完成,且必须 append 到document.head,不能塞进body或延迟执行 - href 必须是完整静态路径(如
/js/feature-v2.a1b2c3.js),不能含变量、模板语法或相对路径错误 - 务必检查是否已存在相同
href的 preload link,避免重复插入导致多次请求 - 不推荐用于字体或 CSS —— 它们对
crossorigin、type、缓存头极其敏感,JS 插入极易漏配
最常被忽略的一点:preload 不是“让 JS 更快执行”,它只管下载。就算你成功预加载了某个 chunk,import() 调用时仍要走完整的解析、编译、执行流程 —— 那些耗时环节,preload 一概不碰。



















