2.2.2 Pwa Offline First
This skill defines the technical standards for building Progressive Web Apps that work reliably regardless of network conditions, install natively on devices, and pass all Lighthouse PWA audits.
1. Web App Manifest (manifest.json)
Goal: Ensure installability and native-like presentation on all platforms.
- Required Fields:
name, short_name, start_url, display (set to standalone), background_color, theme_color, icons (at minimum 192×192 and 512×512 PNG, include maskable purpose variant).
- Optional Enhancements:
description, categories, screenshots (for richer install UI on Android), shortcuts (app launcher shortcuts), share_target (to receive shared content).
- Scope: Set
scope to / or the app's root path. Ensure start_url falls within the declared scope.
- Validation: Test with Chrome DevTools → Application → Manifest panel. Verify installability criteria are met.
2. Service Worker Lifecycle
Goal: Reliable caching and seamless updates without stale content.
- Registration: Register the service worker in the app's entry point with
navigator.serviceWorker.register('/sw.js', { scope: '/' }). Wrap in a feature check.
- Install Event: Pre-cache the App Shell (HTML, CSS, JS, critical fonts, icons) during the
install event. Use cache.addAll() with a versioned cache name (e.g., app-shell-v2).
- Activate Event: Clean up old caches by iterating
caches.keys() and deleting any cache name that doesn't match the current version. Call clients.claim() to immediately take control.
- Update Strategy: Use
skipWaiting() cautiously. Prefer prompting the user with a "New version available — Refresh" banner triggered by the controllerchange event or a Broadcast Channel message from the new SW.
3. Caching Strategies
Goal: Select the right caching strategy for each resource type.
- Cache First (App Shell): HTML, CSS, JS bundles, fonts, icons. Serve from cache; update cache in background via
fetch and store the new response for the next load.
- Network First (API Data): Dynamic content, user data, real-time feeds. Try network; fall back to cached response if offline. Set a network timeout (~3 seconds) before falling back.
- Stale-While-Revalidate (Semi-Static Assets): Images, locale files, non-critical JSON configs. Serve cached version immediately; update cache in background.
- Network Only: Authentication endpoints, payment transactions, real-time WebSocket connections. Never cache sensitive operations.
- Cache Size Management: Implement LRU eviction for dynamic caches. Cap at a reasonable entry count (e.g., 50 API responses, 100 images).
4. Offline Data Persistence (IndexedDB)
Goal: Full offline functionality for data-heavy features.
- Database Design: Use IndexedDB (via
idb wrapper library for Promise-based API) for structured data. Create object stores with appropriate key paths and indexes.
- CRUD Operations: Implement complete Create, Read, Update, Delete operations with proper transaction handling (
readwrite for mutations, readonly for queries).
- Schema Versioning: Use
onupgradeneeded to handle database schema migrations. Never delete user data during upgrades — migrate it forward.
- Storage Quota: Check available storage with
navigator.storage.estimate(). Request persistent storage with navigator.storage.persist() if the app holds critical user data.
5. Background Sync & Offline Queue
Goal: Queue user actions taken offline and replay them when connectivity returns.
- Sync Registration: When a network request fails (e.g., form submission, data save), store the request payload in IndexedDB and register a
sync event with registration.sync.register('sync-pending-actions').
- Sync Handler: In the service worker's
sync event listener, read all pending actions from IndexedDB, replay them via fetch(), and delete them from the queue on success.
- Fallback: If Background Sync API is not supported, implement a polling-based fallback that checks
navigator.onLine and processes the queue on online events.
- Conflict Resolution: For multi-device sync scenarios, implement last-write-wins or timestamp-based merging logic on the backend.
6. Install Prompt Management
Goal: Maximize install rates with strategic prompt timing.
- Capture the Event: Listen for
beforeinstallprompt, prevent default, and store the event reference. Never show the browser's default prompt immediately.
- Custom Install UI: Display a custom install banner or button after the user demonstrates engagement (e.g., 2+ sessions, completed a key action). Use the stored event's
.prompt() method when the user clicks.
- Post-Install: Listen for
appinstalled event. Log the conversion. Hide the install prompt permanently. Optionally show a "Welcome to the app!" onboarding flow.
- iOS Handling: Detect iOS Safari via user agent. Show manual "Add to Home Screen" instructions since iOS does not support
beforeinstallprompt.
7. Lighthouse PWA Audit Targets
Goal: Every PWA must score 100 on the Lighthouse PWA audit.
- Installable: Valid manifest with required icons, registered service worker, served over HTTPS.
- Reliable: Pages load offline (at least a custom offline fallback page). Response time under 200ms from cache.
- Fast: First Contentful Paint < 1.8s. Largest Contentful Paint < 2.5s. Cumulative Layout Shift < 0.1. Time to Interactive < 3.8s.
- Engagement: Custom splash screen, theme color set, viewport configured, content sized to viewport, no horizontal scroll.
- Testing Cadence: Run Lighthouse in CI on every deploy. Block deploys that drop below target scores.
1---2name: pwa-offline-first3description: Service worker lifecycle, caching strategies, install prompts, offline data sync, IndexedDB patterns, Web App Manifest best practices, and Lighthouse scoring targets.4---56# 2.2.2 Pwa Offline First78This skill defines the technical standards for building Progressive Web Apps that work reliably regardless of network conditions, install natively on devices, and pass all Lighthouse PWA audits.910## 1. Web App Manifest (`manifest.json`)11**Goal:** Ensure installability and native-like presentation on all platforms.12* **Required Fields:** `name`, `short_name`, `start_url`, `display` (set to `standalone`), `background_color`, `theme_color`, `icons` (at minimum 192×192 and 512×512 PNG, include `maskable` purpose variant).13* **Optional Enhancements:** `description`, `categories`, `screenshots` (for richer install UI on Android), `shortcuts` (app launcher shortcuts), `share_target` (to receive shared content).14* **Scope:** Set `scope` to `/` or the app's root path. Ensure `start_url` falls within the declared scope.15* **Validation:** Test with Chrome DevTools → Application → Manifest panel. Verify installability criteria are met.1617## 2. Service Worker Lifecycle18**Goal:** Reliable caching and seamless updates without stale content.19* **Registration:** Register the service worker in the app's entry point with `navigator.serviceWorker.register('/sw.js', { scope: '/' })`. Wrap in a feature check.20* **Install Event:** Pre-cache the App Shell (HTML, CSS, JS, critical fonts, icons) during the `install` event. Use `cache.addAll()` with a versioned cache name (e.g., `app-shell-v2`).21* **Activate Event:** Clean up old caches by iterating `caches.keys()` and deleting any cache name that doesn't match the current version. Call `clients.claim()` to immediately take control.22* **Update Strategy:** Use `skipWaiting()` cautiously. Prefer prompting the user with a "New version available — Refresh" banner triggered by the `controllerchange` event or a Broadcast Channel message from the new SW.2324## 3. Caching Strategies25**Goal:** Select the right caching strategy for each resource type.26* **Cache First (App Shell):** HTML, CSS, JS bundles, fonts, icons. Serve from cache; update cache in background via `fetch` and store the new response for the next load.27* **Network First (API Data):** Dynamic content, user data, real-time feeds. Try network; fall back to cached response if offline. Set a network timeout (~3 seconds) before falling back.28* **Stale-While-Revalidate (Semi-Static Assets):** Images, locale files, non-critical JSON configs. Serve cached version immediately; update cache in background.29* **Network Only:** Authentication endpoints, payment transactions, real-time WebSocket connections. Never cache sensitive operations.30* **Cache Size Management:** Implement LRU eviction for dynamic caches. Cap at a reasonable entry count (e.g., 50 API responses, 100 images).3132## 4. Offline Data Persistence (IndexedDB)33**Goal:** Full offline functionality for data-heavy features.34* **Database Design:** Use IndexedDB (via `idb` wrapper library for Promise-based API) for structured data. Create object stores with appropriate key paths and indexes.35* **CRUD Operations:** Implement complete Create, Read, Update, Delete operations with proper transaction handling (`readwrite` for mutations, `readonly` for queries).36* **Schema Versioning:** Use `onupgradeneeded` to handle database schema migrations. Never delete user data during upgrades — migrate it forward.37* **Storage Quota:** Check available storage with `navigator.storage.estimate()`. Request persistent storage with `navigator.storage.persist()` if the app holds critical user data.3839## 5. Background Sync & Offline Queue40**Goal:** Queue user actions taken offline and replay them when connectivity returns.41* **Sync Registration:** When a network request fails (e.g., form submission, data save), store the request payload in IndexedDB and register a `sync` event with `registration.sync.register('sync-pending-actions')`.42* **Sync Handler:** In the service worker's `sync` event listener, read all pending actions from IndexedDB, replay them via `fetch()`, and delete them from the queue on success.43* **Fallback:** If Background Sync API is not supported, implement a polling-based fallback that checks `navigator.onLine` and processes the queue on `online` events.44* **Conflict Resolution:** For multi-device sync scenarios, implement last-write-wins or timestamp-based merging logic on the backend.4546## 6. Install Prompt Management47**Goal:** Maximize install rates with strategic prompt timing.48* **Capture the Event:** Listen for `beforeinstallprompt`, prevent default, and store the event reference. Never show the browser's default prompt immediately.49* **Custom Install UI:** Display a custom install banner or button after the user demonstrates engagement (e.g., 2+ sessions, completed a key action). Use the stored event's `.prompt()` method when the user clicks.50* **Post-Install:** Listen for `appinstalled` event. Log the conversion. Hide the install prompt permanently. Optionally show a "Welcome to the app!" onboarding flow.51* **iOS Handling:** Detect iOS Safari via user agent. Show manual "Add to Home Screen" instructions since iOS does not support `beforeinstallprompt`.5253## 7. Lighthouse PWA Audit Targets54**Goal:** Every PWA must score 100 on the Lighthouse PWA audit.55* **Installable:** Valid manifest with required icons, registered service worker, served over HTTPS.56* **Reliable:** Pages load offline (at least a custom offline fallback page). Response time under 200ms from cache.57* **Fast:** First Contentful Paint < 1.8s. Largest Contentful Paint < 2.5s. Cumulative Layout Shift < 0.1. Time to Interactive < 3.8s.58* **Engagement:** Custom splash screen, theme color set, viewport configured, content sized to viewport, no horizontal scroll.59* **Testing Cadence:** Run Lighthouse in CI on every deploy. Block deploys that drop below target scores.