在 `file://` 协议下,内联 `
JavaScript 模块(ESM)的设计核心之一是严格的词法作用域与静态导入/导出机制。当你在 HTML 中使用:
这段代码确实会执行(无报错),但 hello 仅存在于该模块的私有模块作用域中,既不会挂载到全局 window,也无法被外部脚本或浏览器控制台直接引用——这并非 bug,而是 ESM 的规范行为。
即使你将模块拆分为独立文件(如 utils.js),并在 HTML 中这样写:
——在 file:// 协议下仍会失败,并出现类似错误:
立即学习“Java免费学习笔记(深入)”;
Cross-Origin Request Blocked: The Same Origin Policy disallows reading the remote resource at file:///.../utils.js. (Reason: CORS request not http)
这是因为:浏览器模块加载器强制要求模块 URL 必须基于 http: 或 https: 协议。file:// 被明确排除在模块解析支持之外(MDN 明确说明)。这不是权限问题,而是规范层面的硬性限制。
| 方案 | 原理 | 适用场景 | 备注 |
|---|---|---|---|
| 启动本地 HTTP 服务 | 使用 python3 -m http.server 8000、npx serve 或 VS Code Live Server 插件,以 http://localhost:8000/ 访问页面 | 开发调试、离线项目原型 | ✅ 完全符合标准,支持内联模块 + 外部模块 + 动态 import();推荐首选方案 |
| 动态 import() + 显式暴露 | 在模块内用 window.myModule = await import('./utils.js'),再在控制台调用 window.myModule.hello() | 临时调试,不推荐长期使用 | 需手动触发加载,且依赖 await(控制台需在 async 上下文中执行) |
| 使用 eval() + 字符串模块(不推荐) | 将模块内容读为字符串后 eval() 执行并挂载,绕过模块系统 | 仅限实验,存在安全与维护风险 | 违反模块设计初衷,破坏静态分析、tree-shaking 等现代特性 |
# 终端进入项目目录后执行(Python 3 内置) python3 -m http.server 8000 # 或使用 npm(需安装 serve) npx serve -s # 然后访问 http://localhost:8000/test.html → 所有 ESM 功能正常工作!
此时你的原始示例可安全重构为:
✅ 最佳结构建议:
// main.js
export function hello() { console.log("hello"); }
// 可选:仅开发时挂载(用条件判断避免上线污染全局)
if (location.protocol === 'http:' || location.protocol === 'https:') {
window.DEBUG_MODULE = { hello };
}然后在浏览器控制台中:
>> DEBUG_MODULE.hello() hello
模块不是“更高级的 script”,而是一套全新的执行上下文。理解并尊重它的边界,才是高效调试的前提。