What is the service worker?

A service worker is a script that your browser runs in the background, separate from a web page, opening the door to features that don't need a web page or user interaction. They already include features like push notifications and background sync.

– Google web developer documentation

What does the service worker do in ScandiPWA?

ScandiPWA makes use of the service worker to cache requests on the client-side.

  1. When a resource is first requested, the service worker caches (saves) the response
  2. This response is persisted even if the page is closed and reopened another day
  3. The next time that same resource is requested, the service worker responds with the cached request, which is instantaneous

<aside> ➡️ The service worker cache does not expire by default. Expiration needs to be configured manually – and images, for example, are configured to cache the 50 latest entries, forgetting the rest.

</aside>

How can I customize the caching behavior?

The current caching behavior is implemented in src/service-worker.js. It registers several cache routes, each with its own caching behavior:

<aside> ➡️ Document (HTML page) requests are only served from cache if a user is offline.

</aside>

How does the registerRoute work?

The registerRoute takes two arguments:

<aside> ➡️ Note: Often, instead of manually defining functions, you will use helpers. For example, the first argument can also be a regular expression, and the second argument can be one of the strategies provided by workbox strategies. What are workbox strategies?

</aside>

Where can I find the official registerRoute documentation?

How can I add an additional cache route?

To add a new cache rule:

  1. Override the src/service-worker.js file by copying it into your theme
  2. Add a new registerRoute call
  3. Make sure the match function only matches the files you want to cache
  4. Implement the desired caching strategy in the second argument

<aside> ➡️ Check the existing rules as examples!

</aside>

How can I avoid caching a file?

To avoid caching a file that is currently cached:

  1. Override the src/service-worker.js file by copying it into your theme
  2. Identify which registerRoute call is matching the file
  3. Modify the match logic to not match your file

How can I disable the "new version" popups?

For some projects, you might want to change the behavior of the "a new version is available" popups.

What is the "a new version is available!" popup?

The main problem with caching resources is that the cached version may become outdated when the resource is updated.

If the service worker detects that it has cached an old version of the page, it will prompt the user to refresh the page. This is necessary because the updated version can only be fetched when the page is refreshed.

In some cases, you may wish to change the default behavior of the version updates.

<aside> ➡️ How is the "new version" detection implemented? When a new build is available, there is also a new service worker. The new service worker replaces the old one – and the controllerchange event tells us that there has been a service worker update. When there is a new service worker, we know that there's also possibly other new content!

</aside>

Default behavior

By default, the user has a choice if they want to update immediately or not. If they choose to not refresh the page, they will continue using the old version

Pros:

Cons:

This is implemented in the NewVersionPopup component (where can I find this code?). When a new version is detected, a popup is shown:

componentDidMount() {
    const { showPopup, goToPreviousHeaderState, device } = this.props;

    // ...

    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.addEventListener('controllerchange', () => {
            showPopup({
                title: __('New version available!')
            });

            // ...
        });
    }
}

Option A: Automatic refresh

Instead of displaying a popup that asks the user to refresh the page, you can automatically refresh it whenever there is an update

Pros:

Cons:

To implement this, override the NewVersionPopup component.

scandipwa override component NewVersionPopup

After copying the original componentDidMount function to override it, remove the code that displays the notification, and instead immediately refresh:

componentDidMount() {
    // ...

    if ('serviceWorker' in navigator) {
        navigator.serviceWorker.addEventListener('controllerchange', () => {
            window.location.reload();
        });
    }
}

Option B: Update on the next load

Instead of displaying a popup, the cache is invalidated. For the current page visit, the old version will be still used. However, the new version will be fetched when the user visits the page the next time.

Pros:

Cons:

Override the componentDidMount function to do nothing:

componentDidMount() {}

Tutorials:

How to invalidate old service workers?