Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
earshinov opened this issue Jan 4, 2025 · 1 comment
Open

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

earshinov opened this issue Jan 4, 2025 · 1 comment

Comments

@earshinov
Copy link

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

@earshinov earshinov changed the title resolve .js to .ts in ts-node/register Relative .js imports still not resolved to .ts (under Yarn PNP?) Jan 4, 2025
@t1bb4r
Copy link

t1bb4r commented Jan 9, 2025

@earshinov I don't see this in your tsconfig. Have you tried this setting?

  "ts-node": {
    "experimentalResolver": true,
  }

See https://typestrong.org/ts-node/docs/options#experimentalresolver

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants