Service Worker is a progressive technology, and in this article, I'll show you how to take your frontend app and make it available offline for humans who are using a modern browser while leaving humans with unsupported browsers unaffected.

So first what are Service Workers and how do they help us make offline web apps and sites? Well, service workers are a new browser feature that allows us to have fine grain control of our websites and apps even when they are offline. A service worker is basically a JavaScript file that runs outside of the standard browser window context. With a registered service worker script we can have fine grain control over things such as the browser cache and the network requests.

With this new control we can intercept browser requests and alter the browser cache for when we are offline. For this example we will cache an offline article and serve cached article when the browser is offline instead of the standard browser offline error.

Creating a Service Worker

The first step is to create a new GET /sw.js endpoint. Remember to put it in the top level of the endpoint browser.

Make sure Authentication profile is set to [none], Content type is set to JS and that there is no action set. Service workers can intercept every outbound request from your page. Add the following to the template to do so:

(function () {
  var CACHE = 'cache-and-update';

  self.addEventListener('install', function installEventListenerCallback() {
    return self.skipWaiting();
  });

  self.addEventListener('activate', function installEventListenerCallback() {
    return self.clients.claim();
  });

  self.addEventListener('fetch', function (event) {
    let request = event.request;
    if (request.method !== 'GET' || !/^https?/.test(request.url)) {
      return;
    }

    event.respondWith(cachedOrRemote(request));
    event.waitUntil(update(event.request));
  });

  function cachedOrRemote(request) {
    return caches.open(CACHE).then(function (cache) {
      return cache.match(request).then(cached_response => {
        if (cached_response) {
          return cached_response;
        } else {
          return update(request);
        }
      });
    });
  }

  function update(request) {
    return new Promise(function (resolve, reject) {
      caches.open(CACHE).then(function (cache) {
        fetch(request).then(function (response) {
          cache.put(request, response.clone());
          resolve(response);
        }).catch(reject);
      });
    })
  }
}());

Our service worker file creates an offline file cache to store the pages and assets that we visit for offline usage.

Registering the Service Worker

Next, let's register our Service Worker in our layout file. Add the following code to your layout template (probably called something like 'bootstrap_layout'). This script will check if the browser supports service workers and if so register the service worker. This is a great behavior as our site will work just fine if the browser doesn’t support service workers.

<script>(function () {
  'use strict';

  let SUCCESS_HANDLERS = [];
  let ERROR_HANDLERS = [];

  if ('serviceWorker' in navigator) {
    navigator.serviceWorker.register('/sw.js', { scope: '/' }).then(function (reg) {
      let current = Promise.resolve();

      for (let i = 0; i < SUCCESS_HANDLERS.length; i++) {
        current = current.then(function () {
          return SUCCESS_HANDLERS[i](reg);
        });
      }

      return current.then(function () {
        console.log('Service Worker registration succeeded. Scope is ' + reg.scope);
      });
    }).catch(function (error) {
      let current = Promise.resolve();

      for (let i = 0; i < ERROR_HANDLERS.length; i++) {
        current = current.then(function () {
          return ERROR_HANDLERS[i](error);
        });
      }

      return current.then(function () {
        console.log('Service Worker registration failed with ' + error);
      });
    });
  }

}());</script>

Testing the Service Worker

Now we are ready for testing. In order to test this functionality, you can use the built-in Developer Tools in Chrome. Start by navigating to your web page, and once the Service Worker has installed head over to the Network tab and change the throttling to Offline. If you refresh the page, you should see your offline page!

Did this answer your question?