Misleading error that module does not provide exportΒ #32137
Description
What steps will reproduce the bug?
git clone https://github.com/dandv/lib-does-not-provide-export-foocd lib-does-not-provide-export-foo/use-libnode use-it.js # node v13.9.0
What is the expected behavior?
The script should run and output foo.
What do you see instead?
import { foo } from '../lib/index.js';
^^^
SyntaxError: The requested module '../lib/index.js' does not provide an export named 'foo'
Additional information
Within the context of a large project, this was a pretty odd mystery, when lib/index.js clearly exports foo. Feel free to have some fun figuring out it (not hard with the minimal repro repo, but imagine the confused looks in a real-world scenario). Solution below.
.
.
.
.
.
.
.
.
.
.
Solution
lib/package.json lacks "type": "module".
Proposal
A clearer error would indicate that the imported file is not a module at all. As it is, the error suggested that other symbols were exported fine, so I kept double checking for typos and what not. This happened during a conversion to TypeScript that involved adding one export. The error made me think the problem was that export; it was not - it was that I forgot to add "type": "module" to package.json.
The full title of the bug would be "Misleading error that module does not provide export when "module" is not in fact a module", but that would have been a spoiler.
Activity
himself65 commentedon Mar 8, 2020
formatbe assigned ascommonjsnode/lib/internal/modules/esm/get_format.js
Lines 58 to 59 in c49286b
and
loaderInstanceis thecommonjsloadernode/lib/internal/modules/esm/loader.js
Lines 201 to 218 in c49286b
node/lib/internal/modules/esm/translators.js
Lines 92 to 116 in c49286b
himself65 commentedon Mar 8, 2020
ESMLoaderdirectly usev8esm import, I think we currently haven't checker if a source is esm or cjsMylesBorins commentedon Mar 10, 2020
There seems to be a bug here in the loader itself. This module should not be loaded as ESM, but rather as CJS. Was able to make the repro even smaller
index.mjs
index.cjs
Even though this has ESM syntax in it it should fail to even import as you are attempting to do a named exports of the CJS module. pinging @jkrems and @guybedford to take a look
himself65 commentedon Mar 10, 2020
I don't think it's a bug, because you not mark the file as the
esmmodule. and it's just an incorrect error message. and can we add support that esm loader can check thejsfile asmjsfile and log the message likeLoad js as commonjs errorhybrist commentedon Mar 10, 2020
Maybe I'm missing something but this looks to error correctly because of the lack of an export named
foo, at least according to the issue description:himself65 commentedon Mar 10, 2020
why correctly?
when
import {foo} from '../lib/index.js'; ^^^ SyntaxError: The requested module '../lib/index.js' does not provide an export named 'foo'but, when
this is two kinds of different error types, and the first error message will misleading users.
himself65 commentedon Mar 10, 2020
another example
the error message still occur
import { foo } from '../lib/index.js'; ^^^ SyntaxError: The requested module '../lib/index.js' does not provide an export named 'foo'but I change
use-lib/index.jstothing go weird
(node:24052) ExperimentalWarning: The ESM module loader is experimental. { foo: 123 }himself65 commentedon Mar 10, 2020
I guess that cjs module loader make all codes
export default.node/lib/internal/modules/esm/translators.js
Line 109 in 73f2dbc
hybrist commentedon Mar 10, 2020
I'm not saying it's not confusing right now. The issue is just: This happens before we even try to run the code and that's when a CommonJS syntax errors would happen. It may be possible to somehow detect this specific error and try to gather some more context but it would be tricky.
To go into what you were seeing in your last comment: Exports in ES modules are very different from the "exports" object in CommonJS, confusingly. Each module export is a variable/identifier. The following CommonJS code doesn't create a new variable, it only sets a property on one:
So afterwards the CommonJS still only has a single export - the
module.exportsobject. That's all a CommonJS file exports, from an ES module perspective. Your later code could be rewritten as:So your importing the
defaultexport (themodule.exportsobject) from../lib/index.jswhich is an object that has a propertyfoo, as set above.himself65 commentedon Mar 10, 2020
Yeah, I get you
guybedford commentedon Mar 12, 2020
Marking as a documentation issue since this is a common error that should be well documented. //cc @GeoffreyBooth
dfabulich commentedon May 4, 2020
I think this needs more than just documentation. If you directly run
node lib/index.js, you'll see a really nice little warning:I would have wanted this case to show a better SyntaxError, and maybe a warning, something like:
I'll note that the error is marginally better if you try to import the default export without braces, like this:
import foo from '../lib/index.js'dfabulich commentedon May 4, 2020
I just realized that the scope of this is bigger than "ESM misinterpreted as CJS." This error applies even when the imported script is legit CJS with named exports.
dependency.cjs
dependent.mjs
You get this:
SyntaxError: The requested module './dependency.cjs' does not provide an export named 'name'which is only "true" because ES modules aren't allowed to import CJS named exports.The SyntaxError in this case should be much clearer:
SyntaxError: The requested module './dependency.cjs' is a CommonJS module, which can only provide a default export, not named exports, to an ES module script.kathy-ems commentedon Sep 2, 2020
How do you re-write this so it works?
dfabulich commentedon Sep 3, 2020
This error was considerably enhanced in Node 14.8 I believe. Now the error message says:
And, indeed, that's what you'd do to fix
dependent.mjs.ctavan commentedon Dec 10, 2020
@dandv @dfabulich @kathy-ems Node.js 14.13.0 added support for named CJS exports, see #35249 and this change has also been backported to Node.js v12.20.0.
Can you confirm that
now also works for you if
index.jsis a CJS file?Document minimum node v12 & v14 versions in README. (sucrase issue pull
Update build requirements in CONTRIBUTING.md (#12766)
MahendraBishnoi29 commentedon Jan 26, 2022
How Do I Solve This I'm New to Node JS?
GeoffreyBooth commentedon Jan 26, 2022
Use the suggested code from the error message.
Closing as I think this has been addressed.
tcoulter commentedon Jan 29, 2022
What do we do when it's a dependency that's doing the
import'ing?I'm receiving this error and don't have control over the dependency's code. Any suggestions?
ctavan commentedon Jan 29, 2022
Have you tried reporting this as a bug to the dependency which is causing the issue?
activenode commentedon Jan 12, 2023
Yeah you have to provide a fix in the repo. I'm facing this currently and it's a bit frustrating.