-
Notifications
You must be signed in to change notification settings - Fork 29.7k
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
module: add note when cjs loader throws error #28950
Conversation
I've been working with @gntem as part of the mentorship program and one of the projects we discussed was seeing if we could improve the error messages for using ES modules in Node.js to provide easier onboarding. Currently if you write a Node.js module say
With this PR, the above error message instead becomes:
Providing the actionable information to the user to use modules in Node.js. The tricky case here was catching invalid import syntax as that throws a different unexpected token message depending on the syntax as dynamic |
//cc @nodejs/modules-active-members |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
nits, but nothing blocking
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Pending @bmeck’s comments
c829d54
to
dc3792d
Compare
610067e
to
d2ede7d
Compare
d2ede7d
to
3d5741c
Compare
Why was this closed? |
I don't know, probably a missclick, sorry |
Test failures here all seem to be flakes at this point. Any further feedback on this PR at all? Good to merge? |
lib/internal/modules/cjs/loader.js
Outdated
*/ | ||
if (err.message.startsWith('Unexpected token export') || | ||
(/^\s*import(?=[ {'"*])\s*(?![ (])/).test(lineWithErr)) { | ||
err.stack = 'Note: To load an ES module set "type": "module" ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
err.stack = 'Note: To load an ES module set "type": "module" ' + | |
err.stack = 'To load an ES module, set "type": "module" ' + |
const Import5 = fixtures.path('/es-modules/es-note-unexpected-import-5.cjs'); | ||
|
||
// Expect note to be included in the error output | ||
const expectedNote = 'Note: To load an ES module ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
const expectedNote = 'Note: To load an ES module ' + | |
const expectedNote = 'To load an ES module, ' + |
53c4037
to
1bc60b0
Compare
rescinding my approval as I have a comment/change request
lib/internal/modules/cjs/loader.js
Outdated
*/ | ||
if (err.message.startsWith('Unexpected token export') || | ||
(/^\s*import(?=[ {'"*])\s*(?![ (])/).test(lineWithErr)) { | ||
err.stack = 'To load an ES module, set "type": "module" ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Shouldn't text like this be added to err.message
or something like that? Wedging stuff that isn't a stack trace into err.stack
seems like the wrong place to put it, no?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
actually yeah, good call - this will make the stacks violate the spec, if i can ever get that proposal advanced.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I believe the reasoning here was originally that if we append the message the error looks like:
(node:7720) ExperimentalWarning: The ESM module loader is experimental.
C:\Users\Guy\x.js:1
export var p = 5;
^^^^^^
To load an ES module using --experimental-modules set "type": "module" in
the package.json or use the .mjs extension.
SyntaxError: Unexpected token export
at Module._compile (internal/modules/cjs/loader.js:720:23)
at Object.Module._extensions..js (internal/modules/cjs/loader.js:787:10)
at Module.load (internal/modules/cjs/loader.js:643:32)
at Function.Module._load (internal/modules/cjs/loader.js:556:12)
at internal/modules/esm/translators.js:87:15
at Object.meta.done (internal/modules/esm/create_dynamic_module.js:48:9)
at file:///C:/Users/Guy/x.js:9:13
at ModuleJob.run (internal/modules/esm/module_job.js:111:37)
at processTicksAndRejections (internal/process/task_queues.js:85:5)
at async Loader.import (internal/modules/esm/loader.js:134:24)
where the note is hidden beneath the error frame.
Ideally we'd have more control over mutating these error outputs though.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Correction - I mean the note is hidden beneath the error frame.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe an acceptable solution would be to leave the error contents alone and emit a separate warning with the note?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
You could even overwrite the own data property with an accessory that console.warned.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe an acceptable solution would be to leave the error contents alone and emit a separate warning with the note?
So call console.warn
after the error condition, would be enough, right? it would still print before the error message
and stack
.
lib/internal/modules/cjs/loader.js
Outdated
*/ | ||
if (err.message.startsWith('Unexpected token export') || | ||
(/^\s*import(?=[ {'"*])\s*(?![ (])/).test(lineWithErr)) { | ||
console.warn('To load an ES module, set "type": "module" ' + |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I think we'd want to use process.emitWarning()
instead to allow the end user to decide how to handle warnings?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I can't seem to get the tests passing I changed to listen for .on('warning',(warning) => ..assertions..)
or .on('close',...)
also debugged the stderr output but nothing is showing up, the arguments --trace-warnings
is provided to the spawned process, but no warning is emitted. In that line, I just replaced with the console.warn with
process.emitWarning('To load an ES module, set "type": "module" ' +
'in the package.json or use the .mjs ' +
'extension.\n\n', 'ExperimentalWarning', undefined);
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't think we want it as an ExperimentalWarning
because we'll want it even after ES modules are no longer experimental. I'd say stick with the default (which is just Warning
):
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I wonder if the problem you're having is that the error is thrown before the warning is emitted....
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
To get it to work, you have to use the undocumented now
argument for process.emitWarning()
. I'll add a commit to this branch in a little bit....
This will allow users to know how to change their project to support ES modules.
d25077d
to
3372860
Compare
Updated, rebased, squashed, force-pushed. I think this is ready to go? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM!
Landed in 427e534 |
This will allow users to know how to change their project to support ES modules. PR-URL: nodejs#28950 Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Guy Bedford <guybedford@gmail.com>
Thanks for the contribution! 🎉 |
This will allow users to know how to change their project to support ES modules. PR-URL: #28950 Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Guy Bedford <guybedford@gmail.com>
This will allow users to know how to change their project to support ES modules. PR-URL: #28950 Reviewed-By: Bradley Farias <bradley.meck@gmail.com> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Guy Bedford <guybedford@gmail.com>
subsystem: module: add note to error when import,export is detected.
These will allow users to know how to change their project to support
es modules when the message is displayed.
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes