Repository navigation
Version 22.20.0 tightens Module Loader ? #60290
Description
Activity
Can you provide a minimal reproduction? It would be difficult to do anything about it with the information given, as it seems to be specific to the exact graph and the loader customizations involved.
On a side note this sounds similar to #59963 which was fixed by #60072 but not yet backported to v22. If you can make it go away by testing it in v24.10.0 and above then it's likely it.
- addedloadersIssues and PRs related to ES module loaders.Issues and PRs related to ES module loaders.strip-typesIssues and PRs related to TypeScript type stripping.Issues and PRs related to TypeScript type stripping.esmIssues and PRs related to the ECMAScript Modules implementation.Issues and PRs related to the ECMAScript Modules implementation.
on Oct 17, 2025 mohammedmanna-skyscanner commented
on Oct 17, 2025 AuthorMore actions@joyeecheung here it is 🤞
at readConfigFileAndSetRootDir (/Users/dumb-user/mockingbird/packages/platform-tooling/node_modules/jest-config/build/index.js:2258:13)
at async readInitialOptions (/Users/dumb-user/mockingbird/packages/platform-tooling/node_modules/jest-config/build/index.js:1147:13)
at async readConfig (/Users/dumb-user/mockingbird/packages/platform-tooling/node_modules/jest-config/build/index.js:918:7)
at async readConfigs (/Users/dumb-user/mockingbird/packages/platform-tooling/node_modules/jest-config/build/index.js:1168:26)
at async runCLI (/Users/dumb-user/mockingbird/packages/platform-tooling/node_modules/@jest/core/build/index.js:1393:7)
at async Object.run (/Users/dumb-user/mockingbird/packages/platform-tooling/node_modules/jest-cli/build/index.js:656:9)`
I think the issue is that previously it was using an external TS loader to run typescript (ts-node), while now it's using type stripping and therefore you cannot use require in a ES module.
If you use Node 22.17.0 (before native ts) it throws this error:Error: Jest: Failed to parse the TypeScript config file /Users/marcoippolito/Desktop/jest-bug-reproduction/jest.config.ts Error: Jest: 'ts-node' is required for the TypeScript configuration files. Make sure it is installedYou repo does not have ts-node installed.
And then once you install it, test pass.
If you have ts-node installed it also works with Node v22.18.0, 22.20.0 and latest 24.
So the only difference is thatJest: 'ts-node' is required for the TypeScriptis no longer emitted if you dont have ts-node installed because it will use the native one (you can test it by adding a random enum in the file and see the error)
The error is Jest does not check for ts-node being installed correctly and assumes that if you can run a ts file its ts-node.
So there is nothing much to do on Node.js sidemohammedmanna-skyscanner commented
on Oct 17, 2025 AuthorMore actionsI think the issue is that previously it was using an external TS loader to run typescript (ts-node), while now it's using type stripping and therefore you cannot use require in a ES module. If you use Node 22.17.0 (before native ts) it throws this error:
Error: Jest: Failed to parse the TypeScript config file /Users/marcoippolito/Desktop/jest-bug-reproduction/jest.config.ts Error: Jest: 'ts-node' is required for the TypeScript configuration files. Make sure it is installedYou repo does not have ts-node installed. And then once you install it, test pass. If you have ts-node installed it also works with Node v22.18.0, 22.20.0 and latest 24. So the only difference is that
Jest: 'ts-node' is required for the TypeScriptis no longer emitted if you dont have ts-node installed because it will use the native one (you can test it by adding a random enum in the file and see the error) The error is Jest does not check for ts-node being installed correctly and assumes that if you can run a ts file its ts-nodeI am unsure what you are suggesting, sorry :) .
Also, the issue was never there for node 22.17.1 for me. As soon as I moved to 22.20.0 - it started after 22.20.0. So does it mean the expectation from that version has changed around require() ?no what changed is that now that Node.js can execute typescript natively, Jest does not correctly detect if ts-node is installed, and uses Node.js native type stripping. It's a Jest bug not a node bug.
mohammedmanna-skyscanner commented
on Oct 17, 2025 AuthorMore actionsno what changed is that now that Node.js can execute typescript natively, Jest does not correctly detect if ts-node is installed, and uses Node.js native type stripping. It's a Jest bug not a node bug.
☝️ Got it - makes sense. So would this bug be more appropriate to raise for the Jest package.
no what changed is that now that Node.js can execute typescript natively, Jest does not correctly detect if ts-node is installed, and uses Node.js native type stripping. It's a Jest bug not a node bug.
☝️ Got it - makes sense. So would this bug be more appropriate to raise for the Jest package.
However if you install ts-node (
npm i ts-node) in your repo, the problem goes awaymohammedmanna-skyscanner commented
on Oct 17, 2025 AuthorMore actionsHowever if you install ts-node (npm i ts-node) in your repo, the problem goes away
Ok - but this is where my confusion is, or rather, I wanted to make sure I understood the root cause.
- Before 22.20.0 upgrade, everything was working fine for me. and to be clear, the quickest reproducible example is a package within my project. The top-level package.json has
ts-nodealready.
top-level - package.json. // this has ts-node - packages/platform-tools - package.json. // this didn't and it didn't matter- After 22.20.0 upgrade, it stopped working. So, if I have to now also install
ts-nodein my monorepo package, that's a change. And I am wondering where this bug is e.g. Jest or Node.
top-level - package.json. // this has ts-node - packages/platform-tools - package.json. // You are proposing to install here now too...(which is what I don't get why)Because installing
ts-nodein nested package (along with top-level package.json) - is not a solution if it worked before 22.20.0 - unless this is what's warranted by 22.20.0.May be The issue is that Jest 30+ treats .ts config files differently in certain contexts (like when it's run from workspaces), and
require.resolve()isn't available in ES module scope. But even then, why would it start complaining after a minor node version upgrade.- Before 22.20.0 upgrade, everything was working fine for me. and to be clear, the quickest reproducible example is a package within my project. The top-level package.json has
mohammedmanna-skyscanner commented
on Oct 17, 2025 AuthorMore actionsOK - based on the conversation and some further research... I managed to recover the build. Below is the analysis (some common parts from previous comments)
Root Cause
Node.js 22.18.0 enabled TypeScript type stripping by default. This feature madeNode.jstreat.tsfiles especially, running them through a TypeScript parser/transformer even when loaded by tools like Jest.When jest.config.ts is loaded:
Before Node 22.18.0: The config was treated as a regular module, and require.resolve() worked fine
After Node 22.18.0: Node's built-in TypeScript support intercepts the loading, treating it as an ES module with type stripping, which breaks require.resolve() callsThe issue is NOT:
❌ Jest version mismatch
❌ Node.js version in general (22.17.1 vs 22.20.0)
❌ Missing ts-node or other toolingThe issue IS:
✅ Node 22.18.0's new default TypeScript type stripping feature interfering with Jest's config loading>
AND then....
The require.resolve('uuid') was a workaround NO LONGER NECESSARY 🤦♀️
Because....
The issue was fixed in Jest 28+: According to the GitHub issue, Jest 28 added proper support for the uuid package's exports field.
GitHub Issue: [https://github.com/uuidjs/uuid/issues/451]
SimenB's comment: [https://github.com/uuidjs/uuid/issues/451#issuecomment-1112030160]
I am using Jest 29.7.0: And that workaround interfered with Node 22.18+ native type-stripping.
Version
22.20.0 LTS
Platform
Subsystem
No response
What steps will reproduce the bug?
before 22.20.0 upgrade, we had 22.17.1 and our script configuration was working correctly.
The line of code (script block, and the affected line respecr) - with 22.17.1
"test": "cd ../../ && jest --verbose --testPathPatterns=packages/platform-tooling"moduleNameMapper: { '^uuid$': require.resolve('uuid'), ... },After upgrading to node 22.20.0 - we are seeing the following error stack when that uuid module is being loaded(uuid package version hasn't changed)
`Error: Jest: Failed to parse the TypeScript config file /Users/dumb-user/mockingbird/jest.config.ts
ReferenceError: require is not defined in ES module scope, you can use import instead
🤔 Why does this happen? And here is my stupid theory (please rebut and let me know the root cause)
Node v22.20.0 tightened its module loader so a require() on a .ts file now throws ERR_REQUIRE_ESM whenever the file is treated as an ES module. That change comes from the work introducing the native TypeScript loader (--experimental-strip-types) described in the v22.6.0+ release notes on nodejs.org; the loader defaults .ts to ESM, so plain require() is rejected (?)
When Jest tries to load
jest.config.ts, it calls require(configPath). Since Node 22.20 reports ERR_REQUIRE_ESM, the code in node_modules/jest-config/build/readConfigFileAndSetRootDir.js falls back to await import(configPath). Inside that ESM evaluation require is not defined, so the line^uuid$': require.resolve('uuid')immediately throws the “ReferenceError: require is not defined in ES module scope” you’re seeing(?)Hope this makes sense. And thanks in advance for looking into it.
How often does it reproduce? Is there a required condition?
Immediately after moving from 22.17.1 to 22.20.0
What is the expected behavior? Why is that the expected behavior?
No change in behaviour in any minor/patch version released. Not at least for tightening ESM vs. CJS expectations.
What do you see instead?
As reported above in stack trace.
Additional information
No response