Skip to content

Service Workers

Jonathan Lee edited this page May 26, 2018 · 4 revisions

Overview

To allow Malasakit to run offline, the site backend has been designed to serve essentially static pages, with most of the data storage and rendering logic delegated to the client. This design allows service workers to cache pages and static files, which are then served when the client is offline.

At the time of this writing, service workers are a relatively new technology intended replace the deprecated AppCache standard, so not all browsers may support this feature. For offline field tests, Google Chrome for Android platforms is recommended.

When a device first connects to Malasakit, a service worker script is installed and caches a predetermined list of pages and files. The script then monitors outgoing GET requests, and serves the requested files from the cache when network connectivity is not available. The purpose of a service worker is to execute JavaScript independent of any page, so the script will run in the background even when the Malasakit site is closed. Whenever connectivity is available, the cache should be refreshed with the latest set of pages and files.

To determine whether a service worker was successfully installed on a device, disable the device's network connection, then reload the site. The desired page should appear even without a connection.

Developing with Service Workers

Service workers can be finicky to test and debug. Because they are only registered once and run in the background, they must be manually unregistered and reloaded every time a change is made. This can be done by navigating to chrome://serviceworker-internals, where a service worker can be unregistered by clicking "Unregister". Additionally, clicking "Inspect" will bring up a debug console for the service worker.

Service worker internals interface

JavaScript Promises

The service worker API is implemented on top of the promises API. In short, a Promise represents a delayed computation. Each Promise can be passed callbacks that will be called upon the promise's resolution.

For more information, see the promises API specification,

Service Worker Registration

A service worker must be called from other JavaScript running in a page. For this reason, a sw-bootstrap.js script is loaded with every page and calls a sw.js script that contains the caching logic.

Service Worker Installation

The service worker script (sw.js, in this case) should have an event listener bound to the install event. Upon the event firing, the passed-in callback should open the cache (in a promise), then add all desired resources to the cache. Each resource is uniquely identified in the cache by the URL path and parameters the resource was requested from.

Service Worker Fetching

The script should have an additional event bound to the fetch event. This event will fire whenever a request is made on a page in the domain, even for non-GET methods. Non-GET methods should be ignored (some methods, such as the POST method, cannot even be cached).

In this app, we are using the network first, then cache design. This means that the when a page makes a request, the service worker will first attempt to pull the most up-to-date resources from the server. Cached resources are only served when the request fails (due to a bad connection). An available but intermittent connection may result in several seconds of delay before the request times out and the service worker falls back to using the cache.

Service Worker Security

For security reasons, a service worker cannot request any resources outside of its own scope, as defined by its URL path. For example, if the script's URL is /pcari/sw.js, it can only request other resources that also are in /pcari/, such as /pcari/resource1.html or /pcari/static/resource2.html. Therefore, Malasakit serves the service worker script as a template from the URL_ROOT (a special case so that the script has jurisdiction over all other pages).

Browsers also demand that service workers be served over encrypted HTTPS (secure HTTP), and will refuse to run service workers served through an insecure protocol. LetsEncrypt is a good place to start for obtaining a certificate.

Additional References