This is a guest post by Julien Nicault of Cinémur, a new social film app. In this post, he describes how to use AppCache to improve performance and enable offline usage of web apps.

Modern browsers offer a lot of new APIs to create amazing web apps on both desktop and mobile. One of the things these new APIs enable is the ability to build offline-capable websites.

The application cache manifest (ACM) offers developers a way to make their apps work offline, reduce bandwidth consumption, and load pages much faster. Local storage and WebSQL databases are also great ways to cache data on the client side, and this post will talk about the pros and cons of using each.

The ACM allows you to state which resources you want to load from local storage rather than from the server, reducing total number of server calls and improving speed. By adding the ACM to our web app cinemur.fr, we reduced the number of files retrieved from the server from 230 to 60. The ACM was especially useful on our mobile app, since mobile networks often provide low bandwidth.

Using the ACM

The ACM is a text file with either the .appcache or .manifest extension that resides in the root folder of your application. To allow .appcache files on your server, you need to declare the MIME type in the .htaccess file, like this:

AddType text/cache-manifest appcache

The file content is simply a set of paths to resources on your server that you want to store on the client machine. It looks like this:

There are three sections in the file: CACHE, NETWORK & FALLBACK.

  • The CACHE section contains files you want to load and store on the user’s machine. The first time the user loads your app, the browser will store all the files in the CACHE section of your app cache manifest.

  • The NETWORK section contains all the resources that require a network connection to be loaded.

By default, only the files specified in the manifest are loaded. For example, if you forget to list an image, it will not be displayed on the page. Because of this, sometimes you need to add the magic * in the NETWORK section to instruct the browser to load all other resources which are not explicitly named in the file.

The resources listed in the CACHE section always have priority over others.

  • The FALLBACK section contains a list of secondary resources that are loaded in the event that the network is unavailable while a user is trying to access online content.

The # v 1.0 / 2012-01-14 is only a comment, but it is a type of version number that you can change to force the browser to update the resources. Once the file is modified, it will be updated automatically.

Link the application cache manifest to your app

To use the application cache, you need to add the manifest attribute in the element like this:

<html manifest="myappname.appcache"> 
  ...
</html>

Testing

To test if your files are loaded from application cache instead of the server, load your page in the browser and open the web developer tool you work with. Cached resources will have (from cache) listed in the size column.

The console logs will also show cache processing events and the loading status of your resources.

The full update process

When the browser visits a document that has a manifest attribute but no application cache , it will fetch all the entries in the manifest file, creating the first version of the cache. On subsequent visits to that document, the browser will load the document and other assets in the manifest file from the application cache, not from the server.

The browser will also send a checking event to the window.applicationCache object, then fetch the manifest file, following the appropriate HTTP caching rules. If the currently-cached copy of the manifest is up-to-date, the noupdate event is sent to the applicationCache, and the update process is complete. This is why if you change any resources on the server, you need to also change the manifest file so the browser knows it needs to fetch all the resources again.

If the manifest file has changed, all files in the manifest—as well as those added to the cache by calling applicationCache.add()—are fetched into a temporary cache. For each file fetched into this temporary cache, a progress event is sent to the applicationCache object. If any errors occur, an error event is sent, and the update halts.

Once all the files have been successfully retrieved, they are moved into the real offline cache automatically, and a cached event is sent to the applicationCache object. Since the document has already been loaded into the browser from the cache, the updated document won't be rendered until the document is reloaded (either manually or programatically).

You can use JavaScript to programatically update the cache. You can get the status of the app cache or force it to reload by calling some native functions of the window.applicationCache object like this:

Here we see some limits of the ACM. As you can see, you can’t update a single file using the JS API. You can only check the update process and relaunch the download of all the files. It could be very useful to have more controls on it to optimize the update process and performance.

You can also explicitly ask the browser to locally cache your app’s files by using the Cache-Control http header with an expiration date. This method is quite powerful, too, and allows you to cache single or multiple files automatically without specifying the paths.

If you are offline, the files will not be retrieve from the cache and you’ll see the good old no connection error page in the browser. Using the “FALLBACK” section of ACM, you can provide a landing page for unconnected users to see instead.

Browser compatibility of ACM:

Desktop
Feature Chrome Firefox (Gecko) Internet Explorer Opera Safari
Basic support 4.0+ 3.5+ 10.0+ 10.6+ 4.0+
Mobile
Feature Android Firefox Mobile (Gecko) IE Mobile Opera Mobile Safari Mobile
Basic support 2.1+ -- -- 11.0+ 3.2+

Storage location and clearing the offline cache manually:

In Chrome you can clear the offline cache by selecting "Clear browsing data..." in the preferences or by visiting chrome://appcache-internals/. Safari has a similar "Empty cache" setting in its preferences but a browser restart may also be required.

In Firefox, the offline cache data is stored separately from the Firefox profile—next to the regular disk cache:

  • Windows Vista/7: C:\Users\\AppData\Local\Mozilla\Firefox\Profiles\.\OfflineCache

  • Mac/Linux: /Users//Library/Caches/Firefox/Profiles/./OfflineCache

In Firefox the current status of the offline cache can be inspected on the about:cache page (under the "Offline cache device" heading). Note that:

  • The offline cache is not cleared via Tools -> Clear Recent History (bug 538595)

  • The offline cache is not cleared via Tools -> Options -> Advanced -> Network -> Offline data -> Clear Now (bug 538588).

  • The offline cache can be cleared for each site separately using the "Remove..." button in Tools -> Options -> Advanced -> Network -> Offline data.

Run your app faster than ever using application cache

An additional benefit of reducing server calls with ACM is that a large number of daily visitors will not overload your machines with HTTP requests.

We added the application cache on our web app http://cinemur.fr/ which is very heavy to load. We had more than 230 independent files to load from the servers including sprites, CSS files, a lot of images and big JS libraries.

As I mentioned, when we rolled out the app cache manifest on the app, the number of resources loaded from the server fell down to 60 instead of 230. It’s 1Mb less to load for each connection. I’m pretty sure it saved our lives on some really high-traffic days. The caching process is the same on mobile—we added it to http://m.cinemur.fr /

The ACM is insanely simple to set up, saves bandwidth, and lets your app load much, much faster. I highly recommend adding it to your next web app.