Skip to content

Commit

Permalink
Introduce <script type=webbundle>
Browse files Browse the repository at this point in the history
Introduce <script>-based API for subresource loading with Web Bundles.

See the design doc [1] for the motivation of switching from
<link>-based API to <script>-based API. The explainer [2] was already
updated to use <script>-based API.

This feature is guarded by `SubresourceWebBundles` flag.

We eventually drop the <link rel=webbundle> support and remove the
<link>-based API code once we can confirm <script>-based API can be
used as a replacement of <link>-based API.

This CL should be considered as the first step to switch to
<script>-based API. There are still gaps between <link>-based API and
<script>-based API, which will be addressed later [3].

This CL intentionally adds a very minimum test for <script>-based API
because there are already WPT tests for <script type=webbundle>. They
all have been marked as [ SKIP ] in TestExpectations until now. Now
some of them are passing after this CL.

We'll make the remaining tests pass in follow-up CLs, and also add
tests which are specific to <script>-based API as necessary. These
efforts should be tracked by crbug.com/1245166.

[1]: https://docs.google.com/document/d/1q_SodTcLuwya4cXt1gIRaVrkiaBfwWyPvkY1fqRKkgM/edit?usp=sharing&resourcekey=0-dqrFOGVCYsg8WRZ4RFgwuw
[2]: https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading.md
[3]: WICG/webpackage#670

Bug: 1245166
Change-Id: I5109b6e692baf10fd1d8a31a31d93176d4dc4ad2
  • Loading branch information
hayatoito authored and chromium-wpt-export-bot committed Oct 15, 2021
1 parent da88a17 commit 4ffa3e3
Show file tree
Hide file tree
Showing 2 changed files with 157 additions and 0 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
<meta charset="utf-8" />
<title>script type="webbundle" reuses webbundle resources</title>
<link
rel="help"
href="https://github.com/WICG/webpackage/blob/main/explainers/subresource-loading.md"
/>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script src="../resources/test-helpers.js"></script>

<body>
<script>
window.TEST_WEB_BUNDLE_ELEMENT_TYPE = "script";
setup(() => {
assert_true(HTMLScriptElement.supports("webbundle"));
});

const wbn_url = "../resources/wbn/subresource.wbn";
const resource1 = "../resources/wbn/root.js";
const resource2 = "../resources/wbn/submodule.js";

let script1;
let script2;

function cleanUp() {
if (script1) {
script1.remove();
}
if (script2) {
script2.remove();
}
}

async function countWebBundleResourceEntry() {
return new Promise((resolve) => {
new PerformanceObserver((entryList) => {
const entries = entryList.getEntriesByType("resource");
let cnt = 0;
for (let i = 0; i < entries.length; ++i) {
if (entries[i].name.endsWith("subresource.wbn")) ++cnt;
}
resolve(cnt);
}).observe({ entryTypes: ["resource"] });
});
}

async function assertResource1CanBeFetched() {
const response = await fetch(resource1);
const text = await response.text();
assert_equals(text, "export * from './submodule.js';\n");
}

async function assertResource2CanBeFetched() {
const response = await fetch(resource2);
const text = await response.text();
assert_equals(text, "export const result = 'OK';\n");
}

function createScriptWebBundle1() {
return createWebBundleElement(wbn_url, /*resources=*/ [resource1]);
}

function createScriptWebBundle2() {
return createWebBundleElement(wbn_url, /*resources=*/ [resource2]);
}

async function appendScriptWebBundle1AndFetchResource1() {
const wbn_fetch_cnt = countWebBundleResourceEntry();
script1 = createScriptWebBundle1();
document.body.append(script1);
await assertResource1CanBeFetched();
assert_equals(await wbn_fetch_cnt, 1);
}

promise_test(async (t) => {
t.add_cleanup(cleanUp);

await appendScriptWebBundle1AndFetchResource1();

const wbn_fetch_cnt = countWebBundleResourceEntry();

// Append script2 without removing script1.
// script2 should fetch the wbn again.
script2 = createScriptWebBundle2();
document.body.appendChild(script2);

await assertResource2CanBeFetched();
assert_equals(await wbn_fetch_cnt, 1);
}, "A webbundle should be fetched again when new script element is appended.");

promise_test(async (t) => {
t.add_cleanup(cleanUp);

await appendScriptWebBundle1AndFetchResource1();

const wbn_fetch_cnt = countWebBundleResourceEntry();

// Remove script1, then append script2
// script2 should reuse webbundle resources.
script1.remove();
script2 = createScriptWebBundle2();
document.body.append(script2);

await assertResource2CanBeFetched();
assert_equals(await wbn_fetch_cnt, 0);
}, "'remove(), then append()' should reuse webbundle resources");

promise_test(async (t) => {
t.add_cleanup(cleanUp);

await appendScriptWebBundle1AndFetchResource1();

const wbn_fetch_cnt = countWebBundleResourceEntry();

// Use replaceWith() to replace script1 with script2.
// script2 should reuse webbundle resources.
script2 = createScriptWebBundle2();
script1.replaceWith(script2);

await assertResource2CanBeFetched();
assert_equals(await wbn_fetch_cnt, 0);
}, "replaceWith() should reuse webbundle resources.");

promise_test(async (t) => {
t.add_cleanup(cleanUp);

await appendScriptWebBundle1AndFetchResource1();

const wbn_fetch_cnt = countWebBundleResourceEntry();

// Move script1 to another document. Then append script2.
// script2 should reuse webbundle resources.
const another_document = new Document();
another_document.append(script1);
script2 = createScriptWebBundle2();
document.body.append(script2);

await assertResource2CanBeFetched();
assert_equals(await wbn_fetch_cnt, 0);
}, "append() should reuse webbundle resoruces even if the old script was moved to another document.");
</script>
</body>
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
<DOCTYPE html>
<html>
<title>HTMLScriptElement.supports webbundle</title>
<script src="/resources/testharness.js"></script>
<script src="/resources/testharnessreport.js"></script>
<script>
test(() => {
assert_true(HTMLScriptElement.supports('webbundle'));
}, 'HTMLScriptElement.supports returns true for \'webbundle\'');

test(() => {
assert_false(HTMLScriptElement.supports(' webbundle'));
assert_false(HTMLScriptElement.supports('webbundle '));
}, 'HTMLScriptElement.supports returns false for unsupported types');
</script>

0 comments on commit 4ffa3e3

Please sign in to comment.