Description
Context: I am using esbuild to do dependency-pre-bundling in Vite. This is a multiple-entry build with splitting: true
. The entries are resolved package entry files - e.g.
- node_modules/preact/index.module.js
- node_modules/react/index.js
I'm also using a plugin with onResolve
that redirects any imports to preact
or react
to these already resolved file locations to avoid duplicated copies of them in the resulting bundle.
Preact is a pure ESM module, so its corresponding output entry chunk is expected to preserve the same export signature as the original entry module. However, this is broken if any transitive module in the bundle contains a cjs require()
call to it. E.g. if somewhere down the tree a dependency does this:
const preact = require('preact')
This causes esbuild to wrap the ESM preact module with a CommonJS wrapper and expose only a default
export. This makes sense for the internal interop, but currently this also affects the final output entry chunk for preact: now the output chunk for preact also only has a default
export! This creates a mismatch between the output of the preact chunk and the original entry chunk.
What I imagine esbuild needs to do is to
- move both the preact module and its wrapped CommonJS code to a shared chunk
- re-export the same original exports from the preact entry chunk
- import and use the wrapped CommonJS version in the sub dependency that uses
require()
Currently I have to work around this by detecting exports mismatch between input/output entry chunks and perform additional runtime interop. Would be great to have this fixed in esbuild itself.