You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
Fix - populate separate cache for require(esm) is a breaking change #59868
In webpack we cache build dependencies (and nested require in any deps) and use this logic before (sinplified):
constmodule=require.cache[path];if(module){// it is a common js module// we go through children and then also for their children and etc}elseif(/\.m?js$/.test(path)){// it is ES modules or something else// here we use `es-module-lexer` to get all `import`s}
Now this logic is broken, not only webpack uses this logic, it can break more tools
How often does it reproduce? Is there a required condition?
Always
What is the expected behavior? Why is that the expected behavior?
This change should be a part of the next major release, not minor
It seems what would fix this is some way to properly tell whether the module is ESM or not other than using whether it's in require.cache or not? Because by definition require(esm) should put it there, and there's no documentation asserting that what's in there can only ever be commonjs (for example, it can already be addons). IMO it's more of an incorrect interpretation of what would be in the cache in the first place than a breaking change.
We already cache the detected format on the module, if necessary we can expose it. So that the branch would just be:
constmodule=require.cache[path];if(module){if(module.format==='module'){}if(module.format==='commonjs'){}}elseif(/\.m?js$/.test(path)){// it is something else}
It seems what would fix this is some way to properly tell whether the module is ESM or not other than using whether it's in require.cache or not?
Yes, it will allow to use resolve the problem
Because by definition require(esm) should put it there, and there's no documentation asserting that what's in there can only ever be commonjs (for example, it can already be addons).
Yes, I don't say it is a bug, I said that is a breaking change and should be part of the next major release, for esm we use custom lexer to parse dynamic imports and other dependency stuff, so this change breaks ES modules caches for all webpack users, I saw this logic in other tools (so not only in webpack broken), and the number of places can be much greater, and the problem can also be complex enough to understand why something doesn't work/doesn't cache/doesn't parsed
IMO it's more of an incorrect interpretation of what would be in the cache in the first place than a breaking change.
I wouldn't say so when all previous versions contained only the format, now there are different, which means the API has changed
We already cache the detected format on the module, if necessary we can expose it. So that the branch would just be:
now there are different, which means the API has changed
In Node.js, things that are more in the "adding things that previously didn't exist" category are usually considered semver-minor (e.g., adding module.format would be in the similar category). It can be argued that every change is a breaking change and bug-for-bug compatibility hacks can be applied to make those who depend on undocumented behaviors effectively break less, though.
This should reduce the impact by delaying the cache population until the ESM is directly required (which is necessary for correctness) #59874 - I'll open a different PR to add module.format to help dealing with ESM that actually gets required.
This issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
This issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 240 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.
Activity
alexander-akait commentedon Sep 12, 2025
Also with new logic we have no way to know if this is a ES module or CommonJS
marco-ippolito commentedon Sep 12, 2025
@joyeecheung
alexander-akait commentedon Sep 12, 2025
At a minimum, it would be nice to see an API or property indicating that an ES module was loaded with
require, so it will be easy to handlejoyeecheung commentedon Sep 12, 2025
It seems what would fix this is some way to properly tell whether the module is ESM or not other than using whether it's in require.cache or not? Because by definition
require(esm)should put it there, and there's no documentation asserting that what's in there can only ever be commonjs (for example, it can already be addons). IMO it's more of an incorrect interpretation of what would be in the cache in the first place than a breaking change.We already cache the detected format on the module, if necessary we can expose it. So that the branch would just be:
alexander-akait commentedon Sep 12, 2025
@alexander-akait
Yes, it will allow to use resolve the problem
Yes, I don't say it is a bug, I said that is a breaking change and should be part of the next major release, for esm we use custom lexer to parse dynamic
imports and other dependency stuff, so this change breaks ES modules caches for all webpack users, I saw this logic in other tools (so not only in webpack broken), and the number of places can be much greater, and the problem can also be complex enough to understand why something doesn't work/doesn't cache/doesn't parsedI wouldn't say so when all previous versions contained only the format, now there are different, which means the API has changed
Yes, it will fix the problem
joyeecheung commentedon Sep 12, 2025
In Node.js, things that are more in the "adding things that previously didn't exist" category are usually considered semver-minor (e.g., adding
module.formatwould be in the similar category). It can be argued that every change is a breaking change and bug-for-bug compatibility hacks can be applied to make those who depend on undocumented behaviors effectively break less, though.joyeecheung commentedon Sep 12, 2025
This should reduce the impact by delaying the cache population until the ESM is directly required (which is necessary for correctness) #59874 - I'll open a different PR to add module.format to help dealing with ESM that actually gets required.
module: only put directly require-d ESM into require.cache
module: only put directly require-d ESM into require.cache
module: only put directly require-d ESM into require.cache
ChALkeR commentedon Sep 26, 2025
That's not (entirely) true:
Will misdetect on
module.exports = require('./1.mjs')though (i.e. when the wholeexportsis a re-export of ESM)More hacky:
Note: this is not a recommendation to use that, just noting that "no way" is not technically correct
github-actions commentedon Apr 25, 2026
This issue has been marked as stale due to 210 days of inactivity.
It will be automatically closed in 30 days if no further activity occurs. If this is still relevant, please leave a comment or update it to keep it open.
module: only put directly require-d ESM into require.cache
github-actions commentedon May 25, 2026
This issue has been automatically closed after 30 days of inactivity following its stale status (no activity for a total of 240 days).
If this is still relevant, feel free to reopen it or leave a comment with additional details so we can continue the discussion.