๐Ÿฌ Chapter 100: Capstone 3 โ€” High-Performance Multi-Page E-Commerce Platform & Master Graduation

Offline PWA Caching for E-Commerce

Engineering progressive web application (PWA) resilience with Service Worker cache strategies, Web App Manifest, CacheStorage, and offline Add-to-Cart mutation queues via IndexedDB.

LEARNING OBJECTIVES โŒต
  • Configure an installable Web App Manifest (manifest.json) with e-commerce display modes, adaptive maskable icons, and theme colors.
  • Implement dual Service Worker caching strategies: Cache-First for static assets (fonts, icons, critical CSS) and Stale-While-Revalidate for catalog data.
  • Build an offline fallback page (offline.html) served automatically when network connectivity drops during non-cached navigation.
  • Persist offline cart mutations in IndexedDB and trigger automatic background reconciliation when network connectivity is restored.
๐ŸŽฌ INTERACTIVE VISUAL PIPELINE Core Architecture Simulation
๐ŸŒ
1. Input
Directives & Tags
โš™๏ธ
2. Parse
Tokenizer & AST
๐ŸŒณ
3. Layout
Box Model & Flow
๐ŸŽจ
4. Render
GPU Paint & Composite
PHASE 1: INPUT & DIRECTIVES
Browser receives declarative markup stream, parsing tag tokens and initializing component state.

๐Ÿ“– The Mental Model & Story (Intuitive Foundation)

Imagine boarding a high-speed commuter train. You enter a subterranean tunnel where mobile cellular reception drops to zero bars.

  • In a fragile web application, clicking "Timepieces" displays the dreaded Google Chrome "No Internet Dinosaur" error screen. Your shopping cart disappears, and when the train emerges from the tunnel 10 minutes later, you have to start your entire session over.
  • In a resilient Progressive Web App (PWA), the storefront continues running seamlessly. You browse previously viewed timepieces, inspect high-res photos stored in local cache, adjust quantities in your slideout shopping drawer, and tap "Proceed to Checkout".

The application queues your checkout intent locally in an IndexedDB background mutation mailbox. The moment your phone reconnects to a 5G tower, the Service Worker awakens, syncs your cart payload with the payment API in the background, and displays a subtle notification: "Your order was securely transmitted!"

Offline resilience transforms a website from a fragile remote document into an installed, native-grade desktop and mobile retail experience.


Technical Deep Dive & Specifications

Service Worker Caching Strategies for E-Commerce

Not all web assets should be cached using the same strategy:

+----------------------------------------------------------------------------------------------------+
|                                SERVICE WORKER ROUTING ARCHITECTURE                                 |
+----------------------------------------------------------------------------------------------------+
|                                                                                                    |
|  [ Incoming Request (fetch) ]                                                                      |
|     โ”‚                                                                                              |
|     โ”œโ”€โ”€ 1. Static Assets (CSS, JS, Fonts, App Shell)                                               |
|     โ”‚      โ””โ”€โ”€ Strategy: CACHE-FIRST (Fallback to Network)                                         |
|     โ”‚          - Instant sub-50ms local disk delivery                                              |
|     โ”‚                                                                                              |
|     โ”œโ”€โ”€ 2. Catalog Products & PDP HTML                                                             |
|     โ”‚      โ””โ”€โ”€ Strategy: STALE-WHILE-REVALIDATE                                                    |
|     โ”‚          - Returns cached catalog instantly, then updates cache with fresh price/stock in BG  |
|     โ”‚                                                                                              |
|     โ”œโ”€โ”€ 3. Dynamic Mutations (Checkout / Payment / Cart API)                                       |
|     โ”‚      โ””โ”€โ”€ Strategy: NETWORK-ONLY (Fallback to IndexedDB Queue)                                |
|     โ”‚          - Bypasses HTTP cache to prevent duplicate financial transactions                   |
|     โ”‚                                                                                              |
|     โ””โ”€โ”€ 4. Offline Fallback Catch                                                                  |
|            โ””โ”€โ”€ Serves offline.html if HTML navigation request fails while offline                  |
+----------------------------------------------------------------------------------------------------+

Strategy Comparison Matrix

Asset Class Service Worker Strategy Cache Invalidation Trigger Failure Mode
App Shell (HTML/CSS/JS) Cache-First Service Worker version bump (CACHE_VERSION = 'v2') Loads previous shell
Product Media (Images) Cache-First with LRU eviction Cache size quota / TTL (e.g. 50 items max) Uses placeholder
Catalog Listings Stale-While-Revalidate Background network fetch on each navigation Serves cached snapshot
Checkout API POST Network-Only + IndexedDB Queue Network online event (window.addEventListener('online')) Queued locally

๐Ÿ’ป Interactive Code Playground

Starter Code: Production Web App Manifest (manifest.json)

Production Service Worker (sw.js)

Production Offline Fallback Page (offline.html)

Line-by-Line Code Breakdown

  • Lines 7โ€“16 (manifest.json): Configures standalone PWA installation modes ("display": "standalone"), matching browser theme bars with the luxury dark aesthetic ("theme_color": "#0a0a0c").
  • Lines 17โ€“28 ("purpose": "maskable"): Supplies adaptive maskable icons that Android and iOS automatically crop into circular or squircle launcher badges.
  • Lines 31โ€“38 (sw.js Pre-caching): Pre-populates the cache during the install phase, guaranteeing instant availability of the application shell before first use.
  • Lines 41โ€“52 (caches.delete()): Removes outdated cache versions during the activate event lifecycle, preventing device storage bloat.
  • Lines 63โ€“76 (request.mode === 'navigate'): Detects full HTML page navigations. If the network drops, it serves the cached page or automatically renders offline.html.

Expected Browser Render Output


SYS: ACTIVE
HULL: 98%
CORE: STABLE
NET: ONLINE
HTML STARSHIP CODE TERMINAL playground.html
LIVE RENDER & DIAGNOSTICS CORE TEMP: 45ยฐC
INSPECTING DOM: VALID
TAGS: SCANNING...
{
  "name": "Aura Luxe Haute Horlogerie",
  "short_name": "Aura Luxe",
  "description": "High-performance handcrafted luxury timepieces and bespoke accessories.",
  "start_url": "/index.html?utm_source=pwa",
  "display": "standalone",
  "background_color": "#0a0a0c",
  "theme_color": "#0a0a0c",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any"
    },
    {
      "src": "/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ],
  "categories": ["shopping", "lifestyle"],
  "shortcuts": [
    {
      "name": "View Timepieces",
      "url": "/catalog.html?category=timepieces",
      "icons": [{ "src": "/icons/shortcut-watch.png", "sizes": "96x96" }]
    },
    {
      "name": "Shopping Bag",
      "url": "/catalog.html?open=cart",
      "icons": [{ "src": "/icons/shortcut-cart.png", "sizes": "96x96" }]
    }
  ]
}
const CACHE_VERSION = 'aura-luxe-v1';
const STATIC_CACHE = `${CACHE_VERSION}-static`;
const DYNAMIC_CACHE = `${CACHE_VERSION}-dynamic`;

const STATIC_PRECACHE = [
  '/',
  '/index.html',
  '/catalog.html',
  '/checkout.html',
  '/offline.html',
  '/css/critical.css',
  '/js/store.js'
];

// 1. Install Event: Pre-cache Application Shell
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(STATIC_CACHE).then((cache) => {
      return cache.addAll(STATIC_PRECACHE);
    }).then(() => self.skipWaiting())
  );
});

// 2. Activate Event: Clean up legacy caches
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((keys) => {
      return Promise.all(
        keys.map((key) => {
          if (key !== STATIC_CACHE && key !== DYNAMIC_CACHE) {
            return caches.delete(key);
          }
        })
      );
    }).then(() => self.clients.claim())
  );
});

// 3. Fetch Event: Multi-tier routing strategies
self.addEventListener('fetch', (event) => {
  const { request } = event;
  const url = new URL(request.url);

  // Ignore cross-origin API and chrome extensions
  if (request.method !== 'GET' || !url.origin.includes(self.location.origin)) {
    return;
  }

  // Strategy A: HTML Navigation (Stale-While-Revalidate with Offline Fallback)
  if (request.mode === 'navigate') {
    event.respondWith(
      fetch(request)
        .then((networkResponse) => {
          const clone = networkResponse.clone();
          caches.open(DYNAMIC_CACHE).then((cache) => cache.put(request, clone));
          return networkResponse;
        })
        .catch(() => {
          return caches.match(request).then((cachedResponse) => {
            return cachedResponse || caches.match('/offline.html');
          });
        })
    );
    return;
  }

  // Strategy B: Static Assets & Media (Cache-First)
  event.respondWith(
    caches.match(request).then((cachedResponse) => {
      if (cachedResponse) return cachedResponse;

      return fetch(request).then((networkResponse) => {
        if (!networkResponse || networkResponse.status !== 200) {
          return networkResponse;
        }
        const clone = networkResponse.clone();
        caches.open(DYNAMIC_CACHE).then((cache) => cache.put(request, clone));
        return networkResponse;
      });
    })
  );
});
+---------------------------------------------------------------------------------------------------------+
| [STANDALONE PWA WINDOW - NO BROWSER CHROME]                                                             |
+---------------------------------------------------------------------------------------------------------+
|                                                                                                         |
|                                                  ๐Ÿ“ก                                                     |
|                                       YOU'RE CURRENTLY OFFLINE                                          |
|                                                                                                         |
|       Your internet connection is temporarily unavailable. Previously viewed collections                |
|       and your shopping bag are saved locally.                                                          |
|                                                                                                         |
|                                    [ Check Connection & Retry ]                                         |
|                                                                                                         |
+---------------------------------------------------------------------------------------------------------+

๐Ÿ‹๏ธ Hands-On Exercise

๐ŸŽฏ The Challenge: Build an Offline Add-to-Cart Sync Queue using IndexedDB

Instructions:

  1. Initialize an IndexedDB object store named offline_cart_mutations.
  2. When the user clicks "Add to Bag" while navigator.onLine === false, store the product mutation object with a timestamp.
  3. Listen for window.addEventListener('online', syncOfflineQueue).
  4. When connectivity returns, read the pending mutations from IndexedDB, transmit them to the backend API, clear the store, and notify the user via #live-announcer.

๐Ÿ Starter Code Sandbox

โš ๏ธ Common Pitfalls

  1. Caching POST/PUT Financial Transactions in Service Workers: Caching API responses for payment authorizations. Financial transactions must always be network-only to prevent duplicate billing charges.
  2. Forgetting to Bump CACHE_VERSION During Deployments: Updating your HTML/CSS on the server but leaving const CACHE_VERSION = 'v1' in sw.js. Clients will be trapped on stale cached assets indefinitely.
  3. Omitting purpose: "maskable" Icons: Supplying only raw square PNG icons. Modern mobile OS launchers will render unsightly white borders around the app icon.

๐Ÿ’ก Pro Tips

  1. Call self.skipWaiting() and self.clients.claim(): During Service Worker installation, invoking skipWaiting() activates the new worker immediately, preventing users from getting stuck on legacy cached code until all tabs are closed.
  2. Use Background Sync API (registration.sync.register): On supported browsers, the Background Sync API executes offline sync jobs even if the user closes the browser before the network reconnects.

๐Ÿ“Œ Key Takeaways

  • A valid manifest.json enables installability, standalone display, and home-screen presence.
  • Apply Cache-First for static assets and Stale-While-Revalidate for catalog pages.
  • Always serve an offline.html fallback when navigation requests fail without network connectivity.
  • Store offline mutations (cart adds/updates) in IndexedDB and synchronize when online events fire.
  • Never cache non-idempotent payment or checkout API calls.
  • --
โญ LEARN: HTML ๐ŸŒŸ โš”๏ธ QUIZ BATTLE ARENA // ACTIVE
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 1 / 3

Why is the Stale-While-Revalidate caching strategy ideal for product catalog pages?

Question 1 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 2 / 3

What is the purpose of the purpose: "maskable" property in the Web App Manifest icon array?

Question 2 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP
3x
STREAK!
BONUS ACTIVE
COMBO
? Question 3 / 3

Which client-side storage API should be used to queue offline cart actions and complex product objects?

Question 3 / 3 Topic: HTML Fundamentals
00:45 REMAINING
XP REWARD
+250 XP