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

.js extension import raises MODULE_NOT_FOUND error #77

Open
n1ru4l opened this issue Jul 9, 2022 · 6 comments
Open

.js extension import raises MODULE_NOT_FOUND error #77

n1ru4l opened this issue Jul 9, 2022 · 6 comments

Comments

@n1ru4l
Copy link

n1ru4l commented Jul 9, 2022

See the following reproduction: https://codesandbox.io/s/esbuild-register-js-module-not-found-reproduction-gyogmj

run yarn start

I am pretty sure this should be allowed.

@romanown
Copy link

romanown commented Jul 9, 2022

use 'foo' instead 'foo.js'. although 'foo' is 'foo.ts'. but use need as 'foo'. to try please.
https://codesandbox.io/s/esbuild-register-js-module-not-found-reproduction-forked-y85vvn?file=/index.ts

@n1ru4l
Copy link
Author

n1ru4l commented Jul 9, 2022

foo.js is what TypeScript node16 moduleResolution expects (for importing from a .ta file). Also in Node.js you can attach the .js extension in any version and it behaves the same way as if you did not attach the extension. Thus, to me it seems like esbuild-register should be able to follow this behavior.

@justinhelmer
Copy link

I am experiencing the same issue in a pure ESM package, trying to use esbuild-register/loader to run mocha for my TS files with JS extensions.

@janus-reith
Copy link

Im experiencing the same issue with both esbuild-register and swc-node which also provides an experimental esm loader.
I think I have all the necessary settings in my tsconfig, since tsc is able to build with the same input in ESM mode.
Omitting the .js extension is not an option, TSC which I still depend on for type-checking would fail in that case.

I had a similar issue trying to get swc/jest to work some time ago swc-project/jest#64, that worked eventually with the solution provided in the comments there, that however was specific to jest.
Hope I'm not going too much off topic here, it seems to me like the underlying technical issues are the same and revolve around the discrepancy between ESM explicit extension requirements and tsc + other build tools usually omitting them.
Last time I checked how deno does it, I realized they simply had a patched version of tsc to make it not complain about imports ending with ".ts";

I'm still wondering if there's some way the authors of esbuild-register and swc-node have this working in ESM mode which I simply didn't notice yet, since using them on .ts files and then using tsc for typechecking seems to be the by far most common usecase I guess?

@brookback
Copy link

I am experiencing the same issue in a pure ESM package, trying to use esbuild-register/loader to run mocha for my TS files with JS extensions.

Having the exact same use case, @justinhelmer.

Using esbuild-register to transpile our test .ts files before running Mocha on them with this conf:

// .mocharc.cjs
module.exports = {
    extension: ['ts'],
    'node-option': ['loader=esbuild-register/loader'],

    require: [
        'esbuild-register',
    ],
}

Moving to ts-node and their ESM loader works:

// .mocharc.cjs
module.exports = {
    extension: ['ts'],
    'node-option': ['experimental-specifier-resolution=node', 'loader=ts-node/esm'],
}

@markandrus
Copy link

In my project, I only have ".ts" files that I import as ".js". Based on this, I made a very dumb patch for esbuild-register, and applied it with yarn patch:

diff --git a/dist/node.js b/dist/node.js
index e117be6904a8145923dce5a75b35dfe174666861..12e7be4aba3359fcd71098c85618ae618a98e076 100644
--- a/dist/node.js
+++ b/dist/node.js
@@ -4793,10 +4793,26 @@ function registerTsconfigPaths() {
       const found = matchPath(request);
       if (found) {
         const modifiedArguments = [found, ...[].slice.call(arguments, 1)];
-        return originalResolveFilename.apply(this, modifiedArguments);
+        try {
+          return originalResolveFilename.apply(this, modifiedArguments);
+        } catch (error) {
+          if (error.code === 'MODULE_NOT_FOUND' && found.endsWith('.js')) {
+            modifiedArguments[0] = found.replace(/\.js$/, '.ts');
+            return originalResolveFilename.apply(this, modifiedArguments);
+          }
+          throw error;
+        }
+      }
+    }
+    try {
+      return originalResolveFilename.apply(this, arguments);
+    } catch (error) {
+      if (error.code === 'MODULE_NOT_FOUND' && arguments[0].endsWith('.js')) {
+        arguments[0] = arguments[0].replace(/\.js$/, '.ts');
+        return originalResolveFilename.apply(this, arguments);
       }
+      throw error;
     }
-    return originalResolveFilename.apply(this, arguments);
   };
   return () => {
     Module._resolveFilename = originalResolveFilename;

There is probably a smarter version of this that handles the other typical file suffixes, avoids try/catch, etc.

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

6 participants