如何构建无需在导入时添加.default的ESM/CJS双兼容模块
问题根因
你遇到的需要额外加.default的问题本质是两种模块规范的导出逻辑不兼容:
- TypeScript编译CommonJS格式时,默认会把ES Module的
export default挂载到exports.default属性上,而非直接覆盖module.exports,导致CJS导入时需要手动取.default - ESM导入时仍然需要
.default,是因为Node.js没有正确识别你包的ESM入口的模块格式,把ESM产物误判为CommonJS模块读取
解决方案
按以下步骤修改配置即可实现双规范免.default导入:
1. 调整TypeScript编译配置
给CJS对应的tsconfig(tsconfig-cjs.json)新增两个配置项,开启CommonJS默认导出兼容:
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "CommonJS", "outDir": "./dist/cjs", "esModuleInterop": true, "allowSyntheticDefaultImports": true } }
2. 添加入口兼容逻辑
在你的源码入口文件末尾添加CommonJS导出兼容代码,把默认导出直接挂载到module.exports上:
import someClass from './class'; export default someClass; // 新增CJS兼容代码 if (typeof module !== 'undefined' && module.exports) { module.exports = someClass; module.exports.default = someClass; }
3. 完善package.json配置
首先新增模块格式识别配置,避免Node.js误判产物格式:
- 在
dist/esm目录下新建独立的package.json,内容为:{"type": "module"} - 在
dist/cjs目录下新建独立的package.json,内容为:{"type": "commonjs"}
你也可以修改build命令自动生成这两个配置文件,避免每次手动创建:
"build": "tsc -p tsconfig.json && tsc -p tsconfig-cjs.json && echo '{\"type\":\"module\"}' > dist/esm/package.json && echo '{\"type\":\"commonjs\"}' > dist/cjs/package.json"
然后修改根目录的package.json,新增exports字段明确不同导入方式的入口映射:
{ "main": "dist/cjs/index.js", "module": "dist/esm/index.js", "types": "dist/esm/index.d.ts", "exports": { ".": { "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js", "types": "./dist/esm/index.d.ts" } } }
4. 验证效果
重新执行npm run build构建后,两种导入方式都可以直接使用:
// CJS 导入 const someClass = require('package') const instance = new someClass() // ESM 导入 import someClass from 'package' const instance = new someClass("")
内容的提问来源于stack exchange,提问作者Alexander Craggs
相关产品推荐
相关产品推荐

