<script type="module"> 触发浏览器全流程重构:默认严格模式、独立作用域、静态依赖解析、天然 defer 执行、强制 CORS 与精细缓存。

设置 <script type="module"> 不只是加个属性那么简单——它触发了浏览器对脚本加载、解析、执行全流程的重新调度,底层机制与传统脚本有本质区别。
模块脚本默认启用严格模式且不共享全局作用域
所有 type="module" 脚本自动进入严格模式(无需 "use strict"),同时每个模块拥有独立的顶层作用域。这意味着:
• var 声明不会挂载到 window 上;
• 模块内直接写的 function foo(){} 不会变成全局函数;
• 即使多个模块都定义同名变量,也不会相互污染。
模块依赖图在解析阶段静态构建
浏览器在 HTML 解析时就扫描 import 语句,提前建立依赖树,而不是像传统脚本那样等到执行时才动态查找。这带来两个关键影响:
• import 必须是顶层语法,不能出现在条件或函数内;
• 导入路径必须是字符串字面量(不支持拼接或变量);
• 浏览器可并行预抓取所有依赖,提升加载效率。
模块脚本天然异步且自动 defer
type="module" 脚本默认行为等价于同时设置了 defer 和 async=false:
• 不阻塞 HTML 解析;
• 等待 DOM 构建完成后再按依赖顺序执行;
• 多个模块脚本保持声明顺序执行(即使跨 <script> 标签);
• 即使放在 <head> 里,也绝不会导致“找不到 DOM 元素”的问题。
模块加载强制使用 CORS,且缓存策略更精细
模块脚本及其 import 的资源被视为跨域请求,即使同源也需满足 CORS 要求:
• 本地文件系统(file://)下无法加载模块(会报 CORS 错误);
• 服务器需返回 Access-Control-Allow-Origin: * 或对应域名;
• 每个模块 URL 对应独立的 fetch 请求,浏览器为每个模块维护单独的缓存记录(含 ETag 和 Cache-Control),支持精准缓存失效。
这些变化不是语法糖,而是浏览器引擎对 JavaScript 运行时模型的一次重构。理解它们,才能避开常见陷阱,比如试图用 document.write、误以为模块能直接访问全局变量,或者在开发服务器未配 CORS 时反复报错。

















