如何修复TypeScript库ESM与CommonJS模块导入兼容问题?
解决TypeScript库同时支持ESM和CommonJS的导入问题
1. 主package.json必须配置精准的exports字段
这是Node.js自动适配ESM/CommonJS导入的核心,替换掉旧的main/module字段,明确指定不同导入方式对应的入口:
{ "name": "your-lib", "version": "1.0.0", "exports": { ".": { "import": "./dist/esm/index.js", "require": "./dist/cjs/index.js", "types": "./dist/types/index.d.ts" } }, "types": "./dist/types/index.d.ts", "files": ["dist"] }
exports会让Node.js根据用户的导入方式(import/require)自动匹配对应模块,避免混淆。
2. 精简构建目录的子package.json
只保留type字段,确保和产物模块格式完全匹配:
dist/cjs/package.json:{"type": "commonjs"}dist/esm/package.json:{"type": "module"}
子目录的package.json会覆盖主目录的类型设置,必须保证和该目录下的编译产物格式一致。
3. 拆分TypeScript编译配置
创建两个TS配置文件,分别编译CJS和ESM产物:
tsconfig.cjs.json(编译CommonJS):
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "CommonJS", "outDir": "./dist/cjs", "target": "ES2018", "declaration": false } }
tsconfig.esm.json(编译ESM):
{ "extends": "./tsconfig.json", "compilerOptions": { "module": "ESNext", "moduleResolution": "NodeNext", "outDir": "./dist/esm", "target": "ES2020", "declaration": false } }
- 新增类型单独编译的配置(可选,避免重复生成类型):
在tsconfig.json中添加:
{ "compilerOptions": { "declaration": true, "declarationDir": "./dist/types" } }
然后在package.json的scripts里配置构建命令:
"scripts": { "build": "npm run build:cjs && npm run build:esm && npm run build:types", "build:cjs": "tsc -p tsconfig.cjs.json", "build:esm": "tsc -p tsconfig.esm.json", "build:types": "tsc -p tsconfig.json --emitDeclarationOnly" }
4. 修复ESM产物的扩展名问题
Node.js的ESM要求必须使用完整文件扩展名,开启moduleResolution: NodeNext后,TypeScript会自动处理内部导入的扩展名补全。如果代码中存在手动导入,需确保添加.js后缀(比如import { utils } from './utils.js')。
5. 验证导入逻辑
- CommonJS环境(Node.js默认):
const { ContextManager } = require('your-lib') - ESM环境(项目
package.json设type:module或使用.mjs文件):import { ContextManager } from 'your-lib'
若仍报错,排查以下点:
- Node.js版本需≥14.13.0(稳定支持
exports字段) - 构建产物是否正确生成在对应目录,子
package.json是否存在 - 类型文件路径是否和
exports中的types字段匹配
内容的提问来源于stack exchange,提问作者Dave Mcsavvy
相关产品推荐
相关产品推荐

