When a browser loads a website, it caches the site’s resources (e.g. images, CSS files, JavaScript files) onto your computer. When the browser next loads the same website, it can serve up the cached resources instead of re-downloading the resources, which means speedier loading times for users.

This leads to a common problem, though: if we make edits to a website’s files, how will the browser know to request the new version instead of loading the old, cached version? As long as the edited file has the same filename, the browser can’t tell the difference between the new version and the old one, which means users will see the old version of your code instead of the latest and greatest. :(

Note: Cache busting via query string is not the best solution because some proxy caching services don’t cache files with query strings. The best way is to change the filename itself. Changing filenames, however, involves changing server configurations, so that’ll require a little more work than just appending query strings. You can read more about this from web performance guru Steve Souders and this thorough StackOverflow answer.

We need a way to tell the browser to download only the files that have been edited and load the cached versions for all the other unchanged files. A quick way to do this without changing server configurations is to append a query string to the filenames wherever the files are loaded into your website (e.g. in the <head>). In a <script> tag, it could look like this: <script src="filename.js?v=VersionNumberGoesHere"></script>. Every time you edit a file, you change VersionNumberGoesHere to something new.

Here’s how to do it via Make, specifically GNU Make. Why Make and not Gulp or Grunt? Because Make is more concise and not using another JS tool means one less obfuscation when debugging my JavaScript. Unfortunately, it’s much harder to Google questions about Make. I didn’t find any good tutorials for a Make-specific implementation to this cache problem, so I’d like to share the solution I eventually came up with. This is meant for use in Unix environments (e.g. Linux, Mac OS X), but Windows users can install something like Cygwin to emulate a Unix-like environment.

First, let’s make a file called index.html.in. This will serve as the template Make will uses to produce the final index.html file.

This Makefile will generate the script block to replace %ASSETS%:

Most of the action happens in the Makefile, and it involves 2 steps:

(1) In the .make-script-block target, we first empty the content of .make-script-block. Next, for each file in the JS variable, calculate the file’s MD5 checksum and store it in a variable called checksum. Then echo out the script tag and append the checksum as a query string and write the entire line to a file called .make-script-block. End the for loop.

(2) Then we go to the index.html target. The sed utility searches index.html.in for a pattern matching %ASSETS% and replaces that pattern with the contents of .make-script-block, which should be a file consisting of checksum’d script tags. The result is written into a file called index.html:

Run make index.html and you’ll have your new script tags. By using checksums we ensure that a file’s query string will only change if the file has been changed and that the query string will be relatively unique between updates. If the file hasn’t been touched since last make, then its query string remains the same and the browser will load the cached version instead of re-downloading it.

Hope this helped! Ask any questions in the comments. I’d be happy to explain things and/or help track down answers. :)