Don't forget the Chrome Dev Summit, starting Monday at 10:00am (Pacific) and streaming live on YouTube. Schedule.

Lab: Offline Quickstart

Concepts: Offline Quickstart

Overview

This lab shows you how to add offline capabilities to an application using service workers.

What you will learn

  • How to add offline capabilities to an application

What you should know

  • Basic HTML, CSS, and JavaScript
  • Familiarity with ES2015 Promises

What you will need

  • Computer with terminal/shell access
  • Connection to the internet
  • A browser that supports service workers
  • A text editor

1. Get set up

If you have not downloaded the repository, installed Node, and started a local server, follow the instructions in Setting up the labs.

Open your browser and navigate to localhost:8080/offline-quickstart-lab/app.

If you have a text editor that lets you open a project, open the offline-quickstart-lab/app folder. This will make it easier to stay organized. Otherwise, open the folder in your computer's file system. The app folder is where you will be building the lab.

This folder contains:

  • images folder contains sample images
  • styles/main.css is the main cascading stylesheet for the app
  • index.html is the main HTML page for our sample site/application
  • service-worker.js is the service worker file (currently empty)

2. Taking the app offline

Let's create a service worker to add offline functionality to the app.

2.1 Cache static assets on install

Replace the TODO 2.1 comment in service-worker.js with the following code:

service-worker.js

var CACHE_NAME = 'static-cache';

var urlsToCache = [
  '.',
  'index.html',
  'styles/main.css'
];

self.addEventListener('install', function(event) {
  event.waitUntil(
    caches.open(CACHE_NAME)
    .then(function(cache) {
      return cache.addAll(urlsToCache);
    })
  );
});

Save the file.

Explanation

This code starts by defining a cache name, and a list of URLs to be cached. An install event listener is then added to the service worker. When the service worker installs, it opens a cache and stores the app's static assets. Now these assets are available for quick loading from the cache, without a network request.

Note that . is also cached. This represents the current directory, in this case, app/. We do this because the browser attempts to fetch app/ first before fetching index.html. When the app is offline, this results in a 404 error if we have not cached app/. They should both be cached to be safe.

2.2 Fetch from the cache

Replace TODO 2.2 in service-worker.js with the following code:

service-worker.js

self.addEventListener('fetch', function(event) {
  event.respondWith(
    caches.match(event.request)
    .then(function(response) {
      return response || fetchAndCache(event.request);
    })
  );
});

function fetchAndCache(url) {
  return fetch(url)
  .then(function(response) {
    // Check if we received a valid response
    if (!response.ok) {
      throw Error(response.statusText);
    }
    return caches.open(CACHE_NAME)
    .then(function(cache) {
      cache.put(url, response.clone());
      return response;
    });
  })
  .catch(function(error) {
    console.log('Request failed:', error);
    // You could return a custom offline 404 page here
  });
}

Save the script.

Explanation

This code adds a fetch event listener to the service worker. When a resource is requested, the service worker intercepts the request and a fetch event is fired. The code then does the following:

  • Tries to match the request with the content of the cache, and if the resource is in the cache, then returns it.
  • If the resource is not in the cache, attempts to get the resource from the network using fetch.
  • If the response is invalid, throws an error and logs a message to the console (catch).
  • If the response is valid, creates a copy of the response (clone), stores it in the cache, and then returns the original response.

2.3 Register the service worker

Replace TODO 2.3 in index.html with the following code:

index.html

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('service-worker.js')
  .then(function(registration) {
    console.log('Registered:', registration);
  })
  .catch(function(error) {
    console.log('Registration failed: ', error);
  });
}

Save the file.

Explanation

This code first checks that service worker is supported by the browser. If it is, the service worker that we just wrote is registered, beginning the installation process.

2.4 Test the app offline

Now our app has offline functionality. Save all files and refresh the app/ in the browser. You can check the cache and see that the HTML and CSS are cached from the service worker installation event.

Refresh the page again. This fetches all of the page's assets, and the fetch listener caches any asset that isn't already cached.

Stop the server (use Ctrl+c if your server is running from the command line) or switch the browser to offline mode to simulate going offline. Then refresh the page. The page should load normally!

Explanation

When our app opens for the first time, the service worker is registered, installed, and activated. During installation, the app caches the most critical static assets (the main HTML and CSS). On future loads, each time a resource is requested the service worker intercepts the request, and checks the cache for the resource before going to the network. If the resource isn't in the cache, the service worker fetches it from the network and caches a copy of the response. Since we refreshed the page and fetched all of its assets, everything needed for the app is in the cache and it can now open without the network.

Solution code

To get a copy of the working code, navigate to the solution folder.

Congratulations!

You now know the basics of adding offline functionality to an app.