How to install Service Worker and implement PWA in Magento 2 ?

This is an example of work with Service Worker in our practice. We will show you the process of registration and its setup.

Registration of Service Worker

To connect Service Worker there's a need in an entry point and in Magento 2 that is the Index.html. The following code should be added to the root in the Javascript file of your project. If it's possible, it initializes the Service Worker that you've created. This code checks if there is a Service Worker in the browser and if yes - connects it.

if (process.env.NODE_ENV === 'production' && 'serviceWorker' in navigator) {
    window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js').then();
    });
}

Basic Service Worker setup

The key where all cache for this Service Worker stores:

const CACHE_NAME = 'pwa';

Don't forget to create the files and cache directories of your project for the offline mode. Otherwise, after the finishing of the browser session, the Service Worker ends (it's usually called termination) and won't remember the necessary information. More theory about Service Worker here: What are Service Workers PWA?.

const urlsToCache = [
    '/',
    '/assets/**.*',
    '/bundle.css',
    '/bundle.js',
    '/favicon.ico',
    '/index.html',
];

If Service Worker is installed, this function won't start even when you restart the browser until you delete Service Worker or reset the browser cache:

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(CACHE_NAME).then((cache) => {
            return cache.addAll(urlsToCache);
        })
    );
});

This function works as a gateway, it gets to everything that comes from the browser and transmits this data to the server:

self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((resp) => {
            return resp || fetch(event.request).then((response) => {
                let responseClone = response.clone();

                if (event.request.method === 'GET' && event.request.url.indexOf('http') === 0) {
                    caches.open(CACHE_NAME).then((cache) => {
                        cache.put(event.request, responseClone);
                    });
                }

                return response;
            });
        }).catch(() => {
            return caches.match('/assets/logo.png');
        })
    );
});

Each time the browser starts, this function is triggered. In this instance, it checks if the keys match the current and past Service Worker. If the keys don't match, it clears all of them except the current one. This is mainly needed to update Service Worker and to clear extra information in the browser about the work of previous Service Worker.

self.addEventListener('activate', (event) => {
    const cacheKeysList = [CACHE_NAME];

    event.waitUntil(
        caches.keys().then((keyList) => {
            return Promise.all(keyList.map((key) => {
                if (cacheKeysList.indexOf(key) === -1) {
                    return caches.delete(key);
                }
            }));
        })
    );
});

We hope that was helpful and interesting for you. If you have any questions you may ask them on our social media our social media.

Cheers!