Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Define <link rel=prefetch> #5229

Closed
iamkumaran opened this issue Jan 22, 2020 · 20 comments · Fixed by #8111
Closed

Define <link rel=prefetch> #5229

iamkumaran opened this issue Jan 22, 2020 · 20 comments · Fixed by #8111

Comments

@iamkumaran
Copy link

Bug report

Describe the bug

W3 validator reports error for the following tag,
<link href="/css/0919b1814a0e43ed7c9049ed6289f912a857a8b8a.cbb3cd6b.chunk.css" rel="prefetch" as="style">

To Reproduce

Go to https://validator.w3.org/#validate_by_input and paste the following code.

<head>
  <link href="/detail.js" rel="prefetch" as="script">
  <link href="/css/fbf7c3fcfcd81a51d0fbc055546483b038d3f696.2a2f6965.chunk.css" rel="prefetch" as="style">
  <link href="/chunks/fbf7c3fcfcd81a51d0fbc055546483b038d3f696.6568f0b4d67c968bdfc9.js" rel="prefetch" as="script">
  <link href="/chunks/ab377f30981d503665256a0af9ae1bab719f9341.66f8f60167be674f8392.js" rel="prefetch" as="script">
  <link href="/css/c965037ac80c17d285bafbec9ba17a6ff6120a0a.9d207964.chunk.css" rel="prefetch" as="style">
  <link href="/chunks/c965037ac80c17d285bafbec9ba17a6ff6120a0a.7ac29a0deaac58ac9e61.js" rel="prefetch" as="script">
</head>

You will start seeing the errors like

"A link element with an as attribute must have a rel attribute that contains the value preload."

Expected behavior

There should be no error. As per W3.org as is permitted in rel="prefetch".
https://www.w3.org/TR/resource-hints/#prefetch

Screenshot attached,
image

@domenic
Copy link
Member

domenic commented Jan 22, 2020

I'm a bit confused why you are reporting this here. This is the repository for the standard, not the validator. Shouldn't you be reporting this on the validator repository?

@iamkumaran
Copy link
Author

iamkumaran commented Jan 22, 2020

I did but they recommended to log an issue here.
validator/validator#901 (comment)

@domenic
Copy link
Member

domenic commented Jan 22, 2020

I see. Yes, it appears this comes from the Resource Hints spec not properly integrating with HTML. @domfarolino has had plans to help with that integration eventually.

@domfarolino
Copy link
Member

I'll own this for now

@domfarolino domfarolino self-assigned this Jan 23, 2020
@annevk annevk changed the title W3 Validator reports error for <link> with as attribute Define <link as=prefetch> Jan 24, 2020
@domfarolino domfarolino changed the title Define <link as=prefetch> Define <link rel=prefetch> Jan 29, 2020
@noamr
Copy link
Contributor

noamr commented Feb 13, 2022

I'll own this for now

@domfarolino I want to start integrating prefetch into the HTML spec and saw this comment from 2 years ago... are there still any current efforts around this?

@noamr
Copy link
Contributor

noamr commented Feb 13, 2022

Looking at the different ways prefetched is described at MDN, the Resource hints spec, current WPT support and what implementations do, things are far from being interoperable or tested.

prefetch is described as something that happens "when the browser is idle" which is not well defined, and also described as something that the user-agent can initiate.

It also has some undefined important pieces, such as iframes.

We need to define to some extent:

  • when the prefetch occurs (provide some definition of "idle")
  • who caches the prefetched responses and to what scope (the regular HTTP cache? something equivalent to the map of preload resources? At what point can these responses be consumed?

In broad strokes - prefetch is meant for subsequent navigation which makes it priority lower (fetch at least after document load event) and its scope broader (at least for the subsequent navigation?).

@domenic
Copy link
Member

domenic commented Feb 14, 2022

I think https://wicg.github.io/nav-speculation/prefetch.html, by @jeremyroman, are the current efforts around this?

@noamr
Copy link
Contributor

noamr commented Feb 14, 2022

I think https://wicg.github.io/nav-speculation/prefetch.html, by @jeremyroman, are the current efforts around this?

Yes I also came across this, and it seems to do a lot more than what <link rel=prefetch> does today, or at least to me it appears complex. Did I get the wrong impression?

@domenic
Copy link
Member

domenic commented Feb 14, 2022

I'm not sure. My impression is that it is more complex because it attempts to be privacy-preserving cross-origin (by using partitions and allowing the anonymous-client-ip suggestion). Whereas currently all browsers have turned off cross-origin prefetch due to privacy concerns. The same-origin prefetch spec there seems just the right amount of complex?

I might be wrong on that though, so @jeremyroman is probably best placed to clarify.

@noamr
Copy link
Contributor

noamr commented Feb 14, 2022

Either way, I'd be happy to help migrate whichever parts of prefetch into HTML.

@noamr
Copy link
Contributor

noamr commented Jul 18, 2022

After some internal conversations with the Chrome team, I'm going to submit a PR for prefetch with a simple algorithm:
A prefetch triggers a low-priority fetch of the resource, with prefetch-src CSP.

noamr added a commit to noamr/html that referenced this issue Jul 18, 2022
Prefetch is simply a fetch with `prefetch-src` CSP and no
post-processing of the resource.

Closes whatwg#5229
@pmeenan
Copy link
Contributor

pmeenan commented Jul 20, 2022

Some quick notes from various twitter threads with devs using it, specifically for the case where no-cache prefetches are available for one-time-use from a memory cache (and it isn't just a priority setting backed by the normal disk cache):

  • Some way to limit the duration of the usability of the no-cache resource in the HTTP response. Like max-age but if having a max-age on no-cache is a problem, a different value like max-fresh or something (may require HTTP spec changes).
  • Same, but from the link tag side (client-controlled reduction of the timer). In the case of a "reactive prefetch" implementation where the next page HTML is prefetched on hover of a link and the expectation is that it will be used right away, a very short max-age is more appropriate than 5 minutes.
  • Have Vary: work with the memory cache so that if a login (or similar) barrier is passed, stale content is not served.
  • A way to specify individual cookies that vary applies to for the cookie case (this has been a general HTTP ask for a while and has been discussed before - not sure the current state).

@noamr
Copy link
Contributor

noamr commented Jul 20, 2022

Some quick notes from various twitter threads with devs using it, specifically for the case where no-cache prefetches are available for one-time-use from a memory cache (and it isn't just a priority setting backed by the normal disk cache):

Note that when prefetching we also send a Purpose: Prefetch header. I should add it to the spec PR (!). I wonder if devs can solve some of these issues by sending different cache headers based on that header:

  • Some way to limit the duration of the usability of the no-cache resource in the HTTP response. Like max-age but if having a max-age on no-cache is a problem, a different value like max-fresh or something (may require HTTP spec changes).

How about sending a stale-while-revalidate, only when the prefetch header is available, and then send a no-cache for the real response?

  • Same, but from the link tag side (client-controlled reduction of the timer). In the case of a "reactive prefetch" implementation where the next page HTML is prefetched on hover of a link and the expectation is that it will be used right away, a very short max-age is more appropriate than 5 minutes.

Does sending a short max-age only when the prefetch header is available address this?

@pmeenan
Copy link
Contributor

pmeenan commented Jul 20, 2022

I don't know how web-interoperable including both max-age and no-cache on the same cache-control is.

All of this is assuming a non-cacheable resource (for the disk cache) and a resource that can only be used once. If that part of Chrome's implementation is going to go away and it is going to behave like a normal cache resource then none of this is needed (but prefetching HTML also won't work in a lot of cases).

stale-while-revalidate also assumes multiple uses of the response and would populate the disk cache (and presumably there is no "real" response if the request can be satisfied from the prefetched response).

@noamr
Copy link
Contributor

noamr commented Jul 20, 2022

OK, so I think I understand the alternative proposed here. Something like:

A prefetched resource (without no-store) is available once without revalidation, effectively ignoring no-cache for one consumption, with this expiring after max-age.

Am I getting this right?
Of course this would require the max-age/no-cache combination somehow.

@noamr
Copy link
Contributor

noamr commented Jul 20, 2022

@pmeenan: seems like the main use-case for prefetch with no-cache is fetching documents. Would you say that's right? JS & CSS files that are the other mime-types used by prefetch are largely immutable or at least don't tend to change according to cookies etc.

If that's so, I think trying to solve this here has been done before and led to the current effort on nav-speculation. In a world where nav-speculation is mature, the place where prefetch "shines" is in early fetch of subsequent subresources (mainly styles & scripts). And for that case, fine-tuning for no-cache and the above cases are perhaps less relevant?

@pmeenan
Copy link
Contributor

pmeenan commented Jul 20, 2022

Yeah, if we're delegating the document case (including same-origin) to nav-speculation then I'm totally in favor if getting rid of the current heuristics entirely and just treating it as an idle-time preload into the regular cache (without the "must" that comes with preload).

@noamr
Copy link
Contributor

noamr commented Jul 21, 2022

Yeah, if we're delegating the document case (including same-origin) to nav-speculation then I'm totally in favor if getting rid of the current heuristics entirely and just treating it as an idle-time preload into the regular cache (without the "must" that comes with preload).

That's the idea. The main issue with the current semantics is that it breaks partitioning rules.
Perhaps at some point <link rel=prefetch> can work on top of the partitioned nav-speculation in the cross-origin document case.

@jeremyroman
Copy link
Collaborator

re. Purpose, for nav-speculation we've written a header that subsumes it, Sec-Purpose -- because that name benefits from the automatic treatment of Sec- headers and it allows us to be explicit that it's a HTTP structured header -- and indicated that UAs may send vendor-specific headers (like X-Moz, Purpose, etc) that they've sent in the past. It would be nice if whatever we write down for <link rel=prefetch> ends up making sense in line with that

re. <link rel=prefetch> triggering partitioned nav-speculation prefetch, I think the biggest issue there is going to be how we know a priori that the URL is for a document we intend to navigate to at the top level. A given URL could be an HTML document or not, and even if it is one it could be intended for use in an iframe (which would have different partitioning rules applied to it). Unless we extended <link> again to indicate this, of course.

Finally if we do intend for <link rel=prefetch> to be intended for resources in the current cache partition and will not have the magic 5-minute behavior, then we should be aware that this change might degrade the performance of some sites that are relying on the current behavior, e.g. using libraries intended to speed up such navs. This might be difficult to avoid in any event with the advent of cache partioning, though.

@noamr
Copy link
Contributor

noamr commented Jul 21, 2022

re. <link rel=prefetch> triggering partitioned nav-speculation prefetch, I think the biggest issue there is going to be how we know a priori that the URL is for a document we intend to navigate to at the top level. A given URL could be an HTML document or not, and even if it is one it could be intended for use in an iframe (which would have different partitioning rules applied to it). Unless we extended <link> again to indicate this, of course.

Currently chrome does something internal with as="document" in the prefetch link, though it's unspecified. But we can cross the bridge when we get there,

Finally if we do intend for <link rel=prefetch> to be intended for resources in the current cache partition and will not have the magic 5-minute behavior, then we should be aware that this change might degrade the performance of some sites that are relying on the current behavior, e.g. using libraries intended to speed up such navs. This might be difficult to avoid in any event with the advent of cache partioning, though.

Note that this behavior is Chrome-only, so those sites and libraries cannot rely on this for other browsers.
Sites that rely on it for top-level navigations should switch over to nav-speculation when it's available, or do this themselves with service-workers. I don't think the 5-minute rule is very helpful for prefetching JS/CSS that anyway usually have max-age rather than no-cache.

noamr added a commit to noamr/html that referenced this issue Aug 31, 2022
Prefetch is simply a fetch with `prefetch-src` CSP and no
post-processing of the resource.

Closes whatwg#5229
noamr added a commit to noamr/html that referenced this issue Nov 30, 2022
Prefetch is simply a fetch with `prefetch-src` CSP and no
post-processing of the resource.

Closes whatwg#5229
noamr added a commit to noamr/html that referenced this issue Jan 17, 2023
Prefetch is simply a fetch with `prefetch-src` CSP and no
post-processing of the resource.

Closes whatwg#5229
domenic pushed a commit that referenced this issue Jan 17, 2023
Prefetch is simply a fetch, which populates the HTTP cache, with no post-processing of the resource and with a special header Sec-Purpose: prefetch. (The latter is specified in whatwg/fetch#1576.)

Closes #5229.
Closes w3c/resource-hints#86.
Closes w3c/resource-hints#74.
Closes whatwg/fetch#1008.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Development

Successfully merging a pull request may close this issue.

7 participants