Cover Image
#laravel #performance

Implementing cache-busting for static files

~ 4 MINS READ
21st Dec 2021
Mohammed Omer By Mohammed Omer

What is browser caching?

If you have static files on your website such as images, Javascript files, or CSS files, you don’t want your visitors to request those files every time they make a request to your site (wasting their data and putting more pressure on your server)

So you tell your visitors’ browsers (using your webserver config) to keep those files and not to request them unless they change (the URL to get the file is not the same). This way your visitors only download those files once and use the cache to store them and load them on subsequent requests without hitting the server trying to transfer those files again over the network.

In nginx the configuration to tell browsers to cache certain types of files looks something like this:

location ~* \.(png|jpg|jpeg|svg|css|js|ico)$ {
        expires 100d;
}

This will send an Expires header to tell the browser for how long this file should be cached.

What is cache busting?

when a browser caches static files, they can be in the cache for a long period of time, the problem with this is that if any changes were applied to a cached file on the server, then the browser cannot see those changes and will always get the cached version instead of the new modified version of the file as long as the requested URL of the file has not changed.

The cached version of the files on the visitors’ browsers results in browsers not being able to see the new changes made to the website, and of course, as developers that is not what we want.

So basically what we want is to let the browser cache files for as long as possible while having them update files when they are updated on the server. This way our visitors always see the newest version of the site, and that is what cache-busting is all about.

Laravel mix

There are some tools that will help you achieve that. For example, if you are using laravel you probably used laravel-mix to build your javascript and css. Using the mix helper function appends an ID as a query string to the requested compiled file, and this ID will change every time you build your assets for production enforcing the browsers to request the new version of the asset.

But laravel-mix does not cache your static files on the public folder out of the box (or at least, I couldn’t find a way to make it work with my images folder) so we have to come with another way to add cache-busting to all static files (or maybe any publicly accessible file).

How to apply cache-busting on my app?

I came up with a simple solution that will always append a different query string every time the file changes to enforce browsers to request the new version of the file. It is simply adding the last modified time (a UNIX time) as a query string to every public file (which is not a concern for me, as those files are public in the first place).

I created a PR (it was closed due to issues with multi-server deployments) that makes the asset helper optionally return the file with its last modified time as a query string. It will let you do something like asset('images/test.jpg', version: true) and this will result in a URL like this:

https://your-domain.com/images/test.jpg?id=1639002822

After the PR was closed, I added a global function called version that I use instead of the asset helper to get my public assets with their last modified time appended to them as a query string.

function version($path) : string
{
    $filePath = public_path($path);
    if (!file_exists($filePath)) {
        return asset($path);
    }

    return asset($path) . "?v=" . filemtime($filePath);
} 

Now every time I want to get a public asset I use version('pathToFile') instead of asset('pathToFile') to get the asset with the query string.

This will also work if you have for example a posts public folder that contains all cover images for your posts, you can do something like:

version($post->cover_image)

and that will return the cover image with a version that will change every time the cover image has changed.

I would really want to know if you have any other strategy that enables cache busting on public files, and thanks for taking the time to read this!


If you liked this post consider sharing it :

You may also like

stopwatch14 MINS 
cover
By Mohammed Omer | 22nd Jan 2022
#laravel #linux #nginx
stopwatch2 MINS 
cover
By Mohammed Omer | 27th Mar 2022
#laravel #productivity #tooling #shorts 🔥
stopwatch3 MINS 
cover
By Mohammed Omer | 7th Dec 2021
#laravel #linux
stopwatch4 MINS 
cover
By Mohammed Omer | 1st Dec 2021
#laravel #security #testing
stopwatch6 MINS 
cover
By Mohammed Omer | 15th Jan 2022
#laravel #testing
stopwatch6 MINS 
cover
By Mohammed Omer | 15th Mar 2022
#laravel #tooling #php