A related codelab explains how to integrate service worker into an existing application and how to make it work offline. In this codelab, we'll retrace those steps but this time we'll use a tool called sw-precache to add offline functionality with only six lines of code. It's never been easier to add service worker support to an existing app, and we'll show you how in this codelab.
With the code downloaded, the following instructions describe how to build and start testing the Airhorner app.
Check out the code-lab
branch to get the starting version of the app.
$ git checkout code-lab
You can now run the site using either your favorite HTTP server or by using Python. This command sequence starts a web server running on localhost port 3000:
$ cd app $ python -m SimpleHTTPServer 3000
Open the site in Chrome and you should see a page like this:
Make sure your speakers are on, click the horn and it should make a fairly noticeable sound.
Now kill the server (ctrl-c in the command line). This simulates the network going offline. Then reload the site in the browser. It should show you an error message somewhat like this one:
This fails because our app doesn't yet have offline support, and that's exactly what we'll add in this codelab. But rather than the service worker code by hand, we're going to use the sw-precache
module to generate it and make our lives easier.
As you may recall from the Offline codelab, in order to add offline functionality to a web app, you need to complete the following steps:
sw.js
in this example.index.html
file to register your service worker.The tool we're going to use in this codelab, sw-precache
, is a Node.js module that automatically handles step 1 for you. It magically builds the right event handlers for you so you don't need to write any of the code that goes in sw.js
. But we'll take a look at the generated code and make sure we understand what it's doing.
This project uses gulp
as its build management tool. The package.json
file defines our Node.js package requirements. Install all of the package dependencies listed in package.json
by running the following command:
$ cd .. # go back to top-level directory $ npm install
Now install the sw-precache
module by running the following npm
command (depending on how Node.js and npm are installed, you may or may not need to use the sudo prefix):
$ npm install --save-dev sw-precache
A quirk of gulp is that you typically need to have a global instance of it installed as well as the local instance, so run one more command to complete the setup:
$ npm install -g gulp
Now we can use the gulp
command to build our project but first we need to create a gulp task that uses the sw-precache
module to generate our sw.js
file. Add the following code at the bottom of your gulpfile.js
:
gulp.task('generate-service-worker', function(callback) { var path = require('path'); var swPrecache = require('sw-precache'); var rootDir = 'app'; swPrecache.write(path.join(rootDir, 'sw.js'), { staticFileGlobs: [rootDir + '/**/*.{js,html,css,png,jpg,gif}'], stripPrefix: rootDir }, callback); });
For more information about the sw-precache
API, check the project page on Github. This code tells the swPrecache module to write a file at sw.js
, which arranges to cache all objects in this app ending with extensions js
, html
, css
, png
, jpg
, and gif
.
Now run gulp generate-service-worker
. You should see output like the following:
$ gulp generate-service-worker [11:56:22] Using gulpfile ~/airhorn/gulpfile.js [11:56:22] Starting 'generate-service-worker'... Total precache size is about 75.87 kB for 11 resources. [11:56:22] Finished 'generate-service-worker' after 49 ms $
This process generates a new sw.js
file in the app directory of your project.
Because sw-precache
is a build-time code generation tool, it has direct access to all your local resources, and can efficiently calculate the hash of each to keep track of when things change. It uses those changes to trigger the appropriate service worker lifecycle events and re-downloads only modified resources, meaning that updates are small and efficient, without requiring the developer to manage versioning.
The service worker code generated by sw-precache
will cache and serve the resources that you configure as part of your build process. For mostly static sites, you can have it precache every image, HTML, JavaScript, and CSS file that makes up your site. Everything will both work offline, and load fast on subsequent visits without any extra effort. For sites with lots of dynamic content, or many large images that aren't always needed, precaching a subset of your site often makes the most sense.
You can combine sw-precache
with one of the service worker "recipes" or techniques outlined in the offline cookbook to provide a robust offline experience with sensible fallbacks—e.g. when a large, uncached image is requested offline, serve up a smaller, cached placeholder image instead. You can also use wildcards to precache all of the resources that match a given pattern—there's no list of files or URLs that you have to manually maintain.
Add the following <script>
tag to the bottom of your index.html
file to register your service worker:
<script>
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js').then(function() {
console.log("Service Worker Registered");
});
}
</script>
The above snippet checks to see if the browser supports service workers, and if it does, calls the register
method, which returns a Promise. After the registration is completed, the browser will resolve the Promise and calls the function in the .then()
clause. (Note: this happens asynchronously.)
This is a very simple service worker registration snippet. From the main page, in addition to registering your service worker, you also have the opportunity to listen for service worker lifecycle events. For example, you could display a message to your users saying "Hey, something's been updated in the background, please refresh this page."
You can see a more complete, sophisticated implementation of this sort of service worker lifecycle management code here.
You now have everything you need to convert your airhorn app into an offline airhorn app. Let's now test that claim by running the site using either your favorite HTTP server or by using Python. This command sequence starts a web server running on localhost port 3000:
$ cd app $ python -m SimpleHTTPServer 3000
Open the site in Chrome and you should see a page like this:
Turn up your speakers, click the horn and it should make the now familiar airhorn sound.
Open chrome://serviceworker-internals/
in Chrome. This will show you a list of all the registered service workers, which you can use to verify your service worker has indeed properly registered.
Now kill the server (ctrl-c in the command line). This simulates the network going offline. Then reload the site in the browser and you should see the same page you saw when the server was running. The airhorn should also work, just as it did before.
Give a little honk of the air horn. You've just offlined your airhorner app with only six lines of code!
npm
, gulp
, and the sw-precache
modulesw-precache
to auto-generate service worker event handlers, which, along with six lines of JavaScript code, added offline functionality to the airhorner appsw-precache
to use: Service Worker in Production