的 import 路径必须带扩展名或以 / ./ ../ 开头,因 ESM 要求模块说明符为有效 URL,浏览器不自动补 .js 或解析 package.json;模块有独立顶层作用域,无法访问非模块脚本挂载的 window 变量;本地 file:// 协议下会触发 CORS,需用本地服务器;模块默认 defer 但执行顺序依依赖链而非 HTML 位置。
直接用 就能加载 ES 模块,但默认是严格模式、不共享全局作用域、路径必须带扩展名或以 / ./ ../ 开头——这些不是可选项,是浏览器强制要求。
的 import 路径不能省略扩展名?ESM 的解析规则要求模块说明符(specifier)必须是有效的 URL。浏览器不会像 Node.js 那样自动补 .js,也不会查 package.json 的 exports 字段。
import { foo } from 'utils' → ❌ 报错:Failed to resolve module specifier 'utils'

import { foo } from './utils.js' → ✅ 正确(注意 .js)import { foo } from '/src/utils.js' → ✅ 绝对路径也行import { foo } from 'https://cdn.skypack.dev/lodash-es' → ✅ 远程 URL 也合法type="module" 脚本里无法访问 window 上挂的变量?模块脚本有独立的顶层作用域,和传统 的全局作用域隔离。你在非模块脚本里写的 window.myLib = {...},在模块里读不到 window.myLib,哪怕它先执行。
console.log(myLib) → ReferenceError
console.log(window.myLib) → undefined(即使它确实存在)myLib.js,再用 import { something } from './myLib.js'
export * from 'data:,' 或动态 eval 绕过——既不可靠也不符合 ESM 设计意图CORS 错误,但文件明明在本地?Chrome/Firefox 对 file:// 协议下加载模块有更严格的 CORS 策略。即使所有文件都在同一目录,import 也会被拦截。
Access to script at 'file:///.../utils.js' from origin 'null' has been blocked by CORS policy
npx serve 或 python3 -m http.server 8000
http://127.0.0.1:5500,确保你的 HTML 中的 import 路径与之匹配(如 ./src/main.js)chrome --disable-web-security —— 它禁用的是整个安全模型,不是调试方案index.html
最常被忽略的一点:模块脚本默认是 defer 行为(即 DOM 解析完才执行),但它**不保证执行顺序**——多个 type="module" 脚本之间,只按 HTML 中出现顺序执行;但若某个模块内部又 import 其他模块,则依赖链优先于书写顺序。别假设“写在下面的模块一定后执行”。