Skip to content

Relative .js imports still not resolved to .ts (under Yarn PNP?) #2148

@earshinov

Description

@earshinov

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": "yarn@4.5.1",
  "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 dump 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

References

#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 >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).

✨Solution ✨

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

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions