Esbuild plugin to simplify hybrid (aka dual) packages forging
PoC
Hybrid package is a quite specific approach when, for some reason, you may need to support both modern (esm) and legacy (cjs) architectures. Node.js brings a portion of internal magic for this:
⚠️ When importing CommonJS modules, the module.exports object is provided as the default export. Named exports may be available, provided by static analysis as a convenience for better ecosystem compatibility. https://nodejs.org/api/esm.html#import-statements
Unfortunately, this mechanism does not provide absolute reliability. That's why, the general approach for this case is double bundling, when size is not critical. Otherwise, a little optimization fixes it easily:
index.cjs (generated)
const foo = 'bar'
module.exports = {
foo
}
index.mjs
const {foo} = require('./index.cjs')
export {foo}
This plugin just handles the mentioned routine.
import { build, BuildOptions } from 'esbuild'
import { hybridExportPlugin } from 'esbuild-plugin-hybrid-export'
const plugin = hybridExportPlugin({
to: 'target/esm',
toExt: '.mjs'
})
const config: BuildOptions = {
entryPoints: ['index.ts'],
outdir: 'target/cjs',
plugins: [plugin],
format: 'cjs'
}
await build(config)