Skip to content

[Bug?] [ts-node]: ts-node fails to resolve relative .js imports into .ts under Yarn PNP #6645

@earshinov

Description

@earshinov

Self-service

  • I'd be willing to implement a fix

Describe the bug

Just reported this to ts-node (TypeStrong/ts-node#2148), but thought that the problem might lie on the Yarn PNP's side and you guys could take a look. Following is a copy of that bug report:

Search Terms

ts-node, esm, ts-node-esm, yarn-pnp

Expected Behavior

Given:

  1. A TypeScript project...
  2. ...using ESM...
  3. ...and relative imports with extensions (as recommended for ESM)...
  4. ...with dependencies managed with Yarn PNP (and its own Node loader registered in runtime)

I shouldn't have problems running this TypeScript code with ts-node:

import { a } from './lib/a.js';

Command (actually a package.json script) being used:

yarn node --loader=ts-node/esm.mjs --loader=./.pnp.loader.mjs -- src/main.ts

Actual Behavior

$ yarn run test
(node:12796) [DEP0180] DeprecationWarning: fs.Stats constructor is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)

node:internal/modules/run_main:123
    triggerUncaughtException(
    ^
Error: Qualified path resolution failed: we looked for the following paths, but none could be accessed.

Source path: D:\dev\repro-ts-node-esm-yarn-pnp\src\lib\a.js
Not found: D:\dev\repro-ts-node-esm-yarn-pnp\src\lib\a.js

    at makeError (D:\dev\repro-ts-node-esm-yarn-pnp\.pnp.cjs:5630:34)
    at resolveUnqualified (D:\dev\repro-ts-node-esm-yarn-pnp\.pnp.cjs:7362:13)
    at resolveRequest (D:\dev\repro-ts-node-esm-yarn-pnp\.pnp.cjs:7402:14)
    at Object.resolveRequest (D:\dev\repro-ts-node-esm-yarn-pnp\.pnp.cjs:7458:26)
    at resolve$1 (file:///D:/dev/repro-ts-node-esm-yarn-pnp/.pnp.loader.mjs:2043:21)
    at nextResolve (node:internal/modules/esm/hooks:748:28)
    at Hooks.resolve (node:internal/modules/esm/hooks:240:30)
    at MessagePort.handleMessage (node:internal/modules/esm/worker:199:24)
    at MessagePort.[nodejs.internal.kHybridDispatch] (node:internal/event_target:816:20)
    at MessagePort.<anonymous> (node:internal/per_context/messageport:23:28)

Node.js v22.9.0

Steps to reproduce the problem / Minimal reproduction

Repro project: https://github.com/earshinov/repro-ts-node-esm-yarn-pnp/

The error is seen in the GitHub actions workflow: https://github.com/earshinov/repro-ts-node-esm-yarn-pnp/actions/

Specifications

$ yarn run ts-node -vv
ts-node v10.9.2  # 👈 latest
node v22.9.0
compiler v5.6.3
$ yarn --version
4.5.1

tsconfig.json:

{
  "compilerOptions": {
    "baseUrl": "src",
    "declaration": true,
    "module": "ESNext",
    "moduleResolution": "bundler",
    "noImplicitReturns": true,
    "outDir": "dist",
    "rootDir": "src",
    "skipLibCheck": true,
    "sourceMap": true,
    "strict": true,
    "target": "ESNext"
  },
  "include": [
    "src/**/*.ts"
  ]
}

package.json:

{
  "name": "repro-ts-node-esm-yarn-pnp",
  "private": true,
  "packageManager": "[email protected]",
  "type": "module",
  "scripts": {
    "test": "yarn node --loader=ts-node/esm.mjs --loader=./.pnp.loader.mjs -- src/main.ts",
    "test-with-custom-resolver": "yarn node --loader=ts-node/esm.mjs --loader=./.pnp.loader.mjs --loader=./helpers/resolve-js2ts.mjs -- src/main.ts"
  },
  "devDependencies": {
    "ts-node": "^10.9.2",
    "typescript": "~5.6"
  }
}
  • Operating system and version: Windows 11 Version 2382 (OS Build 22631.4602)
  • Running on the host, no WSL

Workaround

Using a dumb custom resolver. Command:

yarn node --loader=ts-node/esm.mjs --loader=./.pnp.loader.mjs --loader=./helpers/resolve-js2ts.mjs -- src/main.ts

Custom resolver:

export function resolve(specifier, context, nextResolve) {
  console.log(`resolve-js2ts: ${specifier}`);
  if (!specifier.endsWith('.js')) {
    return nextResolve(specifier, context);
  }
  return Promise.resolve(nextResolve(specifier, context)).catch((err) => {
    return Promise.resolve(nextResolve(specifier.replace(/\.js$/, '.ts'), context)).catch(() => {
      throw err;
    });
  });
}

Output:

$ yarn run test-with-custom-resolver
(node:47096) [DEP0180] DeprecationWarning: fs.Stats constructor is deprecated.
(Use `node --trace-deprecation ...` to show where the warning was created)
resolve-js2ts: file:///D:/dev/repro-ts-node-esm-yarn-pnp/src/main.ts
resolve-js2ts: ./lib/a.js
a

Environment

System:
  OS: Windows 11 10.0.22631
  CPU: (12) x64 Intel(R) Core(TM) i7-9850H CPU @ 2.60GHz
Binaries:
  Node: 22.9.0 - C:\Users\EARSHI~1\AppData\Local\Temp\xfs-fde8a036\node.CMD
  Yarn: 4.5.1 - C:\Users\EARSHI~1\AppData\Local\Temp\xfs-fde8a036\yarn.CMD
  npm: 10.8.3 - C:\Program Files\nodejs\npm.CMD

References

TypeStrong/ts-node#1361 - most relevant piece of information I have found. Judging by the fact that the issue is closed and the relevant pull requests have been merged, it would seem that the problem has been fixed in ts-node >1 year ago, except it apparently wasn't. Or maybe I'm dumb and there is another trap somewhere (as it usually is when it comes to Node.js, Yarn PNP, TypeScript and ESM).

Additional context

No response

✨Solution ✨

Do not pass --loader=./.pnp.loader.mjs when running yarn node, #6645 (comment)

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't workingwaiting for feedbackWill autoclose in a while unless more data are provided

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions