node.js v12.20.0+ 通过 package.json 的 "exports" 字段实现 cjs/esm 双兼容:用 "import" 和 "require" 条件分别指向 .mjs 与 .cjs 入口,配合 "types" 提供类型提示,并需确保构建产物语法匹配。

Node.js 从 v12.20.0(LTS)起原生支持 ES Module,但要让同一个包同时兼容 require()(CommonJS)和 import(ESM),并根据加载方式自动选择导出路径,需通过 package.json 的 条件导出(Conditional Exports) 配置实现。核心是利用 "exports" 字段声明不同环境下的入口文件。
配置 package.json 的 exports 字段
在项目根目录的 package.json 中定义 "exports",按条件区分 ESM 和 CommonJS 入口:
-
"import"条件匹配所有 ESM 加载(import、dynamic import()、顶层 await 等) -
"require"条件匹配require()加载(CommonJS) -
"default"是兜底条件,当其他条件都不匹配时生效
示例配置:
{
"type": "module",
"exports": {
".": {
"import": "./dist/index.mjs",
"require": "./dist/index.cjs"
},
"./utils": {
"import": "./dist/utils.mjs",
"require": "./dist/utils.cjs"
}
}
}
注意:"type": "module" 表示整个包默认以 ESM 方式解析,但条件导出会覆盖该行为——即即使包是 ESM 类型,require('./') 仍会走 "require" 分支。
详细的 Three.js 3D 图形参考,涵盖场景设置、相机、几何体、材质、光照、动画、控制器、加载器、数学工具和调试。
确保构建产物格式匹配条件
条件导出只是路由,真正起作用的是你提供的文件后缀与内容格式:
-
.mjs文件必须是合法 ES Module 语法(如export default、import),且不能含require() -
.cjs文件应使用 CommonJS 语法(module.exports、require()),避免export关键字 - 若用 TypeScript,需在
tsconfig.json中分别配置module: "es2020"(生成 .mjs)和module: "commonjs"(生成 .cjs)
处理子路径导出与类型提示
条件导出支持子路径(如 ./utils),也支持为 TypeScript 提供类型定义:
- 在每个条件分支中可追加
"types"字段指向对应类型文件,例如:
"import": { "types": "./dist/index.d.ts", "default": "./dist/index.mjs" } - 推荐使用对象形式写法,提升可读性与扩展性(尤其当需要增加
"development"或"browser"条件时) - TypeScript 5.0+ 能自动识别
"types"字段,无需额外配置typesVersions
验证是否生效
写两个测试文件验证行为是否符合预期:
- 新建
test-cjs.js(后缀 .js +"type": "module"时需显式用.cjs后缀):
console.log(require('.')); // 应加载 index.cjs - 新建
test-esm.mjs:
import pkg from '.'; console.log(pkg); // 应加载 index.mjs - 运行
node test-cjs.cjs和node test-esm.mjs,检查输出和报错信息
若报 ERR_UNSUPPORTED_DIR_IMPORT,说明未正确设置 "exports" 或路径不存在;若 ESM 中出现 require is not defined,说明 .mjs 文件误用了 CommonJS 语法。
Java免费学习笔记:立即使用
解锁 Java 大师之旅:从入门到精通的终极指南










