Sunday, January 29, 2012

Simple Cachebusting for JS

Browsers caching your assets is a good thing. It not only reduces the bandwidth requirements of your site, but it also speeds up loading on the client side every time they visit.

But what happens when you have some changes that you need pushed everywhere to have the site still working? The big thing I'm thinking of here is Javascript. You change the HTML format of a page and all of a sudden your jQuery fails, or your AJAX responses have been tweaked and now your 'onSuccess' functions that work with that data need to be changed... and if they're not, then things don't work.

So what do you do? Of course, there's always the option to stop caching: but that will increase server load, used bandwidth and slow down the loading on the client side. Even if you do disable caching, you're still at the mercy of the client... maybe the browser decides to ignore your cache control requests (or possibly the proxies between the client and the server ignore the requests).

So in trying to work this out, I realised that by adding a random GET parameter will help resolve this issue. Every browser that I have tested against treats the (partial) URL of "random.js?12345" as entirely different from "random.js?12346" as far as caching is concerned, and with good reason. The GET parameter is used for exactly that: to "get" a given resource. It's understandable that the browser would treat these two things as different.

I could use a random number every time to force the cache busting, but that basically sends me back to losing any benefit of browser caching. So the question becomes, what do I use for the GET parameter? Initially I considered using a version number. Every time I changed the JS file, I would change the URL that the generated HTML would use... it would go from "random.js?1.2.3" to "random.js?1.2.4" and so on. In thinking about that implementation, though, I realised that my laziness and forgetfulness would be a deal breaker here as there is no way I would be able to remember to update the URL in (every?) file that references the JS file.

What I ended up doing was actually pretty simple. Every time I include a JS file in the HTML generated by a PHP script, I first quickly find the last modified time of the file and I then append that modified timestamp to the URL.

For my random.js example above, I would do something like the following in my index.php file:
$stats = stat(dirname(__FILE__) . '/random.js');
echo '<script src="random.js?' . $stats['mtime'] . '"/>';
Really simple, perfectly functional and highly cross platform, which is something I always strive to do. If you're not using PHP, then the concept is still the same... you would just need to translate it to your favourite programming language.

Now, if you have a lot of resources that you want to include, maybe you would write a function to try and remove the redundancy, but generally when I do this I only have one or two files to process anyway.

Naturally, the better alternative is to use a framework that does this all for you anyway. A lot of those frameworks do a lot more for you than just the cache busting, so of course they're worth the effort, but if you're not in a situation where you can choose this route, then hopefully the above will help!

No comments:

Post a Comment