When it comes to building Progressive Web Apps, my favourite library has to be the Service Worker toolbox. I’ve previously written about this great library and how it can make life a lot easier for developers by removing boilerplate code and using proven caching strategies that help you build real world PWAs. The truth is, it used to be my favourite library until I discovered Workbox.
Workbox that takes learnings from the Service Worker Toolbox and builds upon it, while at the same time providing a collection of loosely-coupled libraries and tools that focus on different service worker features and use-cases. The great thing about this library is that it helps you simplify your development by making it easy to take advantage of powerful service worker features and automating service worker generation.
At it’s core, Workbox is made up of a module called workbox-sw, which is a service worker library that makes makes fetch requests and caching as easy as possible. However, under the hood, there are a number of lower-level modules that can be used independently or mixed-and-matched depending on your use case. For example, there is a module called workbox-cache-expiration which expires cached responses based on age or a maximum number of entries. Another awesome module is workbox-background-sync, which queues failed requests and uses the Background Sync API to replay those requests when the user comes back online. Awesome stuff!
In this article, I am going to run through some of the basics of the Workbox library, including the Workbox CLI tool, custom caching, improved debugging as well as the offline Google Analytics module.
I wanted to experiment with Workbox using an existing Progressive Web App in order to compare the new library side by side. For this example, I am going to use a PWA that I have already built which is called Awesome Typography; essentially it’s a list of resources that help you build beautiful websites using Web Fonts.
The web pages in the Awesome Typography site are static which makes the content perfect for service worker caching. I also use Google Analytics which should plug in nicely with the workbox-offline-analytics package.
The Workbox CLI tool makes life a lot easier
One of the things that I really like about Workbox is that it comes with a CLI tool that you can use to generate a service worker with some smart defaults. No need to manually create each file in your service worker, the CLI tool will loop through your files and add them to your service worker to be precached.
First off, start by installing the Workbox CLI. Open your terminal (or Command Prompt in Windows) and run the following code:
$ npm install workbox-cli --global
In order to generate a service worker and precache the files in your project, run the following code:
$ workbox-cli generate:sw
You’ll be prompted with a list of questions to determine your project’s setup and voilà, the tool will create a ready-to-use service worker that you can add to your project.
It took me less than five minutes to get this running on the Awesome Typography website. The best thing about the Workbox CLI tool is that you can apply this to any project in just a few steps.
Custom caching and routing
Okay, so we’ve got precaching in place, but what about any HTTP requests that aren’t coming from the Awesome Typography site? This site is all about the web fonts, so it only makes sense that we include a few in each page! The fonts used on this site are from Google Fonts, which means if the user is offline or loses their connection, the site will look a bit funny without the fonts in place.
The CLI tool is great for files that exist on my hard drive, but ideally I want to cache these web fonts too. This is where routing comes into play.
In its most basic form, routing is the process of matching an incoming request with the most appropriate route. Once we have matched a request, we can then decide what we want to do with it. I’ve used the following code inside my service worker and included the Workbox library.
Woah - that looks like a lot of code. Let’s break it down step by step.
Next, we register a new route for 'https://fonts.googleapis.com/(.*)', which will ensure that any HTTP requests that match the origin "fonts.googleapis.com" will be added to added to and retrieved from service worker cache. The code above won't cache anything that doesn't match our route and this kind of flexibility is great because it really gives you the control over what you would like cache.
You may also notice the strategies.cacheFirst function. Workbox takes a lot of the hard work out of writing your own caching logic. It comes with built-in caching strategies that you can mix and match depending on your own custom routes.
For example, you can choose from:
- Cache only
- Cache first, falling back to network
- Cache, with network update
- Network only
- Network first, falling back to cache
If you’d like to learn more about the different caching strategies support in Workbox, I recommend checking out this link for more information.
You can also choose to only cache certain HTTP response statuses. Here I am explicitly choosing 200 responses, but you could choose 404’s or other HTTP statuses depending on your needs.
Finally, and probably my favourite feature, is the ability to force the network to timeout after a certain amount of time using networkTimeoutSeconds. Using this is important because it ensures that if the network takes too long to respond, it will simply fallback and your user won’t be stuck waiting for a resource to load. This is also a great step forward in reducing Single Point of Failure in your web apps.
When it comes to debugging your service worker logic, it can be tricky at the best of times. If you include the development version of the Workbox library in your service worker, you’ll get detailed information logged to the console of your Developer Tools.
This debugging information can be pretty handy when you are left scratching your head why a resource keeps on getting cached! To disable the debugging, simply switch back to the production version of Workbox.
Offline Google Analytics
The first time I started experimenting with service workers and realised how easy it was to build offline web pages, I was blown away! If you have any of your own web apps that work offline, you might be interested in tracking how your users actually use your web app when they are without a network connection. Remember that without a network connection, analytics tools such as Google Analytics aren’t able to send offline usage.
However, Workbox includes a cool module called workbox-offline-analytics that ensures that any Google Analytics requests made while offline are saved using IndexedDB and retried the next time the service worker starts up.
To get started, add the following code to your service worker and include it before any other 'fetch' event handlers are defined.
That’s it! Your web app will now start pushing any Google Analytics requests made offline as soon as it regains a network connection.
If you’d like to experiment and see the code in this article in action, please head over to deanhume.github.io/typography/index.html to see this as a working example.
Whether you are looking to build a full blown PWA or simply use some of the service worker features of Workbox, you can mix and match and get started in no time. In this example, we’ve only looked at a few areas of the Workbox library, but if you’d like to learn more, I thoroughly recommend checking out the Workbox website, it is jam packed with useful examples to get you up and running. Building powerful web applications using service workers doesn’t have to be tough - Workbox takes all the hard work out of it for you!
A big thank you to Robin Osborne, Addy Osmani and the Google team for their help in reviewing this article!