Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can link rel=preload be made to work with fetch?

Tags:

fetch

preload

I have a large JSON blob I would like to have preloaded with my webpage. To do this, I have added <link rel="preload" as="fetch" href="/blob.json"> to my page. I also have a JS request to fetch the same blob.

This does not work, and the console reports:

[Warning] The resource blob.json was preloaded using link preload but not used within a few seconds from the window's load event. Please make sure it wasn't preloaded for nothing.

MDN claims that this can be fixed by adding crossorigin to the link tag. AFAICT, this is not true, and no combination or crossorigin attributes will actually make it work.

Using the copy-as-curl command from the developer console, it seems like there is no combination of link tag plus attributes that will issue the same request as a fetch/XHR call in JS.

I would love to be wrong about this.

like image 963
Carl Avatar asked Oct 03 '18 21:10

Carl


People also ask

What is preload and prefetch?

preload is a declarative fetch, allowing you to force the browser to make a request for a resource without blocking the document's onload event. Prefetch is a hint to the browser that a resource might be needed, but delegates deciding whether and when loading it is a good idea or not to the browser.

What is preload in link rel?

The preload value of the <link> element's rel attribute lets you declare fetch requests in the HTML's <head> , specifying resources that your page will need very soon, which you want to start loading early in the page lifecycle, before browsers' main rendering machinery kicks in.

What is Javascript preload?

The preload attribute specifies if and how the author thinks that the media file should be loaded when the page loads. The preload attribute allows the author to provide a hint to the browser about what he/she thinks will lead to the best user experience.

How do I know if preload is working?

To check whether preloading has any influence on performance, you should have a look at times and the order of the resources being loaded within the DevTools Network Monitor. Having said that, preloading actually does not work in Firefox yet (as of version 68).


3 Answers

Here is the working solution to preload fetch that works both in Chrome and Safari and supports cookies.

Unfortunately, it works only for the same domain requests.

First, do not specify crossorigin attribute for preload tag, this will ensure Safari will send request in no-cors mode and include cookies

<link rel="preload" as="fetch" href="/data.json">

Second, the fetch api request should also be done in no-cors mode and include credentials (cookies). Pay attention that this request cannot have any custom headers (like Accept, Content-Type, etc), otherwise the browser won't be able to match this request with preloaded one.

fetch('/data.json', {
    method: 'GET',
    credentials: 'include',
    mode: 'no-cors',
})

I have tried other combinations of crossorigin attribute value and fetch API configuration, but none of them worked for me in Safari (only in Chrome).

Here is what I have tried:

<link rel="preload" as="fetch" href="/data.json" crossorigin="anonymous">

<script>
fetch('/data.json', {
    method: 'GET',
    credentials: 'same-origin',
    mode: 'cors',
})
</script>

The above works in Chrome, but not in Safari, because cookies are not sent by preload request in Safari.

<link rel="preload" as="fetch" href="/data.json" crossorigin="use-credentials">

<script>
fetch('/data.json', {
    method: 'GET',
    credentials: 'include',
    mode: 'cors',
})
</script>

The above works in Chrome but not in Safari. Though cookies are sent by preload request, Safari is not able to match fetch with preload request probably because of the different cors mode.

like image 123
Eugene Fidelin Avatar answered Oct 12 '22 04:10

Eugene Fidelin


Thanks to the discussion in this bug, I got fetch to work with preload in Chromium 67:

First, add crossorigin attribute to the preload link:

<link rel="preload" as="fetch" href="/blob.json" crossorigin="anonymous">

Second, add same-origin credentials to the fetch request:

fetch(url, {credentials: 'same-origin'}).then(response => {
    console.log(response);
});

Alternatively, you can use XMLHttpRequest instead of fetch (with XHR you don't need to add anything to the request), but only if you're not going to use responseType = 'blob' - it won't work due to another bug.

like image 25
user Avatar answered Oct 12 '22 03:10

user


It looks like this is a difference between Safari and Chrome. Safari posts the warning to console, but Chrome does not, so maybe adding crossorigin to the link element does solve the problem, but Safari has some kind of bug?

like image 1
Carl Avatar answered Oct 12 '22 03:10

Carl