Build a PWA using Workbox
In this article, we will cover how to build a simple news app as Progress Web App (PWA), configure services worker for caching strategies, and offline support using Workbox. The app will simply display a list of random news headlines using NewsAPI and will cache the content so that it can be used without the network.
Workbox is a set of libraries and Node modules that make it easy to cache assets and take full advantage of features used to build Progressive Web Apps.
In case you are new to PWA and would like to learn what is PWA and why we need it, I suggest taking a quick look at this article where the author explains in detail the features and benefits of implementing PWA. In a nutshell, PWAs uses service workers to offer users extra functionalities such as working offline, push notifications, and device hardware access.
A service worker, written in JavaScript, is like a client-side proxy and puts you in control of the cache and how to respond to resource requests. By pre-caching key resources, you can eliminate the dependence on the network, ensuring an instant and reliable experience for your users.
Let’s get started
Lets being by creating an empty PWA app using Monaca CLI.
Monaca CLI is the full stack development tool for hybrid apps. It is compatible with Cordova CLI and makes the development much easier and faster.
Or you can clone from my GitHub repo…
To view the app, let’s open your favorite browser and navigate to http://localhost:8080. If port 8080
is already taken by another application, the port number can be changed within the package.json
file.
Why Workbox?
When previewing the launched app, from the above section, you will notice that it shows This is a PWA template for Monaca App
and that it is already PWA-compliant. What makes it PWA-compliant is that the app already equips the manifest.json
and service-worker.js
.
Since the app is already PWA-compliant, you might question why we need Workbox or how to use it?
Workbox lets you trade complexity for flexibility.
Well, I’m glad you asked. Workbox is a flexible well-defined PWA library that wraps the boilerplate code with methods that developers can use to implement service worker functionality. Out-of-box, it is production-ready with features such as precaching, runtime caching, caching strategies, request routing, etc. As you may know, implementing the service worker is the heart of a PWA. If implemented correctly, the web application could be faster and reliable; but if implemented incorrectly, it can potentially lead to a disaster. As is it said, service workers come with great power, but with great power comes with a cost and complexity.
Non-Workbox vs Workbox
To explain the differences between non-Workbox and Workbox, we are going to compare by coding. Let’s say we want to implement a caching strategy in which the latest resources is not vital to the current application state. Simply put, if there’s a cached version available which will be loaded first while it fetches the latest version and saves it to cache for next time usage (see the picture below for more detail).
Without Workbox, the following code below is an example of how to implement the illustration above in the service worker.
Now, with workbox…
It turns out that the caching behavior that we want from Workbox is called the StaleWhileRevalidate strategy. To implement the same functionality as our illustration, the few lines below can archive this.
I have also added one more option which set the cache expiration to 30 minutes so that the content stored in the cache is not too old. Imagine if we had to implement this without Workbox, it would definitely require more effort.
Start Coding
Now that you are convinced and have no questions. Let’s actually start coding.
Obtain the apiKey
First, we will be implementing a simple feature that fetched a list of headline articles when the app is loaded. We will be using NewsApi, so let’s quickly create a free account and obtain the authentication key (apiKey).
Fetching the news
- Open the
main.js
file under thewww/script
directory and write the following code:
Don’t forget to replace your obtained apiKey from the registration in the
main.js
at line 1.
2. Let’s load the main.js
script inside the index.html
.
3. Add a simple style sheet to light up the room.
To save you time, you can checkout tag 2.0.1
to get all changes.
Again, to view the app run monaca preview
if you have installed monaca
or run npm run dev
from the project directory.
You might need to clear the browser storage (cache storage, unregister service worker) to get the latest result.
As you can see in the above gif file, I’m using Google Chrome to view the app. First, the app displays a list of random articles when it’s loaded. Then I simulate the offline mode by navigating to Developer Tools’ Application
Tab → Service Workers → Offline. Once we refresh the browser, the app displays nothing as we don’t cache any news.
Offline support using Workbox
Next, we will implement caching strategies and offline support for our News App.
Workbox CLI
Since we are going to use Workbox API, let’s first get started by installing Workbox CLI as devDependencies by running the following command.
npm install workbox-cli --save-dev
workbox-cli wraps the workbox-build module, and provides an easy way of integrating Workbox into a command line build process, with flexible configurations.
There are two modes (generateSW and injectManifest) we can use with Workbox CLI, but in this article, we will use the injectManifest as it provides more control and flexibility to configure the service worker. In this mode, we need to create two more files — the source file of service worker and workbox configuration file.
service-worker-src.js: the source file of the service worker. It is where most of the code resides. Let’s create service-worker-src.js
under the project directory and paste the code below.
We have just configured three runtime caches:
- Style sheet: any files (requests) ending with
.css
is cached for one week. - Image: any files (requests) ending with
png|svg|jpg|jpeg
is cached for one week. - News API: any requests containing
https://newsapi.org/v2/top-headlines
is cached for 30 minutes.
Once the response is cached, we can view the app without the network connection (offline mode).
The last line workbox.precaching.precacheAndRoute([])
will be replaced by the list of precache assets configured in workbox.conf.js
.
In this example, for caching, we are using the:
- CacheFirst strategy to cache runtime images and style sheets
- StaleWhileRevalidate strategy to cache runtime News API response.
There are many options for caching strategies that Workbox provides out-of-the-box. You can research the other options more here to find out what fits your needs.
workbox.conf.js: the Workbox configuration file containing the path of the service worker’s source and compiled file and precache configuration. So, let’s create workbox.conf.js
under the project directory and paste in the following code.
For simplicity purpose, we just precache almost everything including style sheet files, HTML files, javascript files, and images located under the www
directory.
Go Offline
Finally, to compile and generate the service worker file, we need to run npx workbox injectManifest workbox-config.js
. Also, we need to run npm run dev
to view the app. To save us some time, let’s create a few simple npm scripts that will generate the service worker and launch the app.
If it’s too much to follow, don’t worry. You can checkout master
branch to get all the changes.
To view the app, let’s run monaca preview
or npm run monaca:preview
if you haven’t install monaca.
Conclusion
In this tutorial, we’ve seen how to use Workbox to configure Service Worker for precaching, runtime caching strategies, and offline support. Workbox provides the best approach for implementing production-ready code with little effort. It helps us to configure service worker properly so that the app is fast and reliable. If you’re a fan of PWA and haven’t tried Workbox yet, I strongly suggest you try at least once. I am sure Workbox will grow on you as it did for me. Hope you find this useful and gives you more reasons to develop PWAs.