whatwg / html

HTML Standard
https://html.spec.whatwg.org/multipage/
Other
8.16k stars 2.69k forks source link

Define <link rel=prefetch> #5229

Closed iamkumaran closed 1 year ago

iamkumaran commented 4 years ago

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 commented 4 years ago

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 commented 4 years ago

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

domenic commented 4 years ago

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 commented 4 years ago

I'll own this for now

noamr commented 2 years ago

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 commented 2 years ago

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:

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 commented 2 years ago

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

noamr commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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

noamr commented 2 years ago

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.

pmeenan commented 2 years ago

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

noamr commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

@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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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 commented 2 years ago

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.