commit 548979d573fa441933336de030904b2463bbe101
parent c4ba35eab1ff9806781777aad6bf54d8c9179020
Author: Yoshi Cheng-Hao Huang <allstars.chh@gmail.com>
Date: Fri, 3 Oct 2025 20:53:29 +0000
Bug 1968890 - Part 4: Handle Dynamic import in LoadRequestedModulesRejected. r=jonco
Reject the dynamic import when the LoadRequestedModules fails.
Differential Revision: https://phabricator.services.mozilla.com/D264806
Diffstat:
2 files changed, 52 insertions(+), 21 deletions(-)
diff --git a/js/loader/ModuleLoaderBase.cpp b/js/loader/ModuleLoaderBase.cpp
@@ -785,6 +785,12 @@ nsresult ModuleLoaderBase::OnFetchComplete(ModuleLoadRequest* aRequest,
}
void ModuleLoaderBase::OnFetchSucceeded(ModuleLoadRequest* aRequest) {
+ // TODO, Bug 1990416: Align the loading descendants behavior of dynamic import
+ // According to the spec, dynamic import should trigger fetching of
+ // descendant modules in the JS engine. However, when the dynamic import’s
+ // module graph is loaded, ScriptLoaders move the request to a Loaded event
+ // queue and invoke ProcessDynamicImport. To account for this behavior,
+ // we perform the fetching of submodules in the host layer instead.
if (aRequest->IsTopLevel() || aRequest->IsDynamicImport()) {
StartFetchingModuleDependencies(aRequest);
} else {
@@ -1238,7 +1244,7 @@ void ModuleLoaderBase::StartFetchingModuleDependencies(
if (!result) {
LOG(("ScriptLoadRequest (%p): LoadRequestedModules failed", aRequest));
- OnLoadRequestedModulesRejected(aRequest, UndefinedHandleValue);
+ OnLoadRequestedModulesRejected(cx, aRequest, UndefinedHandleValue);
}
}
@@ -1292,23 +1298,50 @@ bool ModuleLoaderBase::OnLoadRequestedModulesRejected(
JSContext* aCx, Handle<Value> aHostDefined, Handle<Value> aError) {
auto* request = static_cast<ModuleLoadRequest*>(aHostDefined.toPrivate());
MOZ_ASSERT(request);
- return OnLoadRequestedModulesRejected(request, aError);
+ return OnLoadRequestedModulesRejected(aCx, request, aError);
}
// static
bool ModuleLoaderBase::OnLoadRequestedModulesRejected(
- ModuleLoadRequest* aRequest, Handle<Value> error) {
- LOG(("ScriptLoadRequest (%p): LoadRequestedModules rejected", aRequest));
+ JSContext* aCx, ModuleLoadRequest* aRequest, Handle<Value> error) {
ModuleScript* moduleScript = aRequest->mModuleScript;
- // https://html.spec.whatwg.org/#fetch-the-descendants-of-and-link-a-module-script
- // Step 7. Upon rejection of loadingPromise, run the following
- // steps:
- // Step 7.1. If state.[[ErrorToRethrow]] is not null, set moduleScript's
- // error to rethrow to state.[[ErrorToRethrow]] and run
- // onComplete given moduleScript.
- if (moduleScript && !error.isUndefined()) {
+
+ // TODO, Bug 1990416: Align the loading descendants behavior of dynamic import
+ if (aRequest->IsDynamicImport()) {
+ LOG(
+ ("ScriptLoadRequest (%p): LoadRequestedModules rejected for dynamic "
+ "import",
+ aRequest));
+ // https://tc39.es/ecma262/#sec-ContinueDynamicImport
+ // Step 4.a. Perform ! Call(promiseCapability.[[Reject]], undefined,
+ // « reason »).
+ Rooted<Value> payload(aCx, aRequest->mPayload);
+ if (!error.isUndefined()) {
+ FinishLoadingImportedModuleFailed(aCx, payload, error);
+ } else {
+ nsAutoCString url;
+ aRequest->mURI->GetSpec(url);
+ JS_ReportErrorNumberASCII(aCx, js::GetErrorMessage, nullptr,
+ JSMSG_DYNAMIC_IMPORT_FAILED, url.get());
+ FinishLoadingImportedModuleFailedWithPendingException(aCx, payload);
+ }
+ } else if (moduleScript && !error.isUndefined()) {
+ LOG(
+ ("ScriptLoadRequest (%p): LoadRequestedModules rejected: set error to "
+ "rethrow",
+ aRequest));
+ // https://html.spec.whatwg.org/#fetch-the-descendants-of-and-link-a-module-script
+ // Step 7. Upon rejection of loadingPromise, run the following
+ // steps:
+ // Step 7.1. If state.[[ErrorToRethrow]] is not null, set moduleScript's
+ // error to rethrow to state.[[ErrorToRethrow]] and run
+ // onComplete given moduleScript.
moduleScript->SetErrorToRethrow(error);
} else {
+ LOG(
+ ("ScriptLoadRequest (%p): LoadRequestedModules rejected: set module "
+ "script to null",
+ aRequest));
// Step 7.2. Otherwise, run onComplete given null.
aRequest->mModuleScript = nullptr;
}
@@ -1530,20 +1563,17 @@ void ModuleLoaderBase::ProcessDynamicImport(ModuleLoadRequest* aRequest) {
if (!jsapi.Init(GetGlobalObject())) {
return;
}
-
JSContext* cx = jsapi.cx();
- if (!aRequest->mModuleScript) {
- FinishDynamicImportAndReject(aRequest, NS_ERROR_FAILURE);
- return;
- }
+ MOZ_ASSERT(aRequest->IsDynamicImport());
- if (aRequest->mModuleScript->HasParseError()) {
- Rooted<Value> payload(cx, aRequest->mPayload);
- Rooted<Value> error(cx, aRequest->mModuleScript->ParseError());
- FinishLoadingImportedModuleFailed(cx, payload, error);
+ if (aRequest->IsErrored()) {
+ LOG(("ScriptLoadRequest (%p): ProcessDynamicImport, request has an error",
+ aRequest));
+ // The error is already processed in OnLoadRequestedModulesRejected.
return;
}
+ LOG(("ScriptLoadRequest (%p): ProcessDynamicImport", aRequest));
FinishLoadingImportedModule(cx, aRequest);
}
diff --git a/js/loader/ModuleLoaderBase.h b/js/loader/ModuleLoaderBase.h
@@ -549,7 +549,8 @@ class ModuleLoaderBase : public nsISupports {
Handle<Value> aHostDefined,
Handle<Value> aError);
static bool OnLoadRequestedModulesResolved(ModuleLoadRequest* aRequest);
- static bool OnLoadRequestedModulesRejected(ModuleLoadRequest* aRequest,
+ static bool OnLoadRequestedModulesRejected(JSContext* aCx,
+ ModuleLoadRequest* aRequest,
Handle<Value> aError);
/**