mirror of
https://github.com/servo/servo
synced 2026-04-26 01:25:32 +02:00
script: Add support for modulepreload link elements (#42964)
Add support to modulepreload link elements. Currently we only fetch the root module, as I think it is needs to be discussed whether we should always fetch module dependencies, or if it should be limited due to network constraints. Inside `bind_to_tree` I ended up calling `fetch_and_process_modulepreload` inside a delayed task, since it would cause a crash due to DOM not being in a stable state when firing an event (queueing the event seems to also do the trick). Remaining tests failures are due to not supporting CSS modules and performance entries's `transfer_size` being 0. Testing: Covered by existing tests --------- Signed-off-by: Gae24 <96017547+Gae24@users.noreply.github.com>
This commit is contained in:
@@ -74,8 +74,9 @@ use crate::dom::csp::{GlobalCspReporting, Violation};
|
||||
use crate::dom::document::Document;
|
||||
use crate::dom::element::Element;
|
||||
use crate::dom::globalscope::GlobalScope;
|
||||
use crate::dom::html::htmlscriptelement::{HTMLScriptElement, SCRIPT_JS_MIMES, Script};
|
||||
use crate::dom::htmlscriptelement::substitute_with_local_script;
|
||||
use crate::dom::html::htmlscriptelement::{
|
||||
HTMLScriptElement, SCRIPT_JS_MIMES, Script, substitute_with_local_script,
|
||||
};
|
||||
use crate::dom::node::NodeTraits;
|
||||
use crate::dom::performance::performanceresourcetiming::InitiatorType;
|
||||
use crate::dom::promise::Promise;
|
||||
@@ -641,9 +642,10 @@ impl ModuleOwner {
|
||||
fn notify_owner_to_finish(&self, module_tree: Option<Rc<ModuleTree>>, can_gc: CanGc) {
|
||||
match &self {
|
||||
ModuleOwner::Worker(_) => unimplemented!(),
|
||||
ModuleOwner::DynamicModule(_) => unimplemented!(),
|
||||
ModuleOwner::DynamicModule(_) => {},
|
||||
ModuleOwner::Window(script) => {
|
||||
let document = script.root().owner_document();
|
||||
let script = script.root();
|
||||
let document = script.owner_document();
|
||||
|
||||
let load = match module_tree {
|
||||
Some(module_tree) => Ok(Script::Module(module_tree)),
|
||||
@@ -651,16 +653,15 @@ impl ModuleOwner {
|
||||
};
|
||||
|
||||
let asynch = script
|
||||
.root()
|
||||
.upcast::<Element>()
|
||||
.has_attribute(&local_name!("async"));
|
||||
|
||||
if !asynch && (*script.root()).get_parser_inserted() {
|
||||
document.deferred_script_loaded(&script.root(), load, can_gc);
|
||||
} else if !asynch && !(*script.root()).get_non_blocking() {
|
||||
document.asap_in_order_script_loaded(&script.root(), load, can_gc);
|
||||
if !asynch && script.get_parser_inserted() {
|
||||
document.deferred_script_loaded(&script, load, can_gc);
|
||||
} else if !asynch && !script.get_non_blocking() {
|
||||
document.asap_in_order_script_loaded(&script, load, can_gc);
|
||||
} else {
|
||||
document.asap_script_loaded(&script.root(), load, can_gc);
|
||||
document.asap_script_loaded(&script, load, can_gc);
|
||||
};
|
||||
},
|
||||
}
|
||||
@@ -738,7 +739,8 @@ impl FetchResponseListener for ModuleContext {
|
||||
let global = self.owner.global();
|
||||
let (url, module_type) = &self.module_request;
|
||||
|
||||
if let Some(window) = global.downcast::<Window>() {
|
||||
if let ModuleOwner::Window(_) = self.owner {
|
||||
let window = global.downcast::<Window>().unwrap();
|
||||
window
|
||||
.Document()
|
||||
.finish_load(LoadType::Script(url.clone()), cx);
|
||||
@@ -1187,6 +1189,52 @@ pub(crate) fn fetch_an_external_module_script(
|
||||
);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#fetch-a-modulepreload-module-script-graph>
|
||||
pub(crate) fn fetch_a_modulepreload_module(
|
||||
url: ServoUrl,
|
||||
destination: Destination,
|
||||
global: &GlobalScope,
|
||||
options: ScriptFetchOptions,
|
||||
on_complete: impl FnOnce(bool) + 'static,
|
||||
) {
|
||||
let referrer = global.get_referrer();
|
||||
let owner = ModuleOwner::DynamicModule(Trusted::new(global));
|
||||
|
||||
// Note: There is a specification inconsistency, `fetch_a_single_module_script` doesn't allow
|
||||
// fetching top level JSON/CSS module scripts, but should be possible when preloading.
|
||||
let module_type = if let Destination::Json = destination {
|
||||
Some(ModuleType::JSON)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
// Step 1. Fetch a single module script given url, settingsObject, destination, options, settingsObject,
|
||||
// "client", true, and with the following steps given result:
|
||||
fetch_a_single_module_script(
|
||||
url,
|
||||
owner.clone(),
|
||||
destination,
|
||||
options,
|
||||
referrer,
|
||||
module_type,
|
||||
true,
|
||||
Some(IntroductionType::SRC_SCRIPT),
|
||||
move |result| {
|
||||
// Step 1. Run onComplete given result.
|
||||
on_complete(result.is_none());
|
||||
|
||||
// Step 2. Assert: settingsObject's global object implements Window.
|
||||
assert!(owner.global().is::<Window>());
|
||||
|
||||
// Step 3. If result is not null, optionally fetch the descendants of and link result
|
||||
// given settingsObject, destination, and an empty algorithm.
|
||||
if let Some(module) = result {
|
||||
fetch_the_descendants_and_link_module_script(module, destination, owner);
|
||||
}
|
||||
},
|
||||
);
|
||||
}
|
||||
|
||||
/// <https://html.spec.whatwg.org/multipage/#fetch-an-inline-module-script-graph>
|
||||
pub(crate) fn fetch_inline_module_script(
|
||||
owner: ModuleOwner,
|
||||
|
||||
Reference in New Issue
Block a user