Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

JS file caching is different when included via script tag vs GET

I've been stuck in caching hell for the past couple of days and while I'm starting to get it still struggling a little bit.

Desired Result
I want to include a JS file on a site and have it cached and/or only fetch a new copy of the file when the file has been changed on the server. I DO CANNOT use version tags or hashes in the file name. The file name needs to stay consistent.

Where I'm at
From what I understand after reading up on this using Etags are the perfect solution for this. They will update when the file is changed and will send the new version of the file if tags don't match. And this seems to work when I request the file via the browser

So you can see that on first request i get a 200 and download size is 292 B and on second request because tags match I get a 304 and download size is 137 B (Just header size I assume). Great! This is exactly what I want.

enter image description here

My request header with looks for the etag: enter image description here

My Problem
Now this works when I request the file from the browser, but adding a js file in a script tag doesn't send request headers the same way. So, opening the following html file

<!DOCTYPE html>
<html>
    <body>
        <script src="https://myTestSite.com/testCache.js"> 
        </script>
    </body>
</html>

My js file is fetched every time because the if-none-match request header is not present. How do I replicate the behavior that was observed in the above scenario when using html script tag? enter image description here enter image description here

TL;DR
How do I use Etags to request only modified JS files when using html script tags and not simple browser GET request?

like image 831
bos570 Avatar asked Jun 27 '19 03:06

bos570


2 Answers

I got it working but not completely as I had expected it to. Here's what I ended up doing.

In the directory where I wanted to serve my js file from I added an .htaccess file

<FilesMatch "\.(js|css)$">
    Header set Cache-Control "no-cache, must-revalidate"
</FilesMatch>

I realized that if I was locally adding my js files to cache it would always pull from the local cache and never even make the request to the server. So, even if the Etag had been changed my client would never know because the file was already locally cached.

So, I decided to not cache the file at all and revalidate. So, while I do have a slight overhead of the http headers, I will always get the latest file without needing to fetch the whole file every single time.

like image 67
bos570 Avatar answered Nov 15 '22 17:11

bos570


Another option (and maybe simpler) is to add a random querystring to the end of your resource URI:

<script src="https://myTestSite.com/testCache.js?version=<random_value>"></script>

This still means you are fetching the same file from the server (server will ignore the querystring when returning the resource) so you do not have to change anything on your backend.

The random value may be auuid, this will ensure randomness. Also the key maybe anything not necessarily version.

like image 3
adnanmuttaleb Avatar answered Nov 15 '22 16:11

adnanmuttaleb