| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
Sorry, something went wrong.
|
Review requested:
|
Sorry, something went wrong.
|
if the solution is feasible and finds approval, the --experimental-detect-module could already be removed in this PR. wdyt? |
Sorry, something went wrong.
Sorry, something went wrong.
|
Also, |
Sorry, something went wrong.
There was a problem hiding this comment.
+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
Sorry, something went wrong.
There was a problem hiding this comment.
Great work! Thanks for getting to the bottom of this.
Sorry, something went wrong.
Will check your comments and split it into two PRs, will happen maybe beginning of next week. |
Sorry, something went wrong.
Lovely! |
Sorry, something went wrong.
|
split done, this fixes the --experimental-detect-module edge cases, no unflagging of the option. |
Sorry, something went wrong.
There was a problem hiding this comment.
still LGTM
Sorry, something went wrong.
Sorry, something went wrong.
Co-authored-by: Gabriel Bota <gabriel.bota@dynatrace.com>
Sorry, something went wrong.
Co-authored-by: Geoffrey Booth <webadmin@geoffreybooth.com>
Sorry, something went wrong.
| 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.
The Utf8Value here can’t be temporary, it needs to outlive the const char* or otherwise it is use-after-free.
Sorry, something went wrong.
There was a problem hiding this comment.
fixed
Sorry, something went wrong.
| 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.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
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.
Sorry, something went wrong.
There was a problem hiding this comment.
The exception would be surprising for a hook - resolve shouldn't be poking into the file system, that should be load's job.
Sorry, something went wrong.
There was a problem hiding this comment.
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.
Sorry, something went wrong.
|
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. |
Sorry, something went wrong.
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 load changes that in the scenario that transforms ESM to cjs during a load hook execution. |
Sorry, something went wrong.
|
@joyeecheung I tried today to modfiy this part according to your suggestion to have resolve in detect-module mode not setting anything in format if source is undefined (i.e. not try to read from file contained in url). Generally speaking, eliminating the resolve time "hint" detection everywhere would be a breaking change and it is IMO out of scope for this PR. With current implementation the hint quality is better than it was before because of the detectModuleType call. There are still cases where it cannot be determined, like mentioned before, but no currently existing tests are affeced by those. 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? |
Sorry, something went wrong.
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. |
Sorry, something went wrong.
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. |
Sorry, something went wrong.
|
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 context.format being ready - it could count on the result of nextLoad() containing a valid format, but not in the context that's provided before nextLoad is called. The doc also says that context.format can be undefined in load too. |
Sorry, something went wrong.
|
In terms of format, I think there are actually two concepts:
e.g. if it's a .js file not bound by a type field in package.json, it's assumed format is "commonjs" while confirmed format is "undefined" after resolve. Internally, the format that gets passed around is the confirmed format and is also what gets surfaced to user hooks. The problem is that this PR is going along with the direction that mixes the two into one in the load hook, then it's going to lead to detection with too many assumptions. |
Sorry, something went wrong.
I’ve been referring to “a .js file not bound by a type field in package.json” as an “ambiguous” file. I think what we have now is that resolve sometimes returns a format hint of commonjs for ambiguous files, whereas with detection enabled it should probably be returning no hint at all; and then we determine the format during load. I don’t think certain cases changing from resolve returning format: 'commonjs' to format: undefined should be considered a breaking change, because per our docs format is optional and hooks shouldn’t rely on it being present or set to a particular value. Do others agree with that? (And the hooks are still experimental, after all.) Because it does feel like the right approach here is to update the test so that it no longer expects format: 'commonjs' for ambiguous files, and we do the detection during load rather than potentially reading the source twice or reading it too early. |
Sorry, something went wrong.
|
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. |
Sorry, something went wrong.
|
Talking to @dygabo and @joyeecheung, I think we need to explore a solution that doesn’t involve reading from disk during the resolve step. I’m going to mark this as draft for now so that it doesn’t get merged in the meantime. It could be that we simply change the hinted format returned by resolve when detection is enabled: for ambiguous files, where detection will eventually determine the format, instead of resolve returning commonjs we return undefined, and this is just a change (possibly breaking, depending on your point of view). If enabling detection in general is considered semver-major, because things that used to error would no longer do so, then we can add this to the list of semver-major changes that happen as part of unflagging detection. I think in a detection-enabled world, we would want a hint of commonjs only for unambiguous CommonJS—.cjs extension or "type": "commonjs"—just as I think the module hint is currently only for unambiguous ESM. It would feel wrong otherwise. I think the next step is to open a PR that unflags detection and updates all the tests accordingly, including making this format change. In that PR we can analyze the tests that needed changing and why, to gauge the scale of the breaking changes. We can mark it as don’t-backport so that it’s released in 23.0.0 only, and after we see the reaction to Node 23 we might consider backporting it if we ultimately decide that the changes aren’t truly semver-major and that the changes to experimental features aren’t too drastic. |
Sorry, something went wrong.
| Back | FazBrowse Home | New Git URL |
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 => green
Co-authored-by: @GeoffreyBooth
@nodejs/loaders