A Smarter Way to Handle Asset Caching with Cache Manifest Files
There are a number of ways to handle the caching of assets like js, css, html etc. In the past my favorite has always been to automatically append a timestamp to the filename when pushing into prod. I have also tried automating this with gulp using gulp-rev which works really well. But last week I came across a new method for dealing with offline applications on HTML5Rocks which needed to distinguish between content available offline and that which needed a network connection. It outlined a way of notifying the client of file changes in order to force the client cache to refresh. This got me thinking if I could do this for offline applications why not leverage the same technique for traditional websites and applications. Here is the proof of concept that I came up with.
There are two key things to notice here. First is on the html tag. A new attribute for specifying a cache manifest file. This is the file that tells the browser what to cache and when it needs to update. We'll call ours app.mf.
The second piece is the script at the bottom. This is a really simple js script that on page load adds an event listener to the updateready event. When this event is triggered it checks to see if the window.applicationCache.UPDATEREADY property is set to 1. This indicates that the manifest file has changed and the cache has been updated on the client. That is great for all subsequent pages but the current page was already pulled from cache so we need to refresh. This is handled with a simple reload().
Next lets take a look at the app.mf manifest file.
# Explicitly cached entries
# offline.html will be displayed if the user is offline
# All other resources (e.g. sites) require the user to be online.
# Additional resources to cache
This is a really straightforward file in this instance because we are really only using it for the file timestamp and version at the top. Notice that we set the Network setction to * indicating that all assets should be pulled from the network instead of using local copies. There is a log more that can be done with this file so be sure to checkout the Application Cache API specification.
The last thing we need to do is make sure that Apache sends the right headers back for the .mf files. To do this we will add a single line to our .htaccess file in the root directory of this demo application.
AddType text/cache-manifest .appcache
To test this all out load up our index.html page. You'll be greeted with a beautiful Hello cache manifest v1 messages. Now go into index.html and change the text to read Hello cache manifest v2. Reload the page in the browser and you will get the cached copy. Now update the app.mf timestamp:version to read # 2015-03-08:v2 or todays date. Reload the page in the browser again and it will automatically pull in the latest version.
This doesn't look like much at first but keep in mind this will handle all client cached assets with a single edit to the manifest file. At the same time you don't have to muddy up your filenames with timestamps or random numbers. This is a clean and simple solution to a problem we all face everyday.
The best part is this API has fairly wide browser support according to caniuse.com.