Harnessing the Power of Service Workers: Building Offline-Ready Web Apps

Jitendra Kumar
Engineering @ Housing/Proptiger/Makaan
6 min readJun 12, 2024

In the dynamic world of web development, where user experience reigns supreme, having a web application that functions seamlessly even in offline mode is no longer a luxury but a necessity. Enter service workers — the unsung heroes behind the scenes, making this magic possible. In this blog post, we’ll delve into the world of service workers, exploring what they are, how they work, and how you can harness their power to supercharge your web applications.

What is a service worker ?

At its core, a service worker is a script that runs in the background of a web application, separate from the main JavaScript thread. It acts as a proxy between your web page and the network, enabling a host of powerful features such as offline functionality. This means that even if the user loses internet connection, the service worker can still serve cached content, providing a seamless offline experience.

How service worker caching is different than standard browser caching ?

  1. Location and Scope:

Service Worker: JavaScript files running in the background, separate from the main browser thread.

Browser Caching: Resources stored within the browser itself, part of the main browsing environment.

2. Control Over Network Requests:

Service Worker: Provides fine-grained control over network requests, allowing interception and customized handling.

Browser Caching: More passive, resources are stored and retrieved by the browser without direct developer intervention.

3. Offline Functionality:

Service Worker: Enables creation of offline experiences by caching and serving resources even when offline.

Browser Caching: Improves performance but doesn’t inherently provide offline functionality.

4. Persistence and Management:

Service Worker: Persistent and programmatically managed caches, controlled by developers.

Browser Caching: Managed by the browser, with limited developer control over cache lifecycle.

Where service worker data is stored ?

Service worker caching is stored in a separate storage called the “Cache Storage,” which is distinct from “Local Storage” and “Session Storage.” The Cache Storage is part of the Service Worker API and provides a way to store and manage cached responses (resources) separately from the browser’s regular HTTP cache. On the other hand, “Local Storage” and “Session Storage” are part of the Web Storage API and serve a different purpose. They are used to store key-value pairs as strings in the browser and are typically used for storing small amounts of data that need to persist across page reloads but are not intended for caching resources like CSS, JavaScript, or images.

Sample image below showing cached data with cache name DIGIPORT_COMMON under Cache Storage under Application tab :

Sample image showing cached data under Cache Storage with cache name DIGIPORT_COMMON

Understanding the lifecycle and flow of service workers is crucial before delving into how they’re utilized to make web applications offline :

A service worker has a lifecycle that includes several key events. These events define when the service worker is installed, activated, and how it handles fetch requests. Here’s an overview of the service worker lifecycle and how they are used:

  1. Registration :

Before you can use a service worker, it needs to be registered in your web application.

Typically, you register a service worker using JavaScript in your web page.

The service worker is then associated with a specific scope (the URL path where it has control).

2. Installation:

When a service worker is registered for the first time or when there are updates to the service worker file, it goes through an installation phase.

The install event is fired during this phase, allowing you to cache assets or perform other setup tasks.

3. Activation:

After installation, the service worker enters the activation phase.

The activate event is fired during activation, and it is commonly used for tasks like cache cleanup or managing the service worker’s versions.

4. Fetch Handling:

After activation, the service worker is ready to handle network requests. It intercepts fetch requests made by your web application and can respond with cached content or make network requests.

The fetch event is where you define how the service worker should respond to network requests.

5. Message event:

The message event is an important event in the context of service workers and web pages. It enables communication between a web page and a service worker, allowing them to exchange data and trigger actions. This event is typically used to send messages from a web page to a service worker or between different service workers.

Now that you’ve acquired sufficient insight into service workers, you’re ready to proceed with making your application offline :

Steps :

  1. Create a Service Worker File: Create a JavaScript file for your service worker, typically named sw.js. Place this file in the root directory of your web application.
  2. Register the Service Worker: In your web page’s JavaScript code, you need to register the service worker. You can register in your main HTML file or a separate JavaScript file. Here’s an example of how to register a service worker:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(function(registration) {
console.log('Service Worker registered with scope:', registration.scope);
})
.catch(function(error) {
console.error('Service Worker registration failed:', error);
});
}

3. Below is the sw.js file updated to include the service worker events, install and activate, along with the fetch event for cache-then-network policy:

const CACHE_NAME = 'MY-CACHE';
const FILES_TO_CACHE = [
'/index.html',
'/styles.css',
'/script.js',
'/image.jpg'
]; // this array may contain any cdn paths along with static assets

// Installation Event
self.addEventListener('install', (e) => {
console.log('ServiceWorker Install');
self.skipWaiting();
e.waitUntil(caches.open(CACHE_NAME).then((cache) => {
return cache.addAll(FILES_TO_CACHE);
}));
});

// Activation Event
self.addEventListener('activate', function(event) {
event.waitUntil(
// Get all cache keys
caches.keys().then(function(cacheNames) {
// Return a promise that resolves when all outdated caches are deleted
return Promise.all(
cacheNames.map(function(cacheName) {
// Check if the cache name is different from the current cache
if (cacheName !== CACHE_NAME) {
// If it is, delete the cache
return caches.delete(cacheName);
}
})
);
})
);
});

// Fetch Event
self.addEventListener('fetch', function(event) {
event.respondWith(
caches.match(event.request).then(function(response) {
// If response is found in cache, return it
if (response) {
return response;
}
// If response is not found in cache, fetch it from the network
return fetch(event.request).then(function(networkResponse) {
// Cache the fetched response for future use
caches.open(CACHE_NAME).then(function(cache) {
cache.put(event.request, networkResponse.clone());
});
// Return the fetched response to the page
return networkResponse;
}).catch(function(error) {
// Handle fetch errors, e.g., no internet connection
console.error('Fetch error:', error);
// Optionally, respond with a custom offline page
return caches.match('/offline.html');
});
})
);
});

4. Your web app is nearly prepared for offline functionality. It’s essential to note that if certain resources or network requests your app needs are requested before the service worker is registered, there’s an important step to consider.

To make sure everything works without a hitch (handling above problem), it’s a good idea to reload the page again once the service worker is registered for first time. This ensures that all the necessary resources ( static and cdn resources or network requests) your web app needs are cached properly for offline use. By doing this, you prevent any potential errors or missing resources, making sure your app works seamlessly offline without causing any trouble for users.

Advantages of using service worker for offline functionality :

  • Improved User Experience: Users can access your web app even in environments with poor or no internet connectivity, leading to higher engagement and satisfaction.
  • Faster Performance: By serving cached content, service workers can significantly reduce load times, providing a snappy experience for users.
  • Reduced Server Load: Caching resources locally reduces the number of requests sent to the server, resulting in lower server load and bandwidth usage.

Conclusion : Integrating service workers into your web application opens up a world of possibilities, from enhancing performance to enabling offline functionality. By understanding and leveraging the power of service workers, you can create web experiences that are faster, more reliable, and resilient, providing users with seamless access to your content and services, whether they’re online or offline. So, why wait? Start harnessing the potential of service workers today and take your web app to the next level!”

--

--