Workbox is a new project from Google that makes service worker use-cases such as caching, background sync and queueing of analytics whilst offline easier to code.

"Workbox is a rethink [on] our previous service worker libraries and tools, sw-toolbox and sw-precache, and is designed to be more modular, flexible, and extensible."

As stated above, Workbox is a rethink on their old service worker libraries and tools. Personally I used sw-precache before but I found the generated service worker code it created difficult to read. Workbox fixes this (in my opinion) as its modular and much easier to reason with. Find a list of all the packages in Workbox here.

Workbox + Webpack

Yes! Workbox comes with official Webpack integration! Previously sw-precache had an unofficial project called sw-precache-webpack-plugin, so its nice that there is support out-of-the-box now.

Basic Configuration

yarn add --dev workbox-webpack-plugin

Add plugin to your webpack config.

import WorkboxPlugin from 'workbox-webpack-plugin'; // ... plugins: [ // ... new WorkboxPlugin({ globDirectory: './dist/', globPatterns: ['**/*.{html,js,css}'], swDest: './dist/service-worker.js' }) ]

Register the service worker in your JS code.

// register service worker if ('serviceWorker' in navigator) { navigator.serviceWorker.register('/service-worker.js'); }

Run your webpack-dev-server or alternative and you should notice any HTML, JS or CSS files served from dist are now cached in the service worker on repeat visits!

File Revisions

If you inspect your generated service-worker.js file you'll notice it's quite small in size (in comparison to sw-precache ). It will contain the file revisions and an import to workbox-sw where the actual work will happen.

Example output:

importScripts('workbox-sw.prod.v1.0.1.js'); /** * DO NOT EDIT THE FILE MANIFEST ENTRY * ... */ const fileManifest = [ { "url": "/main.css", "revision": "c751059c834d06d8a066535504616945" }, { "url": "/main.js", "revision": "dbe85ddb2050f016120d2e018a677b40" } ]; const workboxSW = new self.WorkboxSW(); workboxSW.precache(fileManifest);

The registered service worker will immediately return cached main.js and main.css files on repeat visits. However depending on the caching strategy used it will also check the revision hash for any changes and fetch and cache the new revisions in the background.

Advanced Configuration

More often that not, you'll need more control over what is cached, strategies used and custom code inside the server worker. You can do this by setting your own service worker and using the WorkboxSW object directly.

Here's part of a configuration I used for a server-side rendered React + Redux app. I did not output a HTML file to the dist folder so my cache was instead managed by routes instead.

Update webpack config to add swSrc which is a path to your own custom service worker. This now injects the manifest into your custom service worker and disables the generating of one.

import WorkboxPlugin from 'workbox-webpack-plugin'; // ... plugins: [ // ... new WorkboxPlugin({ globDirectory: './dist/', globPatterns: ['**/*.{html,js,css}'], swSrc: './src/client/service-worker.js', swDest: './dist/service-worker.js' }) ]

Add custom service worker file.

More example code from the official sites are available here and here.

importScripts('https://unpkg.com/workbox-sw@1.1.0'); // Create Workbox service worker instance const workboxSW = new WorkboxSW({ clientsClaim: true }); // Placeholder array which is populated automatically by workboxBuild.injectManifest() workboxSW.precache([]); // Register png files e.g. https://localhost:3000/images/1.png workboxSW.router.registerRoute(/\.png$/, workboxSW.strategies.networkFirst()); // Register example path e.g. https://localhost:3000/example workboxSW.router.registerRoute('/example', workboxSW.strategies.staleWhileRevalidate()); // Register express like route paths e.g. https://localhost:3000/list/one workboxSW.router.registerRoute('/list/:itemId', workboxSW.strategies.staleWhileRevalidate({ cacheName: 'cache-with-expiration', cacheExpiration: { maxEntries: 20, maxAgeSeconds: 120 } }) );

With this custom service worker you can start to control caching strategies and more at a granular level.

Setting clientsClaim to true here tells the service worker to take control when it has been activated. You can read more about clientsClaim here and here.

Copy workbox-sw from node-modules

If you don't want to use https://unpkg.com/workbox-sw@1.0.1 but instead use your local node-modules build file with your custom service worker you can do this.

yarn add --dev copy-webpack-plugin yarn add workbox-sw

Add the plugin to your webpack config.

plugins: [ // copy WorkboxSW production build file new CopyWebpackPlugin([ { from: require.resolve('workbox-sw'), to: 'workbox-sw.prod.js' } ]) // ... ]

Update your custom service worker file.

importScripts('workbox-sw.prod.js'); // ...

Conclusion

Workbox is great and looks like it will only get better! I'm not sure if it's being used widely in production yet. At time of writing it's in active development and there are lots of GitHub issues. However I'll be keeping a close eye on it for my future Progressive Web Apps.

PWA all the things ❤️.

References