`require()` of a bundled ESM module returns a fresh object on every call (regression from 0.14.27)
- Dominant language
- Go
- Stars
- 40.1k
- Forks
- 1.3k
- PR merge metrics
- No merged PRs in 30d
Description
> [!NOTE]
> Found this issue while attempting to switch Electron core from webpack -> esbuild. Claude identified the underlying issue and I manually verified. This issue and the PR that will follow both used AI assistance (via claude code)
When a bundled CJS-shaped file calls `require()` on a bundled ESM-shaped module, esbuild emits `(init_foo(), __toCommonJS(foo_exports))`. Since f4ff26d37cc75bd5757161a29bac7e986e7ecef9 (0.14.27), `__toCommonJS` allocates a fresh wrapper on every call, so two `require()` calls for the same module return different objects.
This diverges from Node's CJS semantics (cached `module.exports`), webpack's `__webpack_require__` cache, and esbuild ≤ 0.14.26 (which memoized via WeakMap). The removal commit calls the cache "unnecessary", which is true for the entry-point `module.exports = __toCommonJS(...)` use, but not for inline `require()` of a bundled ESM module.
**Repro** ([playground](https://esbuild.github.io/try/#YgAwLjI4LjAALS1idW5kbGUAZQBlbnRyeS5qcwBjb25zdCBhID0gcmVxdWlyZSgnLi9lc20tbW9kJyk7CmNvbnN0IGIgPSByZXF1aXJlKCcuL2VzbS1tb2QnKTsKY29uc29sZS5sb2coJ2EgPT09IGI6JywgYSA9PT0gYik7IC8vIGZhbHNlIChyZWdyZXNzaW9uKQoAAGVzbS1tb2QuanMAZXhwb3J0IGNvbnN0IHZhbHVlID0gNDI7Cg)):
```js
// esm-mod.js
export const value = 42;
// entry.js
const a = require('./esm-mod');
const b = require('./esm-mod');
console.log('a === b:', a === b);
```
```sh
npx esbuild entry.js --bundle | node
# a === b: false
```
**Expected:** `true`
**Real-world impact:** code that aliases two specifiers to the same module (e.g. exposing `'timers'` and `'node:timers'` from a sandbox `require` shim) or that registers state on `require('foo')` and reads it back via a second `require('foo')` silently breaks.
Contributor guide
No contributing guide indexed for this repository
Research direction
Start with the entry.js and esm-mod.js reproduction and run the provided npx esbuild entry.js --bundle | node command. Inspect the generated __toCommonJS path and compare the two require() results; done means repeated requires of the bundled ESM module return the same object, with the reproduction printing true.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- go, javascript
- Domain
- build-system, compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 48/100