2. 如何在 ESM 里使用 CJS 的包
约 717 字大约 2 分钟
2025-06-24
在 ES Modules (ESM) 中引入 CommonJS (CJS) 的包,需要根据不同的运行环境(Node.js / 浏览器 / 打包工具)和模块系统进行适配。以下是详细解决方案:
Node.js 环境下的 ESM 引入 CJS
Node.js 支持在 ESM 中直接 import
CommonJS 模块,但需注意:
1、直接 import
(推荐)
// ESM 文件(如 app.mjs 或 package.json 设置 "type": "module")
import cjsPackage from "commonjs-package"; // 默认导入
import { namedExport } from "commonjs-package"; // 具名导入(如果 CJS 支持)
注意事项:
如果 CJS 模块使用
module.exports = ...
,需用default
导入:import cjsDefault from "commonjs-package"; // 对应 module.exports = ...
如果 CJS 模块导出多个属性(如
exports.a = ...; exports.b = ...
),可以用:import * as cjsModule from "commonjs-package"; // 全部导入为命名空间 console.log(cjsModule.a, cjsModule.b);
2、动态 import()
(异步加载)
const cjsModule = await import("commonjs-package"); // 返回 Promise
console.log(cjsModule.default); // 对应 module.exports
3、使用 createRequire
(兼容复杂场景)
如果遇到兼容性问题,可以使用 node:module
手动创建 require
:
import { createRequire } from "node:module";
const require = createRequire(import.meta.url);
const cjsModule = require("commonjs-package"); // 传统 require
浏览器环境(通过打包工具)
在浏览器中运行 ESM 时,需借助 Webpack / Vite / Rollup 等工具处理 CJS 依赖:
1、Webpack / Vite / Rollup
这些工具会自动转换 CJS 为 ESM,无需额外配置:
// 直接 import,打包工具会处理
import cjsPackage from "commonjs-package";
2、浏览器原生 ESM + CDN
如果直接使用浏览器 ESM(无打包工具),需确保 CJS 包提供 ESM 版本(如通过 esm.sh
或 skypack.dev
):
<script type="module">
import lodash from "https://esm.sh/lodash"; // CDN 提供 ESM 版本
console.log(lodash.get({ a: 1 }, "a"));
</script>
TypeScript 项目中的 CJS 导入
如果使用 TypeScript,需确保 tsconfig.json
正确配置:
{
"compilerOptions": {
"module": "ESNext", // 或 "CommonJS"(如果输出 CJS)
"moduleResolution": "node16", // 或 "nodenext"(支持 node: 和 CJS 互操作)
"esModuleInterop": true, // 允许 default 导入 CJS
"allowSyntheticDefaultImports": true // 兼容无 default 导出的 CJS 模块
}
}
然后可以正常 import
:
import _ from "lodash"; // 即使 lodash 是 CJS,也能正确导入
常见问题及解决
问题 1:__dirname
和 __filename
在 ESM 中不可用
import { fileURLToPath } from "node:url";
import { dirname } from "node:path";
const __filename = fileURLToPath(import.meta.url);
const __dirname = dirname(__filename);
问题 2:CJS 包没有默认导出
import * as cjsModule from "commonjs-package"; // 全部导入
const { namedExport } = cjsModule; // 解构
问题 3:循环依赖导致 undefined
- CJS 和 ESM 混用时可能出问题,尽量统一模块系统。
- 使用动态
import()
延迟加载。
总结
场景 | 推荐方案 |
---|---|
Node.js ESM | 直接 import 或 createRequire |
浏览器 ESM | 打包工具(Webpack/Vite)或 ESM CDN |
TypeScript | 配置 esModuleInterop: true |
动态加载 | await import('cjs-package') |
最佳实践:
- 新项目:尽量使用 ESM 规范的包。
- 旧项目迁移:逐步替换 CJS 依赖,或用
createRequire
过渡。 - 浏览器环境:优先选择 ESM CDN 或打包工具。
这样就能在 ESM 中无缝使用 CJS 包! 🚀
更新日志
2025/8/24 08:17
查看所有更新日志
e7112
-1于