NPM包导入失败求助:CommonJS与ESM模块兼容问题
ESM与CommonJS模块兼容问题解决方案
方案1:让NPM包同时支持双模块格式
最稳妥的方式是让你的包同时适配ESM和CommonJS,不管项目用哪种模块系统都能直接用,步骤如下:
- 给包新增一个CommonJS专用的ts配置文件
tsconfig.cjs.json:
{ "files": ["src/globaltype.ts"], "compilerOptions": { "target": "es2016", "module": "CommonJS", "declaration": true, "outDir": "./build/cjs", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
- 把原来的tsconfig改名为
tsconfig.esm.json,调整输出目录为ESM专用:
{ "files": ["src/globaltype.ts"], "compilerOptions": { "target": "es2016", "module": "es2015", "declaration": true, "outDir": "./build/esm", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
- 更新包的package.json,配置多入口并完善脚本:
{ "name": "nodecustomerrorhandler", "version": "1.0.14", "description": "basic error handling module for node basic projects", "type": "module", "exports": { ".": { "import": "./build/esm/globaltype.js", "require": "./build/cjs/globaltype.js" } }, "main": "./build/cjs/globaltype.js", "module": "./build/esm/globaltype.js", "types": "./build/esm/globaltype.d.ts", "repository": { "type": "git" }, "scripts": { "build": "tsc -p tsconfig.esm.json && tsc -p tsconfig.cjs.json" }, "license": "ISC", "devDependencies": { "typescript": "^5.0.4" } }
- 重新执行
npm run build并发布包,之后CommonJS项目用require、ESM项目用import都能正常运行。
方案2:把项目改成纯ESM格式
如果想把项目切换到ESM,需要调整几个关键点:
- 项目package.json添加
"type": "module":
{ "name": "affiliatesystem", "version": "1.0.0", "type": "module", "main": "test.file.js", "scripts": { "dev": "ts-node-dev --esm --respawn src/server.ts" } }
- 修改项目的tsconfig,适配ESM模块解析:
{ "files": ["src/server.ts"], "compilerOptions": { "target": "es2016", "module": "NodeNext", "moduleResolution": "NodeNext", "rootDir": "./", "typeRoots": ["./src/globals.d.ts"], "outDir": "src/build", "esModuleInterop": true, "forceConsistentCasingInFileNames": true, "strict": true, "skipLibCheck": true } }
- 启动脚本要加
--esm参数,让ts-node-dev支持ESM - 项目里的导入语句统一用ESM格式:
import { GlobalErrorClass } from 'nodecustomerrorhandler',不能再用require
方案3:在CommonJS项目中动态导入ESM包
如果不想改包也不想动项目的模块系统,直接用动态import就行:
async function bootstrap() { const { GlobalErrorClass } = await import('nodecustomerrorhandler'); // 在这里使用GlobalErrorClass } bootstrap();
注意这种方式需要把模块相关逻辑放在异步函数里,适合不需要同步加载的场景。
内容的提问来源于stack exchange,提问作者kingNodejs
相关产品推荐
相关产品推荐

