-
Notifications
You must be signed in to change notification settings - Fork 29.8k
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: resolve format for all situations with auto module detection on #53044
module: resolve format for all situations with auto module detection on #53044
Conversation
Review requested:
|
if the solution is feasible and finds approval, the |
Also, |
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.
+1
Tip
While my review shows my support, I am not a core collaborator, and this review has no power / place in the approval process
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.
Great work! Thanks for getting to the bottom of this.
Will check your comments and split it into two PRs, will happen maybe beginning of next week. |
Lovely! |
1d7b4de
to
b7ec307
Compare
split done, this fixes the |
afb82c8
to
b2f221f
Compare
33d3bed
to
f4d6382
Compare
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.
still LGTM
266c499
to
6445e1a
Compare
Co-authored-by: Gabriel Bota <[email protected]>
6445e1a
to
6132129
Compare
6132129
to
5753afc
Compare
Co-authored-by: Geoffrey Booth <[email protected]>
5753afc
to
bd945b6
Compare
src/node_contextify.cc
Outdated
Local<String> code; | ||
if (args[0]->IsUndefined()) { | ||
CHECK(!filename.IsEmpty()); | ||
const char* filename_str = Utf8Value(isolate, filename).out(); |
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.
The Utf8Value here can’t be temporary, it needs to outlive the const char* or otherwise it is use-after-free.
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.
fixed
CHECK(!filename.IsEmpty()); | ||
const char* filename_str = Utf8Value(isolate, filename).out(); | ||
std::string contents; | ||
int result = ReadFileSync(&contents, filename_str); |
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.
Reading from disk from the native layer here doesn’t seem right - it’s not guaranteed that this is on disk and at a location pointed to by filename (the filename can be some artificial ID). The JS land should be refactored to only call this after source code is confirmed instead.
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.
this comes as part of the trials to cover the module type resolution for the resolve
. I would expect if any of that happens (correct me if I'm wrong) that ReadFileSync
will return != 0
here and this would cause the early exit with an exception.
Additionally we call this from managed code here. I am guessing that at this stage the fileUrl was already validated but that is at this stage just an assumption. This test made me think that.
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.
The exception would be surprising for a hook - resolve shouldn't be poking into the file system, that should be load's job.
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.
that is changed now, the comment above is obsolete. The function would return undefined on file access errors. But I am still looking for a way to remove this file access without losing the test.
IMO it doesn’t make sense to eagerly detect the format at resolve, the format should only be confirmed during loading, when the source becomes available. Until then it should be allowed to be undefined. For one it’s not guaranteed that the filename is actually readable from the fs at resolve time. Also for libraries like tsx that uses the defaultResolve to probe possible default entry points, doing the detection at resolve incurs unnecessary overhead on formats that are not recognizable by Node.js. That should be left to default load when the final source code is available. |
With current version it still is allowed and it might happen that it is undefined (if one of the cases occur where it cannot be determined during resolve, like the typescript case, or file not accessible). The more confusing part is IMO where like with the last test being added, it can be determined but the |
@joyeecheung I tried today to modfiy this part according to your suggestion to have With current implementation the hint quality is better than it was before because of the One example: tests like this one are not passing because they are based on loaders like this that expect the format to be determined by resolve. I did not find a quick solution for this. Do you or @GeoffreyBooth, @aduh95 have an idea on how to solve it? |
Doesn't this PR "improves" the format detection in resolve by trying harder (even though reading from the file system at resolve phase might be the wrong way to try it), and hence make the breaking change necessary for correcting this design flaw even more breaking than it already is? Format detection in resolve should be a best effort (tentative based on file extensions and package.json info) IMO, and we shouldn't go out of our ways to detect the format by reading the file and even parsing it at resolve phase. That leads to unnecessary overhead to the overall design especially if user hooks point to a non-existent URL or a file with unrecognizable format at resolve phase (for better error stack traces) and only override the format detection at load. |
I agree with this and also that the file read has an impact on the running time. But I am slightly out of ideas on how to solve the one failing test that I mentioned. I will give it one more try, see what solution I can find. Any suggestions on how to solve it are appreciated. |
Is the failing test something like https://github.com/dygabo/node/blob/fix-for-unflagging-module-format-detection/test/fixtures/es-module-loaders/builtin-named-exports-loader.mjs#L31 ? In that case I think it's the test that's making wrong assumptions - the loader hook should not count on the |
In terms of format, I think there are actually two concepts:
e.g. if it's a |
I’ve been referring to “a Because it does feel like the right approach here is to update the test so that it no longer expects |
Thinking about this a bit more over the past hours, I understand the concerns and am looking into alternative solution to propose.
I hope this makes sense. Having said that, I will continue to look for alternatives but this might take some time. |
Talking to @dygabo and @joyeecheung, I think we need to explore a solution that doesn’t involve reading from disk during the It could be that we simply change the hinted I think the next step is to open a PR that unflags detection and updates all the tests accordingly, including making this |
superseded and solved by #53619. |
triggered by #53015
solves: #53016
this should be a consistent fix to always resolve the module format correctly.
Enabling module detection by default made a few other tests need some adjustments because in this case they don't generate errors anymore. e.g.
test-esm-cjs-exports.js
instead of error becasue a .mjs imports a .js with ESM syntax it now successfully imports it and generates the warning that this should be fixed to avoid the performance penalty.Kindly please review and let me know what you think (if changes are necessary).
make test && make lint
=> greenCo-authored-by: @GeoffreyBooth
@nodejs/loaders