Skip to content

Commit f8a6f15

Browse files
authored
Add initial spec for prerender-until-script
1 parent e8e5e5c commit f8a6f15

File tree

1 file changed

+79
-43
lines changed

1 file changed

+79
-43
lines changed

prerendering.bs

Lines changed: 79 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -234,9 +234,10 @@ Modify [[HTML#speculation-rules]] as follows to support prerendering.
234234

235235
<h3 id="speculation-rules-parsing">Parsing</h3>
236236

237-
Extend the [=speculation rule set=] [=struct=] with one additional [=struct/item=]:
237+
Extend the [=speculation rule set=] [=struct=] with two additional [=struct/items=]:
238238

239239
* <dfn for="speculation rule set">prerender rules</dfn>, a [=list=] of [=speculation rules=], initially empty
240+
* <dfn for="speculation rule set">prerender_until_script rules</dfn>, a [=list=] of [=speculation rules=], initially empty
240241

241242
Extend the [=speculation rule=] [=struct=] with one additional [=struct/item=]:
242243

@@ -245,11 +246,11 @@ Extend the [=speculation rule=] [=struct=] with one additional [=struct/item=]:
245246
<div algorithm="parse a speculation rule set string">
246247
Modify [=parse a speculation rule set string=] as follows:
247248

248-
* Remove the <var ignore>typesToTreatAsPrefetch</var> construct, and instead parse |parsed|["`prerender`"] into the [=speculation rule set/prerender rules=] list, in an identical manner to what is done for |parsed|["`prefetch`"] and the [=speculation rule set/prefetch rules=].
249+
* Remove the <var ignore>typesToTreatAsPrefetch</var> construct, and instead parse |parsed|["`prerender`"] into the [=speculation rule set/prerender rules=] list, and |parsed|["`prerender_until_script`"] into the [=speculation rule set/prerender_until_script rules=] list, both in an identical manner to what is done for |parsed|["`prefetch`"] and the [=speculation rule set/prefetch rules=].
249250

250251
* Discard rules parsed from |parsed|["`prefetch`"] if the [=speculation rule/target navigable name hint=] is not null.
251252

252-
* Discard rules parsed from |parsed|["`prerender`"] if the [=speculation rule/requirements=] contain "`anonymous-client-ip-when-cross-origin`".
253+
* Discard rules parsed from |parsed|["`prerender`"] and |parsed|["`prerender_until_script`"] if the [=speculation rule/requirements=] contain "`anonymous-client-ip-when-cross-origin`".
253254

254255
<p class="note">Implementations will still be allowed to treat prerender candidates as prefetches, per the modifications in [[#speculation-rules-processing]].</p>
255256
</div>
@@ -269,9 +270,10 @@ Extend the [=speculation rule=] [=struct=] with one additional [=struct/item=]:
269270

270271
<h3 id="speculation-rules-processing">Processing model</h3>
271272

272-
A <dfn>prerender candidate</dfn> is a [=speculative load candidate=] with the following additional [=struct/item=]:
273+
A <dfn>prerender candidate</dfn> is a [=speculative load candidate=] with the following additional [=struct/items=]:
273274

274275
* <dfn for="prerender candidate">target navigable name hint</dfn>, a [=valid navigable target name or keyword=] or null
276+
* <dfn for="prerender candidate">should block scripts</dfn>, a [=boolean=], initially false
275277

276278
<div algorithm="consider speculative loads steps">
277279
Update the [=consider speculative loads=] algorithm to bail out early if <var ignore>document</var>'s [=node navigable=] is a [=prerendering navigable=], with an explanatory note about how performing speculative loads in a speculatively-loaded page is too wasteful.
@@ -282,43 +284,14 @@ A <dfn>prerender candidate</dfn> is a [=speculative load candidate=] with the fo
282284

283285
1. Let |prerenderCandidates| be an empty [=list=].
284286
1. [=list/For each=] |ruleSet| of |document|'s [=Document/speculation rule sets=]:
285-
1. [=list/For each=] |rule| of |ruleSet|'s [=speculation rule set/prerender rules=]:
286-
1. [=list/For each=] |url| of |rule|'s [=speculation rule/URLs=]:
287-
1. Let |referrerPolicy| be the result of [=computing a speculative load referrer policy=] given |rule| and null.
288-
1. [=list/Append=] a new [=prerender candidate=] with
289-
290-
<dl class="props">
291-
: [=speculative load candidate/URL=]
292-
:: |url|
293-
294-
: [=speculative load candidate/No-Vary-Search hint=]
295-
:: |rule|'s [=speculation rule/No-Vary-Search hint=]
296-
297-
: [=speculative load candidate/eagerness=]
298-
:: |rule|'s [=speculation rule/eagerness=]
299-
300-
: [=speculative load candidate/referrer policy=]
301-
:: |referrerPolicy|
302-
303-
: [=speculative load candidate/tags=]
304-
:: |rule|'s [=speculation rule/tags=]
305-
306-
: [=prerender candidate/target navigable name hint=]
307-
:: |rule|'s [=speculation rule/target navigable name hint=]
308-
</dl>
309-
310-
to |prerenderCandidates|.
311-
1. If |rule|'s [=speculation rule/predicate=] is not null, then:
312-
1. Let |links| be the result of [=finding matching links=] given |document| and |rule|'s [=speculation rule/predicate=].
313-
1. [=list/For each=] |link| of |links|:
314-
1. Let |target| be |rule|'s [=speculation rule/target navigable name hint=].
315-
1. If |target| is null, set it to the result of [=getting an element's target=] given |link|.
316-
1. Let |referrerPolicy| be the result of [=computing a speculative load referrer policy=] given |rule| and |link|.
317-
1. [=list/Append=] a [=prerender candidate=] with
318-
287+
1. [=list/For each=] (|rules|, |shouldBlockScripts|) of « (|ruleSet|'s [=speculation rule set/prerender rules=], false), (|ruleSet|'s [=speculation rule set/prerender_until_script rules=], true) »:
288+
1. [=list/For each=] |rule| of |rules|:
289+
1. [=list/For each=] |url| of |rule|'s [=speculation rule/URLs=]:
290+
1. Let |referrerPolicy| be the result of [=computing a speculative load referrer policy=] given |rule| and null.
291+
1. [=list/Append=] a new [=prerender candidate=] with
319292
<dl class="props">
320293
: [=speculative load candidate/URL=]
321-
:: |link|'s [=HTMLHyperlinkElementUtils/url=]
294+
:: |url|
322295

323296
: [=speculative load candidate/No-Vary-Search hint=]
324297
:: |rule|'s [=speculation rule/No-Vary-Search hint=]
@@ -333,10 +306,42 @@ A <dfn>prerender candidate</dfn> is a [=speculative load candidate=] with the fo
333306
:: |rule|'s [=speculation rule/tags=]
334307

335308
: [=prerender candidate/target navigable name hint=]
336-
:: |target|
337-
</dl>
309+
:: |rule|'s [=speculation rule/target navigable name hint=]
338310

311+
: [=prerender candidate/should block scripts=]
312+
:: |shouldBlockScripts|
313+
</dl>
339314
to |prerenderCandidates|.
315+
1. If |rule|'s [=speculation rule/predicate=] is not null, then:
316+
1. Let |links| be the result of [=finding matching links=] given |document| and |rule|'s [=speculation rule/predicate=].
317+
1. [=list/For each=] |link| of |links|:
318+
1. Let |target| be |rule|'s [=speculation rule/target navigable name hint=].
319+
1. If |target| is null, set it to the result of [=getting an element's target=] given |link|.
320+
1. Let |referrerPolicy| be the result of [=computing a speculative load referrer policy=] given |rule| and |link|.
321+
1. [=list/Append=] a [=prerender candidate=] with
322+
<dl class="props">
323+
: [=speculative load candidate/URL=]
324+
:: |link|'s [=HTMLHyperlinkElementUtils/url=]
325+
326+
: [=speculative load candidate/No-Vary-Search hint=]
327+
:: |rule|'s [=speculation rule/No-Vary-Search hint=]
328+
329+
: [=speculative load candidate/eagerness=]
330+
:: |rule|'s [=speculation rule/eagerness=]
331+
332+
: [=speculative load candidate/referrer policy=]
333+
:: |referrerPolicy|
334+
335+
: [=speculative load candidate/tags=]
336+
:: |rule|'s [=speculation rule/tags=]
337+
338+
: [=prerender candidate/target navigable name hint=]
339+
:: |target|
340+
341+
: [=prerender candidate/should block scripts=]
342+
:: |shouldBlockScripts|
343+
</dl>
344+
to |prerenderCandidates|.
340345
1. Let |speculativeLoadCandidates| be the union of |prefetchCandidates| and |prerenderCandidates|.
341346

342347
Update subsequent steps for canceling not-still-being-speculated [=prefetch records=] to operate on |speculativeLoadCandidates| instead of |prefetchCandidates|.
@@ -382,7 +387,7 @@ A <dfn>prerender candidate</dfn> is a [=speculative load candidate=] with the fo
382387

383388
1. Set |prefetchRecord|'s [=prefetch record/prerendering target navigable name hint=] to |candidate|'s [=prerender candidate/target navigable name hint=].
384389

385-
1. [=Start a referrer-initiated navigational prerender=] given |document| and |prefetchRecord|.
390+
1. [=Start a referrer-initiated navigational prerender=] given |document|, |prefetchRecord|, and |candidate|'s [=prerender candidate/should block scripts=].
386391

387392
1. If the user agent did not run the previous step, then [=start a referrer-initiated navigational prefetch=] given |document| and |prefetchRecord|.
388393

@@ -429,6 +434,17 @@ By default, a [=navigable=]'s [=navigable/loading mode=] is "`default`". A navig
429434

430435
<p class="note">Although there are only two values for the [=navigable/loading mode=], we use a flexible structure in anticipation of other future loading modes, such as those provided by fenced frames, portals, and uncredentialed (cross-site) prerendering. It's not yet clear whether that anticipation is correct; if, as those features gain full specifications, it turns out not to be, we will instead convert this into a boolean.
431436

437+
Every [=navigable=] has a <dfn for="navigable">scripting mode</dfn>, which is one of the following:
438+
439+
: "`enabled`"
440+
:: Scripts are executed as normal.
441+
: "`blocked-until-activation`"
442+
:: Scripts are blocked until the navigable is activated.
443+
444+
By default, a [=navigable=]'s [=navigable/scripting mode=] is "`enabled`".
445+
446+
<p class="note">The scripting mode is a property of the navigable, instead of the document, so that it can persist across navigations within the same navigable. This is important for cases like the initial `about:blank` document, or for client-side redirects that occur before activation.</p>
447+
432448
Every [=prerendering traversable=] has a <dfn for="prerendering traversable">prerender initial response search variance</dfn>, which is a [=URL search variance=] or null, and is initially null.
433449

434450
<dl class="domintro">
@@ -497,7 +513,7 @@ Every {{Document}} has an <dfn for="Document">allow cross origin iframes navigat
497513
</div>
498514

499515
<div>
500-
To <dfn export>start a referrer-initiated navigational prerender</dfn> given a {{Document}} |referrerDoc| and a [=prefetch record=] |prefetchRecord|:
516+
To <dfn export>start a referrer-initiated navigational prerender</dfn> given a {{Document}} |referrerDoc|, a [=prefetch record=] |prefetchRecord|, and a boolean |blockScripts|:
501517

502518
1. [=Assert=]: |prefetchRecord|'s [=prefetch record/URL=]'s [=url/scheme=] is an [=HTTP(S) scheme=].
503519

@@ -524,6 +540,8 @@ Every {{Document}} has an <dfn for="Document">allow cross origin iframes navigat
524540
<p class="note">This is just a hint. The value has no normative implications. It would still be perfectly fine in the future to [=prerendering traversable/activate=] in place of a different predecessor traversable that was not hinted at.
525541

526542
1. Set |prerenderingTraversable|'s [=navigable/loading mode=] to "`prerender`".
543+
544+
1. If |blockScripts| is true, set |prerenderingTraversable|'s [=navigable/scripting mode=] to "`blocked-until-activation`".
527545

528546
1. Set |prefetchRecord|'s [=prefetch record/prerendering traversable=] to |prerenderingTraversable|.
529547

@@ -612,6 +630,14 @@ Every {{Document}} has an <dfn for="Document">allow cross origin iframes navigat
612630

613631
1. [=map/Set=] [=Accept-CH cache=][|origin|] to |hintSet|.
614632

633+
1. If |navigable|'s [=navigable/scripting mode=] is "`blocked-until-activation`":
634+
635+
1. Set |navigable|'s [=navigable/scripting mode=] to "`enabled`".
636+
637+
1. Unblock script execution in |navigable|'s [=navigable/active document=].
638+
639+
<p class="XXX">The precise mechanism for how script execution is resumed, especially how previously-queued tasks are processed, needs to be specified in more detail.</p>
640+
615641
1. Let |doc| be |navigable|'s [=navigable/active document=].
616642

617643
1. <p class="XXX">We should really propagate the loading mode change here, in the posted task. This is where implementations would update what is returned by {{Document/prerendering|document.prerendering}}. However, right now it lives on the traversable, so it gets magically updated when we move over the session history entry. Probably we need to move it to the {{Document}}.
@@ -950,6 +976,14 @@ To <dfn export>get the supported loading modes</dfn> for a [=response=] |respons
950976

951977
Various behaviors are disallowed in [=prerendering navigables=] because they would be intrusive to the user, since the prerendered content is not being actively interacted with.
952978

979+
<h3 id="pausing-script-execution">Pausing script execution</h3>
980+
981+
If a [=navigable=]'s [=navigable/scripting mode=] is "`blocked-until-activation`", the user agent must not execute script in the navigable's [=navigable/active document=]. This includes, but is not limited to executing `<script>` elements.
982+
983+
<p class="XXX">The precise mechanism for how script execution is blocked, and how various script-related tasks are queued instead of being processed, needs to be specified in more detail.</p>
984+
985+
<p class="note">This effectively pauses all JavaScript execution until the page is activated. For inline event handlers, the expected behavior is under discussion.</p>
986+
953987
<h3 id="patch-downloading">Downloading resources</h3>
954988

955989
Modify the <a spec=HTML>download the hyperlink</a> algorithm to ensure that downloads inside [=prerendering navigable=] are delayed until [=prerendering traversable/activate|activation=], by inserting the following before the step which goes [=in parallel=]:
@@ -976,6 +1010,8 @@ Modify the <a spec=HTML>download the hyperlink</a> algorithm to ensure that down
9761010

9771011
Many specifications need to be patched so that, if a given algorithm invoked in a [=prerendering navigable=], most of its work is deferred until the navigable's [=navigable/top-level traversable=] is [=prerendering traversable/activated=]. This is tricky to do uniformly, as many of these specifications do not have great hygeine around <a href="https://html.spec.whatwg.org/multipage/webappapis.html#event-loop-for-spec-authors">using the event loop</a>. Nevertheless, the following sections give our best attempt.
9781012

1013+
<p class="note">Note that if the [=navigable/scripting mode=] is "`blocked-until-activation`", the scripts that would invoke these algorithms are not executed in the first place until activation.</p>
1014+
9791015
<h4 id="delay-while-prerendering">The {{[DelayWhilePrerendering]}} extended attribute</h4>
9801016

9811017
To abstract away some of the boilerplate involved in delaying the action of asynchronous methods until [=prerendering traversable/activate|activation=], we introduce the <dfn extended-attribute>[DelayWhilePrerendering]</dfn> Web IDL extended attribute. It indicates that when a given method is called in a [=prerendering navigable=], it will immediately return a pending promise and do nothing else. Only upon activation will the usual method steps take place, with their result being used to resolve or reject the previously-returned promise.

0 commit comments

Comments
 (0)