1. Welcome
In this lab, you'll take website with an existing service worker and convert it to using Workbox. This is the second in a series of companion codelabs for the Progressive Web App workshop. The previous codelab was Going Offline. There are six more codelabs in this series.
What you'll learn
- Convert an existing Service Worker to use Workbox
- Add an offline fallback to a PWA
What you should know
- Basic HTML and JavaScript
What you will need
- A browser that supports Service Workers
2. Get Set Up
Start by either cloning or downloading the starter code needed to complete this codelab:
If you clone the repo, make sure you're on the pwa03--workbox
branch. The zip file contains the code for that branch, too.
This codebase requires Node.js 14 or higher. Once you have the code available, run npm ci
from the command line in the code's folder in order to install all of the dependencies you'll need. Then, run npm start
to start the development server for the codelab.
The source code's README.md
file provides an explanation for all distributed files. In addition, the following are the key existing files you'll be working with throughout this codelab:
Key Files
service-worker.js
- Application's service worker fileoffline.html
- Offline HTML to use when a page isn't available
3. Migrate to Workbox
Looking at the existing service worker, precaching looks like it can be broken down into two steps:
- Cache relevant files during Service Worker install
- Serve those files again with a Cache Only strategy
The index.html
file and the /
route both still make sense to precache, as this web app's HTML isn't going to change much, but the other files, like the CSS and JavaScript, may change and we don't really want to need to go through the whole Service Worker lifecycle every time they do. Additionally, the current service worker only takes into account a subset of our CSS and JavaScript, we want all of it covered. Caching these items with a Stale While Revalidate strategy makes more sense; quick response that can be updated in the background as needed.
Precaching revisited
Migrating to Workbox, we don't need to keep any of the existing code, so delete everything in service-worker.js
. In the previous lab, we set up this Service Worker to be compiled, so we can use ESModule Imports here to bring in Workbox from its NPM modules. Let's start by revisiting precaching. In service-worker.js
, add the following code:
import { warmStrategyCache } from 'workbox-recipes';
import { CacheFirst } from 'workbox-strategies';
import { registerRoute } from 'workbox-routing';
import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { ExpirationPlugin } from 'workbox-expiration';
// Set up page cache
const pageCache = new CacheFirst({
cacheName: 'page-cache',
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
new ExpirationPlugin({
maxAgeSeconds: 30 * 24 * 60 * 60,
}),
],
});
warmStrategyCache({
urls: ['/index.html', '/'],
strategy: pageCache,
});
registerRoute(({ request }) => request.mode === 'navigate', pageCache);
Explanation
To get precaching set up for /index.html
and /
, there are five modules to pull from. While that may seem like a lot, this code is much more powerful than the previous code written.
It starts by setting up a new Cache First caching strategy, chosen instead of a Cache Only strategy to allow for other pages to be added to the cache as needed. A name is given to it, page-cache
. Workbox strategies can take a number of plugins that can affect the lifecycle of saving and retrieving content from the cache. Here, two plugins, the Cacheable Response plugin and the Expiration plugin, are used to ensure only good server responses are cached, and that each item in cache will get flushed after 30 days.
Next, the strategy's cache gets warmed with /index.html
and /
using the warm strategy cache Workbox recipe. This will add those items to this cache during the service worker's install event.
Finally, a new route is registered. Any request that's a page navigation will be managed by this Cache First strategy, either pulling from the cache or the network and then caching the response.
Caching assets
With route precaching sorted, it's time to re-implement caching for the site's assets; it's CSS and JavaScript. To do so, first add StaleWhileRevalidate
to your workbox-strategies
import, then add the following code to the bottom of your Service Worker:
// Set up asset cache
registerRoute(
({ request }) => ['style', 'script', 'worker'].includes(request.destination),
new StaleWhileRevalidate({
cacheName: 'asset-cache',
plugins: [
new CacheableResponsePlugin({
statuses: [0, 200],
}),
],
}),
);
Explanation
This route starts by determining if the type of request is a style, a script, or a worker, corresponding to CSS, JavaScript, or Web Workers. If it is, it uses a Stale While Revalidate strategy, trying to serve from the cache first, falling back to the network if not available, while trying to update the version in cache from the network if possible. Like the page strategy, this strategy will only cache good responses.
4. Add offline fallback
With the original service worker migrated to Workbox, there's one more thing that needs to be done to prevent the PWA from crashing when offline; adding an offline fallback.
Offline fallbacks can be set for anything that may not be available when offline: pages, fonts, CSS, JavaScript, images, etc.... At a minimum, a page fallback should be set for all PWAs so if a user navigates to a page not in cache, they'll stay within your app's context.
Workbox recipes provides an offline fallback recipe that can be used to do just this! To use it, first add offlineFallback
to your workbox-recipes
import, then add the following code to the bottom of your Service Worker:
// Set up offline fallback
offlineFallback({
pageFallback: '/offline.html',
});
Explanation
The offline fallback recipe sets up a Cache Only strategy that gets warmed with the provided fallbacks. It then sets up a Workbox default catch handler, catching any failed routing requests (if there's nothing in the cache and something can't be reached on the network), pulling the content of the relevant files from the cache and returning it as content as long as the request continues to fail.
5. Congratulations!
You've learned how to take use Workbox to set up caching strategies for routes and provide an offline fallbacks for your PWA.
The next codelab in the series is IndexedDB