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

async import of typescript file doesn't work from cjs #184

Open
rchl opened this issue Nov 10, 2023 · 9 comments
Open

async import of typescript file doesn't work from cjs #184

rchl opened this issue Nov 10, 2023 · 9 comments

Comments

@rchl
Copy link

rchl commented Nov 10, 2023

Environment

Node 18
jiti 1.21.0

Reproduction

  1. Create two files

test.cjs

(async function foo() {
    await import('./typescript');
})();

typescript.ts

console.log('TYPESCRIPT FILE')
  1. Run npx jiti@latest test.cjs

Describe the bug

Trying to import *.ts file using async import from cjs file fails with:

node:internal/errors:496
    ErrorCaptureStackTrace(err);
    ^

Error [ERR_MODULE_NOT_FOUND]: Cannot find module '/.../typescript' imported from /.../test.cjs

It works if the test.cjs file is renamed to test.mjs

Additional context

Note that the actual case where I've noticed it is a lot less contrived. I found this issue by trying to configure @nuxtjs/sentry using a file that the module needed to import.

So I've set the serverConfig: '~/config/sentry.server' option which the Sentry module then tries to import using async import. The issue is that that sentry module is imported through the CJS export rather than MJS so then it fails. (note how exports are defined in the module: https://github.com/nuxt-community/sentry-module/blob/ad424f10763d5c08826e250f715ebde699d4edfa/package.json#L19-L27).

Logs

No response

@pi0
Copy link
Member

pi0 commented Nov 10, 2023

Thanks for reporting.

Minimal reproduction: https://stackblitz.com/edit/stackblitz-starters-3fj5rs?file=package.json

It seems transformation is not happening because the file has an explicit .cjs extension and also no ESM syntax (dynamic import is valid in Node.js CJS environment) and therefore we use native. (src)

I think we can also enable jiti transforms when in cjs, dynamic import syntax is detected but it adds overhead for all current .cjs files that go through and don't require it. Perhaps we can enable this behavior behind a flag so you can enable for sentry module importer?

@rchl
Copy link
Author

rchl commented Nov 10, 2023

How would I enable the flag in that case, given that the code looks like this?

https://github.com/nuxt-community/sentry-module/blob/977a74e7b28f360116514258adcf8cbcec2b5be1/src/options.ts#L243-L245

Note that this code is triggered by Nuxt when it loads the Sentry module (and uses CJS export by default).

@pi0
Copy link
Member

pi0 commented Nov 10, 2023

You need an explicit jiti instance in place of await import(). Also consider that it is only happening for stub mode when module is not transformed yet that uses implicit jiti for dynamic imports.

@rchl
Copy link
Author

rchl commented Nov 10, 2023

By "stub" do you mean the mode used during development only? Because that's not the case here.

Please have a look at dist/module.cjs at https://www.npmjs.com/package/@nuxtjs/sentry?activeTab=code . This is the file that Nuxt loads.

(Sorry if I'm saying obvious things. Just clarifying in case I misunderstood).

With all that said, I'm contemplating just forcing mjs for the module like:

diff --git a/package.json b/package.json
index 3fcd235..733a350 100755
--- a/package.json
+++ b/package.json
@@ -17,13 +17,7 @@
     "registry": "https://registry.npmjs.org"
   },
   "type": "module",
-  "exports": {
-    ".": {
-      "import": "./dist/module.mjs",
-      "require": "./dist/module.cjs"
-    }
-  },
-  "main": "./dist/module.cjs",
+  "main": "./dist/module.mjs",
   "types": "./dist/module.d.ts",
   "files": [
     "dist"

which I feel like would be perfectly fine. At least for versions of Nuxt that use jiti but that's probably reasonable to expect everyone using.

@pi0
Copy link
Member

pi0 commented Nov 10, 2023

Yep, I got it. Regardless I think it would be always much much safer if in this line you expect resolvedPath pointing to a possibly Typescript entry, to use an explicit jiti.import() and ensures doing transforms and i expect Nuxt uses native ESM for loading module (which in Node.js has no TS support)

Would love to hear your feedback about doing it :)

@rchl
Copy link
Author

rchl commented Nov 10, 2023

I've tried quickly and that seems to work too.
Though I'm really tempted to just forcing Nuxt to load the module using MJS since that's so much cleaner...

@pi0
Copy link
Member

pi0 commented Nov 10, 2023

If nuxt uses MJS/Native ESM, i think this issue is irrelevant no? Because mainly we want typescript support from what i understand and it is possible when jiti transform happens. (we do transform dynamic import in native ESM files when passed to jiti only because we have do transform anyway as currently jiti is based on CJS. Is is a coincidence that works with ESM!)

Depending on Nuxt behavior that might use jiti implicitly for ESM files, is not sure assumption and can be broken in the future.

(update: reading above seems confusing explanation haha feel free to DM me if you have questions!)

@rchl
Copy link
Author

rchl commented Nov 12, 2023

If I'd want to do everything by the book then how would I initialize jiti in an ESM context?

jiti documentation says to use __filename:

const jiti = require("jiti")(__filename);

which would technically work when running in Nuxt since it seems to "polyfill" that but if I'd assume that I'm running in a native ESM context then it wouldn't be available.

@pi0
Copy link
Member

pi0 commented Nov 12, 2023

This should work in ESM context (PR welcome for docs!)

import initJiti from 'jiti'
const jiti = initJiti(import.meta.url)
console.log(jiti.resolve('.'))

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