modulepreload 专用于预加载 ES 模块并自动解析其静态 import 依赖图,而 preload 仅下载指定资源且需手动声明 as 类型;前者支持模块缓存复用与依赖预取,后者无模块语义。
加速原生模块化脚本的依赖预加载">
modulepreload 和普通 preload 有什么区别
关键在“模块图解析”这个动作——rel="preload" 只下载资源,不执行;而 rel="modulepreload" 不仅下载,还会提前解析其 ES 模块依赖图(包括 import 语句里的路径),为后续 import() 或顶层 import 做好准备。这意味着:如果某个模块被多次 import(比如被多个入口文件引用),用 modulepreload 预加载后,浏览器能复用已解析的模块记录,避免重复解析。
必须写对 href 和 type,否则无效
常见错误是漏掉 type="module" 或写错 href 路径。浏览器只认 type="module" 的 link 为模块预加载指令;href 必须和实际 import 中写的路径完全一致(包括扩展名、大小写、相对/绝对路径)。例如:
<link rel="modulepreload" href="./utils.js" type="module">
如果代码里写的是 import { foo } from './utils.mjs',那这里必须写 ./utils.mjs,否则预加载失败且无提示。
- 不支持
crossorigin属性以外的其他属性(比如integrity必须配crossorigin) -
href不能是动态拼接的字符串,必须是静态字面量 - 多个
modulepreload标签之间无执行顺序保证,但依赖关系由模块图决定,不是靠 HTML 顺序
什么时候该用,什么时候不该用
适合场景:核心模块(如路由、状态管理、UI 基础组件)被多个入口或动态 import 引用;不适合场景:只被一个地方 import 且体积很小(
- 优先预加载那些有深层依赖的模块(比如 A → B → C),这样 B 和 C 也会被顺带解析
- 不要预加载
import()动态导入的“页面级 chunk”,它们本就按需加载,预加载会破坏懒加载意图 - 服务端渲染(SSR)中生成
modulepreload时,注意路径要匹配客户端运行时环境(比如不带/dist前缀)
如何验证是否生效
打开 Chrome DevTools 的 Network 面板,筛选 JS,找对应资源的 Initiator 列——如果显示 modulepreload,说明触发成功;再看 Timing 选项卡,确认 Start Time 是否显著早于首次 import 时间点。更直接的方式是打断点:console.time('import utils') + import('./utils.js'),对比加/不加 modulepreload 的耗时差异。
容易忽略的一点:模块预加载不会改变执行时机,它只影响“解析开始时间”。如果模块里有大量同步初始化逻辑(比如遍历大数组、正则编译),仍会在 import 时阻塞,预加载对此无帮助。

















