ESBuild构建库时默认导出被嵌套的问题排查与解决
问题原因分析
你遇到的默认导出嵌套问题,本质是模块格式不匹配导致的模块互操作异常:
- 你的源码使用ES模块的
export default导出类,但ESBuild默认将Node平台代码打包为CommonJS格式时,会把ES模块的default导出映射到module.exports.default上,而非直接赋值给module.exports。 - 当消费方用ES模块语法导入这个CommonJS产物时,Node.js的模块互操作机制会把整个
module.exports对象作为ES模块的default导出,最终就出现了{ default: [class JWTSigner2] }的嵌套结构,需要额外取一次default才能拿到类。
解决方案
方案1:输出ES模块格式(推荐)
让库的产物保持ES模块格式,和源码模块系统一致,从根源避免互操作问题:
- 修改ESBuild配置,添加
format: 'esm'指定输出ES模块:
esbuild.build({ entryPoints: entryPoints, bundle: true, outdir: path.join(__dirname, outdir), outbase: path.join(__dirname, functionDir), platform: 'node', format: 'esm', // 新增:指定输出ES模块 external: ['aws-sdk'], minify: isProd, sourcemap: !isProd, }).catch(() => process.exit(1))
- 在库的
package.json中配置type: "module",明确告知Node.js这是ES模块:
{ "name": "jwt-on-kms", "type": "module", "main": "./dist/index.js", "types": "./dist/index.d.ts", // 可选:同时支持CommonJS和ES模块的双入口配置 "exports": { ".": { "import": "./dist/index.js", "require": "./dist/index.cjs" } } }
如果需要同时兼容CommonJS和ES模块,可额外构建一份CommonJS产物(设置format: 'cjs'),并通过exports字段指定不同入口。
方案2:修正CommonJS产物的导出逻辑
如果必须输出CommonJS格式,可通过以下方式让默认导出直接映射到module.exports:
- 在源码中补充CommonJS导出语句(适合TypeScript项目):
export default class JWTSigner { // 类实现 } // 补充CommonJS导出,让require和import都能直接拿到类 module.exports = JWTSigner; // 为TypeScript类型添加兼容声明 declare module 'jwt-on-kms' { export = JWTSigner; }
- 或通过ESBuild的
banner配置自动修正导出:
esbuild.build({ entryPoints: entryPoints, bundle: true, outdir: path.join(__dirname, outdir), outbase: path.join(__dirname, functionDir), platform: 'node', format: 'cjs', // 明确指定CommonJS格式 external: ['aws-sdk'], minify: isProd, sourcemap: !isProd, // 添加banner修正导出逻辑 banner: { js: 'const mod = module.exports; module.exports = mod.default;' } }).catch(() => process.exit(1))
额外检查:TypeScript配置(若使用TS)
确保tsconfig.json的compilerOptions中开启模块互支持:
{ "compilerOptions": { "esModuleInterop": true, "module": "NodeNext", "moduleResolution": "NodeNext" } }
内容的提问来源于stack exchange,提问作者Jex__y
相关产品推荐
相关产品推荐

