tsx icon indicating copy to clipboard operation
tsx copied to clipboard

ERR_MODULE_NOT_FOUND importing mts from mjs file from mts file

Open aredridel opened this issue 2 years ago • 5 comments

Bug description

tsx index.mts to run

index.mts imports file.mjs by import x from "./file.mjs"

file.mjs imports rootfile.mts by import x from "./rootfile.mjs"

I expect this to resolve rootfile.mts and work.

❯ tsx index.mts
Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/home/projects/rootfile.mjs' imported from /home/projects/node-war8wy/file.mjs
    at get (https://node-war8wy.w-corp.staticblitz.com/blitz.a0ea75dd36396805bd36e49d0b54d86602583e15.js:6:292488)
    at U@file:///home/projects/node-war8wy/node_modules/ (esbuild-kit/esm-loader/dist/index.js:19:1634)
    at <anonymous> (<anonymous>) {
  code: 'ERR_MODULE_NOT_FOUND'
}

Reproduction

https://stackblitz.com/edit/node-war8wy has the reproduction

Environment

  System:
    OS: Linux 5.0 undefined
    CPU: (8) x64 Intel(R) Core(TM) i9-9880H CPU @ 2.30GHz
    Memory: 0 Bytes / 0 Bytes
    Shell: 1.0 - /bin/jsh
  Binaries:
    Node: 16.14.2 - /usr/local/bin/node
    Yarn: 1.22.19 - /usr/local/bin/yarn
    npm: 7.17.0 - /usr/local/bin/npm
  npmPackages:
    tsx: ^3.11.0 => 3.11.0 

Can you contribute a fix?

  • [ ] I’m interested in opening a pull request for this issue.

aredridel avatar Nov 03 '22 01:11 aredridel

Thanks for the reproduction.

The .mjs -> .mts resolution isn't happening because it's not coming from a TypeScript file.

Do you know if TypeScript supports that?

BTW In ./file.mjs, it should be importing from ./rootfile.mjs instead of ../rootfile.mjs.

privatenumber avatar Nov 03 '22 14:11 privatenumber

BTW In ./file.mjs, it should be importing from ./rootfile.mjs instead of ../rootfile.mjs.

Doh, missed that in my simplification.

aredridel avatar Nov 03 '22 14:11 aredridel

Do you know if TypeScript supports that?

ts-node does, and tsc does this:

tsc --noEmit --allowJs file.mjs index.mts rootfile.mts

(no output)

but if I rename rootfile.mts to rootfile.bad,

❯ tsc --noEmit --allowJs file.mjs index.mts rootfile.mts
error TS6053: File 'rootfile.mts' not found.
  The file is in the program because:
    Root file specified for compilation


Found 1 error.

aredridel avatar Nov 03 '22 14:11 aredridel

Would love to see an update on this. This project is essentially unusable in any project that isn't 100% typescript

cbetori avatar Sep 24 '23 00:09 cbetori

Given this is a personal project, I mainly work on issues that I'm impacted by.

If you'd like me to prioritize this issue, you can incentivize it by sponsoring me.

privatenumber avatar Sep 24 '23 08:09 privatenumber

To anyone stumbling on this issue, you can bypass it somehow by writing a custom node loader leveraging tsx resolve/load implementation.

Place that somewhere like ./node/loader.js:

import { load, resolve as resolveTsx } from 'tsx';

export { load };

export async function resolve(specifier, ctx, defaultResolve) {
  // JS imports can point to JS or TS files, so we need to check both.
  if (specifier.endsWith('.js')) {
    const specifierTs = specifier.replace(/\.js$/, '') + '.ts';
    try {
      return await resolveTsx(specifierTs, ctx, defaultResolve);
    } catch (err) {
      return resolveTsx(specifier, ctx, defaultResolve);
    }
  }

  // Fallback for other files (like module imports, json, etc.)
  return resolveTsx(specifier, ctx, defaultResolve);
}

And you'll also need to register this loader using node registration protocol, so place the following in ./node/register.js for example:

import { register } from 'node:module';
import { pathToFileURL } from 'node:url';

register('./node/loader.js', pathToFileURL('./'));

Then instead of calling tsx mystuff.js directly, use node --import ./node/register.js mystuff.js. If using node<20, use node --loader ./node/loader.js mystuff.js, no need for a registration. This works on node20+ too but with a warning that they may drop support for --loader in the future.

AurelienRibon avatar Mar 07 '24 14:03 AurelienRibon

Happy to accept a PR to address this. Basically, tsx should read the allowJs config, and if it's enabled, treat JS files as TypeScript files during resolution.

Locking thread to direct further dialogue in the form of PRs.

privatenumber avatar Mar 07 '24 14:03 privatenumber

:tada: This issue has been resolved in v4.7.3

If you appreciate this project, please consider supporting this project by sponsoring :heart: :pray:

privatenumber avatar Apr 25 '24 10:04 privatenumber