4

I'm trying to use prefetching (via a link with rel="prefetch") for a JavaScript resource in an html page. In Chrome, I see the prefetch request get kicked off with a "Type" of "javascript". If I subsequently try and fetch the same JavaScript resource by inserting a script tag into the page, I'd expect this to be fetched from the browser cache, rather than a new request being fired off to fetch the resource from the CDN. However, this is not the case. I see a new request being made with the "Type" of "script". I'm assuming that the issue is related to the mismatch in type between this request and the prefetch request.

Is there a way to force the prefetch request to use a type of script or some other way to avoid the JavaScript file being fetched again?

I've tried using an "as" attribute value of "script", but that seems to have no effect.

I'm aware that rel="preload" is an alternative option. This works, but the usual advice seems to be that preloading is only appropriate for resources you're about to use and prefetching is a better choice for resources you will use after navigating elsewhere in your web page. Chrome also warns if you use preload and don't use the resource within a few seconds.

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <title>Page Title</title>
    <link rel="prefetch" href="https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.8/angular-cookies.js" />
    <script type="text/javascript">
        setTimeout(function() {
             const scriptElement = document.createElement("script");
             scriptElement.src = "https://cdnjs.cloudflare.com/ajax/libs/angular.js/1.7.8/angular-cookies.js";
             document.head.appendChild(scriptElement);
         }, 2000);
    </script>
</head>
<body>
</body>
</html>

See above for example repro code. I'd expect the script tag inside the setTimeout to use the already fetched resource, but instead I see a new request being fired off.

praetorian1
  • 173
  • 1
  • 13

1 Answers1

1

I figured this one out, finally. You're likely seeing this happen because Disable Cache is on in Chrome dev tools: Disabling Chrome cache for website development

This doesn't just disable previously-cached assets – it also means that something like this would download an asset twice:

<script src="foo.js">
<script src="foo.js">

With that checkbox unchecked, you should successfully see your asset getting cached:

screenshot of a prefetch-cached resource

That all being said, it is very important to note that in my testing, Chrome is not smart enough to realize that a prefetch and a regular download for the same resource is happening at the same time – it won't attempt to cache one for the other. So if your prefetching takes longer than your setTimeout millisecond value, you will see duplicate downloads!

This is certainly because what you and I are doing here is in some ways an abuse of prefetching. It's supposed to be a way to download resources used for the next navigation. C'est la vie!

Is there a way to force the prefetch request to use a type of script or some other way to avoid the JavaScript file being fetched again?

I've tried using an "as" attribute value of "script", but that seems to have no effect.

Just as a final note, the type differences of script and javascript are to be expected. This is Dev Tools trying to tell you that one of the files is going to be executed and the other is merely getting downloaded.

Leland
  • 2,019
  • 17
  • 28