Asset caching with service worker
TL,DR: In a recent electron -based project we took advantage of service workers and the new cache API to cache hundreds of assets in the browser for offline access. The service worker’s API leaves me perfectly happy: It allows to implement any caching strategy you wish, while you retain control over the whole process. Currently the service worker is only ready for Chrome and Firefox.
One requirement the electron app had to meet was to cache hundreds of binary assets (images or PDFs, more than 100MB) from a cross-origin server for offline accessibility in the browser.
Caching binary data today
Currently browsers allow two different strategies for caching assets:
- Use a Cache-Manifest , which has good browser support, but does not allow to cache assets from other servers and requires you to have a static file with URLs, we cannot have a comfortable API which simply caches all URLs dynamically. Furthermore working with it is no fun at all, since specs and implementations could not stand reality.
- Make a HTTP request, base64-encode the images if required and put them into the LocalStorage, WebSQL or IndexDB . Storage space varies, so you might have low storage limits and depend on the requirement, that the user confirms the browser message, when required space exceeds limits. But the real pain comes, when you have to detect that the client is offline — when offline you have to add base64-encoded image content to the DOM in order to display the image. And when it comes to other assets like PDFs, there is no easy option at all.
Welcome to service workers and the new cache
Both options didn’t work for us, since they couldn’t meet our requirements . Since we are using electron , and therefore must only support Chrome, there is a third option today:
- Use the new cache API (something totally new and different to the bad old cache manifest) and let the browser cache the assets for you. Then register a service worker, which is able to intercept all HTTP requests, and return the cached assets.
There is already support for both service workers and the related new cache in todays versions of Chrome, Firefox and the Android browser.
The cache API is Promise-based and comes with support for multiple caches, which allows you to mark group of assets as stale easily. The API is ridiculously simple: You open the cache with caches.open() and then add URLs by cache.addAll().
So, lets see some code
The implementation is quite simple and short — especially when you consider, that this was not even possible recently. In our app we have a list of assets we want to add to the cache. In order to do that we have a helper function, the code consists mainly of error handling and logging:
We just have to pass a list of URLs to store the responses for all passed URLs to the cache . The browser does all the work for us, we just call cache.addAll(). When the browser finished cashing all assets, the callback is executed.
In order to return the cache contents instead of performing a network request, we have to register a service worker first, which will be able to intercept network requests, nothing special here:
Last we have the actual service worker.
The event will be triggered, before the browser responds to any request to the server and path where it was registered as, and also to XHTTP Requests performed by websites from this server. This allows us to intercept all requests to “assets.contentful.com” were all our assets are hosted and return the response from the cache .
Check lines 7–10, which show all the beauty of the service worker API. We check the cache for a matching request, which can be returned. Otherwise we try to request it from the network (a more sophisticated strategy for images could be to check if the the browser is offline and return a default image).
Service worker has a great API
Its stunning how easy it is to implement the caching functionality, while retaining control over the caching process and each request. After all the hassle with cache manifest we finally get a great API (before we had no API), which comes with even more features and comfort we could hope for. Check out the Offline Cookbook from Jake Archibald’s, the pope of the offline world, to learn more on how to implement different caching strategies.
Next we need support in Safari and IE, to be able to use the service worker in the wild.