PWA — Cheat Sheet

Tags: pwa, service-worker, cache-api, web-manifest, indexeddb, offline, workbox

Level: intermediate

TL;DR: Progressive Web Apps combine web reach with native app capabilities using Service Workers, Web App Manifests, and aggressive caching.

Key concepts

Service Workers act as programmable client-side network proxies running in background threads.

Web App Manifest is a JSON file defining app metadata, display modes, and icons for installation.

Cache Storage API provides programmatic caching for network requests and responses.

Service Worker lifecycle consists of registering, installing, activating, and fetching phases.

IndexedDB stores structured client-side data for complete offline capability.

Caching strategies determine how requests route between network and cache.

Background Sync API defers network requests until stable connectivity resumes.

Push API and Notification API enable background push notifications even when closed.

Web capabilities provide hardware access like file system, Bluetooth, and contacts.

Typical questions and ready answers

Q: How does a Service Worker differ from a Web Worker?R: I explain that both run off the main thread, but a Service Worker acts as a network proxy intercepting HTTP requests and controlling caching, whereas Web Workers handle CPU-intensive computations without request interception capabilities.

Q: What are the most common caching strategies and when do you use them?R: I use Cache-First for hashed static assets, Network-First for real-time dynamic data, and Stale-While-Revalidate for non-critical assets like avatars where immediate rendering and background updating work best.

Q: How do you handle Service Worker updates safely without breaking active client sessions?R: I avoid calling self.skipWaiting() automatically to prevent version mismatch across open tabs. Instead, I notify users with an "Update available" prompt that triggers activation and page reload upon user confirmation.

Q: Why does a Service Worker require HTTPS?R: Because it intercepts network traffic and can manipulate HTTP responses, making an unencrypted Service Worker vulnerable to man-in-the-middle attacks.

Pitfalls and common mistakes

Caching sw.js via HTTP cache headers prevents clients from receiving Service Worker updates.

Calling skipWaiting() blindly can crash active tabs running mismatched asset versions.

Forgetting that Service Workers run in a worker context without access to DOM or window.

Failing to clean up outdated caches during the activate event, exhausting browser quota.

Storing unbounded dynamic API responses in Cache Storage without size eviction policies.

Assuming background sync works across all iOS Safari versions due to partial WebKit support.

Snippets and commandsTypeScript

// Service Worker Registration
if ('serviceWorker' in navigator) {
  window.addEventListener('load', async () => {
    try {
      const registration = await navigator.serviceWorker.register('/sw.js', { scope: '/' });
      registration.addEventListener('updatefound', () => {
        const newWorker = registration.installing;
        newWorker?.addEventListener('statechange', () => {
          if (newWorker.state === 'installed' && navigator.serviceWorker.controller) {
            console.log('New update available');
          }
        });
      });
    } catch (error) {
      console.error('Service Worker registration failed:', error);
    }
  });
}

TypeScript

// sw.js: Stale-While-Revalidate Caching Strategy
const CACHE_NAME = 'app-cache-v1';

self.addEventListener('fetch', (event: FetchEvent) => {
  event.respondWith(
    caches.open(CACHE_NAME).then(async (cache) => {
      const cachedResponse = await cache.match(event.request);
      const networkFetch = fetch(event.request).then((networkResponse) => {
        if (networkResponse.ok) {
          cache.put(event.request, networkResponse.clone());
        }
        return networkResponse;
      });
      return cachedResponse || networkFetch;
    })
  );
});

JSON

// manifest.json
{
  "name": "Progressive Web App",
  "short_name": "PWA",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#0f172a",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

To review

[ ] Storage quota estimation and eviction policies via navigator.storage.estimate()

[ ] iOS Safari limitations on background sync and web push notifications

[ ] Workbox window integration and Precaching strategies

[ ] Periodic Background Sync API lifecycle and browser permission requirements

[ ] Navigation preload optimization for Service Worker start-up latency

References

MDN Web Docs: Progressive Web Apps

W3C Service Workers Specification

Google Chrome Developers: Workbox Documentation

web.dev: Learn PWA

Jarvis Interviews
Jarvis