Service Workers Basics

Excerpt

Service Workers are another kind of worker scripts in the background. They can interesect any network requests for the given domain and path and can provide caching.

Use a secure server

Service Workers require using the https protocol. To create a key and certificate you can follow the instructions in the yesterdays story: 21 Key and certificate for https on localhost.

Then add these to your server and enable using https. For simple experiments you can use the `liveserver` but the demo here at github.io also works and you can at least follow the implementation.

Register

Service Workers are ^bound to a given domain (and path) and are not bound to a web page. They will continue executing even after navigating away from the domain.

Starting a Service Worker is done by registering a URL for a javascript file:


await navigator.serviceWorker.register('worker.js');
  

The script will be loaded and executed async and the events will happen. By using the navigator.serviceWorker object some methors are available to control the service in the background.

Implementing a Service Worker

In the javascript file you will setup the worker and listen to events. The following events are the most important:

install -- This event can be used for pre-loading or cleanup of the cache.

activate -- When the service worker is activated. You should call self.clients.claim(); to enable all actually running pages (including the current) page to use the service worker.

fetch -- This event will be used to inform about that the current page executes a fetch(). Here caching can be implemented.

Here is a basic Service Worker for strong caching of several files but not services:


// Service Worker implementation for caching static data
// of type *.htm, *.js', *.css', *.ico'
// bot not *.json or other services

const cacheName = 'pwa-v2';

const cacheFileTypes = new Set([
  'htm', 'js', 'css', 'ico', 'pdf'
]);

const cachePreloadFiles = [
  'advent2022.css',
  'advent2022.js'
];


self.addEventListener('install', (evt) => {
  console.log('sw:install...');
  evt.waitUntil(
    caches.open(cacheName)
      .then(cache => {
        console.log('sw:delete...');
        cache.delete('/favicon.ico');
        return (cache);
      })
      .then(cache => {
        console.log('sw:add...');
        return (cache.addAll(cachePreloadFiles));
      })
  );
});


self.addEventListener('activate', (_evt) => {
  console.log('sw:activated.');
  self.clients.claim();
});


// Try for a cached ressource and add response to the Cache.
async function tryAddCache(req) {
  console.log('try:', req.url);
  let response = await caches.match(req);

  if (response) {
    console.log('sw:fromCache', req.url);
  } else {
    console.log('sw:fetch', req.url);
    response = await fetch(req);
    const cl = response.clone();
    caches.open(cacheName)
      .then(cache => {
        console.log('sw:toCache', req.url);
        cache.put(req, cl);
      });
  }
  return response;
};


self.addEventListener('fetch', (evt) => {
  const req = evt.request;
  const url = new URL(evt.request.url);
  const path = url.pathname;
  console.log('sw:request', req.mode, path);

  const pos = path.lastIndexOf('.');

  // caching allowed ?
  if ((pos >= 0) && (cacheFileTypes.has(path.substring(pos + 1).toLowerCase()))) {
    const res = tryAddCache(req);
    console.log('sw:response', res);
    evt.respondWith(res);

  } else {
    // default fetch procedure...
  }
});


// End.
    

Implementation hints

This is only one step towards pwa applications but an important one.

To see registerend and running Service Workers in your browser open the url edge://serviceworker-internals/ (or similar). This list has some useful functionality to stop and unregister service workers. You may need while development.

Do not enable caching while you implement. It my hurt.

In edge://serviceworker-internals/ you can find the "inspect" button that can be used to start a debugger for a specific Service Worker and see the console output.

See Also

Tags

JavaScript