The #ChromeDevSummit site is live, happening Nov 12-13 in San Francisco, CA
Check it out for details and request an invite. We'll be diving deep into modern web tech & looking ahead to the platform's future.

Workbox

What is Workbox SW?

The workbox-sw module provide an extremely easy way to get up and running with the Workbox modules and simplifies the loading of the Workbox modules and offers some simply helper methods.

You can use workbox-sw via our CDN or you use it with a set of workbox files on your own server.

Using Workbox SW via CDN

The easiest way to start using this module is via the CDN. You just need to add the following to your service worker:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.1/workbox-sw.js');

With this you’ll have the workbox namespace in your service worker that will provide access to all of the Workbox modules.

workbox.precaching.*
workbox.routing.*
etc

There is some magic that happens as you start to use the additional modules.

When you reference a module for the first time, workbox-sw will detect this and load the module before making it available. You can see this happening in the network tab in DevTools.

Workbox Libraries Loading in DevTools

These files will be cached by your browser making them available for future offline use.

Using Local Workbox Files Instead of CDN

If you don’t want to use the CDN, it’s easy enough to switch to Workbox files hosted on your own domain.

The simplest approach is to get the files via workbox-cli's copyLibraries command or from a GitHub Release, and then tell workbox-sw where to find these files via the modulePathPrefix config option.

If you put the files under /third_party/workbox/, you would use them like so:

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

workbox.setConfig({
  modulePathPrefix: '/third_party/workbox/'
});

With this, you’ll use only the local Workbox files.

Avoid Async Imports

Under the hood, loading new modules for the first time involves calling importScripts() with the path to the corresponding JavaScript file (either hosted on the CDN, or via a local URL). In either case, an important restriction applies: the implicit calls to importScripts() can only happen inside of a service worker's install handler or during the synchronous, initial execution of the service worker script.

In order to avoid violating this restriction, a best practice is to reference the various workbox.* namespaces outside of any event handlers or asynchronous functions.

For example, the following top-level service worker code is fine:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.1/workbox-sw.js');

// This will work!
workbox.routing.registerRoute(
  new RegExp('\.png$'),
  workbox.strategies.cacheFirst()
);

But this code could be a problem if you have not referenced workbox.strategies elsewhere in your service worker:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.1/workbox-sw.js');

self.addEventListener('fetch', (event) => {
  if (event.request.url.endsWith('.png')) {
    // Oops! This causes workbox-strategies.js to be imported inside a fetch handler,
    // outside of the initial, synchronous service worker execution.
    const cacheFirst = workbox.strategies.cacheFirst();
    event.respondWith(cacheFirst.makeRequest({request: event.request}));
  }
});

If you need to write code that would otherwise run afoul of this restriction, you can explicitly trigger the importScripts() call outside of the event handler by using the workbox.loadModule() method:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.1/workbox-sw.js');

// This will trigger the importScripts() for workbox.strategies and its dependencies:
workbox.loadModule('workbox-strategies');

self.addEventListener('fetch', (event) => {
  if (event.request.url.endsWith('.png')) {
    // Referencing workbox.strategies will now work as expected.
    const cacheFirst = workbox.strategies.cacheFirst();
    event.respondWith(cacheFirst.makeRequest({request: event.request}));
  }
});

Alternatively, you can create a reference to the relevant namespaces outside of your event handlers, and then use that reference later on:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/3.6.1/workbox-sw.js');

// This will trigger the importScripts() for workbox.strategies and its dependencies:
const {strategies} = workbox;

self.addEventListener('fetch', (event) => {
  if (event.request.url.endsWith('.png')) {
    // Using the previously-initialized strategies will work as expected.
    const cacheFirst = strategies.cacheFirst();
    event.respondWith(cacheFirst.makeRequest({request: event.request}));
  }
});

Force Use of Debug or Production Builds

All of the Workbox modules come with two builds, a debug build which is contains logging and additional type checking and a production build which strips the logging and type checking.

By default, workbox-sw will use the debug build for sites on localhost, but for any other origin it’ll use the production build.

If you want to force debug or production builds you set the debug config option.

workbox.setConfig({
  debug: 
});

Skip Waiting and Clients Claim

Some developers want to be able to publish a new service worker and have it update and control a web page as soon as possible, skipping the default service worker lifecycle.

If you find yourself wanting this behavior, workbox-sw provides some helper methods to make this easy:

workbox.skipWaiting();
workbox.clientsClaim();