如何在浏览器端 Vanilla JS 中正确使用 ES 模块导出与导入

1次阅读

如何在浏览器端 Vanilla JS 中正确使用 ES 模块导出与导入

本文详解如何在纯浏览器环境中(无构建工具)将 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 包),建议引入轻量构建工具(如 Viteesbuild),但对纯静态配置对象等简单场景,原生 ESM 已完全足够,零依赖、零配置、开箱即用。

text=ZqhQzanResources