nomodule是现代浏览器的“跳过指令”,非旧浏览器兼容开关;必须与type="module"成对使用,单独写会导致新旧浏览器均白屏,且legacy-bundle.js须为es5兼容的iife/umd格式并含polyfill。

nomodule 不是兼容开关,而是现代浏览器的“跳过指令”——它只让 Chrome 61+、Firefox 60+、Safari 11+ 这类支持 type="module" 的浏览器忽略对应脚本;旧浏览器(如 IE11、Android 4.4 WebView)根本识别不了这个属性,会照常加载并执行它。单独使用 nomodule 脚本,新旧用户都可能白屏。
为什么单独写 <script nomodule src="fallback.js"></script> 会白屏
现代浏览器看到 nomodule 就跳过,不发请求、不解析、不执行;旧浏览器虽会尝试加载,但若前面没有 type="module" 脚本兜底,整个页面 JS 逻辑就断了。更糟的是 IE11 实际上会静默忽略整行标签——既不报错,也不执行,你以为它在跑,其实什么都没干。
- Chrome DevTools Network 面板里搜
fallback.js,它不该出现(说明被跳过) - IE11 控制台执行
typeof module返回"undefined",但fallback.js也未运行,基本可判定是单写nomodule导致的丢弃 - 正确结构必须是两行并存,且顺序无关,但推荐模块优先:
<script type="module" src="app.mjs"></script><script nomodule src="legacy-bundle.js"></script>
nomodule 脚本必须是真正 ES5 兼容的 IIFE/UMD 格式
nomodule 只管“要不要加载”,不管“能不能运行”。哪怕脚本进了 IE11,以下任一情况都会立刻崩溃:
- 语法层面:含
const、let、=>、${}、class→ 直接SyntaxError - API 层面:调用
fetch()、Promise、Array.from()、Object.assign()→ReferenceError或静默失败 - DOM 层面:用
element.classList.add()(IE9–)、querySelector()(IE7–)、addEventListener()(IE8–)→ 报错或无响应 - 构建时必须显式设
targets: { ie: "11" },不能依赖 Babel 默认 preset;core-js/stable需手动引入,且 polyfill 必须在所有业务代码之前执行 - 输出格式只能是 IIFE 或 UMD,严禁含
import/export,禁用dynamic import()
Safari 10.1 的双执行陷阱与运行时规避方案
Safari 10.1(macOS 10.12.4 / iOS 10.3)是个特例:它识别 type="module",却错误地也执行 nomodule 脚本,导致 UI 初始化两次、事件重复绑定、数据请求翻倍。
- 最稳妥的缓解方式是加一层运行时检测,只在“半吊子”浏览器中注入 fallback:
<script nomodule> if(!('noModule' in document.createElement('script'))) { document.write('<script src="app.fallback.js"></script>'); } - 利用
'noModule' in HTMLScriptElement.prototype判断是否真正支持nomodule语义,只有 Safari 10.1 这类浏览器会进入document.write分支 - 不要用 UA 字符串判断——新版 Safari 已隐藏版本标识,且 UA 可伪造
真正容易被忽略的点是:旧浏览器执行 nomodule 脚本时默认同步阻塞 HTML 解析,哪怕你写了 async,IE11 也完全不认;所以 legacy-bundle.js 必须压缩到最小,关键初始化逻辑建议内联进 HTML,而不是依赖额外请求。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











