Don't Forget to Plant It!

Building an HTML5 Application, Part 3: Let’s Take This Offline

Here’s Part 1 and Part 2 of this series.

So after taking a break to spend time with family (yay!) and doing taxes (bleh!), I was able to spend some time on Thymer again. It’s time to get it working offline.

Since it doesn’t require a server, Thymer is a perfect candidate to be an offline application. In HTML5 you do this by telling the browser what files it should store locally so they are available offline. You do this in a file called the Cache Manifest file. The one for Thymer looks like this:

1
2
3
4
5
6
7
8
9
10
11
12
CACHE MANIFEST
# Revision: 10
alarm.mp3
alarm.ogg
alarm.wav
clock_32x32.png
index.html
jquery-1.5.2.min.js
minus_12x3.png
reload_12x14.png
thymer.css
thymer.js

In this file, I list all the files I’m going to need when offline. It’s important to note that files listed here must follow the same origin policy, meaning the files must be served from the same domain. I ran into this since I was using a Google hosted version of jQuery, and had to switch to self-hosting instead.

Another important thing to note is the second line of the manifest, where I specify the revision of the manifest in a comment. Browsers will only update their offline cache when the manifest changes, and not when the files listed in the manifest change. Common practice then is to update the revision number in the manifest to notify browsers to update their cache.

I ended up creating a rake task to generate the cache manifest, updating the file list when new files are added and incrementing the revision number on any changes. To update the manifest, I just run the manifest task:

1
rake thymer.appcache

Once the manifest file is created, I need to reference that manifest from the page. You do this by setting the manifest attribute on the html element:

1
2
<!doctype html>
<html manifest="thymer.appcache">

Handling Updates in the Browser

Some browsers must be explicitly told to update the application cache when it sees an update. Here’s how that is done:

1
2
3
4
5
6
7
8
9
10
11
12
13
// check for updates
if ('applicationCache' in window) {
$('#update-button').click(function() {
// Ensure the browser uses the latest version of the code
window.applicationCache.swapCache();
// Reload the application
window.location.reload();
});
window.applicationCache.addEventListener('updateready', function() {
$("#update").show();
}, false);
}

In the above code, I just show a short message with a link to swapCache() and reload when a new update is available. Note that in some browsers, the update doesn’t happen until swapCache() is called, while others it’s automatic and all you really have to do is reload.

In JavaScript, you can detect your current offline/online status with navigator.onLine. You can also listen to offline and online events in the document body. For Thymer, I decided to check the manifest for updates when the browser comes back online:

1
2
3
4
// Check for updates when the browser comes back online
$(document.body).bind('online', function(){
window.applicationCache.update();
});

In testing, it looks like listening for online event doesn’t yet work in Chrome or Safari.

Other Notes

  • When serving the manifest file, make sure it is served with a Content-Type header of ‘text/cache-manifest’.

  • A lot of references and tutorials I found often named the manifest file cache.manifest, but it looks like .appcache will ultimately be the standard extension. This make sense, since the latter will probably have a lesser chance of name collisions with other file types.

  • I ended up declaring all versions of my audio file in the manifest, which is less that optimal since browsers would only use one of the three sources. I could dynamically generate the manifest based on User Agent, but that’s less than ideal.

  • You can browse the contents of the offline cache in FF by going to about:cache from the address bar. In Chrome, you can see it for the current page under the Resources tab from within the Web Inspector. Didn’t see where this information was available in Safari.

That’s a Wrap

That’s it for Offline mode. In the next and most likely the final post in this series, I’m going to get Thymer onto the Chrome web store. If you want to learn more about Offline mode, HTML5Rocks has curated a bunch of articles related to offline. And here is the source code referenced by this post.

Comments