Precaching with Workbox

Published on

Precaching is one of the most common things you'll do in a service worker, and Workbox offers lots of flexibility in how you can accomplish this important task, regardless of which one of Workbox's build tools you choose. In this guide, you'll learn how to precache assets using both generateSW and injectManifest, as well as which of these methods might be the best fit for your project.

Precaching with generateSW

generateSW is the easiest way to precache assets in Workbox. The big thing to remember about generateSW is that you are not writing your own service worker—you're asking Workbox to generate one for you. However, you can influence its behavior through a variety of configuration options.

generateSW does different things by default depending on which build tool you use. When using workbox-webpack-plugin, you don't have to specify any configuration options. By default, the plugin will precache everything webpack includes in its dependency graph and write a service worker named service-worker.js to the directory specified by output.path

On the other hand, if you use workbox-build or workbox-cli, only HTML, CSS and JavaScript assets read from the local filesystem will be precached by default. Configuration-wise, you have to specify swDest and the globDirectory option in the generateSW config for precaching to work. Chances are, you'll want to configure additional options affecting your service worker behavior as well, so take a look through the documentation.

Warning

If too many assets in your project are precached with the default settings, use one of the glob options to exclude resources in the generateSW configuration. When using workbox-webpack-plugin, consult the plugin's GenerateSW documentation to find out how to prevent unwanted assets from being precached, as its configuration differs from generateSW.

Precaching with injectManifest

Using injectManifest isn't as easy as using generateSW, but you're trading off ease of use for greater flexibility. Where generateSW handles the entire service worker generation for you, injectManifest takes a service worker you write as its source and injects a list of URLs to precache, while leaving the rest of your service worker as-is.

When you use injectManifest, you're responsible for wiring up precaching logic. When injectManifest examines your input service worker, it looks for a special self.__WB_MANIFEST variable and replaces it with the precache manifest. If this variable isn't present, injectManifest will throw an error.

If you need to change the string injectManifest looks for to something different than self.__WB_MANIFEST, you can do so by specifying the injectionPoint option in its configuration.

The list of entries in the precache manifest can be tweaked with additional configuration options.

Caution

Unlike generateSW, injectManifest won't automatically bundle the Workbox runtime for you! To see how to manage this in use cases that rely on injectManifest, check out the side-by-side comparison below.

Side-by-side comparison

Click on each of the tabs below to compare the usage of the generateSW and injectManifest methods:

Since generateSW generates a service worker, you only need to specify a configuration. Below is an example using workbox-build:

// build-sw.js
import {generateSW} from 'workbox-build';

generateSW({
swDest: './dist/sw.js',
globDirectory: './dist',
globPatterns: [
'**/*.js',
'**/*.css',
'**/*.svg'
]
});

The service worker can then be built on the command line with Node:

node build-sw.js

Since injectManifest requires a source service worker, a minimally viable example requires a source service worker file. If all that's needed is precaching, that input service worker might look something like this:

import {precacheAndRoute} from 'workbox-precaching';

precacheAndRoute(self.__WB_MANIFEST);

Note the self.__WB_MANIFEST string. This is a placeholder that Workbox replaces with the precache manifest. Below is a valid configuration for this use case:

// build-sw.js
import {injectManifest} from 'workbox-build';

injectManifest({
swSrc: './src/sw.js',
swDest: './dist/sw.js',
globDirectory: './dist',
globPatterns: [
'**/*.js',
'**/*.css',
'**/*.svg'
]
});

injectManifest is preferable if you have complex requirements, such as advanced routing, custom caching strategies, or other things that aren't covered by the options generateSW provides.

Caution

The above examples assume that you're in a Node environment that natively supports ES modules without a build step. In versions of node prior to version 16, you may have to set a flag to enable ES module support, or rely on CommonJS semantics using module.exports.

Conclusion

Precaching in Workbox is much simpler than if you had to manage precaching on your own, especially where versioned assets compiled by bundlers are concerned. However, precaching isn't the only thing you'll likely do in a service worker. As you proceed, you'll learn other techniques, such as runtime caching.

Published on Improve article

This site uses cookies to deliver and enhance the quality of its services and to analyze traffic. If you agree, cookies are also used to serve advertising and to personalize the content and advertisements that you see. Learn more about our use of cookies.