html icon indicating copy to clipboard operation
html copied to clipboard

Define <link rel=prefetch>

Open iamkumaran opened this issue 5 years ago • 20 comments

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

iamkumaran avatar Jan 22 '20 15:01 iamkumaran

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?

domenic avatar Jan 22 '20 15:01 domenic

I did but they recommended to log an issue here. https://github.com/validator/validator/issues/901#issuecomment-577185406

iamkumaran avatar Jan 22 '20 18:01 iamkumaran

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.

domenic avatar Jan 22 '20 18:01 domenic

I'll own this for now

domfarolino avatar Jan 23 '20 07:01 domfarolino

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 avatar Feb 13 '22 12:02 noamr

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?).

noamr avatar Feb 13 '22 12:02 noamr

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

domenic avatar Feb 14 '22 15:02 domenic

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?

noamr avatar Feb 14 '22 15:02 noamr

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.

domenic avatar Feb 14 '22 16:02 domenic

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

noamr avatar Feb 14 '22 16:02 noamr

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 avatar Jul 18 '22 08:07 noamr

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).

pmeenan avatar Jul 20 '22 13:07 pmeenan

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?

noamr avatar Jul 20 '22 14:07 noamr

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).

pmeenan avatar Jul 20 '22 14:07 pmeenan

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 avatar Jul 20 '22 16:07 noamr

@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?

noamr avatar Jul 20 '22 18:07 noamr

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).

pmeenan avatar Jul 20 '22 18:07 pmeenan

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.

noamr avatar Jul 21 '22 05:07 noamr

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.

jeremyroman avatar Jul 21 '22 15:07 jeremyroman

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 avatar Jul 21 '22 16:07 noamr