type="module"与nomodule配合实现浏览器分流:现代浏览器执行modern.js(原生es模块),旧浏览器执行legacy.js(babel转译+polyfill)。需构建双产物、polyfill前置、css/html同步降级。

<script type="module"></script> 本身不会降级,旧浏览器(如 IE11、Safari ≤10.0、Edge ≤18)根本不知道这个 type 值,直接跳过整条 <script></script> 标签——不加载、不解析、不报错。所以单靠它无法实现兼容,必须配合 nomodule 属性,形成“二选一”的加载逻辑。
type="module" 和 nomodule 是一对开关
- 现代浏览器(Chrome 61+、Firefox 60+、Safari 10.1+、Edge 16+)识别
type="module",执行该脚本,并自动忽略所有带nomodule的<script></script>标签。 - 旧浏览器不认识
type="module",静默跳过它,但会正常加载并执行带nomodule的脚本。
典型写法:
<script type="module" src="modern.js"></script><script nomodule src="legacy.js"></script>
注意:
在 Java 中初始化和管理阿里云 SDK客户端。包括单例模式、线程安全、endpoint 与 region 配置、VPC 终端节点、同步与异步等。
-
modern.js应为原生 ES 模块格式(含import/export),由现代构建工具(如 Vite、Webpack)输出,通常用@babel/preset-modules编译,保留async/await等特性,只修复已知 bug。 -
legacy.js是完整转译 + polyfill 后的传统脚本(如 IIFE 或 UMD),用@babel/preset-env配合{ targets: { ie: '11' } }构建,确保语法和 API 全面兼容。 - 两个
<script></script>标签应放在相同位置(建议模块在前),顺序不影响逻辑,但影响资源加载优先级。
构建时必须输出两套产物
不能只写双标签而共用一个 JS 文件。需要构建工具明确生成:
-
modern.js:面向支持type="module"的浏览器(覆盖约 88% 用户),体积小、启动快; -
legacy.js:面向旧浏览器,含 Babel 转译 +core-js/stable+regenerator-runtime,可能还需es6-promise(尤其针对 IE11)。
主流工具默认支持:
- Vite:通过
@vitejs/plugin-legacy自动生成legacychunk 和对应<script nomodule></script>; - Webpack:用
html-webpack-plugin插件或自定义模板注入双标签,配合targets分别配置两套babel-loader; - Rollup / esbuild:需手动拆分入口或使用插件(如
rollup-plugin-multi-entry)产出双版本。
不能省略的配套处理
-
Polyfill 加载时机:
legacy.js必须把 polyfill 放在最前面(如import 'core-js/stable'; import 'regenerator-runtime/runtime';),否则async/await或Promise在执行前就报错。 -
全局污染控制:避免
legacy.js中的变量泄漏到全局,推荐打包为 IIFE;若用 UMD,确认window上无意外挂载。 -
CSS 和 HTML 也要同步降级:比如
:has()选择器、var(--color)自定义属性,在旧浏览器中同样静默失效,需搭配@supports检测或 JS 运行时判断 + class 切换。
本质上,这不是“让旧浏览器理解 ES Modules”,而是用浏览器原生行为做分流——用对的工具,在对的环境跑对的代码。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










