Skip to main content

๐Ÿ“ฑ PWA Architecture and Capabilities

A Progressive Web App is an ordinary website that has learned a few new tricks: it can be installed to the home screen, launch full-screen, work offline, and re-engage users with notifications โ€” all from the same URL you already ship. This lesson maps the moving parts so the two lessons that follow (service workers and offline-first) fit into a clear whole.

๐ŸŽฏ Learning Objectives

By the end of this lesson, you will be able to:

  • Explain what "progressive" means and how progressive enhancement underpins PWAs
  • Identify the three technical pillars โ€” HTTPS, the web app manifest, and service workers
  • Author a valid manifest.webmanifest and wire up an install prompt
  • Describe the app-shell and PRPL architecture patterns and when to use them
  • Audit a real PWA with Lighthouse and read the installability report

Estimated Time: 35โ€“45 minutes  โ€ข  Difficulty: Intermediate

Hands-on: Add a manifest and a custom install button to a plain web page, then verify it in Chrome DevTools.

In This Lesson

What Is a Progressive Web App?

A Progressive Web App (PWA) is a website built with a set of browser capabilities that let it feel like a platform app: it can be installed, run offline, and behave reliably on flaky networks. There is no PWA framework to install and no app store to submit to โ€” a PWA is a capability profile, not a new kind of project. Any React, Angular, Vue, or hand-written site can become one.

The word progressive comes from progressive enhancement: you build a baseline that works everywhere, then layer on advanced features for browsers that support them. A browser that lacks service workers still gets a working website; a modern one additionally gets offline support and installability.

๐Ÿ’ก A useful analogy: A PWA is like a hybrid car. On the open highway (a modern browser) it uses every system it has. When conditions get worse (an old browser, a dead network) it quietly falls back to the essentials and still gets you where you're going โ€” it never simply stops.

๐Ÿ“– Key Terms

Progressive enhancement: start from a functional baseline and add capabilities only where they're supported.

Installability: the browser's ability to add your app to the home screen or app launcher.

App shell: the minimal HTML/CSS/JS that renders your UI frame, cached for instant repeat loads.

The term was coined in 2015 by Alex Russell and Frances Berriman to name a pattern that was already emerging. Since then, companies from Twitter to Starbucks have shipped PWAs to cut load times and data usage while maintaining a single codebase for web and "app."

The Three Technical Pillars

Three requirements turn a site into an installable, offline-capable PWA. Miss any one and the browser will not offer to install it.

The three pillars of a PWA HTTPS provides a secure origin; the web app manifest describes how the app is installed; the service worker provides offline behavior. All three sit on top of a normal website. HTTPS Secure origin Required for SW Trust & integrity Manifest Name & icons Display mode Installability Service Worker Intercept fetches Cache resources Offline & push A normal, standards-based website (HTML ยท CSS ยท JavaScript)
Figure 1 โ€” The three pillars sit on top of an ordinary website. HTTPS is the security foundation, the manifest makes the app installable, and the service worker adds offline behavior.

1. HTTPS โ€” a secure origin

Service workers can intercept every request your page makes, so the browser only allows them on secure origins. In practice that means HTTPS in production (and http://localhost during development, which the browser treats as secure). HTTPS also protects the integrity of the code the browser caches.

2. The web app manifest

A small JSON file that tells the browser what to display when the app is installed โ€” its name, icons, colors, and how it should launch. Without it, there is nothing to install. We cover it in detail next.

3. The service worker

A background JavaScript file that acts as a programmable network proxy. It can serve cached responses when the network is down, sync data later, and receive push messages. This is the topic of the next lesson.

โš ๏ธ A manifest alone is not offline

A manifest makes an app installable, but an installed PWA with no service worker still shows the browser's offline error when the network drops. Offline reliability comes from the service worker's caching โ€” the manifest just controls how the app looks and launches.

The Web App Manifest

The manifest is a JSON file (conventionally manifest.webmanifest, though .json also works) linked from every page:

<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#2f3ba2">

A minimal but installable manifest needs a name, a start URL, a standalone display mode, and at least a 192px and a 512px icon (a maskable icon is strongly recommended so Android can crop it to the device's icon shape):

{
  "name": "Weather Now",
  "short_name": "Weather",
  "description": "Fast, offline-capable weather forecasts",
  "start_url": "/?source=pwa",
  "scope": "/",
  "display": "standalone",
  "background_color": "#3e4eb8",
  "theme_color": "#2f3ba2",
  "icons": [
    { "src": "/icons/icon-192.png", "sizes": "192x192", "type": "image/png" },
    { "src": "/icons/icon-512.png", "sizes": "512x512", "type": "image/png" },
    {
      "src": "/icons/icon-maskable-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable"
    }
  ]
}

๐Ÿ“– Key manifest fields

display โ€” standalone (no browser chrome, most common), fullscreen, minimal-ui, or browser.

start_url โ€” where the app opens from the home-screen icon; add a query param to measure launches in analytics.

scope โ€” the set of URLs the installed app "owns"; navigations outside it open in a browser tab.

theme_color โ€” tints the OS status bar and task-switcher card.

You do not have to hand-write eight icon sizes anymore. Modern builds generate them from a single source: Vite PWA and the Angular and CLI generators emit the manifest and icons for you. What matters is understanding what those fields do.

Installability & the Install Prompt

When a site meets the install criteria (HTTPS, a valid manifest, and โ€” on Chromium โ€” a registered service worker with a fetch handler), the browser fires a beforeinstallprompt event. Capturing it lets you show your own install button at a moment that makes sense, instead of the browser's default mini-banner.

let deferredPrompt = null;
const installButton = document.querySelector('#install-btn');

// The browser wants to show its install prompt โ€” intercept it.
window.addEventListener('beforeinstallprompt', (event) => {
  event.preventDefault();          // suppress the automatic mini-infobar
  deferredPrompt = event;          // stash it for later
  installButton.hidden = false;    // reveal our own button
});

installButton.addEventListener('click', async () => {
  if (!deferredPrompt) return;
  deferredPrompt.prompt();                       // show the native dialog
  const { outcome } = await deferredPrompt.userChoice;
  console.log(`User response: ${outcome}`);      // 'accepted' | 'dismissed'
  deferredPrompt = null;                          // it can only be used once
  installButton.hidden = true;
});

// Fires after a successful install (from your button OR the browser menu).
window.addEventListener('appinstalled', () => {
  installButton.hidden = true;
  console.log('PWA installed');
});

Console output after the user accepts

User response: accepted
PWA installed

โš ๏ธ iOS is different

Safari on iOS does not fire beforeinstallprompt. Users install a PWA manually via the Share menu โ†’ "Add to Home Screen." Detect installed/standalone mode with window.matchMedia('(display-mode: standalone)').matches and consider showing iOS users a short hint instead of an install button.

Capabilities Beyond the Browser

Once installed and backed by a service worker, a PWA unlocks capabilities that used to require a native app.

graph TD A["Installed PWA"] --> B["Offline access"] A --> C["Push notifications"] A --> D["Background sync"] A --> E["Home-screen launch"] B --> B1["Cached shell & data"] C --> C1["Re-engage users"] D --> D1["Retry queued requests"] E --> E1["Standalone, no browser UI"]
CapabilityWhat it enablesPowered by
Offline accessApp loads and functions with no networkService worker + Cache API
Push notificationsRe-engage users even when the app is closedPush API + service worker
Background syncDefer failed writes until connectivity returnsBackground Sync API + IndexedDB
InstallabilityHome-screen icon, standalone windowManifest
DiscoverabilityIndexed by search engines, shareable via URLIt is still the web

๐Ÿ’ก Why teams choose PWAs

Starbucks rebuilt its ordering flow as a PWA roughly 100ร— smaller than its native app while still working offline to browse the menu. Uber's PWA loads in seconds on 2G. The recurring win: one codebase, no app-store gatekeeping, and reach on devices where users will never install a native app.

Architecture Patterns

The app-shell model

Split your app into a shell โ€” the header, navigation, and layout that rarely change โ€” and the content that fills it. Cache the shell on first visit so subsequent loads paint instantly from the cache while fresh content streams in over the network.

graph LR A["First visit"] --> B["Download & cache shell"] B --> C["Render shell"] C --> D["Fetch content"] E["Repeat visit"] --> F["Shell served from cache instantly"] F --> D

The PRPL pattern

PRPL is a performance-oriented delivery strategy. Modern bundlers automate most of it, but knowing the intent helps you configure them:

  • Push / preload the critical resources for the first route
  • Render that initial route as fast as possible
  • Pre-cache the remaining routes in the service worker
  • Lazy-load everything else on demand via code-splitting

โœ… Auditing with Lighthouse

Open Chrome DevTools โ†’ Lighthouse, tick the "Progressive Web App" and "Performance" categories, and generate a report. It checks the manifest, HTTPS, offline start, icon sizes, and viewport, and gives concrete fixes. Run it after every meaningful change โ€” it is the fastest feedback loop for PWA compliance.

Hands-on Exercise

๐Ÿ‹๏ธ Make a plain page installable

Objective: Add a manifest and a working install button to an existing static page, then verify installability in DevTools.

Instructions:

  1. Create manifest.webmanifest with name, short_name, start_url, display: "standalone", theme_color, and a 192px + 512px icon.
  2. Link it from your <head> and add a <meta name="theme-color">.
  3. Register a minimal service worker (just an empty fetch handler is enough to satisfy the install criteria) โ€” you'll flesh it out in the next lesson.
  4. Add a hidden #install-btn and wire up the beforeinstallprompt handler shown above.
  5. Serve over localhost, open DevTools โ†’ Application โ†’ Manifest, and confirm there are no errors and the "Install" affordance appears.
๐Ÿ’ก Hint

If the install button never appears, check the Application โ†’ Manifest panel for warnings (a missing 512px icon and a non-standalone display are the usual culprits), and confirm your service worker registered without errors in Application โ†’ Service Workers. Remember it will not fire on file:// โ€” you must serve the page.

โœ… Minimal service worker to satisfy the criteria
// sw.js โ€” the smallest SW that makes Chrome offer installation
self.addEventListener('install', () => self.skipWaiting());
self.addEventListener('activate', (e) => e.waitUntil(clients.claim()));
self.addEventListener('fetch', (event) => {
  // A fetch handler must exist for installability; pass through for now.
  event.respondWith(fetch(event.request));
});

Register it from your page: navigator.serviceWorker?.register('/sw.js');

๐ŸŽฏ Quick Quiz

Question 1: Which file makes a PWA installable by describing its name, icons, and display mode?

Question 2: Why do service workers require HTTPS (or localhost)?

Question 3: What does the app-shell pattern optimize for?

Best Practices

โœ… Do

  • Ship a baseline that works before the service worker installs (progressive enhancement).
  • Provide a maskable 512px icon and a sensible theme_color.
  • Show the install prompt in response to a user gesture at a relevant moment, not on first paint.
  • Run Lighthouse after every meaningful change and fix its PWA warnings.

โš ๏ธ Don't

  • Don't assume a manifest gives you offline support โ€” that requires a caching service worker.
  • Don't cache authenticated or user-specific responses without careful thought.
  • Don't rely on beforeinstallprompt on iOS โ€” it never fires there.
  • Don't nag: an install prompt shoved at every visitor hurts trust and conversion.

Summary & Quiz

๐ŸŽ‰ Key Takeaways

  • A PWA is a capability profile layered onto a normal website via progressive enhancement โ€” not a framework.
  • The three pillars are HTTPS, the web app manifest, and a service worker.
  • The manifest controls installability and appearance; the service worker controls offline behavior.
  • Capture beforeinstallprompt to offer a tasteful, well-timed install experience (iOS excepted).
  • The app-shell and PRPL patterns keep first and repeat loads fast.

๐Ÿ“š Further Reading

๐Ÿš€ What's Next?

You now know what a PWA is and which pieces make it installable. Next we go deep on the engine behind offline behavior โ€” the service worker: its lifecycle, how it intercepts fetches, and the caching strategies you'll reach for.

๐ŸŽ‰ Nice work!

The map is in place. Time to build the engine room โ€” service workers await.