Commit 80b8282d authored by Kunihiko Sakamoto's avatar Kunihiko Sakamoto Committed by Commit Bot

Implement link rel=modulepreload

This implements link rel=modulepreload without submodules fetch,
behind the Experimental Web Platform feature flag.

LinkLoader fetches module script using Modulator::FetchSingle, so it
populates the module map but does not fetch descendant modules.
Unlike the preload fetches by link rel=preload, this doesn't set
FetchParameters::SetLinkPreload flag, so it works like a regular
script fetch.

HTMLPreloadScanner fetches module scripts in a similar way to
speculative preload of <script type=module>, i.e. just fetch a
ScriptResource and not populate the module map.

Spec PR: https://github.com/whatwg/html/pull/2383
Intent to implement:
https://groups.google.com/a/chromium.org/forum/#!topic/blink-dev/ynkrM70KDD4

Bug: 740886
Change-Id: I5f4420e305f4962b3fbe3f703ce95a5a43e4f7a9
Reviewed-on: https://chromium-review.googlesource.com/662697
Commit-Queue: Kunihiko Sakamoto <ksakamoto@chromium.org>
Reviewed-by: default avatarKinuko Yasuda <kinuko@chromium.org>
Reviewed-by: default avatarHiroki Nakagawa <nhiroki@chromium.org>
Reviewed-by: default avatarKouhei Ueno <kouhei@chromium.org>
Cr-Commit-Position: refs/heads/master@{#515490}
parent 4536c5cc
<!DOCTYPE html>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<body>
<script>
function verifyNumberOfDownloads(url, number) {
var numDownloads = 0;
let absoluteURL = new URL(url, location.href).href;
performance.getEntriesByName(absoluteURL).forEach(entry => {
if (entry.transferSize > 0) {
numDownloads++;
}
});
assert_equals(numDownloads, number, url);
}
function attachAndWaitForLoad(element) {
return new Promise((resolve, reject) => {
element.onload = resolve;
element.onerror = reject;
document.body.appendChild(element);
});
}
function attachAndWaitForError(element) {
return new Promise((resolve, reject) => {
element.onload = reject;
element.onerror = resolve;
document.body.appendChild(element);
});
}
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/dummy.js';
return attachAndWaitForLoad(link).then(() => {
verifyNumberOfDownloads('resources/dummy.js', 1);
// Verify that <script> doesn't fetch the module again.
var script = document.createElement('script');
script.type = 'module';
script.src = 'resources/dummy.js';
return attachAndWaitForLoad(script);
}).then(() => {
verifyNumberOfDownloads('resources/dummy.js', 1);
});
}, 'link rel=modulepreload');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/module1.js';
return attachAndWaitForLoad(link).then(() => {
// Currently, modulepreload doesn't perform submodules fetch.
verifyNumberOfDownloads('resources/module1.js', 1);
verifyNumberOfDownloads('resources/module2.js', 0);
var script = document.createElement('script');
script.type = 'module';
script.src = 'resources/module1.js';
return attachAndWaitForLoad(script);
}).then(() => {
verifyNumberOfDownloads('resources/module1.js', 1);
verifyNumberOfDownloads('resources/module2.js', 1);
});
}, 'link rel=modulepreload with submodules');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/syntax-error.js';
return attachAndWaitForError(link);
}, 'link rel=modulepreload for a module with syntax error');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = 'resources/not-exist.js';
return attachAndWaitForError(link);
}, 'link rel=modulepreload for a module with network error');
promise_test(function(t) {
var link = document.createElement('link');
link.rel = 'modulepreload';
link.href = null;
return attachAndWaitForError(link);
}, 'link rel=modulepreload with bad href attribute');
</script>
</body>
import { y } from './module2.js';
export let x = y + 1;
...@@ -194,7 +194,8 @@ void DynamicModuleResolver::ResolveDynamically( ...@@ -194,7 +194,8 @@ void DynamicModuleResolver::ResolveDynamically(
ScriptFetchOptions options(referrer_info.Nonce(), IntegrityMetadataSet(), ScriptFetchOptions options(referrer_info.Nonce(), IntegrityMetadataSet(),
String(), referrer_info.ParserState(), String(), referrer_info.ParserState(),
referrer_info.CredentialsMode()); referrer_info.CredentialsMode());
ModuleScriptFetchRequest request(url, options); ModuleScriptFetchRequest request(url, modulator_->GetReferrerPolicy(),
options);
// Step 2.4. "Fetch a module script graph given url, settings object, // Step 2.4. "Fetch a module script graph given url, settings object,
// "script", and options. Wait until the algorithm asynchronously completes // "script", and options. Wait until the algorithm asynchronously completes
......
...@@ -47,6 +47,7 @@ class DynamicModuleResolverTestModulator final : public DummyModulator { ...@@ -47,6 +47,7 @@ class DynamicModuleResolverTestModulator final : public DummyModulator {
private: private:
// Implements Modulator: // Implements Modulator:
ReferrerPolicy GetReferrerPolicy() override { return kReferrerPolicyDefault; }
ScriptState* GetScriptState() final { return script_state_.get(); } ScriptState* GetScriptState() final { return script_state_.get(); }
ModuleScript* GetFetchedModuleScript(const KURL& url) final { ModuleScript* GetFetchedModuleScript(const KURL& url) final {
......
...@@ -140,6 +140,7 @@ void ModuleMap::FetchSingleModuleScript(const ModuleScriptFetchRequest& request, ...@@ -140,6 +140,7 @@ void ModuleMap::FetchSingleModuleScript(const ModuleScriptFetchRequest& request,
// with moduleMap[url], and abort these steps." [spec text] // with moduleMap[url], and abort these steps." [spec text]
// Step 11. "Set moduleMap[url] to module script, and asynchronously complete // Step 11. "Set moduleMap[url] to module script, and asynchronously complete
// this algorithm with module script." [spec text] // this algorithm with module script." [spec text]
if (client)
entry->AddClient(client); entry->AddClient(client);
} }
......
...@@ -175,7 +175,8 @@ TEST_F(ModuleMapTest, sequentialRequests) { ...@@ -175,7 +175,8 @@ TEST_F(ModuleMapTest, sequentialRequests) {
platform->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings platform->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
KURL url(NullURL(), "https://example.com/foo.js"); KURL url(NullURL(), "https://example.com/foo.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
// First request // First request
TestSingleModuleClient* client = new TestSingleModuleClient; TestSingleModuleClient* client = new TestSingleModuleClient;
...@@ -217,7 +218,8 @@ TEST_F(ModuleMapTest, concurrentRequestsShouldJoin) { ...@@ -217,7 +218,8 @@ TEST_F(ModuleMapTest, concurrentRequestsShouldJoin) {
platform->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings platform->AdvanceClockSeconds(1.); // For non-zero DocumentParserTimings
KURL url(NullURL(), "https://example.com/foo.js"); KURL url(NullURL(), "https://example.com/foo.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
// First request // First request
TestSingleModuleClient* client = new TestSingleModuleClient; TestSingleModuleClient* client = new TestSingleModuleClient;
......
...@@ -222,6 +222,21 @@ bool ScriptLoader::BlockForNoModule(ScriptType script_type, bool nomodule) { ...@@ -222,6 +222,21 @@ bool ScriptLoader::BlockForNoModule(ScriptType script_type, bool nomodule) {
return nomodule && script_type == ScriptType::kClassic; return nomodule && script_type == ScriptType::kClassic;
} }
// Step 16 of https://html.spec.whatwg.org/#prepare-a-script
network::mojom::FetchCredentialsMode ScriptLoader::ModuleScriptCredentialsMode(
CrossOriginAttributeValue cross_origin) {
switch (cross_origin) {
case kCrossOriginAttributeNotSet:
return network::mojom::FetchCredentialsMode::kOmit;
case kCrossOriginAttributeAnonymous:
return network::mojom::FetchCredentialsMode::kSameOrigin;
case kCrossOriginAttributeUseCredentials:
return network::mojom::FetchCredentialsMode::kInclude;
}
NOTREACHED();
return network::mojom::FetchCredentialsMode::kOmit;
}
bool ScriptLoader::IsScriptTypeSupported(LegacyTypeSupport support_legacy_types, bool ScriptLoader::IsScriptTypeSupported(LegacyTypeSupport support_legacy_types,
ScriptType& out_script_type) const { ScriptType& out_script_type) const {
return IsValidScriptTypeAndLanguage(element_->TypeAttributeValue(), return IsValidScriptTypeAndLanguage(element_->TypeAttributeValue(),
...@@ -321,18 +336,7 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position, ...@@ -321,18 +336,7 @@ bool ScriptLoader::PrepareScript(const TextPosition& script_start_position,
// 16. "Let module script credentials mode be determined by switching // 16. "Let module script credentials mode be determined by switching
// on CORS setting:" // on CORS setting:"
network::mojom::FetchCredentialsMode credentials_mode = network::mojom::FetchCredentialsMode credentials_mode =
network::mojom::FetchCredentialsMode::kOmit; ModuleScriptCredentialsMode(cross_origin);
switch (cross_origin) {
case kCrossOriginAttributeNotSet:
credentials_mode = network::mojom::FetchCredentialsMode::kOmit;
break;
case kCrossOriginAttributeAnonymous:
credentials_mode = network::mojom::FetchCredentialsMode::kSameOrigin;
break;
case kCrossOriginAttributeUseCredentials:
credentials_mode = network::mojom::FetchCredentialsMode::kInclude;
break;
}
// 17. "If the script element has a nonce attribute, // 17. "If the script element has a nonce attribute,
// then let cryptographic nonce be that attribute's value. // then let cryptographic nonce be that attribute's value.
...@@ -697,7 +701,8 @@ void ScriptLoader::FetchModuleScriptTree(const KURL& url, ...@@ -697,7 +701,8 @@ void ScriptLoader::FetchModuleScriptTree(const KURL& url,
// options." // options."
auto* module_tree_client = ModulePendingScriptTreeClient::Create(); auto* module_tree_client = ModulePendingScriptTreeClient::Create();
modulator->FetchTree(ModuleScriptFetchRequest(url, options), modulator->FetchTree(
ModuleScriptFetchRequest(url, modulator->GetReferrerPolicy(), options),
module_tree_client); module_tree_client);
prepared_pending_script_ = ModulePendingScript::Create( prepared_pending_script_ = ModulePendingScript::Create(
element_, module_tree_client, is_external_script_); element_, module_tree_client, is_external_script_);
......
...@@ -75,6 +75,9 @@ class CORE_EXPORT ScriptLoader : public GarbageCollectedFinalized<ScriptLoader>, ...@@ -75,6 +75,9 @@ class CORE_EXPORT ScriptLoader : public GarbageCollectedFinalized<ScriptLoader>,
static bool BlockForNoModule(ScriptType, bool nomodule); static bool BlockForNoModule(ScriptType, bool nomodule);
static network::mojom::FetchCredentialsMode ModuleScriptCredentialsMode(
CrossOriginAttributeValue);
// https://html.spec.whatwg.org/#prepare-a-script // https://html.spec.whatwg.org/#prepare-a-script
bool PrepareScript(const TextPosition& script_start_position = bool PrepareScript(const TextPosition& script_start_position =
TextPosition::MinimumPosition(), TextPosition::MinimumPosition(),
......
...@@ -31,6 +31,8 @@ ...@@ -31,6 +31,8 @@
#include "core/html/LinkRelAttribute.h" #include "core/html/LinkRelAttribute.h"
#include "platform/runtime_enabled_features.h"
namespace blink { namespace blink {
LinkRelAttribute::LinkRelAttribute() LinkRelAttribute::LinkRelAttribute()
...@@ -45,6 +47,7 @@ LinkRelAttribute::LinkRelAttribute() ...@@ -45,6 +47,7 @@ LinkRelAttribute::LinkRelAttribute()
is_link_next_(false), is_link_next_(false),
is_import_(false), is_import_(false),
is_manifest_(false), is_manifest_(false),
is_module_preload_(false),
is_service_worker_(false), is_service_worker_(false),
is_canonical_(false) {} is_canonical_(false) {}
...@@ -90,6 +93,9 @@ LinkRelAttribute::LinkRelAttribute(const String& rel) : LinkRelAttribute() { ...@@ -90,6 +93,9 @@ LinkRelAttribute::LinkRelAttribute(const String& rel) : LinkRelAttribute() {
icon_type_ = kTouchPrecomposedIcon; icon_type_ = kTouchPrecomposedIcon;
} else if (DeprecatedEqualIgnoringCase(link_type, "manifest")) { } else if (DeprecatedEqualIgnoringCase(link_type, "manifest")) {
is_manifest_ = true; is_manifest_ = true;
} else if (DeprecatedEqualIgnoringCase(link_type, "modulepreload")) {
if (RuntimeEnabledFeatures::ModulePreloadEnabled())
is_module_preload_ = true;
} else if (DeprecatedEqualIgnoringCase(link_type, "serviceworker")) { } else if (DeprecatedEqualIgnoringCase(link_type, "serviceworker")) {
is_service_worker_ = true; is_service_worker_ = true;
} else if (DeprecatedEqualIgnoringCase(link_type, "canonical")) { } else if (DeprecatedEqualIgnoringCase(link_type, "canonical")) {
......
...@@ -57,6 +57,7 @@ class CORE_EXPORT LinkRelAttribute { ...@@ -57,6 +57,7 @@ class CORE_EXPORT LinkRelAttribute {
bool IsLinkNext() const { return is_link_next_; } bool IsLinkNext() const { return is_link_next_; }
bool IsImport() const { return is_import_; } bool IsImport() const { return is_import_; }
bool IsManifest() const { return is_manifest_; } bool IsManifest() const { return is_manifest_; }
bool IsModulePreload() const { return is_module_preload_; }
bool IsServiceWorker() const { return is_service_worker_; } bool IsServiceWorker() const { return is_service_worker_; }
bool IsCanonical() const { return is_canonical_; } bool IsCanonical() const { return is_canonical_; }
...@@ -72,6 +73,7 @@ class CORE_EXPORT LinkRelAttribute { ...@@ -72,6 +73,7 @@ class CORE_EXPORT LinkRelAttribute {
bool is_link_next_ : 1; bool is_link_next_ : 1;
bool is_import_ : 1; bool is_import_ : 1;
bool is_manifest_ : 1; bool is_manifest_ : 1;
bool is_module_preload_ : 1;
bool is_service_worker_ : 1; bool is_service_worker_ : 1;
bool is_canonical_ : 1; bool is_canonical_ : 1;
}; };
......
...@@ -8,6 +8,7 @@ ...@@ -8,6 +8,7 @@
#include "core/dom/Element.h" #include "core/dom/Element.h"
#include "core/html_names.h" #include "core/html_names.h"
#include "core/origin_trials/origin_trials.h" #include "core/origin_trials/origin_trials.h"
#include "platform/runtime_enabled_features.h"
#include "platform/wtf/HashMap.h" #include "platform/wtf/HashMap.h"
namespace blink { namespace blink {
...@@ -31,9 +32,14 @@ bool RelList::ValidateTokenValue(const AtomicString& token_value, ...@@ -31,9 +32,14 @@ bool RelList::ValidateTokenValue(const AtomicString& token_value,
ExceptionState&) const { ExceptionState&) const {
if (SupportedTokens().Contains(token_value)) if (SupportedTokens().Contains(token_value))
return true; return true;
return OriginTrials::linkServiceWorkerEnabled( if (OriginTrials::linkServiceWorkerEnabled(
GetElement().GetExecutionContext()) && GetElement().GetExecutionContext()) &&
token_value == "serviceworker"; token_value == "serviceworker")
return true;
if (RuntimeEnabledFeatures::ModulePreloadEnabled() &&
token_value == "modulepreload")
return true;
return false;
} }
} // namespace blink } // namespace blink
...@@ -121,6 +121,7 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -121,6 +121,7 @@ class TokenPreloadScanner::StartTagScanner {
link_is_style_sheet_(false), link_is_style_sheet_(false),
link_is_preconnect_(false), link_is_preconnect_(false),
link_is_preload_(false), link_is_preload_(false),
link_is_modulepreload_(false),
link_is_import_(false), link_is_import_(false),
matched_(true), matched_(true),
input_is_image_(false), input_is_image_(false),
...@@ -199,6 +200,9 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -199,6 +200,9 @@ class TokenPreloadScanner::StartTagScanner {
type = ResourceTypeForLinkPreload(); type = ResourceTypeForLinkPreload();
if (type == WTF::nullopt) if (type == WTF::nullopt)
return nullptr; return nullptr;
} else if (IsLinkRelModulePreload()) {
request_type = PreloadRequest::kRequestTypeLinkRelPreload;
type = Resource::kScript;
} }
if (!ShouldPreload(type)) { if (!ShouldPreload(type)) {
return nullptr; return nullptr;
...@@ -239,10 +243,9 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -239,10 +243,9 @@ class TokenPreloadScanner::StartTagScanner {
if (!request) if (!request)
return nullptr; return nullptr;
if (Match(tag_impl_, scriptTag)) { if ((Match(tag_impl_, scriptTag) && type_attribute_value_ == "module") ||
request->SetScriptType(type_attribute_value_ == "module" IsLinkRelModulePreload()) {
? ScriptType::kModule request->SetScriptType(ScriptType::kModule);
: ScriptType::kClassic);
} }
request->SetCrossOrigin(cross_origin_); request->SetCrossOrigin(cross_origin_);
...@@ -343,6 +346,7 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -343,6 +346,7 @@ class TokenPreloadScanner::StartTagScanner {
!rel.IsDNSPrefetch(); !rel.IsDNSPrefetch();
link_is_preconnect_ = rel.IsPreconnect(); link_is_preconnect_ = rel.IsPreconnect();
link_is_preload_ = rel.IsLinkPreload(); link_is_preload_ = rel.IsLinkPreload();
link_is_modulepreload_ = rel.IsModulePreload();
link_is_import_ = rel.IsImport(); link_is_import_ = rel.IsImport();
} else if (Match(attribute_name, mediaAttr)) { } else if (Match(attribute_name, mediaAttr)) {
matched_ &= MediaAttributeMatches(*media_values_, attribute_value); matched_ &= MediaAttributeMatches(*media_values_, attribute_value);
...@@ -485,6 +489,11 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -485,6 +489,11 @@ class TokenPreloadScanner::StartTagScanner {
!url_to_load_.IsEmpty(); !url_to_load_.IsEmpty();
} }
bool IsLinkRelModulePreload() const {
return Match(tag_impl_, linkTag) && link_is_modulepreload_ &&
!url_to_load_.IsEmpty();
}
bool ShouldPreloadLink(WTF::Optional<Resource::Type>& type) const { bool ShouldPreloadLink(WTF::Optional<Resource::Type>& type) const {
if (link_is_style_sheet_) { if (link_is_style_sheet_) {
return type_attribute_value_.IsEmpty() || return type_attribute_value_.IsEmpty() ||
...@@ -504,6 +513,8 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -504,6 +513,8 @@ class TokenPreloadScanner::StartTagScanner {
type_from_attribute))) { type_from_attribute))) {
return false; return false;
} }
} else if (link_is_modulepreload_) {
return true;
} else if (!link_is_import_) { } else if (!link_is_import_) {
return false; return false;
} }
...@@ -552,6 +563,7 @@ class TokenPreloadScanner::StartTagScanner { ...@@ -552,6 +563,7 @@ class TokenPreloadScanner::StartTagScanner {
bool link_is_style_sheet_; bool link_is_style_sheet_;
bool link_is_preconnect_; bool link_is_preconnect_;
bool link_is_preload_; bool link_is_preload_;
bool link_is_modulepreload_;
bool link_is_import_; bool link_is_import_;
bool matched_; bool matched_;
bool input_is_image_; bool input_is_image_;
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/DocumentWriteIntervention.h" #include "core/dom/DocumentWriteIntervention.h"
#include "core/dom/ScriptLoader.h"
#include "core/loader/DocumentLoader.h" #include "core/loader/DocumentLoader.h"
#include "platform/CrossOriginAttributeValue.h" #include "platform/CrossOriginAttributeValue.h"
#include "platform/loader/fetch/FetchInitiatorInfo.h" #include "platform/loader/fetch/FetchInitiatorInfo.h"
...@@ -62,21 +63,9 @@ Resource* PreloadRequest::Start(Document* document) { ...@@ -62,21 +63,9 @@ Resource* PreloadRequest::Start(Document* document) {
if (script_type_ == ScriptType::kModule) { if (script_type_ == ScriptType::kModule) {
DCHECK_EQ(resource_type_, Resource::kScript); DCHECK_EQ(resource_type_, Resource::kScript);
network::mojom::FetchCredentialsMode credentials_mode = params.SetCrossOriginAccessControl(
network::mojom::FetchCredentialsMode::kOmit; document->GetSecurityOrigin(),
switch (cross_origin_) { ScriptLoader::ModuleScriptCredentialsMode(cross_origin_));
case kCrossOriginAttributeNotSet:
credentials_mode = network::mojom::FetchCredentialsMode::kOmit;
break;
case kCrossOriginAttributeAnonymous:
credentials_mode = network::mojom::FetchCredentialsMode::kSameOrigin;
break;
case kCrossOriginAttributeUseCredentials:
credentials_mode = network::mojom::FetchCredentialsMode::kInclude;
break;
}
params.SetCrossOriginAccessControl(document->GetSecurityOrigin(),
credentials_mode);
} else if (cross_origin_ != kCrossOriginAttributeNotSet) { } else if (cross_origin_ != kCrossOriginAttributeNotSet) {
params.SetCrossOriginAccessControl(document->GetSecurityOrigin(), params.SetCrossOriginAccessControl(document->GetSecurityOrigin(),
cross_origin_); cross_origin_);
......
...@@ -31,9 +31,12 @@ ...@@ -31,9 +31,12 @@
#include "core/loader/LinkLoader.h" #include "core/loader/LinkLoader.h"
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/css/MediaList.h" #include "core/css/MediaList.h"
#include "core/css/MediaQueryEvaluator.h" #include "core/css/MediaQueryEvaluator.h"
#include "core/dom/Document.h" #include "core/dom/Document.h"
#include "core/dom/ModuleScript.h"
#include "core/dom/ScriptLoader.h"
#include "core/frame/FrameConsole.h" #include "core/frame/FrameConsole.h"
#include "core/frame/LocalFrame.h" #include "core/frame/LocalFrame.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
...@@ -44,6 +47,7 @@ ...@@ -44,6 +47,7 @@
#include "core/inspector/ConsoleMessage.h" #include "core/inspector/ConsoleMessage.h"
#include "core/loader/DocumentLoader.h" #include "core/loader/DocumentLoader.h"
#include "core/loader/NetworkHintsInterface.h" #include "core/loader/NetworkHintsInterface.h"
#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
#include "core/loader/private/PrerenderHandle.h" #include "core/loader/private/PrerenderHandle.h"
#include "core/loader/resource/LinkFetchResource.h" #include "core/loader/resource/LinkFetchResource.h"
#include "platform/Prerender.h" #include "platform/Prerender.h"
...@@ -135,6 +139,13 @@ void LinkLoader::NotifyFinished() { ...@@ -135,6 +139,13 @@ void LinkLoader::NotifyFinished() {
client_->LinkLoaded(); client_->LinkLoaded();
} }
void LinkLoader::NotifyModuleLoadFinished(ModuleScript* module) {
if (!module || module->IsErrored())
client_->LinkLoadingErrored();
else
client_->LinkLoaded();
}
void LinkLoader::DidStartPrerender() { void LinkLoader::DidStartPrerender() {
client_->DidStartLinkPrerender(); client_->DidStartLinkPrerender();
} }
...@@ -287,6 +298,24 @@ static bool IsSupportedType(Resource::Type resource_type, ...@@ -287,6 +298,24 @@ static bool IsSupportedType(Resource::Type resource_type,
return false; return false;
} }
static bool MediaMatches(Document& document,
const String& media,
ViewportDescription* viewport_description) {
if (media.IsEmpty())
return true;
MediaValues* media_values =
MediaValues::CreateDynamicIfFrameExists(document.GetFrame());
if (viewport_description) {
media_values->OverrideViewportDimensions(
viewport_description->max_width.GetFloatValue(),
viewport_description->max_height.GetFloatValue());
}
scoped_refptr<MediaQuerySet> media_queries = MediaQuerySet::Create(media);
MediaQueryEvaluator evaluator(*media_values);
return evaluator.Eval(*media_queries);
}
static Resource* PreloadIfNeeded(const LinkRelAttribute& rel_attribute, static Resource* PreloadIfNeeded(const LinkRelAttribute& rel_attribute,
const KURL& href, const KURL& href,
Document& document, Document& document,
...@@ -309,21 +338,10 @@ static Resource* PreloadIfNeeded(const LinkRelAttribute& rel_attribute, ...@@ -309,21 +338,10 @@ static Resource* PreloadIfNeeded(const LinkRelAttribute& rel_attribute,
return nullptr; return nullptr;
} }
if (!media.IsEmpty()) {
MediaValues* media_values =
MediaValues::CreateDynamicIfFrameExists(document.GetFrame());
if (viewport_description) {
media_values->OverrideViewportDimensions(
viewport_description->max_width.GetFloatValue(),
viewport_description->max_height.GetFloatValue());
}
// Preload only if media matches // Preload only if media matches
scoped_refptr<MediaQuerySet> media_queries = MediaQuerySet::Create(media); if (!MediaMatches(document, media, viewport_description))
MediaQueryEvaluator evaluator(*media_values);
if (!evaluator.Eval(*media_queries))
return nullptr; return nullptr;
}
if (caller == kLinkCalledFromHeader) if (caller == kLinkCalledFromHeader)
UseCounter::Count(document, WebFeature::kLinkHeaderPreload); UseCounter::Count(document, WebFeature::kLinkHeaderPreload);
Optional<Resource::Type> resource_type = Optional<Resource::Type> resource_type =
...@@ -371,6 +389,69 @@ static Resource* PreloadIfNeeded(const LinkRelAttribute& rel_attribute, ...@@ -371,6 +389,69 @@ static Resource* PreloadIfNeeded(const LinkRelAttribute& rel_attribute,
link_fetch_params); link_fetch_params);
} }
static void ModulePreloadIfNeeded(const LinkRelAttribute& rel_attribute,
const KURL& href,
Document& document,
const String& media,
const String& nonce,
CrossOriginAttributeValue cross_origin,
ViewportDescription* viewport_description,
ReferrerPolicy referrer_policy,
SingleModuleClient* client) {
if (!document.Loader() || !rel_attribute.IsModulePreload())
return;
// TODO(ksakamoto): add UseCounter
if (href.IsEmpty()) {
document.AddConsoleMessage(
ConsoleMessage::Create(kOtherMessageSource, kWarningMessageLevel,
"<link rel=modulepreload> has no `href` value"));
return;
}
if (!href.IsValid()) {
document.AddConsoleMessage(ConsoleMessage::Create(
kOtherMessageSource, kWarningMessageLevel,
"<link rel=modulepreload> has an invalid `href` value " +
href.GetString()));
return;
}
// Preload only if media matches
if (!MediaMatches(document, media, viewport_description))
return;
// https://github.com/whatwg/html/pull/2383
// 5. Let settings object be the link element's node document's relevant
// settings object.
// |document| is the node document here, and its context document is the
// relevant settings object.
Document* context_document = document.ContextDocument();
Modulator* modulator =
Modulator::From(ToScriptStateForMainWorld(context_document->GetFrame()));
DCHECK(modulator);
if (!modulator)
return;
network::mojom::FetchCredentialsMode credentials_mode =
ScriptLoader::ModuleScriptCredentialsMode(cross_origin);
ModuleScriptFetchRequest request(
href, referrer_policy,
ScriptFetchOptions(nonce, IntegrityMetadataSet(), String(),
kParserInserted, credentials_mode));
modulator->FetchSingle(request, ModuleGraphLevel::kDependentModuleFetch,
client);
Settings* settings = document.GetSettings();
if (settings && settings->GetLogPreload()) {
document.AddConsoleMessage(ConsoleMessage::Create(
kOtherMessageSource, kVerboseMessageLevel,
"Module preload triggered for " + href.Host() + href.GetPath()));
}
}
static Resource* PrefetchIfNeeded(Document& document, static Resource* PrefetchIfNeeded(Document& document,
const KURL& href, const KURL& href,
const LinkRelAttribute& rel_attribute, const LinkRelAttribute& rel_attribute,
...@@ -447,6 +528,9 @@ void LinkLoader::LoadLinksFromHeader( ...@@ -447,6 +528,9 @@ void LinkLoader::LoadLinksFromHeader(
kReferrerPolicyDefault); kReferrerPolicyDefault);
PrefetchIfNeeded(*document, url, rel_attribute, cross_origin, PrefetchIfNeeded(*document, url, rel_attribute, cross_origin,
kReferrerPolicyDefault); kReferrerPolicyDefault);
ModulePreloadIfNeeded(rel_attribute, url, *document, header.Media(),
header.Nonce(), cross_origin, viewport_description,
kReferrerPolicyDefault, nullptr);
} }
if (rel_attribute.IsServiceWorker()) { if (rel_attribute.IsServiceWorker()) {
UseCounter::Count(&frame, WebFeature::kLinkHeaderServiceWorker); UseCounter::Count(&frame, WebFeature::kLinkHeaderServiceWorker);
...@@ -489,6 +573,9 @@ bool LinkLoader::LoadLink( ...@@ -489,6 +573,9 @@ bool LinkLoader::LoadLink(
if (resource) if (resource)
finish_observer_ = new FinishObserver(this, resource); finish_observer_ = new FinishObserver(this, resource);
ModulePreloadIfNeeded(rel_attribute, href, document, media, nonce,
cross_origin, nullptr, referrer_policy, this);
if (const unsigned prerender_rel_types = if (const unsigned prerender_rel_types =
PrerenderRelTypesFromRelAttribute(rel_attribute, document)) { PrerenderRelTypesFromRelAttribute(rel_attribute, document)) {
if (!prerender_) { if (!prerender_) {
...@@ -522,6 +609,7 @@ void LinkLoader::Trace(blink::Visitor* visitor) { ...@@ -522,6 +609,7 @@ void LinkLoader::Trace(blink::Visitor* visitor) {
visitor->Trace(finish_observer_); visitor->Trace(finish_observer_);
visitor->Trace(client_); visitor->Trace(client_);
visitor->Trace(prerender_); visitor->Trace(prerender_);
SingleModuleClient::Trace(visitor);
PrerenderClient::Trace(visitor); PrerenderClient::Trace(visitor);
} }
......
...@@ -33,6 +33,7 @@ ...@@ -33,6 +33,7 @@
#define LinkLoader_h #define LinkLoader_h
#include "core/CoreExport.h" #include "core/CoreExport.h"
#include "core/dom/Modulator.h"
#include "core/loader/LinkLoaderClient.h" #include "core/loader/LinkLoaderClient.h"
#include "platform/CrossOriginAttributeValue.h" #include "platform/CrossOriginAttributeValue.h"
#include "platform/PrerenderClient.h" #include "platform/PrerenderClient.h"
...@@ -50,8 +51,7 @@ struct ViewportDescriptionWrapper; ...@@ -50,8 +51,7 @@ struct ViewportDescriptionWrapper;
// The LinkLoader can load link rel types icon, dns-prefetch, prefetch, and // The LinkLoader can load link rel types icon, dns-prefetch, prefetch, and
// prerender. // prerender.
class CORE_EXPORT LinkLoader final class CORE_EXPORT LinkLoader final : public SingleModuleClient,
: public GarbageCollectedFinalized<LinkLoader>,
public PrerenderClient { public PrerenderClient {
USING_GARBAGE_COLLECTED_MIXIN(LinkLoader); USING_GARBAGE_COLLECTED_MIXIN(LinkLoader);
...@@ -106,6 +106,8 @@ class CORE_EXPORT LinkLoader final ...@@ -106,6 +106,8 @@ class CORE_EXPORT LinkLoader final
LinkLoader(LinkLoaderClient*, scoped_refptr<WebTaskRunner>); LinkLoader(LinkLoaderClient*, scoped_refptr<WebTaskRunner>);
void NotifyFinished(); void NotifyFinished();
// SingleModuleClient implementation
void NotifyModuleLoadFinished(ModuleScript*) override;
Member<FinishObserver> finish_observer_; Member<FinishObserver> finish_observer_;
Member<LinkLoaderClient> client_; Member<LinkLoaderClient> client_;
......
...@@ -6,11 +6,14 @@ ...@@ -6,11 +6,14 @@
#include <base/macros.h> #include <base/macros.h>
#include <memory> #include <memory>
#include "bindings/core/v8/V8BindingForCore.h"
#include "core/frame/Settings.h" #include "core/frame/Settings.h"
#include "core/html/LinkRelAttribute.h" #include "core/html/LinkRelAttribute.h"
#include "core/loader/DocumentLoader.h" #include "core/loader/DocumentLoader.h"
#include "core/loader/LinkLoaderClient.h" #include "core/loader/LinkLoaderClient.h"
#include "core/loader/NetworkHintsInterface.h" #include "core/loader/NetworkHintsInterface.h"
#include "core/loader/modulescript/ModuleScriptFetchRequest.h"
#include "core/testing/DummyModulator.h"
#include "core/testing/DummyPageHolder.h" #include "core/testing/DummyPageHolder.h"
#include "platform/loader/fetch/MemoryCache.h" #include "platform/loader/fetch/MemoryCache.h"
#include "platform/loader/fetch/ResourceFetcher.h" #include "platform/loader/fetch/ResourceFetcher.h"
...@@ -318,6 +321,79 @@ INSTANTIATE_TEST_CASE_P(LinkLoaderPreloadTest, ...@@ -318,6 +321,79 @@ INSTANTIATE_TEST_CASE_P(LinkLoaderPreloadTest,
LinkLoaderPreloadTest, LinkLoaderPreloadTest,
::testing::ValuesIn(kPreloadTestParams)); ::testing::ValuesIn(kPreloadTestParams));
struct ModulePreloadTestParams {
const char* href;
const char* nonce;
CrossOriginAttributeValue cross_origin;
ReferrerPolicy referrer_policy;
bool expecting_load;
network::mojom::FetchCredentialsMode expected_credentials_mode;
};
constexpr ModulePreloadTestParams kModulePreloadTestParams[] = {
{"", nullptr, kCrossOriginAttributeNotSet, kReferrerPolicyDefault, false,
network::mojom::FetchCredentialsMode::kOmit},
{"http://example.test/cat.js", nullptr, kCrossOriginAttributeNotSet,
kReferrerPolicyDefault, true, network::mojom::FetchCredentialsMode::kOmit},
{"http://example.test/cat.js", nullptr, kCrossOriginAttributeAnonymous,
kReferrerPolicyDefault, true,
network::mojom::FetchCredentialsMode::kSameOrigin},
{"http://example.test/cat.js", "nonce", kCrossOriginAttributeNotSet,
kReferrerPolicyNever, true, network::mojom::FetchCredentialsMode::kOmit}};
class LinkLoaderModulePreloadTest
: public ::testing::TestWithParam<ModulePreloadTestParams> {};
class ModulePreloadTestModulator final : public DummyModulator {
public:
ModulePreloadTestModulator(const ModulePreloadTestParams* params)
: params_(params), fetched_(false) {}
void FetchSingle(const ModuleScriptFetchRequest& request,
ModuleGraphLevel,
SingleModuleClient*) override {
fetched_ = true;
EXPECT_EQ(KURL(NullURL(), params_->href), request.Url());
EXPECT_EQ(params_->nonce, request.Options().Nonce());
EXPECT_EQ(kParserInserted, request.Options().ParserState());
EXPECT_EQ(params_->expected_credentials_mode,
request.Options().CredentialsMode());
EXPECT_EQ(AtomicString(), request.GetReferrer());
EXPECT_EQ(params_->referrer_policy, request.GetReferrerPolicy());
}
bool fetched() const { return fetched_; }
private:
const ModulePreloadTestParams* params_;
bool fetched_;
};
TEST_P(LinkLoaderModulePreloadTest, ModulePreload) {
const auto& test_case = GetParam();
std::unique_ptr<DummyPageHolder> dummy_page_holder =
DummyPageHolder::Create();
ModulePreloadTestModulator* modulator =
new ModulePreloadTestModulator(&test_case);
Modulator::SetModulator(
ToScriptStateForMainWorld(dummy_page_holder->GetDocument().GetFrame()),
modulator);
Persistent<MockLinkLoaderClient> loader_client =
MockLinkLoaderClient::Create(true);
LinkLoader* loader = LinkLoader::Create(loader_client.Get());
KURL href_url = KURL(NullURL(), test_case.href);
loader->LoadLink(LinkRelAttribute("modulepreload"), test_case.cross_origin,
String() /* type */, String() /* as */, String() /* media */,
test_case.nonce, test_case.referrer_policy, href_url,
dummy_page_holder->GetDocument(), NetworkHintsMock());
ASSERT_EQ(test_case.expecting_load, modulator->fetched());
}
INSTANTIATE_TEST_CASE_P(LinkLoaderModulePreloadTest,
LinkLoaderModulePreloadTest,
::testing::ValuesIn(kModulePreloadTestParams));
TEST(LinkLoaderTest, Prefetch) { TEST(LinkLoaderTest, Prefetch) {
struct TestCase { struct TestCase {
const char* href; const char* href;
......
...@@ -18,16 +18,20 @@ class ModuleScriptFetchRequest final { ...@@ -18,16 +18,20 @@ class ModuleScriptFetchRequest final {
STACK_ALLOCATED(); STACK_ALLOCATED();
public: public:
ModuleScriptFetchRequest(const KURL& url, const ScriptFetchOptions& options) ModuleScriptFetchRequest(const KURL& url,
ReferrerPolicy referrer_policy,
const ScriptFetchOptions& options)
: ModuleScriptFetchRequest(url, : ModuleScriptFetchRequest(url,
options, options,
Referrer::NoReferrer(), Referrer::NoReferrer(),
referrer_policy,
TextPosition::MinimumPosition()) {} TextPosition::MinimumPosition()) {}
~ModuleScriptFetchRequest() = default; ~ModuleScriptFetchRequest() = default;
const KURL& Url() const { return url_; } const KURL& Url() const { return url_; }
const ScriptFetchOptions& Options() const { return options_; } const ScriptFetchOptions& Options() const { return options_; }
const AtomicString& GetReferrer() const { return referrer_; } const AtomicString& GetReferrer() const { return referrer_; }
ReferrerPolicy GetReferrerPolicy() const { return referrer_policy_; }
const TextPosition& GetReferrerPosition() const { return referrer_position_; } const TextPosition& GetReferrerPosition() const { return referrer_position_; }
private: private:
...@@ -37,15 +41,18 @@ class ModuleScriptFetchRequest final { ...@@ -37,15 +41,18 @@ class ModuleScriptFetchRequest final {
ModuleScriptFetchRequest(const KURL& url, ModuleScriptFetchRequest(const KURL& url,
const ScriptFetchOptions& options, const ScriptFetchOptions& options,
const String& referrer, const String& referrer,
ReferrerPolicy referrer_policy,
const TextPosition& referrer_position) const TextPosition& referrer_position)
: url_(url), : url_(url),
options_(options), options_(options),
referrer_(referrer), referrer_(referrer),
referrer_policy_(referrer_policy),
referrer_position_(referrer_position) {} referrer_position_(referrer_position) {}
const KURL url_; const KURL url_;
const ScriptFetchOptions options_; const ScriptFetchOptions options_;
const AtomicString referrer_; const AtomicString referrer_;
const ReferrerPolicy referrer_policy_;
const TextPosition referrer_position_; const TextPosition referrer_position_;
}; };
......
...@@ -137,7 +137,7 @@ void ModuleScriptLoader::Fetch(const ModuleScriptFetchRequest& module_request, ...@@ -137,7 +137,7 @@ void ModuleScriptLoader::Fetch(const ModuleScriptFetchRequest& module_request,
// Step 5. "... referrer is referrer, ..." [spec text] // Step 5. "... referrer is referrer, ..." [spec text]
if (!module_request.GetReferrer().IsNull()) { if (!module_request.GetReferrer().IsNull()) {
resource_request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer( resource_request.SetHTTPReferrer(SecurityPolicy::GenerateReferrer(
modulator_->GetReferrerPolicy(), module_request.Url(), module_request.GetReferrerPolicy(), module_request.Url(),
module_request.GetReferrer())); module_request.GetReferrer()));
} }
// Step 5. "... and client is fetch client settings object." [spec text] // Step 5. "... and client is fetch client settings object." [spec text]
......
...@@ -204,7 +204,8 @@ void ModuleScriptLoaderTest::TestFetchDataURL( ...@@ -204,7 +204,8 @@ void ModuleScriptLoaderTest::TestFetchDataURL(
TestModuleScriptLoaderClient* client) { TestModuleScriptLoaderClient* client) {
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create(); ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
KURL url("data:text/javascript,export default 'grapes';"); KURL url("data:text/javascript,export default 'grapes';");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch, registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
GetModulator(), client); GetModulator(), client);
} }
...@@ -251,7 +252,8 @@ void ModuleScriptLoaderTest::TestInvalidSpecifier( ...@@ -251,7 +252,8 @@ void ModuleScriptLoaderTest::TestInvalidSpecifier(
TestModuleScriptLoaderClient* client) { TestModuleScriptLoaderClient* client) {
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create(); ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
KURL url("data:text/javascript,import 'invalid';export default 'grapes';"); KURL url("data:text/javascript,import 'invalid';export default 'grapes';");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
GetModulator()->SetModuleRequests({"invalid"}); GetModulator()->SetModuleRequests({"invalid"});
registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch, registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
GetModulator(), client); GetModulator(), client);
...@@ -287,7 +289,8 @@ void ModuleScriptLoaderTest::TestFetchInvalidURL( ...@@ -287,7 +289,8 @@ void ModuleScriptLoaderTest::TestFetchInvalidURL(
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create(); ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
KURL url; KURL url;
EXPECT_FALSE(url.IsValid()); EXPECT_FALSE(url.IsValid());
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch, registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
GetModulator(), client); GetModulator(), client);
} }
...@@ -322,7 +325,8 @@ void ModuleScriptLoaderTest::TestFetchURL( ...@@ -322,7 +325,8 @@ void ModuleScriptLoaderTest::TestFetchURL(
url, testing::CoreTestDataPath("module.js"), "text/javascript"); url, testing::CoreTestDataPath("module.js"), "text/javascript");
ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create(); ModuleScriptLoaderRegistry* registry = ModuleScriptLoaderRegistry::Create();
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch, registry->Fetch(module_request, ModuleGraphLevel::kTopLevelModuleFetch,
GetModulator(), client); GetModulator(), client);
} }
......
...@@ -363,7 +363,8 @@ void ModuleTreeLinker::FetchDescendants(ModuleScript* module_script) { ...@@ -363,7 +363,8 @@ void ModuleTreeLinker::FetchDescendants(ModuleScript* module_script) {
// [FD] Step 7. ... perform the internal module script graph fetching // [FD] Step 7. ... perform the internal module script graph fetching
// procedure given ... with the top-level module fetch flag unset. ... // procedure given ... with the top-level module fetch flag unset. ...
ModuleScriptFetchRequest request( ModuleScriptFetchRequest request(
urls[i], options, module_script->BaseURL().GetString(), positions[i]); urls[i], options, module_script->BaseURL().GetString(),
modulator_->GetReferrerPolicy(), positions[i]);
InitiateInternalModuleScriptGraphFetching( InitiateInternalModuleScriptGraphFetching(
request, ModuleGraphLevel::kDependentModuleFetch); request, ModuleGraphLevel::kDependentModuleFetch);
} }
......
...@@ -123,6 +123,7 @@ class ModuleTreeLinkerTestModulator final : public DummyModulator { ...@@ -123,6 +123,7 @@ class ModuleTreeLinkerTestModulator final : public DummyModulator {
private: private:
// Implements Modulator: // Implements Modulator:
ReferrerPolicy GetReferrerPolicy() override { return kReferrerPolicyDefault; }
ScriptState* GetScriptState() override { return script_state_.get(); } ScriptState* GetScriptState() override { return script_state_.get(); }
void FetchSingle(const ModuleScriptFetchRequest& request, void FetchSingle(const ModuleScriptFetchRequest& request,
...@@ -218,7 +219,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeNoDeps) { ...@@ -218,7 +219,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeNoDeps) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js"); KURL url("http://example.com/root.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -239,7 +241,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeInstantiationFailure) { ...@@ -239,7 +241,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeInstantiationFailure) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js"); KURL url("http://example.com/root.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -264,7 +267,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreePreviousInstantiationFailure) { ...@@ -264,7 +267,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreePreviousInstantiationFailure) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js"); KURL url("http://example.com/root.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -285,7 +289,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWithSingleDependency) { ...@@ -285,7 +289,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWithSingleDependency) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js"); KURL url("http://example.com/root.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -311,7 +316,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps) { ...@@ -311,7 +316,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js"); KURL url("http://example.com/root.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -350,7 +356,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps1Fail) { ...@@ -350,7 +356,8 @@ TEST_F(ModuleTreeLinkerTest, FetchTreeWith3Deps1Fail) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/root.js"); KURL url("http://example.com/root.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -406,7 +413,8 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyTree) { ...@@ -406,7 +413,8 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyTree) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/depth1.js"); KURL url("http://example.com/depth1.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
...@@ -431,7 +439,8 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyOfCyclicGraph) { ...@@ -431,7 +439,8 @@ TEST_F(ModuleTreeLinkerTest, FetchDependencyOfCyclicGraph) {
ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create(); ModuleTreeLinkerRegistry* registry = ModuleTreeLinkerRegistry::Create();
KURL url("http://example.com/a.js"); KURL url("http://example.com/a.js");
ModuleScriptFetchRequest module_request(url, ScriptFetchOptions()); ModuleScriptFetchRequest module_request(url, kReferrerPolicyDefault,
ScriptFetchOptions());
TestModuleTreeClient* client = new TestModuleTreeClient; TestModuleTreeClient* client = new TestModuleTreeClient;
registry->Fetch(module_request, GetModulator(), client); registry->Fetch(module_request, GetModulator(), client);
......
...@@ -110,7 +110,8 @@ void WorkletGlobalScope::FetchAndInvokeScript( ...@@ -110,7 +110,8 @@ void WorkletGlobalScope::FetchAndInvokeScript(
Modulator* modulator = Modulator::From(ScriptController()->GetScriptState()); Modulator* modulator = Modulator::From(ScriptController()->GetScriptState());
// [FMWST] Step 3. "Perform the internal module script graph fetching // [FMWST] Step 3. "Perform the internal module script graph fetching
// procedure ..." // procedure ..."
ModuleScriptFetchRequest module_request(module_url_record, options); ModuleScriptFetchRequest module_request(
module_url_record, modulator->GetReferrerPolicy(), options);
// Step 3 to 5 are implemented in // Step 3 to 5 are implemented in
// WorkletModuleTreeClient::NotifyModuleTreeLoadFinished. // WorkletModuleTreeClient::NotifyModuleTreeLoadFinished.
......
...@@ -642,6 +642,10 @@ ...@@ -642,6 +642,10 @@
{ {
name: "ModernMediaControls", name: "ModernMediaControls",
}, },
{
name: "ModulePreload",
status: "experimental",
},
{ {
name: "ModuleScriptsDynamicImport", name: "ModuleScriptsDynamicImport",
}, },
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment