Menu Sheet Overlay
Search Sheet

Service Workers

    What is a service worker? #

    A service worker is a JavaScript program that can be loaded into a browser for a variety of uses, most significantly as a local proxy for HTTP requests. It runs separately from any page, and is persistent between visits to the associated site. Each service worker is loaded for a scope, which consists of a specific URL path and any sub-path of that path. For our purposes, the worker scope is almost always an entire domain. The worker is said to control its scope, and has full control over:

    The worker has access to local caches, which it can use to store responses for any request it controls. These caches can then be used offline, or in preference to network requests, in a configurable way.

    Service workers are a key element in Progressive Web Apps, and are required for several features in Google’s definition of a PWA. These include:

    Mobify uses a single combined service worker for PWA Messaging and offline/homescreen features.

    Browser support #

    Service worker support began to appear in browsers in early 2015, and was first implement by Google in Chrome. As of March 2017, the browser support for service workers is:

    This does not include any iOS browsers, including Chrome and Firefox for iOS, due to the lack of support in the underlying engine. Not all browsers that support service workers allow all features to be used. In particular, Messaging may only work on a subset of these browsers.

    Server requirements for service worker #

    The service worker, once loaded, has complete control over the page, independent of the server. Thus, there are stringent requirements on loading the service worker, to minimize the possibility of a malicious service worker being loaded for a site. These requirements are

    Once the worker script is loaded, it is able to load other scripts from other secure locations, including from other origins. This chain-loading functionality is very useful in Mobify’s worker design, as we will see below.

    Loading Mobify’s service worker #

    Since the worker script must be deployed to the site it will be used on, we get maximum flexibility if that script is as simple as possible. For Mobify Progressive Web builds, the worker script is just a ‘loader’, intended to be deployed once and left unchanged. It then loads the main body of the worker from the Mobify CDN, where it is stored alongside all the other bundle assets.

    In addition to the requirements above for all service workers, this pattern requires additional conditions to ensure that the worker is updated as new versions are deployed. Browsers will attempt to auto-update each service worker every 24 hours, but will only update if the main worker script has changed contents. In our case, the main worker script is the worker loader, which does not change, so we need to do additional work to update the worker.

    Every time a user with a service worker-compatible browser visits a site with a Mobify service worker, the page will attempt to re-register the worker, with a query parameter that depends on the current build ID. This will update the worker if the URL has changed (meaning a new build is available), and do nothing if the URL is the same (since the contents of that URL are the same).

    The requirements for the deployment of the Mobify service worker loader are therefore:

    Service worker cache structure #

    The Mobify service worker currently uses four caches, each with their own expiration policy:

    Assets that are necessary for offline mode must be stored in the bundle cache, so that they will not expire or be evicted before the offline mode is triggered. This is mostly a concern for users who have used the add-to-homescreen feature.

    Service worker code structure #

    The service worker is structured as a set of event handlers that are registered for the various service worker events. Three events are relevant to our application:

    The bulk of the worker’s work is done in fetch handlers. Other handlers support Messaging (push, pushSubscriptionChange, notificationclick and message).

    Building a worker using the SDK #

    The SDK, as of version 0.14.1, includes the main body of the Mobify service worker. The worker script in the project can import the worker function from progressive-web-sdk/dist/worker/main and call it to register all of the standard event handlers. It creates and manages the caches described above. The generated project extends the SDK worker to include Messaging support by loading an additional script via the Messaging CDN.

    This function takes a configuration object with few parameters that are used to configure the caching and the handling of URLs. They are:

    The function returns an object of the form:

        isDebug,    // the worker should run with debug logging
        toolbox     // the sw-toolbox module used by the worker

    Other worker code that manages extra caches (such as the Messaging service worker) may also use the toolbox reference.

    Android service worker notes #

    When testing a feature on Android which requires a secure origin, you may run into errors with the service worker. Even though localhost is whitelisted, you will still have to access your bundle via IP address (of your computer), and that isn’t considered a secure origin.

    To get around this, set up port forwarding in Chrome:

    1) Connect your Android device to your computer via USB.

    2) Go to chrome://inspect/#devices in Chrome on your computer.

    3) Click on the Port forwarding… button.

    4) Add a new entry with a Device port of 8443 and Local address of localhost:8443.

    5) Select the Enable port forwarding check box.

    The Android device will now forward its localhost requests to your computer, which will be serving your PWA bundle.