w3ctag / design-reviews

W3C specs and API reviews
Creative Commons Zero v1.0 Universal
326 stars 55 forks source link

Design Review: Speculation Rules (Prefetch) #721

Closed jeremyroman closed 1 year ago

jeremyroman commented 2 years ago

Past reviews: Speculation Rules, Prerendering

Braw mornin' TAG!

I'm requesting a TAG review of Speculation Rules (prefetch).

Speculation Rules is a flexible syntax for defining what outgoing links/URLs are eligible to be prepared speculatively before navigation (e.g., prefetched).

In particular this request covers the use of this feature to cause prefetching. In particular, the specification attempts to define prefetching consistent with partitioned storage (cross-partition prefetches are isolated) and with IP anonymization (implementation-defined, but e.g. via a proxy service).

Further details:

We'd prefer the TAG provide feedback as:

☂️ open a single issue in our GitHub repo for the entire review

otherdaniel commented 2 years ago

This proposal uses a <script> element to host JSON content that describes the prefech rules. This potentially conflicts with CORB and the proposed ORB security mechanisms. Both try to prevent loading JSON resources into unexpected contexts. And JSON in <script> is certainly unexpected.

It's not entirely clear to me whether there is actually a conflict or whether this is a near miss, but in either case I believe the interaction with CORB/ORB requires a close look. (Possibly CSP, also.)

Since this concern is merely about rule representation, there should be numerous ways to avoid the issues without touching the substance of the proposal: Using something other than <script>, or having a unique mimetype and strictly require it, or insisting that speculation rules are always inline and won't be fetched. One could also try to modify CORB/ORB in order to accommodate Speculation Rules. The explainer thankfully already touches on these issues, so I'm hopeful this can be resolved.

jeremyroman commented 2 years ago

@otherdaniel As you've noted the explainer touches on this and the spec also has an issue to expand the section type confusion to cover MIME issues.

Given the precedent from import maps (which also uses <script>), I think this would likely resolve to requiring a MIME type whose essence is application/speculationrules+json explicitly. AFAIK this is consistent with the guidance for CORB/ORB; is there more work that is required there?

otherdaniel commented 2 years ago

I think this would likely resolve to requiring a MIME type whose essence is application/speculationrules+json explicitly. AFAIK this is consistent with the guidance for CORB/ORB; is there more work that is required there?

I agree, I think that's a viable solution.

(The "requiring" bit is important, though. The problems CORB/ORB try to solve ultimately stem from the fact that browsers try to be extra clever and accept content with missing or inappropriate MIME types. So the required MIME type should be a must, not a should. But I think that's what you meant)

hadleybeeman commented 2 years ago

Linking to our early design review

LeaVerou commented 2 years ago

I looked at this briefly during a breakout today, but we ran out of time before discussing with the rest of the group, so these are just my own thoughts, and do not necessarily represent TAG consensus (yet):

A rule may include a score between 0.0 and 1.0 (inclusive), defaulting to 0.5, which is a hint about how likely the user is to navigate to the URL. It is expected that UAs will treat this monotonically (i.e., all else equal, increasing the score associated with a rule will make the UA speculate no less than before for that URL, and decreasing the score will not make the UA speculate where it previously did not). However, the user agent may select a link with a lower author-assigned score than another if its heuristics suggest it is a better choice.

I would imagine the likelihood of a link being clicked might change throughout the user's interaction, so I wonder if this would make more sense as an <a> attribute? That way it can be updated by script to account for things like is it in the viewport, is the cursor close to it etc or any other arbitrary thing that makes it more or less likely to be clicked.

tomayac commented 2 years ago
  • Any syntax for speculatively prefetching a lot of stuff brings up concerns about sustainability etc. It's a lot of wasted bandwidth, which for some users may be prohibitively expensive. If we are to make this a whole lot easier, which will lead to even more wasted bandwidth, there should be a way for users to opt out.

One way apps could make this more sustainable could be by checking for the Save-Data header or the navigator.conection.saveData bit.

In tomayac/netinfo/README.md, I have brought up the idea of exposing the fact whether a network is metered via a new navigator.conection.metered bit, which would be more aligned with the way Android handles this: save data is for foreground things like sending lower-res images, and metered network is for background things like not syncing data (or in the concrete case not prefetching).

jeremyroman commented 2 years ago

I looked at this briefly during a breakout today, but we ran out of time before discussing with the rest of the group, so these are just my own thoughts, and do not necessarily represent TAG consensus (yet):

  • I do agree that the current syntax for prefetch/prerender is clumsy and tedious, and the Quicklink example is quite compelling. Although, with the current syntax, a library would still be needed to do what Quicklink does, since there is no criteria for "is this link in the user's viewport?"

I'm hopeful that since this is more about heuristics for picking the best links to prefetch/prerender rather than correctness, that user agents will be able to do a decent job of this by default, appropriate for the device's form factor etc. For example, on a UA with a cursor input device (like a desktop computer), hover might be a really good signal (instant.page uses this), whereas on a UA with touch input but a small viewport (like a mobile phone), hover might not be available but the viewport is a really strong signal of user intent.

If that evolution doesn't prove as fruitful as I hope we might benefit from having authors expressly tell UAs which signals are strong hints about user intent.

  • Any syntax for speculatively prefetching a lot of stuff brings up concerns about sustainability etc. It's a lot of wasted bandwidth, which for some users may be prohibitively expensive. If we are to make this a whole lot easier, which will lead to even more wasted bandwidth, there should be a way for users to opt out.

I agree that users should be able to opt out, for a variety of reasons including cost and privacy. User agents are in a position to help with this too, for example by not prefetching (or by prefetching only very high-probability URLs) when the user is on a metered connection or has low battery life.

This is one advantage of giving a place for UAs to help developers out with this decision -- if we don't, developers can do it anyway, but using APIs that don't make it easy for the UA to intercede on the user's behalf because it's less distinguishable from fetches critical to the immediate user intent.

  • I agree it's weird to use a different language (JSON) to essentially annotate HTML elements but I also agree that extending HTML with these annotations would be clumsy.

It's certainly imperfect but JSON has great tooling in both server- and client-side web technologies, and there is similar use of it in import maps and web bundles.

  • On syntax: Cramming the entire logic for a conditional in a property name is not very extensible. E.g. if_not_selector_matches is essentially a microsyntax for doing negation and specifying what this criteria is going to match on (selector, href, etc). These could be entirely independent if the conditionals are an array of object literals, with one object literal per conditional. This would also allow for additional matching metadata in the future, which you may need for other criteria. E.g. if a proximity to cursor criteria is introduced, you may want to specify distance, velocity etc, if a viewport criteria is introduced you may want to specify offset etc. With the current syntax, each criteria only takes a single argument.

That's a fair point. If you never need two conditions of the same type, then I do think you can get somewhat far with the syntax sketch I had there (it's not specified or implemented yet), but your proposal certainly has its advantages. What I am hoping to avoid is making a boolean algebra microsyntax of arbitrary complexity (or having to write a little language that needs a parser, even) -- but I'm not strongly attached to this yet.

{
  "prefetch": [
    { "source": "document", "if": [{"not": {"href_matches": "..."}}, {"selector_matches": "..."}] }
  ]
}

Definitely a tough balance to strike so that it's as simple as possible while still being useful enough. At some point I start to be reminded of JSON Schema.

Filed WICG/nav-speculation#160 for this question.

A rule may include a score between 0.0 and 1.0 (inclusive), defaulting to 0.5, which is a hint about how likely the user is to navigate to the URL. It is expected that UAs will treat this monotonically (i.e., all else equal, increasing the score associated with a rule will make the UA speculate no less than before for that URL, and decreasing the score will not make the UA speculate where it previously did not). However, the user agent may select a link with a lower author-assigned score than another if its heuristics suggest it is a better choice.

I would imagine the likelihood of a link being clicked might change throughout the user's interaction, so I wonder if this would make more sense as an <a> attribute? That way it can be updated by script to account for things like is it in the viewport, is the cursor close to it etc or any other arbitrary thing that makes it more or less likely to be clicked.

Very possibly! I think it depends a little on whether developers find it more useful to give live-updating hints as the user interacts or whether they just want to provide a bit of a bump to built-in heuristics. This can to some extent be emulated by developers defining e.g. classes for "low likelihood", "medium likelihood", "high likelihood" and then keying off those in rules. But that's awkward if this is a common case, in which case this absolutely should become an attribute as you suggest.

Filed WICG/nav-speculation#159 for this question.

torgo commented 2 years ago

Question: is this an "early review"? What is the time-line? Also it says in Chrome status that you're in the middle of an origin trial. Has there been any feedback from this that you can share? Also it still shows no signal from other implementers. Can you let us know any multistakeholder status?

jeremyroman commented 2 years ago

611 was the corresponding early review. We're hoping to ship in Chrome relatively soon.

So far most of the feedback I'm aware of can largely be bucketed as:

We've asked on multiple occasions for engagement from other vendors, though there hasn't been a lot. The WICG proposal for this repository captures some of that. We've requested Mozilla and WebKit positions, without response.

hober commented 2 years ago

@jeremyroman, thanks for filing WICG/nav-speculation#159 and WICG/nav-speculation#160 back in April, based on @LeaVerou's feedback. It doesn't look like those issues have been touched since, though. Is there anything more you need from us to make progress on them?

jeremyroman commented 2 years ago

@jeremyroman, thanks for filing WICG/nav-speculation#159 and WICG/nav-speculation#160 back in April, based on @LeaVerou's feedback. It doesn't look like those issues have been touched since, though. Is there anything more you need from us to make progress on them?

Not at present, but I expect to incorporate that insight when we extend the feature in that direction, which I think will be relatively soon. Thanks again for the feedback.

domenic commented 2 years ago

Hi TAG. We have a slight expansion to this feature coming up, which I will drop a comment about here instead of opening a new issue. However please let me know if it'd be more helpful to open something new, especially since what I'm asking about is prerendering and this review at least started being about prefetch.

Chrome shipped same-origin prerendering, based on speculation rules, in May. We're now looking to expand this to cover cross-origin same-site prerendering, i.e. cases like https://a.example.com/ prerendering https://b.example.com/. This will include credentials/storage access, since those are site keyed, but it will also require an opt-in from the target site via a new HTTP response header, Supports-Loading-Mode: credentialed-prerender, to protect the origin security boundary.

We've updated the spec and explainer in https://github.com/WICG/nav-speculation/commit/16570ff808267383a393064ff951b764911be78f , with perhaps the most relevant reading being:

We've also updated the relevant security & privacy questionnaire, but none of the questions there were directly relevant to this expansion; probably the new section mentioned above is the most useful from a security and privacy perspective.

Thanks for your time!

pweis88 commented 1 year ago

We're now looking to expand this to cover cross-origin same-site prerendering, i.e. cases like https://a.example.com/ prerendering https://b.example.com/. This will include credentials/storage access, since those are site keyed, but it will also require an opt-in from the target site via a new HTTP response header, Supports-Loading-Mode: credentialed-prerender, to protect the origin security boundary.

We're exploring different use cases for prerendering in Google Workspace apps that would require cross-origin same-site support. This is generally needed for cross-app user journeys, a good example of which is prerendering of Google Docs documents (docs.google.com) that users are likely to navigate to from e.g. Drive (drive.google.com) or Gmail.

torgo commented 1 year ago

Hi @domenic we're noting a lack of multi-stakeholder interest in this. Do you have any info on this can you can share? We're concerned about developer complexity when it comes to this feature, especially considering the need for a new HTTP header that requires server configuration. Is there an alternative design that wouldn't require as much complexity? Never the less, regarding the design it's good to see it's an opt in.

domenic commented 1 year ago

we're noting a lack of multi-stakeholder interest in this. Do you have any info on this can you can share?

Nothing beyond the standards positions linked in the original post, sorry!

Edit: I realized they were not linked in the original post after all. Here they are:

In general we've found that second and third implementers often take a while to follow on these sort of progressive enhancement/for-performance features.

We're concerned about developer complexity when it comes to this feature, especially considering the need for a new HTTP header that requires server configuration. Is there an alternative design that wouldn't require as much complexity?

It depends on what you mean. Fundamentally, an opt-in is needed, for security reasons. I don't think that opt-in is very complex; it's a single HTTP header, and things don't get much simpler than that.

It's possible that you're referring to the difficulty of configuring HTTP headers, which is e.g. impossible on some older static hosts like GitHub pages, and thus requires the use of other free hosting like Netlify/CloudFlare Pages/etc. (Or to use a non-free host.) We could support even those older static hosts by working on this future extension which the explainer explained, i.e. <meta http-equiv="supports-loading-mode">. Arguably, this adds a good bit of complexity, as in-markup versions come with a lot of restrictions around parsing, appearing within the first few thousand bytes, etc. But it does make the feature easier, at least for those stuck on such older static hosts.

Is that what you were referring to, or was there a different meaning of complexity that I missed?


We have a number of other small enhancements to speculation rules/prefetching/prerendering coming up, e.g. support for customizing the referrer policy used. We're planning to continue pinging this thread with small summaries like I did previously, but if you'd prefer us to hold off (e.g. until the base feature gains more implementers) or start new threads, please let us know!

kjmcnee commented 1 year ago

Hello. We have an extension to the speculation rules syntax to allow the referrer policy of a speculative request to be set explicitly. A key use case for this is to allow a site with a lax referrer policy to adopt cross-site prefetching by using a strict policy specifically for the prefetch.

Explainer: https://github.com/WICG/nav-speculation/blob/main/triggers.md#explicit-referrer-policy Spec: https://wicg.github.io/nav-speculation/speculation-rules.html Tests: Mainly in https://github.com/web-platform-tests/wpt/blob/master/speculation-rules/prefetch/referrer-policy-from-rules.https.html Chrome Status: https://chromestatus.com/feature/4694585584910336

(Note that as of this writing, the most recent version of the spec hasn't yet been published at that link, but should be available soon.)

Please take a look.

jeremyroman commented 1 year ago

Just adding a quick update here. We're planning on launching an origin trial which covers some of the extended aspects of this, some of which TAG previously provided feedback on:

torgo commented 1 year ago

Hi @domenic thanks for sending the standards positions links. Just quickly on this point of complexity:

It's possible that you're referring to the difficulty of configuring HTTP headers

Yes that's what I'm referring to - it kind of puts it out of reach for "rank and file" web developers...

LeaVerou commented 1 year ago

Hello. We have an extension to the speculation rules syntax to allow the referrer policy of a speculative request to be set explicitly. A key use case for this is to allow a site with a lax referrer policy to adopt cross-site prefetching by using a strict policy specifically for the prefetch.

Explainer: WICG/nav-speculation@main/triggers.md#explicit-referrer-policy Spec: wicg.github.io/nav-speculation/speculation-rules.html Tests: Mainly in web-platform-tests/wpt@master/speculation-rules/prefetch/referrer-policy-from-rules.https.html Chrome Status: chromestatus.com/feature/4694585584910336

(Note that as of this writing, the most recent version of the spec hasn't yet been published at that link, but should be available soon.)

Please take a look.

Hi there,

Could you please submit this as a separate design review (and link to this issue, since it's blocked on this). Thanks!

torgo commented 1 year ago

We have a number of other small enhancements to speculation rules/prefetching/prerendering coming up, e.g. support for customizing the referrer policy used. We're planning to continue pinging this thread with small summaries like I did previously, but if you'd prefer us to hold off (e.g. until the base feature gains more implementers) or start new threads, please let us know!

Yes please do continue to update this thread with summaries of the changes or additions, but also can you please update the explainer when you do this? I think we have more work to do as TAG on this review before we can close it.

domenic commented 1 year ago

Hmm, we seem to be getting conflicting messages :). Should we post new issues, or update this thread? Both?

We always update the explainer (and spec, and tests) whenever we work on new features, as you can see from the above updates wherein we link to the new explainer sections.

torgo commented 1 year ago

Hi @domenic - Sorry for the mixed messages. Lea was asking specifically about the new proposal from @kjmcnee and I was referring to general updates of the original subject of the review. So yes, we would very much like to see a separate review opened when there is a new proposal. However the explainer link Kevin provided is to a document fragment, not to a separate explainer doc. Could you please clarify what we're being asked to review? To be clear: if it's a new piece of functionality that can be written up in an explainer doc, with the specific user needs being addressed, then please open up a new review (with a new explainer). If it's a delta to something we're already reviewing, then please update the current review text/explainer and let us know specifically what changed and why in a comment.

kjmcnee commented 1 year ago

Hello. My previous comment was about specifying how speculation rules interact with referrer policy, so I would consider that a delta of this review, rather than a new proposal.

The change is the addition of the "Explicit referrer policy" section of the explainer.

LeaVerou commented 1 year ago

Hi there,

We looked at this again in a breakout today.

The general consensus was that we agree that the functionality is useful, but we have some architectural concerns about the syntax this is introducing in the Web Platform, especially since its is introducing a novel precedent that could affect the direction of even more future Web Platform features.

One thing that came up in the discussion was that this is syntax that is annotating other HTML elements en masse, and the only precedent in the Web Platform for doing so is CSS. Since it could be argued that this is presentational, we were wondering if you have explored extending CSS for this.

Most of your criteria syntax is CSS selectors anyway, and while Selectors do not include matching for URL patterns, this would be more broadly useful anyway, and would make a good addition to selectors anyway. Since CSS is inherently reactive, this would also naturally afford dynamic scoring for links.

It seems that something like this could reduce the API surface of this feature to a couple of CSS properties, making it simpler to implement and test.

Sorry this has been taking so long. We're trying to make a concerted effort to come back with actionable feedback so we can close this issue as the consensus is generally positive. We look forward to hearing more as the origin trials progress. If you have other specific issues you would like to ask for TAG's feedback on please let us know.

rhiaro commented 1 year ago

We have an extension to the speculation rules syntax to allow the referrer policy of a speculative request to be set explicitly. A key use case for this is to allow a site with a lax referrer policy to adopt cross-site prefetching by using a strict policy specifically for the prefetch.

Are there risks authors or users should know about if the inverse of this was the case? ie. a strict policy by default is overridden by a lax explicit prefetch policy? (perhaps because of a misconfiguration, or because different people configure the server headers to those who author the pages?)

kjmcnee commented 1 year ago

Are there risks authors or users should know about if the inverse of this was the case? ie. a strict policy by default is overridden by a lax explicit prefetch policy? (perhaps because of a misconfiguration, or because different people configure the server headers to those who author the pages?)

If a lax policy is specified in the rule and it's for a same-site prefetch, that's the policy we use. If it's cross-site however, a lax explicit policy would prevent the prefetch attempt due to the sufficiently-strict referrer policy requirement.

So the risk would be that authors cause their prefetch attempts to be ignored. For debuggability, in the chromium implementation, we surface when an attempt is ignored due to this requirement in DevTools.

jeremyroman commented 1 year ago

Hi again, and thanks for the feedback.

I assume that you're referring to the "where" condition syntax specifically1. For further context on that, we did previously revise it to be more general (see #160, #177) in response to https://github.com/w3ctag/design-reviews/issues/721#issuecomment-1101600240. I did look at options leaning more heavily on CSS (and have taken another look now), but I still don't think it is a great fit here.

Speculation rules provide page authors with the ability to determine, across the page, what sorts of links are suitable to preload and what sorts are not. When that's determined by URL it looks a little bit like Content Security Policy or service worker scopes; when it's determined by page structure, CSS selectors are a useful tool. I actually would tend to expect the former to be more common, and so I'd like for it to have good ergonomics. I'm concerned putting it inside CSS syntax might hurt ergonomics in the URL pattern case2. The existing case of explicit URLs (especially for navigation other than to existing links) is not solved by a pure CSS solution.

For those speculation rules that do target links, I definitely want to be reactive to changes in document structure in the same way that CSS is – which is why the current proposal does use the selector syntax to describe that structure and Chromium's implementation relies on the style engine for invalidation. More deeply integrating this concept (related to navigation speculation) into CSS implementations and specifications seems from our experience more likely to increase the coupling with, and thus burden to, CSS implementations and specifications.

Fundamentally, this control over preloading doesn't seem presentational to me. Even though it leverages the structure and semantics of the document using selectors, it doesn't affect the appearance (or aural output, etc) of the page. The precedent we most had in mind when creating this was import maps, which also have wide-ranging effects on a page, via a JSON specifier syntax embedded in a Githubissues.

  • Githubissues is a development platform for aggregating issues.