Safari 10.1 是唯一已知现代浏览器中 nomodule 失效的场景,会同时执行 type="module" 和 nomodule 脚本,导致双倍初始化;必须在 nomodule 脚本内添加运行时检测(如判断 module.constructor.name === 'Module')来阻止执行。

nomodule 脚本在 Safari 10.1 会被重复执行
这是唯一已知的现代浏览器中 nomodule 失效的场景:Safari 10.1(macOS 10.12.4 / iOS 10.3)识别 type="module" 并执行它,但**错误地也加载并执行了 nomodule 脚本**。结果不是“跳过”,而是双倍初始化——UI 渲染两次、事件绑定重复、API 请求翻倍。
- 这不是配置错误,是 Safari 10.1 的引擎缺陷,无法通过 HTML 属性修复
- Chrome、Firefox、Safari 11+、Edge 16+ 都严格遵循规范:执行
type="module",跳过nomodule - 检测方式:在 Safari 10.1 控制台执行
typeof module返回"object"(说明支持模块),但同时console.log出现在nomodule脚本里 → 就是双执行
用运行时检测阻止 nomodule 脚本在 Safari 10.1 中执行
不能依赖 HTML 层面的属性组合,必须在 nomodule 脚本内部加一层判断:只在真正不支持模块的旧浏览器中运行逻辑。
- 在
legacy-bundle.js开头插入检测逻辑:if (typeof module !== 'undefined' && module.constructor.toString().includes('Module')) {<br> // Safari 10.1 会进这里,直接 return<br> exit;<br>} - 更稳妥写法(兼容所有 edge case):
if (typeof window !== 'undefined' && 'onbeforeunload' in window && typeof module === 'object' && module.constructor.name === 'Module') {<br> // Safari 10.1 特征组合,退出执行<br> throw new Error('Skip legacy bundle in partial-module browser');<br>} - 不要用
!window.module或!window.import—— Safari 10.1 的window.module是undefined,但脚本仍会执行
为什么不能靠构建时排除 Safari 10.1
构建工具(如 Webpack、Rollup)按目标浏览器生成代码,但 nomodule 脚本本身是给“不支持模块”的浏览器用的,Safari 10.1 在 Browserslist 里属于 safari 10,默认被归入“支持模块”范围 —— 所以你打包出的 legacy-bundle.js 很可能根本没为它做兼容处理,甚至含 const 或 => ,导致 SyntaxError 后静默失败。
- Browserslist 配置
supports esmodules会把 Safari 10.1 判为支持模块,但它实际行为是“半支持” - 即使你显式加
safari 10.1到 targets,Babel 也不会自动注入运行时检测,仍需手动加 guard - polyfill 如
core-js/stable在 Safari 10.1 里可能触发重复注册(比如 Promise polyfill 被执行两次)
真正安全的 nomodule 加载链
HTML 层面的 nomodule 只是加载开关,不是执行保险。最终是否执行,取决于脚本内部是否做了 Safari 10.1 的兜底判断。
立即学习“前端免费学习笔记(深入)”;
- 正确结构必须是三段式:
<script type="module" src="app.mjs"></script><br><script nomodule src="legacy-bundle.js"></script><br><noscript><div>JS 已禁用</div></noscript>
-
legacy-bundle.js必须是 IIFE 格式,开头带 Safari 10.1 检测,结尾无副作用(比如不自动调用init()) - 所有 DOM 操作和初始化逻辑,必须包裹在检测之后,不能放在顶层作用域
nomodule 唯一不可绕过的运行时陷阱。它不报错、不阻断、只悄悄让一切发生两次——最容易被忽略的,恰恰是最难 debug 的。



















