esm: fix relative require in non-file CJS source - #65557
Open
zeexzeex wants to merge 1 commit into
Open
Conversation
When a load hook provides the source of a CommonJS module, the require calls in that source are meant to go through the ESM loader so that the registered hooks apply to them, as documented for the load hook. That did not happen when the module had a URL that is not a file:. The require function built for those modules called Module._resolveFilename() before handing the specifier to the ESM resolver, only to look at the extension of the resulting path and decide whether to treat the request as JSON or as a native addon. Because the CJS resolver works on file paths, it cannot resolve a relative specifier against a referrer such as custom:cjs, so it threw MODULE_NOT_FOUND and the ESM resolution below it was never reached. The resolve hook was not called at all. Keep that lookup, since the JSON and .node branches depend on it, but let it fail when the referrer is not a file and leave the specifier for the ESM resolver to handle. A specifier that the hooks do not claim now fails with ERR_UNSUPPORTED_RESOLVE_REQUEST, which reports that the referrer scheme is not hierarchical, instead of MODULE_NOT_FOUND coming from the CJS resolver. Signed-off-by: Avocado <ujubongbong@gmail.com>
Collaborator
|
Review requested:
|
Codecov Report✅ All modified and coverable lines are covered by tests. Additional details and impacted files@@ Coverage Diff @@
## main #65557 +/- ##
==========================================
- Coverage 90.05% 90.05% -0.01%
==========================================
Files 751 751
Lines 254420 254433 +13
Branches 47975 47981 +6
==========================================
+ Hits 229121 229131 +10
+ Misses 16483 16481 -2
- Partials 8816 8821 +5
🚀 New features to boost your workflow:
|
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes: #53198
The
loadhook documentation states that when a hook provides the sourceof a CommonJS module, the
requirecalls that source makes go through theESM loader, so the registered hooks apply to them:
That does not hold when the module has a URL that is not a
file:. Therequirebuilt for those modules callsModule._resolveFilename()beforehanding the specifier to the ESM resolver, only to read the extension of
the resulting path and decide whether the request is JSON or a native
addon. The CJS resolver works on file paths, so it cannot resolve
./relativeagainst a referrer such ascustom:cjs. It throwsMODULE_NOT_FOUNDand the ESM resolution below it is never reached, whichis why the
resolvehook is not called at all.The error code is the tell: the ESM loader reports
ERR_MODULE_NOT_FOUND,so a bare
MODULE_NOT_FOUNDmeans the CJS resolver produced it. This iswhat @aduh95 pointed out when confirming the bug.
The lookup has to stay, since the JSON and
.nodebranches depend on theresolved path, so this lets it fail when the referrer is not a file and
leaves the specifier for the ESM resolver to handle. When the referrer is
a
file:URL the error is rethrown, so nothing changes there.This only affects
module.register(). The same case already works withmodule.registerHooks(), which takes a different path(
loadCJSModuleWithModuleLoad).Behaviour change
A specifier that the hooks do not claim now fails with
ERR_UNSUPPORTED_RESOLVE_REQUESTinstead ofMODULE_NOT_FOUND. Thereferrer scheme is not hierarchical, so the specifier genuinely cannot be
resolved, and the new error says that; the old one wrongly suggested the
CJS resolver was in charge. Flagging it here in case reviewers would
rather keep the previous code.