You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
{{ message }}
Repository navigation
"Cannot find module" when main file not index.js with experimental-specifier-resolution=node #32103
The script should display Success!, and does do so if mypackage/Lib.js is renamed to mypackage/index.js.
What do you see instead?
internal/modules/esm/resolve.js:61
let url = moduleWrapResolve(specifier, parentURL);
^
Error: Cannot find module /home/dandv/prg/node-cant-find-module-with-main-not-index.js/mypackage imported from /home/dandv/prg/node-cant-find-module-with-main-not-index.js/run.js
at Loader.defaultResolve [as _resolve] (internal/modules/esm/resolve.js:61:13)
at Loader.resolve (internal/modules/esm/loader.js:85:40)
at Loader.getModuleJob (internal/modules/esm/loader.js:191:28)
at ModuleWrap.<anonymous> (internal/modules/esm/module_job.js:42:40)
at link (internal/modules/esm/module_job.js:41:36) {
code: 'ERR_MODULE_NOT_FOUND'
}
Additional information
I'm trying to run node with -experimental-specifier-resolution=node because TypeScript can't output .mjs files and I want to use extension-less import statements. I prefer to use Lib.js instead of index.js to distinguish in my IDE between the main files of multiple packages in my monorepo that otherwise would all look like index.js.
I'm trying to run node with -experimental-specifier-resolution=node because TypeScript can't output .mjs files and I want to use extension-less import statements.
TypeScript has only limited support for ES modules so far. But in many cases the following workaround works:
Add "type": "module" to package.json.
Use import './some-file.js' in your TypeScript source code. TypeScript will find .ts files if you use .js in the specifier.
Run the app without the experimental resolution flag.
(That's the more verbose version of Jordan's "If you use explicit extensions". :))
Reacted by Jordan Harband, Alex Yang, Emmanuel Darko, Francois004, F35X, Steven Samuel Marroquín González, Nikolay Chistyakov, Yaojian, Damien Golding, Benn Huang and 9 more
Reacted by Steven Samuel Marroquín González, Prateek Goyal and Cedric Greiten
Reacted by Prateek Goyal, Kieu Quang and David Enke
So the issue appears to be that to support that we introduced for experimental-specifier-resolution does not respect the package.json main field. I can get the example to work by changing the Lib.js file to be index.js. This is definitely a bug in the support for experimental resolution. I'm not 100% where the bug lives but this is where we should be resolving package main for experimental resolution
It is possible that some order of operations bug is not even checking for the package.main... and tbh the work we've done around exports is going to confuse this a bit too. I'll try and find some time to dig in but this is going to have to be lower priority for me personally, so if anyone else wants to pick this up please go ahead!
as an aside, thanks so much for these amazing bug reports @dandv
functionmoduleResolve(specifier/* string */,base/* URL */){/* -> URL */// Order swapped from spec for minor perf gain.// Ok since relative URLs cannot parse as URLs.letresolved;if(shouldBeTreatedAsRelativeOrAbsolutePath(specifier)){resolved=newURL(specifier,base);}else{try{resolved=newURL(specifier);}catch{returnpackageResolve(specifier,base);}}returnfinalizeResolution(resolved,base);}
The parameter specifier is ./mypackage here, so it passes the relative path check and returns as is directly. So the package main resolve related code won't run.
I am working on this, maybe I will submit a PR in about a few days.
Seeing the same thing on Node 14.1, OSX. In my package.json I have
"type": "module",
I then have one file, server.js, which in turn imports another file, serverModule.js:
server.js
import startServer from './serverModule';
startServer({});
serverModule.js
import args from './get-args';
// ......
export default startServer;
Now, I notice that adding .js to any import in the chain solves it for that particular file. For example, this solves the import of serverModule.js in server.js:
@ryzokuken I believe this actually still remains an implementation bug and I believe my suggestion in #32612 (comment) might be related to the fix here.
That said, we might end up deprecating this flag before the fix at this rate...
Where's the solution after this much of comments and showing expertise? No solution is found in github forum. Yall show how much yall know. I come here often to github to see some solutions to the problem. There's always talking. Please provide the solutions in simple words my experts. Some people are naive out there. Not everybody pros like yall
Reacted by JoeDesylva, Silly-V, Ivan Breslauer, Elbaz and Enxhi
Reacted by Ankit Gupta, Markus Dolic, Ivan Breslauer, Elbaz, Filipe Merker, Stephanie Mendoza and Dan Dascalescu
The solution is to upgrade to Node.js v16.4.0 or later, or wait for v14.17.4 once it is released next week. I'll try to backport it to v12.x as well.
EDIT: The patch has landed on v12.22.4, v14.17.4 and v16.4.0.
This still seems like a bug in Node 16.15.0. Why would we need to include the .js suffix for Node to find our modules? I'm not looking to import things in Typescript by adding .js to the end of the path, when the file is .ts -- even though TS might support this, it's not the proper solution.
What am I missing here?
Reacted by Renato Melo, Alex Szabo, Thomas Shank, Kishan Mistri, Enxhi and Robert Penner
I'm in the same page as @JoshMcCullough. As far as I got it from the previous comments, this problem would be solved and we wouldn't need to put the extension explicitly in our imports. I could solve this by adding --experimental-modules --es-module-specifier-resolution=node to scripts, either for prod or dev.
Config ["type": "module"] in package.json, then update tsconfig.json to ts-node's ESM support and pass the loader flag to node in scripts, node --loader ts-node/esm ./index.ts. tsconfig.json:
Activity
MylesBorins commentedon Mar 6, 2020
/cc @nodejs/modules
ljharb commentedon Mar 6, 2020
The repro link seems correct to me; if so, this seems like a bug.
If you use explicit extensions, and don't use experimental specifier resolution, what happens?
hybrist commentedon Mar 6, 2020
TypeScript has only limited support for ES modules so far. But in many cases the following workaround works:
"type": "module"topackage.json.import './some-file.js'in your TypeScript source code. TypeScript will find.tsfiles if you use.jsin the specifier.(That's the more verbose version of Jordan's "If you use explicit extensions". :))
dandv commentedon Mar 7, 2020
Then the script runs correctly.
MylesBorins commentedon Mar 10, 2020
So the issue appears to be that to support that we introduced for
experimental-specifier-resolutiondoes not respect the package.json main field. I can get the example to work by changing theLib.jsfile to beindex.js. This is definitely a bug in the support for experimental resolution. I'm not 100% where the bug lives but this is where we should be resolving package main for experimental resolutionhttps://github.com/nodejs/node/blob/master/src/module_wrap.cc#L1180-L1186
This is where it seems like where we are doing the resolution itself
https://github.com/nodejs/node/blob/master/src/module_wrap.cc#L826-L862
It is possible that some order of operations bug is not even checking for the package.main... and tbh the work we've done around exports is going to confuse this a bit too. I'll try and find some time to dig in but this is going to have to be lower priority for me personally, so if anyone else wants to pick this up please go ahead!
as an aside, thanks so much for these amazing bug reports @dandv
lingsamuel commentedon Apr 1, 2020
I figured out the exact reason.
Note: Related C++ code is rewritten using JS in this commit, new related code location link:
https://github.com/nodejs/node/blob/master/lib/internal/modules/esm/resolve.js#L594
More comments can be found in the historical C++ file in the commit link above.
The parameter
specifieris./mypackagehere, so it passes the relative path check and returns as is directly. So thepackage main resolverelated code won't run.I am working on this, maybe I will submit a PR in about a few days.
csvan commentedon May 5, 2020
EDIT: This is working as intended, I misunderstood the spec. See https://nodejs.org/api/esm.html#esm_import_specifiers
Leaving the below for history only.
Seeing the same thing on Node 14.1, OSX. In my package.json I have
I then have one file,
server.js, which in turn imports another file,serverModule.js:server.js
serverModule.js
Now, I notice that adding
.jsto any import in the chain solves it for that particular file. For example, this solves the import ofserverModule.jsinserver.js:But then in turn it complains about
import args from './get-args';in that file, and so on. It seems like file endings are required, but that runs contrary to the description here: https://medium.com/@nodejs/announcing-core-node-js-support-for-ecmascript-modules-c5d6dc29b663pujakjha commentedon Jun 17, 2020
Thanks! This solution worked for me.
ryzokuken commentedon Jun 29, 2020
This seems resolved, closing. Feel free to reopen if something needs to be discussed further, thank you.
guybedford commentedon Jun 29, 2020
@ryzokuken I believe this actually still remains an implementation bug and I believe my suggestion in #32612 (comment) might be related to the fix here.
That said, we might end up deprecating this flag before the fix at this rate...
1 remaining item
module: fix legacy `node` specifier resolution to resolve `"main"` field
module: fix legacy `node` specifier resolution to resolve `"main"` field
module: fix legacy `node` specifier resolution to resolve `"main"` field
module: fix legacy `node` specifier resolution to resolve `"main"` field
scanner77 commentedon Jul 23, 2021
Where's the solution after this much of comments and showing expertise? No solution is found in github forum. Yall show how much yall know. I come here often to github to see some solutions to the problem. There's always talking. Please provide the solutions in simple words my experts. Some people are naive out there. Not everybody pros like yall
aduh95 commentedon Jul 23, 2021
The solution is to upgrade to Node.js v16.4.0 or later, or wait for v14.17.4 once it is released next week. I'll try to backport it to v12.x as well.
EDIT: The patch has landed on v12.22.4, v14.17.4 and v16.4.0.
module: fix legacy `node` specifier resolution to resolve `"main"` field
module: fix legacy `node` specifier resolution to resolve `"main"` field
JoshMcCullough commentedon May 19, 2022
This still seems like a bug in Node 16.15.0. Why would we need to include the
.jssuffix for Node to find our modules? I'm not looking to import things in Typescript by adding.jsto the end of the path, when the file is.ts-- even though TS might support this, it's not the proper solution.What am I missing here?
renatoam commentedon Jun 5, 2022
I'm in the same page as @JoshMcCullough. As far as I got it from the previous comments, this problem would be solved and we wouldn't need to put the extension explicitly in our imports. I could solve this by adding
--experimental-modules --es-module-specifier-resolution=nodeto scripts, either for prod or dev.Is there something that we can do to solve this?
Node version: 16.15.0
Typescript version: ^4.7.3
Example:
Maikpwwq commentedon Aug 31, 2023
Config
["type": "module"]in package.json, then update tsconfig.json to ts-node's ESM support and pass the loader flag to node in scripts,node --loader ts-node/esm ./index.ts. tsconfig.json: