nomodule 不是降级开关而是加载分流指令,需与 type="module" 成对使用:现代浏览器执行 module 脚本并忽略 nomodule,旧浏览器跳过 module 并执行 nomodule 脚本;safari 10.1 存在双加载问题,需运行时检测规避。

ES Module 本身不提供降级能力,nomodule 也不是降级开关,而是加载分流指令。它和 type="module" 必须成对使用,才能让现代浏览器执行模块脚本、旧浏览器执行兼容脚本——这不是“自动回退”,而是浏览器根据自身能力主动选择加载哪一条路径。
nomodule 的真实作用:现代浏览器跳过,旧浏览器执行
支持 ES Module 的浏览器(Chrome 61+、Firefox 60+、Safari 11+、Edge 16+)会:
- 加载并执行
<script type="module" src="app.mjs"></script> - 完全忽略(不请求、不解析、不执行)带
nomodule的脚本
不支持 ES Module 的浏览器(如 IE11、Android 4.4 WebView)会:
- 静默跳过
type="module"标签(不认识该 type,不报错也不加载) - 把
<script nomodule src="legacy-bundle.js"></script>当作普通text/javascript脚本加载并执行
注意:IE11 实际上会忽略整个 nomodule 标签(包括属性和 src),所以仅靠它无法覆盖 IE11 —— 必须确保 legacy-bundle.js 是独立可运行的、无语法/ API 报错的完整产物。
正确写法:必须双 script 并存,顺序建议模块优先
标准结构如下:
<script type="module" src="app.mjs"></script><script nomodule src="legacy-bundle.js"></script>
关键点:
在 Linux 上通过 Chrome 挂载/VNC 自动发布小红书长笔记。Agent 撰写标题和正文后执行 xhs_publish.sh --publish --submit,触发小红书发布。
- 两者互斥,没有交集;现代用户只加载
app.mjs,旧用户只加载legacy-bundle.js - 不能只写其中一行,否则新旧用户都可能白屏
- DOM 顺序不影响逻辑,但把
type="module"放前面更符合语义直觉
legacy-bundle.js 必须真正兼容旧环境
nomodule 只控制“是否加载”,不管“能否运行”。即使脚本成功进入 IE11,以下问题仍会导致崩溃:
-
语法错误:含
const、箭头函数、模板字符串、解构赋值 → 需 Babel 转译到 ES5,目标设为ie 9或更低 -
API 缺失:用
fetch()、Promise、Array.from()、element.classList→ 需提前注入 polyfill 或改用兼容写法(如XMLHttpRequest、className、attachEvent) -
构建格式错误:不能是 ESM 格式,必须是 IIFE 或 UMD,且不能含
import/export
推荐做法:用 Webpack/Rollup 分别打包两个产物,legacy-bundle.js 内联关键 polyfill(如 core-js、whatwg-fetch),并压缩体积。
Safari 10.1 的特殊处理
Safari 10.1(macOS 10.12.4 / iOS 10.3)会同时加载并执行 type="module" 和 nomodule 脚本,造成重复初始化、事件绑定冲突、内存浪费。
缓解方式:在 nomodule 脚本前加一段运行时检测:
<script>
if (!('noModule' in document.createElement('script'))) {
document.write('<script src="legacy-bundle.js"></script>');
}
这段代码只在 Safari 10.1 这类“半支持”浏览器中生效,避免双加载。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










