Skip to content

[Bug]: Module resolution via package.json exports fails if no cache available #5216

@wvanderdeijl

Description

@wvanderdeijl

Version

29.4.6

Steps to reproduce

git clone https://github.com/wvanderdeijl/ts-jest-repro.git
cd ts-jest-repro/packages/tests
npm i
npx jest --clear-cache
npx jest # this test fails
npx jest # second run succeeds

Expected behavior

npx jest should succeed just after clearing the cache as well when the cache is populated

Actual behavior

first run of npx jest after npx jest --clear-cache fails due to a typescript error about invalid types:

npx jest
  console.log
    setup-jest.ts is running!

      at Object.<anonymous> (setup-jest.ts:5:9)

 FAIL  ./strict.test.ts
  ● Test suite failed to run

    strict.test.ts:3:7 - error TS2322: Type '"nested-types"' is not assignable to type '"root-entrypoint-types"'.

    3 const local: 'root-entrypoint-types' = thing;
            ~~~~~

Test Suites: 1 failed, 1 total
Tests:       0 total
Snapshots:   0 total
Time:        0.626 s
Ran all test suite

This is caused by the module resolution finding packages/library/dist/nested-types.d.ts as type definition for the library/foo import whereas it should have found packages/library/dist/root-entrypoint-types.d.ts

Debug log

first run (after --clean-cache): https://raw.githubusercontent.com/wvanderdeijl/ts-jest-repro/refs/heads/main/ts-jest-first-run.log
second run (with primed cache): https://raw.githubusercontent.com/wvanderdeijl/ts-jest-repro/refs/heads/main/ts-jest-second-run.log

Additional context

See the README at https://github.com/wvanderdeijl/ts-jest-repro for my own analysis what might be going wrong.

It appears there is an early phase in the jest run where ts-jest resolves modules with a typescript compiler that has been started with the tsconfig.json from the project. This will use things like moduleResolution and customConditions from that config and might use modern ways to resolve modules.

Later in the jest run, ts-jest actually invokes the typescript compiler to compile ts to js. Before doing that it changes some of the config of the already instantiated compiler and removes customConditions and resets moduleResolution to old school nodejs10. With those settings the moduleResolution will not use the exports from package.json files and will not be able to resolve some modules.

The reproduce case has deliberately been setup with both exports in package.json AND node10 compatible resolving based on filesystem structure to demonstrate which resolving method is used.

Why is this different with/without cache?
The key is having a setupFilesAfterEnv in jest.config.js. Without a cache this initially goes to both phases for this setup file; phase 1 with module resolving with tsconfig.json settings and the phase 2 for compilation of that file (which resets the compiler to node10). After the setup has completed jest starts working on the normal tests and these also go through the two phases but by this time the compiler has been reset to node10 bij phase 2 of the setup file and the phase 1 of the test files now use this compiler.
On the second run, the setup file is cached so is not compiled and thus the compiler is not reset to node10. Jest then continues on to the real tests and performs phase 1 with the default tsconfig.json settings and now does use modern module resolution.

This might also be related to #4774 and #4639 as they also talk about different behavior with a clean or a primed cache.

Environment

System:
    OS: macOS 26.3.1
    CPU: (16) arm64 Apple M4 Max
  Binaries:
    Node: 18.18.0 - /Users/wilfred/.nvm/versions/node/v18.18.0/bin/node
    npm: 9.8.1 - /Users/wilfred/.nvm/versions/node/v18.18.0/bin/npm
  npmPackages:
    jest: ^29.7.0 => 29.7.0

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions