Progressive web apps – offline web applications using service worker

Google documentation describes service workers as a way to bring features, typically reserved for native apps, to the web—such as offline experiences, background syncs, and push notifications. These functions depend on the technical backbone that service workers provide.

Think of a service worker like an assistant running in the background, capable of performing tasks that browsers normally wouldn’t handle. Unlike traditional browser features, service workers are designed to work asynchronously and operate independently of the webpage. They can access domain-wide events, such as network fetches, cache resources, and respond to network requests. This combination allows web apps to function offline, which has been one of the advantages native apps have had over web-based ones. With service workers, the web can now catch up, making web apps as versatile as native apps. In fact, service workers may even replace HTML5 Application Cache in the future. But there’s a catch—service workers are HTTPS-only.

One of the significant advantages of using service workers is how easily they allow web apps to load cached assets first, even before making a network request. This offline functionality, common in native apps, is a major reason people still prefer them. Here, service workers come to the rescue, solving the issue for web applications. This is why native apps are on their way out!

But are service workers universally supported?

Service workers were first drafted in May 2014. Since then, browser support has steadily increased. Now, major browsers like Chrome, Firefox, and Opera support almost all the main APIs, and Safari is considering adding service workers as part of its five-year plan. You can check the full compatibility status for various browsers.

Let’s walk through how to set up a service worker. The following code registers the service worker on your webpage. Once registered, you can begin running tasks using the worker. Note that the serviceWorker.js file should reside in the root directory of your application.

(function () {
    if ("serviceWorker" in navigator) {
        navigator.serviceWorker.register('serviceWorker.js', { scope: "./" }) // setting scope of sw
        .then(function(registration) {
          console.info('Service worker is registered!');
        })
        .catch(function(error) {
          console.error('Service worker failed ', error);
        });
    }
})();

Inside serviceWorker.js, you’ll find the install event, which fires when the service worker is installing itself. Here, we attach a callback to cache the array of files. The promise will resolve once the installation is complete.

let cacheName = 'res-1.0';

let files = [
    'js/bootstrap.min.js',
    'js/libraries.js',
    'css/bootstrap.min.css',
    'img/ajax-loader.gif',
    'img/dot.gif'
];

self.addEventListener('install', (event) => {
    event.waitUntil(
        caches.open(self.cacheName)
        .then((cache) => {
            return cache.addAll(files)
            .then(() => {
                console.info('All files are cached');
                return self.skipWaiting(); // Forces the waiting service worker to become active
            })
            .catch((error) =>  {
                console.error('Failed to cache', error);
            });
        })
    );
});

We also have a fetch event that triggers when resources are fetched over the network. The following code first checks if the file is available in the cache. If it is, it will return the cached version; otherwise, it fetches the file from the network.

self.addEventListener('fetch', (event) => {
    event.respondWith(
        caches.match(event.request).then((response) => {
            if (response) {
                return response; // return from cache
            }

            // fetch from network
            return fetch(event.request).then((response) => {
                return response;
            }).catch((error) => {
                console.error('Fetching failed:', error);
                throw error;
            });
        })
    );
});

To debug your service worker, open your webpage in Chrome. Chrome’s Developer Tools are perfect for troubleshooting. Go to the “Application” tab, select “Service Worker,” and you’ll see your service worker running.