使用Commander开发Node CLI遇ESM与CommonJS兼容错误求解决
解决Node CLI中ESM与CommonJS的冲突问题
1. 保留package.json的ESM配置
必须保留 "type": "module" —— 你依赖的chalk、Commander等目前多为纯ESM包,移除该配置会触发ERR_REQUIRE_ESM错误,这是无法绕过的。
2. 修正TypeScript配置(tsconfig.json)
按照Node 16官方规范调整TS编译参数,确保输出纯ESM格式,避免生成CommonJS的exports语法:
{ "compilerOptions": { "target": "ES2020", "module": "ESNext", "moduleResolution": "NodeNext", "esModuleInterop": false, "skipLibCheck": true, "strict": true, "outDir": "./dist", "rootDir": "./src", "resolveJsonModule": true, "declaration": true }, "include": ["src/**/*"], "exclude": ["node_modules"] }
关键参数说明:
module: "ESNext"+moduleResolution: "NodeNext":确保TS编译输出完全符合Node ESM规范- 关闭
esModuleInterop:ESM环境不需要这个CommonJS兼容选项,开启反而可能导致语法冲突
3. 修正桶文件(barrel)的导出语法
桶文件绝对不能使用CommonJS的module.exports,必须统一用ESM的export语法:
错误写法(会触发exports is not defined):
module.exports = { foo: require('./foo'), bar: require('./bar') };
正确写法:
// 单个导出 export { default as foo } from './foo'; export { bar } from './bar'; // 或批量导出 export * from './foo'; export * from './bar';
4. 调整CLI入口的执行逻辑
在package.json中配置正确的bin字段,指向编译后的ESM入口文件:
{ "type": "module", "bin": { "your-cli-name": "./dist/bin/cli.js" }, "scripts": { "build": "tsc", "start": "node ./dist/bin/cli.js" } }
开发阶段若要直接运行TS文件,建议使用tsx替代ts-node(ts-node对ESM的支持需要复杂配置):
npm install -D tsx
然后修改开发脚本:
"scripts": { "dev": "tsx ./src/bin/cli.ts" }
5. 清理残留的CommonJS语法
全局检查所有源码文件,确保没有使用require()、module.exports、exports.xxx这类CommonJS语法,全部替换为ESM的import/export。
错误根源说明
- 保留
"type": "module"时触发ReferenceError:你的代码(大概率是桶文件)存在CommonJS导出语法,ESM环境不允许这类写法。 - 移除
"type": "module"时触发ERR_REQUIRE_ESM:chalk、Commander等依赖是纯ESM包,无法在CommonJS环境中用require()引入。
内容的提问来源于stack exchange,提问作者octavemirbeau
相关产品推荐
相关产品推荐

