
本文详解如何在纯浏览器环境中(无构建工具)将 Node.js 风格的 module.exports 迁移为标准 ES 模块语法,解决 Cannot use import statement outside a module 和 module is not defined 等常见错误。
本文详解如何在纯浏览器环境中(无构建工具)将 node.js 风格的 `module.exports` 迁移为标准 es 模块语法,解决 `cannot use import statement outside a module` 和 `module is not defined` 等常见错误。
在浏览器中直接运行 JavaScript 时,Node.js 的 CommonJS 模块系统(如 module.exports / require())默认不可用——它仅在 Node.js 运行时环境中生效。你当前遇到的两个核心错误:
- Uncaught SyntaxError: Cannot use import statement outside a module
- Uncaught ReferenceError: module is not defined
正是由于混用了不兼容的模块语法:index.js 使用了 import,但未声明为模块;而 test.js 使用了仅 Node.js 支持的 module.exports,在浏览器中根本无法解析。
✅ 正确做法是统一采用原生浏览器支持的 ES 模块(ESM)标准:
1. 修改 test.js:使用 export default
// test.js —— 纯前端可用的 ES 模块
export default {
white: "#fff",
black: "#000"
};⚠️ 注意:
- 不要写 module.exports = {...} 或 exports.xxx = ...;
- 不要使用 require();
- 文件扩展名保持 .js 即可(无需 .mjs,只要加载方式正确)。
2. 修改 index.js:使用标准 import 语法 + 相对路径
// index.js
import style from './test.js'; // ✅ 必须带扩展名,且为相对路径(如 './test.js' 或 '../config/colors.js')
console.log(style.white); // 输出 "#fff"
const btn = document.getElementById("mybtn");
btn.addEventListener("click", () => {
document.getElementById("show-alert").classList.remove("d-none");
});3. 关键:HTML 中以 type="module" 加载脚本
在 index.html 中,必须将 <script> 标签显式声明为模块</script>:
<!-- ✅ 正确:启用 ES 模块支持 --> <script type="module" src="index.js"></script> <!-- ❌ 错误:普通脚本无法解析 import --> <!-- <script src="index.js"></script> --> <!-- 同时移除旧的非模块化引用 --> <!-- <script type="module" src="test.js"></script> → 不需要单独引入,由 import 自动处理 -->
? 补充说明:
- type="module" 启用后,脚本自动以严格模式执行,支持顶层 await、动态 import() 及静态 import/export;
- 浏览器会自动按 ESM 规则解析依赖图,无需打包工具;
- 所有路径必须是有效的相对或绝对 URL(如 './test.js', '../utils/colors.js', 'https://cdn.example.com/lib.mjs'),不支持 Node.js 的包名解析(如 'lodash')。
4. 完整修正后的 HTML 片段(精简版)
<!-- index.html -->
<!DOCTYPE html>
<html>
<head>
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/css/bootstrap.min.css" rel="stylesheet"/>
</head>
<body>
<div class="d-flex align-items-center justify-content-center" id="record">
<div class="input-group mb-3 input-group-lg w-50">
<input type="text" class="form-control" id="rec-id" placeholder="Enter ID">
<button class="btn btn-success" id="mybtn" type="button">Enter</button>
</div>
</div>
<div class="d-flex align-items-center justify-content-center d-none" id="show-alert">
<div class="alert alert-danger alert-dismissible fade show">
<button type="button" class="btn-close" data-bs-dismiss="alert"></button>
<strong>Danger!</strong> Button was clicked
</div>
</div>
<!-- ✅ 唯一需要的脚本标签:声明为 module 并指向入口 -->
<script type="module" src="index.js"></script>
<!-- Bootstrap JS(需在 module 之前或之后均可,但注意依赖顺序) -->
<script src="https://cdn.jsdelivr.net/npm/@popperjs/core@2.11.8/dist/umd/popper.min.js"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.3/dist/js/bootstrap.min.js"></script>
</body>
</html>✅ 总结:三大必要条件
| 项目 | 正确写法 | 错误示例 |
|---|---|---|
| 导出语法 | export default { ... } 或 export const white = "#fff"; | module.exports = { ... } |
| 导入语法 | import style from './test.js';(路径含扩展名) | import style from 'test'; 或 require('./test') |
| HTML 加载 | <script type="module" src="index.js"></script> | <script src="index.js"></script> |
? 提示:若未来需支持更复杂的模块(如第三方 npm 包),建议引入轻量构建工具(如 Vite 或 esbuild),但对纯静态配置对象等简单场景,原生 ESM 已完全足够,零依赖、零配置、开箱即用。










