加 type="module" 启用原生 ES 模块,但需满足路径显式(含 ./ 或 / 及 .js)、禁用 file://、避免裸导入、启用 HTTP 服务、确保 MIME 类型正确及跨域加 crossorigin 属性。

直接加 type="module" 就能启用原生 ES 模块,但浏览器不会自动补路径、不认裸名、拒绝 file:// 加载——不是语法写错,而是环境或路径没对齐。
为什么加了 type="module" 还报 "Cannot use import statement outside a module"
这不是代码问题,是上下文没切进去:
- 写了
import却放在没加type="module"的<script></script>里,浏览器按 classic 脚本执行,直接抛错 -
import('./a.js')动态导入写在非模块脚本里,import()只能在模块上下文中调用 - 双击打开 HTML(
file://协议),Chrome/Firefox 压根不发请求,控制台只显示空错误或 CORS 相关提示
路径必须带 ./ 或 /,且不能省略 .js
浏览器不做任何推测,所有 import 路径必须显式、可解析:
-
import { foo } from './utils.js'✅ 显式相对路径 + 扩展名 -
import { foo } from './utils'❌ 缺扩展名,报Failed to resolve module specifier -
import { foo } from 'lodash'❌ 裸导入,原生不支持,除非配<script type="importmap"></script> -
import { foo } from 'utils.js'❌ 裸路径,浏览器无法判断是相对还是绝对,直接SyntaxError
模块脚本默认 defer,但和传统 defer 完全不同
它不是“延迟执行”,而是“按模块图顺序执行”:
- 多个
<script type="module" src="a.js"></script>和<script type="module" src="b.js"></script>严格按 DOM 中出现顺序执行,哪怕 b.js 下载更快 - 模块顶层声明的
const、function不会挂到window上,作用域彻底隔离 -
document.currentScript在模块里始终是null,别依赖它
本地开发必须起 HTTP 服务,不能双击打开
模块加载走的是 mode: 'cors',哪怕同源,file:// 协议也直接被拒:
- 用
npx serve、python3 -m http.server或 VS Code Live Server 启服务 - 确保服务器返回正确的 MIME 类型:
Content-Type: application/javascript - 跨域模块(如 CDN 上的
lodash-es)必须加crossorigin属性,否则静默失败
最容易被忽略的是:模块加载包含解析、实例化、执行三个阶段,而 modulepreload 只做第一件事——它只下载,不解析也不执行,且 href 必须和后续 src 完全一致(含查询参数)。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











