nomodule 不是降级开关而是加载过滤器,仅旧浏览器执行且现代浏览器完全不下载;必须与 type="module" 成对使用,否则新旧用户均可能白屏。

nomodule 不是降级开关,而是加载过滤器:只在不支持 type="module" 的浏览器中执行,现代浏览器根本不会下载它。单独用 nomodule 会导致旧用户没脚本可执行,现代用户反而加载了两份。
为什么 nomodule 单独用会失效
IE11、Android 4.4 WebView 等老环境确实会执行 <script nomodule src="legacy.js"></script>,但 Chrome/Firefox/Safari 从不下载也不执行它——连网络请求都不会发。如果你只写了这一行,现代用户什么 JS 都没加载;如果还漏掉了 type="module" 脚本,旧用户也白屏。
- IE11 完全忽略
nomodule属性(不报错,也不执行),但它识别不了type="module",所以只靠nomodule无法覆盖它 - 老浏览器不支持
async/defer的精细控制,nomodule脚本默认同步阻塞解析,必须压缩+内联关键逻辑 - 构建产物里若把
nomodule脚本打包进现代 bundle,就彻底失去意义——它必须是独立、编译后的 IIFE/UMD 格式
type="module" 和 nomodule 必须成对出现
两者不是“主备”,而是互斥的加载通道:现代浏览器走左边,旧浏览器走右边,中间没有交集。
文章转信息图。将文章/笔记转化为手机可读的 HTML 信息图,自动匹配视觉风格。触发场景:文章转图、笔记转图、信息图、转小红书图、做张图、可视化这篇文章、文生图。
- 顺序建议:先写
<script type="module" src="app.mjs"></script>,再写<script nomodule src="legacy-bundle.js"></script>(DOM 顺序不影响逻辑,但符合直觉) -
app.mjs必须是合法 ES 模块:含import/export,不能有document.write,且默认defer行为不可取消 -
legacy-bundle.js必须不含任何现代语法:不能用const、箭头函数、Promise、fetch——nomodule不管语法,只管加载 - 动态
import()在旧版构建中容易残留,需确认 Babel 或 Webpack 已启用dynamic-import-node插件并正确转译
旧浏览器执行 nomodule 脚本时的真实限制
即使成功加载了 legacy-bundle.js,它仍可能在 IE8–IE10 中崩溃,因为这些环境连基础 API 都不支持。
-
querySelector、classList、addEventListener在 IE8 中不存在,必须降级为getElementById、className、attachEvent - ES6+ 语法(如模板字符串、解构)必须经 Babel 转译到 ES5,且目标设为
ie 9或更低(ie 8需额外处理JSON、Array.prototype.forEach等) - 若用到
localStorage,IE6/7 需 fallback 到userDatabehavior,且要手动调用load()/save(),不能依赖自动持久化 - 不要在
nomodule脚本里做 UA 判断再加载 polyfill——旧浏览器解析速度慢,多一层异步加载极易超时或失败
真正难的不是加两个 script 标签,而是让 legacy-bundle.js 在 IE8 这类环境里不抛错、能初始化、有基本交互。它需要独立构建、独立测试、独立维护,而不是“新代码编译一下就完事”。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!










