The Situation

We were building a webapp that has to work on older browsers without JavaScript. Naturally we're trying to reduce duplications so we didn't roll with JS Models but delivered finished markup over XHR. This worked really good as long as the frontend was “stoopid” and just displaying things but became a bit of a hassle when we started to add functionallity.

One of the things we had to add were full offline capabilities. To achieve this we surely needed to use the application cache. In this post I want to pick some problems that we have encountered, most of them are pretty obvious (afterwards ;)).

Cache Manifest

If you have no idea what this is you probably want to read this. Here are the main painpoints with the cachefile that you will need to solve.

Never checks the referenced files

So as the idea is the files are cached forever . The browser will not check if your scripts or stylesheets have been updated unless you change the manifest .

We use assetic to combine all our scripts and styles to one file so we can save roundtrips and on a singlepage application you want to have everything around anyways. So the only problem here was to get the automatic generated scriptnames (for cache busting) into the manifest file. For this we still have our own branch of the assetic bundle but will hopefully deliver a cleaner solution in the future.

Doesn't check your homepage either

So obviously you're not only having scripts and styles in your manifest but you also need a startup page. Here we had to invest quite some time since at the current state we had all the content delivered. The project was for a newspaper so it would be quite bad if we show the same frontpage every day.

The solution here was that we built a “loader seed”. On startup we will check if the current content is from today and hide it if that's not true to not confuse the user (otherwise she would always see the frontpage from the first visit until it's replaced). This solution allows modern browsers to work offline and update while older browser will just fetch a new homepage and receive the recent content. The only ones that will be screwed are browsers that support the application cache but have javascript disabled. I think we can live with that.

Things you tend to forget

Our loader only updates the content not the layout (if you want the layout to update you need to change something in the manifest). We have the username in the top right corner, now if you logout and login as a different user you will still see the user that created the cache entry. The solution here is to update the username from the script as well.

Updates

window.applicationCache.update()

This will only recheck the manifest file. If the manifest itself didn't change it will not update your scripts and styles. Also watch out with cache headers for the manifest file itself – if it comes from the browser cache you can run into issues where nothing ever updates.

Manifest updated

If you update the manifest the browser will still run the old scripts, but already download the new resources. Only after a reload it will update the resources. You can prevent this by swapping the cache manually and reloading the page. Here is the snippet from html5rocks.com:

window.applicationCache.addEventListener('updateready', function () {
    window.applicationCache.swapCache();
    window.location.reload();
}, false);

In most cases you want to ask the user if he wants to update right now or continue on the old version, but in our case we're not yet displaying content anyways so the user will only notice a slower starting once when we update.

Storage

I think this is something that will change in the future but at the moment you don't have to worry too much about it as you will get plenty of space for normal usage. In chrome you have the shared temprary storage which will give you a couple of GBs in most cases.

MimeType

Just as a hint… If you don't deliver as text/cache-manifest you will be in trouble. Make sure it's configured on your production environment ;)

Development Environment

This caused quite some trouble. Generally you don't want to have the manifest enabled for development because it will cause you a lot of trouble if you want to refresh the site. On the other hand the site will act differently if the parts come from the cache and others get fetched individually. We still ended up disabling it for dev (but had to fix some issues that popped up on staging then).

Conclusion

Introducing the application cache is not hard, but you have to think of the small things you tend to forget if you introduce it into an existing site. Share you experiences in the comments if you think I didn't cover all the troubles :)