Back to Curriculum

Progressive Web Applications (PWA)

📚 Lesson 20 of 20 ⏱️ 55 min

Progressive Web Applications (PWA)

55 min

Progressive Web Applications (PWAs) are web applications that use modern web technologies to deliver app-like experiences that work across all devices and platforms. PWAs combine the best of web and native apps: they're discoverable like websites (indexed by search engines, shareable via URLs), installable like native apps (appear on home screens, launch in standalone mode), and work offline with push notifications. PWAs provide a compelling alternative to native apps, especially for businesses wanting to reach users across platforms without maintaining separate codebases for iOS, Android, and web.

The Web App Manifest is a JSON file that provides metadata about your web application, enabling it to be installed on users' devices. The manifest includes the app name, short name, description, icons (multiple sizes for different devices), start URL, display mode (standalone, fullscreen, minimal-ui, browser), theme colors, background color, orientation preferences, and scope. When users install a PWA, it appears on their home screen with your specified icon and launches in its own window without browser UI, making it feel like a native application. The manifest is essential for PWA installability.

Service Workers are JavaScript files that act as network proxies between your web app and the network, enabling powerful features like offline functionality, background sync, and push notifications. Service workers run in the background, separate from your web page, and can intercept network requests, cache resources, and serve cached content when offline. They're the foundation of PWA offline capabilities and enable apps to work reliably even with poor or no network connectivity. Service workers use event-driven architecture with lifecycle events (install, activate, fetch) and require HTTPS (except for localhost).

Offline support is a key PWA feature that dramatically improves user experience. Service workers can cache app shell (HTML, CSS, JavaScript) and data, serving cached content when the network is unavailable. Common caching strategies include cache-first (serve from cache, fallback to network—good for static assets), network-first (try network, fallback to cache—good for dynamic content), stale-while-revalidate (serve cache immediately, update in background—good for frequently updated content), and network-only or cache-only for specific use cases. Proper caching strategies ensure fast load times, reliable offline functionality, and reduced server load.

Installability is another crucial PWA feature. When a PWA meets certain criteria (served over HTTPS, has a valid manifest with required fields, has a registered service worker, meets engagement heuristics), browsers offer an install prompt. Once installed, PWAs appear on home screens, launch in standalone mode, and can be found in app drawers. Installation makes PWAs feel native while maintaining the web's advantages: easy updates (no app store approval), smaller file sizes, cross-platform compatibility, and discoverability. The install experience varies by browser and platform but generally provides a seamless way to "add to home screen."

Best practices include ensuring your site works offline with service workers, providing a complete manifest with all required fields and multiple icon sizes, using HTTPS (required for service workers), designing for mobile-first experiences with touch-friendly interfaces, providing app-like navigation and interactions, implementing proper error handling and offline indicators, testing installation across different browsers and devices, and monitoring PWA metrics (install rates, engagement, offline usage). PWAs should feel fast, reliable, and engaging, matching or exceeding native app experiences while maintaining the web's reach, accessibility, and ease of development. PWAs represent the future of web applications, combining web and native app benefits.

Key Concepts

  • PWAs provide app-like experiences using web technologies.
  • Web App Manifest provides metadata for installability.
  • Service Workers enable offline functionality and background processing.
  • PWAs are installable, work offline, and can send push notifications.
  • HTTPS is required for service workers and PWA features.

Learning Objectives

Master

  • Understanding PWA concepts and capabilities
  • Creating Web App Manifests for installability
  • Implementing Service Workers for offline functionality
  • Building installable, app-like web experiences

Develop

  • Modern web application architecture thinking
  • Understanding offline-first development
  • Creating engaging, native-like web experiences

Tips

  • Ensure your site uses HTTPS (required for service workers).
  • Provide complete manifest with icons, name, and display mode.
  • Implement service worker caching strategies for offline support.
  • Test PWA installation and offline functionality across browsers.

Common Pitfalls

  • Not using HTTPS, preventing service worker registration.
  • Incomplete manifest files, preventing installation.
  • Poor caching strategies, leading to stale or missing content offline.
  • Not testing offline functionality, leaving users with broken experiences.

Summary

  • PWAs provide app-like experiences using web technologies.
  • Web App Manifest enables installation and native-like behavior.
  • Service Workers enable offline functionality and background processing.
  • PWAs are installable, work offline, and feel like native apps.
  • Proper PWA implementation requires HTTPS, manifest, and service workers.

Exercise

Create a basic PWA structure with a web app manifest and service worker registration.

<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>My PWA App</title>
  
  <!-- PWA Meta Tags -->
  <meta name="theme-color" content="#2196F3">
  <meta name="apple-mobile-web-app-capable" content="yes">
  <meta name="apple-mobile-web-app-status-bar-style" content="default">
  <meta name="apple-mobile-web-app-title" content="My PWA App">
  
  <!-- Web App Manifest -->
  <link rel="manifest" href="manifest.json">
  
  <!-- App Icons -->
  <link rel="icon" type="image/png" sizes="32x32" href="icons/icon-32x32.png">
  <link rel="icon" type="image/png" sizes="16x16" href="icons/icon-16x16.png">
  <link rel="apple-touch-icon" href="icons/icon-192x192.png">
</head>
<body>
  <header>
    <h1>My PWA App</h1>
    <p>This is a Progressive Web Application</p>
  </header>
  
  <main>
    <section>
      <h2>Features</h2>
      <ul>
        <li>Offline functionality</li>
        <li>Installable on devices</li>
        <li>Responsive design</li>
        <li>Fast loading</li>
      </ul>
    </section>
    
    <section>
      <h2>Install Prompt</h2>
      <button id="installBtn" style="display: none;">Install App</button>
      <p id="installStatus">Installation status will appear here</p>
    </section>
  </main>
  
  <script>
    // Service Worker Registration
    if ('serviceWorker' in navigator) {
      window.addEventListener('load', () => {
        navigator.serviceWorker.register('/sw.js')
          .then(registration => {
            console.log('SW registered: ', registration);
          })
          .catch(registrationError => {
            console.log('SW registration failed: ', registrationError);
          });
      });
    }
    
    // Install Prompt
    let deferredPrompt;
    
    window.addEventListener('beforeinstallprompt', (e) => {
      e.preventDefault();
      deferredPrompt = e;
      
      const installBtn = document.getElementById('installBtn');
      installBtn.style.display = 'block';
      
      installBtn.addEventListener('click', () => {
        installBtn.style.display = 'none';
        deferredPrompt.prompt();
        
        deferredPrompt.userChoice.then((choiceResult) => {
          if (choiceResult.outcome === 'accepted') {
            document.getElementById('installStatus').textContent = 'App installed successfully!';
          } else {
            document.getElementById('installStatus').textContent = 'App installation cancelled.';
          }
          deferredPrompt = null;
        });
      });
    });
    
    // Check if app is already installed
    window.addEventListener('appinstalled', () => {
      document.getElementById('installStatus').textContent = 'App is already installed!';
    });
  </script>
</body>
</html>

<!-- manifest.json -->
{
  "name": "My PWA App",
  "short_name": "PWA App",
  "description": "A sample Progressive Web Application",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#2196F3",
  "icons": [
    {
      "src": "icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

<!-- sw.js (Service Worker) -->
const CACHE_NAME = 'my-pwa-v1';
const urlsToCache = [
  '/',
  '/index.html',
  '/styles.css',
  '/script.js'
];

self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then((cache) => {
        return cache.addAll(urlsToCache);
      })
  );
});

self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request)
      .then((response) => {
        if (response) {
          return response;
        }
        return fetch(event.request);
      })
  );
});

Exercise Tips

  • Add icons of different sizes (192x192, 512x512) to your manifest.
  • Implement different caching strategies in your service worker.
  • Test offline functionality by disconnecting from the network.
  • Check PWA installation criteria using browser DevTools.

Code Editor

Output