最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
HTML模块加载性能:借助modulepreload提前预加载关键JS模块的方法
时间:2026-07-09 11:30:57 编辑:袖梨 来源:一聚教程网
modulepreload不会加速模块执行,只提前拉取网络资源;其与defer、async的本质区别在于:defer控制执行时机但不预下载,async异步下载并立即执行会破坏依赖顺序,而modulepreload仅在HTML解析早期发起fetch,不解析、不执行、不构建模块图。
modulepreload 不会让模块执行变快,它只提前拉取网络资源;写错路径、漏 crossorigin、没列子模块,就等于没写。
modulepreload 和 defer/async 的根本区别在哪
很多人加了 modulepreload 还在等模块执行,其实它根本不碰执行逻辑。浏览器拿到后只 fetch,不 parse、不构建 module graph、不执行任何代码。
-
defer:DOM 解析完才执行,但下载时机由 parser 决定,可能晚于首屏渲染 -
async:下载完立刻执行,破坏模块顺序,无法用于有 import 依赖的链路 -
modulepreload:只做一件事——在 HTML 解析早期发起 fetch,把模块和显式声明的依赖放进缓存,后续<script type="module" src="...">才真正触发解析与执行
为什么写了 modulepreload 却没生效
常见静默失效,控制台不报错,Network 面板也看不到请求,问题基本锁定在这几个硬性条件上:
-
href值必须和后续<script type="module" src="...">的src完全一致——协议、域名、路径、查询参数(如?v=1.2.3)一个都不能差 - 只要模块走 CDN 或跨域服务(哪怕只是静态托管平台),
<link>必须带crossorigin属性,否则浏览器直接忽略 - 不支持相对路径:
./main.mjs或../utils.js会被跳过,必须用绝对路径或根相对路径(如/assets/main.mjs) -
modulepreload不递归加载子模块——main.mjs里import './utils.js',你得手动再加一行<link rel="modulepreload" href="/assets/utils.js" crossorigin>
怎么写一个真正有效的 modulepreload 链
手写容易漏、难维护,尤其构建产物带 hash 时。但理解规则才能 debug:
立即学习“前端免费学习笔记(深入)”;
- 多个
<link rel="modulepreload">标签建议按执行依赖顺序排列:先vendor.mjs,再main.mjs,部分浏览器会复用 TCP 连接 - 每个
href必须指向最终解析后的 URL(比如 Vite 构建后是/assets/main.a1b2c3.js,不是src/main.js) - 不能对非模块脚本使用:
type="text/javascript"的文件加modulepreload会静默失败 - 必须放在
<head>中,且早于首个<script type="module">;放在<body>里无效
真实项目别手写——Vite 默认开启 build.modulePreload,Webpack 可配 webpack-preload-plugin,Rollup 推荐 rollup-plugin-module-preload。它们能静态分析 AST,提取所有静态 import 路径并注入完整列表。
最容易被忽略的是:modulepreload 只对静态 import 生效,动态 import() 和 import map 映射的 bare specifier 不在它的作用范围内;而且即使预加载成功,模块语法错误、路径拼错、CSP 拦截这些执行期问题,依然会导致 Failed to load module script,和预加载无关。
相关文章
- 蚂蚁庄园今日答案(每日更新)2026年1月16日 07-17
- 蚂蚁庄园今日正确答案1月16日 07-17
- 死亡搁浅2全部34个武器的解锁方法条件是什么 07-17
- 星塔旅人全部角色特殊回忆触发条件方式合集 07-17
- Palia帕利亚1.12至1.18村民需求物品清单大全 07-17
- 舒舒服服小岛时光全部魔法种子分布详情图 07-17