Masterbook/Chapter 71• 5 min read
View Raw Code on GitHub

What are Service Workers and PWA concepts?

What Are Service Workers and PWA Concepts?

Progressive Web Apps (PWAs) bridge the gap between traditional web pages and native applications. They use modern browser APIs to deliver reliable, installable, offline-capable experiences. At the heart of a PWA is the service worker, a script that runs separately from the main page and controls how the app interacts with the network.

What is a service worker?

A service worker is a background script registered by your application. Once installed and activated, it sits between your app and the network, intercepting network requests and deciding how to respond. Because it runs independently of any web page, it can respond to events even when your site is not open. Service workers can:

  • Cache assets and data so your app can work offline or with poor connectivity.
  • Serve cached responses immediately while fetching updated data in the background.
  • Manage background tasks like push notifications or background sync.
  • Act as a proxy to modify or log requests and responses.

Service workers have no direct access to the DOM. They communicate with pages via the postMessage API and must be served over HTTPS for security.

Lifecycle

Service workers follow a predictable lifecycle:

  1. Registration - Your page calls navigator.serviceWorker.register('/sw.js') to start installing a worker. Registration happens on page load and must succeed before the service worker can control pages.
  2. Installation - The service worker downloads and runs the installation code. You typically pre-cache core assets in the install event so they are available offline.
  3. Activation - After installation, the service worker activates. It clears old caches and takes control of pages within its scope. New versions wait to activate until all pages using the old version are closed, so updates don't disrupt the current users.
  4. Idle/Fetch - Once active, the worker listens for events such as fetch, push and sync. It decides how to respond to network requests—either from the cache, network or a combination.

Only one service worker can control a given scope (directory path) at a time. When you update your worker script, the browser downloads the new version, installs it in the background and waits to activate until the old version has no more clients.

Registering and using a service worker

Here's a minimal example that installs a service worker and caches an asset:

// main.js - register the service worker
if ("serviceWorker" in navigator) {
    window.addEventListener("load", () => {
        navigator.serviceWorker.register("/sw.js").catch((err) => {
            console.error("Service worker registration failed:", err);
        });
    });
}

// sw.js - service worker
const CACHE_NAME = "pwa-cache-v1";
const ASSETS = ["/", "/styles.css", "/index.html", "/logo.png"];
self.addEventListener("install", (event) => {
// Pre-cache core assets
        event.waitUntil(
        caches.open(CACHE_NAME).then((cache) => cache.addAll(ASSETS))
    );
});
self.addEventListener("activate", (event) => {
// Remove old caches
    event.waitUntil(
    caches.keys().then((keys) => Promise.all(keys.filter((key) => key !== CACHE_NAME).map((key) => caches.delete(key)))));
});
self.addEventListener("fetch", (event) => {
// Respond with cache first, then network
    event.respondWith(
    caches.match(event.request).then((cached) => {
return ( cached || fetch(event.request).then((response) => {
// Update the cache for next time
return caches.open(CACHE_NAME).then((cache) => {
cache.put(event.request, response.clone());
return response;
});
})
);
})
);
});

In the example, the service worker caches static assets during installation and serves them from the cache when offline. It also updates the cache whenever a fresh version is downloaded.

PWA concepts beyond service workers

  1. Web App Manifest - A JSON file (manifest.webmanifest) describing your app's name, icons, theme colors and how it should appear when installed on a user's home screen. It allows users to add your PWA to their device.
  2. HTTPS - PWAs require secure contexts. Browsers block service worker registration on insecure origins to prevent man-in-the-middle attacks.
  3. Responsive design - PWAs should adapt to different screen sizes and device capabilities.
  4. Installability - When a PWA meets criteria (served over HTTPS, has a manifest, registered service worker and user engagement), the browser prompts users to install the app.
  5. Offline and connectivity independence - Caching and local data storage enable the app to function even when the network is unavailable.

Real-world analogy

Imagine a restaurant that uses a waiter to handle orders. Instead of every customer shouting orders to the kitchen (the network), the waiter (the service worker) intercepts orders, writes them down, and checks if some meals are already prepared (cached). If the meal is ready, the waiter serves it immediately. Otherwise, the waiter sends the order to the kitchen and serves it when it's done. If the restaurant closes (the user goes offline), the waiter can still serve meals that were prepared earlier.

Common pitfalls and best practices

  • Scope placement: Place your service worker file at the top of the directory you want it to control. A worker registered at /sw.js controls the entire site, while /blog/sw.js only controls files under /blog.
  • Updates not activating: New versions wait until all pages using the old worker are closed. Use self.skipWaiting() in the install event and clients.claim() in the activate event to take control immediately, but beware that this can refresh pages unexpectedly.
  • Caching too much: Cache only assets that are necessary for offline use. Uncontrolled caching can fill storage or serve stale content.
  • Offline fallbacks: Provide fallback pages or messages when resources cannot be fetched.

Practice questions

Conceptual questions

  1. What is a service worker and how does it differ from a regular web worker?
  2. Describe the lifecycle of a service worker. Why doesn't a new service worker take control immediately after installation?
  3. How does a Progressive Web App benefit from a service worker? List at least three capabilities.
  4. Why must service workers be served over HTTPS?
  5. Explain how caching strategies (cache-first, network-first, stale-while-revalidate) work. When would you use each?

Coding exercises

  1. Write a script to register a service worker and log whether registration succeeded or failed.
  2. Modify the example service worker so that it serves a fallback HTML page (offline.html) when the requested page is not available offline and the network is down.
  3. Implement a caching strategy where the service worker always fetches resources from the network first and falls back to the cache if the network request fails.
  4. Add code to your service worker to display a push notification when receiving a push event. How would you handle the user clicking on the notification?