加了type="module"的script会启用es模块加载器,强制严格模式、延迟执行、作用域隔离、同源/cors策略及.js路径要求,与传统脚本行为完全不同。

为什么 type="module" 会让 <script></script> 行为完全不同
加了 type="module" 的 <script></script> 不再是传统脚本——它会启用浏览器原生 ES 模块加载器,自动按模块语义解析 import 和 export,且默认启用严格模式、延迟执行(相当于 defer),更重要的是:它强制使用同源或 CORS 策略加载依赖,本地文件系统(file://)下直接报错 CORS request not HTTP。
- 不加
type="module"的脚本无法使用import/export,语法错误直接抛Unexpected token 'export' -
type="module"脚本总是异步执行,即使写在里也不会阻塞 HTML 解析 - 模块路径必须带扩展名(如
./utils.js),不能省略.js(否则报Failed to resolve module specifier) - 模块作用域隔离:每个模块顶层
var/let/const都不会污染全局,window上查不到
如何正确书写模块入口和导入路径
模块路径不是相对 HTML 位置,而是相对于当前模块文件的 URL。比如 index.html 引入 main.js,而 main.js 中的 import { foo } from './utils.js',这个 ./utils.js 是从 main.js 所在目录找,不是从 index.html 所在目录。
- 绝对路径(以
/开头)从站点根目录解析,如import mod from '/src/lib.js' - 相对路径(
./或../)必须显式写.js后缀,import { a } from './a'❌,import { a } from './a.js'✅ - 裸导入(如
import _ from 'lodash')不被原生支持,会报Failed to resolve module specifier;必须用完整路径或配合构建工具/导入映射(<script type="importmap"></script>) - 动态
import()返回 Promise,可用于按需加载,但路径规则同上,也要带后缀
常见报错及对应修复方式
开发时最常卡在这几个地方,不是代码写错,而是环境或路径没对齐:
-
Access to script at 'file:///...' from origin 'null' has been blocked by CORS policy→ 必须用本地服务器启动(如npx serve、python3 -m http.server),不能双击打开 HTML -
Uncaught TypeError: Failed to resolve module specifier 'xxx'→ 检查路径是否拼错、后缀是否缺失、大小写是否匹配(Linux/macOS 区分大小写) -
Cannot use import statement outside a module→ 当前脚本没加type="module",或者被其他非模块脚本提前执行并污染了上下文 -
Export 'xxx' is not defined→ 导出名拼写错误,或导出语句写在if块里(模块顶层必须是静态声明)
模块脚本与传统脚本混用要注意什么
可以共存,但行为差异会引发隐性问题。比如一个 type="module" 脚本里 import 了某个工具函数,另一个普通脚本试图从 window 上取,取不到——因为模块内 export 不会挂到全局。
- 不要指望模块里的
export自动变成全局变量,跨脚本通信得靠显式暴露(如window.myLib = {...})或统一模块入口 - 多个
type="module"脚本之间共享同一个模块图,相同路径只执行一次,但普通脚本每次都会重新执行 - 如果要用模块功能又想兼容旧环境,可以用
type="module"+nomodule双写法:<script type="module" src="main.mjs"></script><script nomodule src="fallback.js"></script>
file:// 下反复刷新却看不到报错详情。前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











