es modules需配合nomodule实现可靠降级:现代浏览器执行type="module"脚本并忽略nomodule脚本,旧浏览器忽略type="module"但执行nomodule脚本;safari 10.1需额外检测处理。

ES Modules(type="module")本身不兼容旧浏览器,但可以通过 nomodule 属性配合双脚本策略实现可靠降级——这不是自动 fallback,而是靠浏览器对 type 值的识别差异来分流执行。
为什么只写 type="module" 不行
IE、Edge 12–18、Safari ≤10.1 等旧浏览器完全不认识 type="module" 这个值,会静默忽略整个 <script></script> 标签:不下载、不解析、不报错。这意味着页面在这些浏览器里可能 JS 完全不执行,功能直接丢失。
- 它不会退化为
text/javascript,也不会触发任何兜底逻辑 - 模块脚本默认具有
defer行为,但旧浏览器连这个行为都接触不到 - 单独使用
type="module"只是“开关”,不是“桥接器”
正确降级:module + nomodule 成对出现
现代浏览器执行 type="module" 脚本,并跳过所有带 nomodule 的脚本;旧浏览器忽略 type="module",但会正常加载并执行 nomodule 脚本。
-
<script type="module" src="app.mjs"></script>:供 Chrome 61+、Firefox 60+、Safari 11+ 使用,支持import/export、顶层await等 -
<script nomodule src="app.js"></script>:供 IE11、Android 4.4 WebView 等使用,必须是 ES5 语法、无模块语法、含必要 polyfill - 两个
<script></script>应放在同一位置(推荐模块在前),且nomodule单独写无效,必须与type="module"配合才有意义
旧脚本必须真正兼容,不能只靠标签
nomodule 只控制是否加载,不解决语法或 API 兼容问题。如果 app.js 里写了 const、箭头函数、Promise 或 fetch,IE11 仍会报错。
- Babel 编译目标需明确设为
targets: { ie: "11" } - 手动补全缺失 API:如
Array.prototype.includes需引入core-js/stable或自行 polyfill - 避免在
nomodule脚本中使用import()动态导入——旧浏览器不支持 - Webpack/Vite 构建时,确认
build.target或babel-preset-env的 targets 与实际覆盖范围一致
Safari 10.1 是特例,需额外处理
Safari 10.1 支持 type="module",但不识别 nomodule,会导致两个脚本都被执行。解决方案是在 type="module" 脚本最前面插入轻量级检测逻辑:
- 运行时判断
CSS.supports('selector(:has(a))')或'noModule' in HTMLScriptElement.prototype - 若检测失败,动态移除
nomodule脚本或阻止其执行 - 更稳妥做法:用
webshim或自定义 polyfill 在页面早期注入兼容层
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南











