cyberangles guide

Building Progressive Web Apps with Angular: A Comprehensive Guide

In today’s digital landscape, users expect web applications to deliver native-like experiences—fast load times, offline access, and the ability to "install" on their devices without the hassle of app stores. **Progressive Web Apps (PWAs)** bridge this gap by combining the best of web and mobile apps. They are reliable, fast, and engaging, working seamlessly across devices and network conditions. Angular, a powerful front-end framework, provides robust tools to simplify PWA development. With built-in support for service workers, manifest files, and caching strategies, Angular empowers developers to transform standard web apps into PWAs with minimal effort. In this guide, we’ll explore how to build a production-ready PWA using Angular, covering everything from setup to deployment.

Table of Contents

  1. What is a Progressive Web App (PWA)?
  2. Why Angular for PWAs?
  3. Prerequisites
  4. Setting Up Your Angular Project
  5. Adding PWA Support to Angular
  6. Customizing the Web App Manifest
  7. Configuring the Angular Service Worker
  8. Implementing Offline Functionality
  9. Adding Installability Features
  10. Testing and Debugging Your PWA
  11. Advanced PWA Features with Angular
  12. Deploying Your Angular PWA
  13. Conclusion
  14. References

What is a Progressive Web App (PWA)?

A Progressive Web App (PWA) is a type of web application that uses modern web APIs and best practices to deliver a native app-like experience. Key characteristics of PWAs include:

  • Reliability: Load instantly and work offline or on low-quality networks.
  • Speed: Smooth interactions with minimal jank.
  • Engagement: Feel like native apps, with features like installability, push notifications, and full-screen mode.

PWAs are built on web standards (HTML, CSS, JavaScript) and work across all modern browsers, making them platform-agnostic.

Why Angular for PWAs?

Angular simplifies PWA development with built-in tools and features:

  • Angular Service Worker (NGSW): A production-ready service worker library that handles caching, offline support, and app updates.
  • PWA Schematic: An automated setup tool (ng add @angular/pwa) that generates manifest files, configures service workers, and links assets—eliminating manual setup.
  • Integrated Tooling: Seamless integration with Angular CLI for building, testing, and deploying PWAs.
  • TypeScript Support: Strong typing ensures robust code, critical for maintaining large PWAs.

Prerequisites

Before getting started, ensure you have:

  • Node.js (v14+ recommended) and npm/yarn installed.
  • Angular CLI: Install globally via npm install -g @angular/cli.
  • Basic familiarity with Angular concepts (components, services, CLI commands).

Setting Up Your Angular Project

First, create a new Angular project (or use an existing one). Open your terminal and run:

ng new angular-pwa-demo --routing --style=css
cd angular-pwa-demo

The --routing flag adds Angular Router (useful for multi-page PWAs), and --style=css sets CSS as the styling language (adjust to scss if preferred).

Adding PWA Support to Angular

Angular’s PWA schematic automates the heavy lifting. Run the following command in your project directory:

ng add @angular/pwa

This command:

  • Adds @angular/service-worker as a dependency.
  • Generates a manifest.json file (for installability and app metadata).
  • Creates an ngsw-config.json file (configures the service worker).
  • Updates angular.json to enable service worker in production builds.
  • Adds default icons (replace these with your app’s icons later).

Customizing the Web App Manifest

The manifest.json file (in the src/ directory) defines your PWA’s metadata, enabling features like “Add to Home Screen” prompts and full-screen mode. Let’s customize it:

{
  "name": "Angular PWA Demo", // Full app name (shown in install prompts)
  "short_name": "AngularPWA", // Short name (used on home screen)
  "description": "A demo PWA built with Angular", // App description
  "start_url": "/", // URL loaded when the app is launched
  "display": "standalone", // App display mode: "fullscreen", "standalone", "minimal-ui", or "browser"
  "background_color": "#ffffff", // Background color for splash screens
  "theme_color": "#4285f4", // Color for browser UI (e.g., address bar)
  "icons": [
    {
      "src": "assets/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png"
    },
    {
      "src": "assets/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }
  ]
}

Key Fields Explained:

  • display: "standalone": Makes the app look like a native app (no browser toolbar).
  • theme_color: Ensures the browser’s address bar matches your app’s branding.
  • icons: Provide multiple sizes to support different devices (e.g., smartphones, tablets, desktops).

Configuring the Angular Service Worker

The ngsw-config.json file (in the project root) controls how the Angular Service Worker (NGSW) caches assets and handles network requests. Let’s break down its structure:

{
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/manifest.json",
          "/*.css",
          "/*.js"
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/assets/**",
          "/*.(eot|svg|cur|jpg|png|webp|gif|otf|ttf|woff|woff2|ani)"
        ]
      }
    }
  ],
  "dataGroups": [
    {
      "name": "api-data",
      "urls": [
        "https://api.example.com/data/**" // Cache API requests from this URL
      ],
      "cacheConfig": {
        "maxSize": 50, // Max cached requests
        "maxAge": "6h", // Cache duration
        "timeout": "10s", // Fallback to cache if network is slow
        "strategy": "freshness" // Prioritize network, then cache
      }
    }
  ]
}

Key Sections:

  • index: The main HTML file to serve for all routes (required for SPAs).
  • assetGroups: Caches static assets (HTML, CSS, JS, images).
    • installMode: "prefetch": Caches assets immediately on install (for critical app files).
    • installMode: "lazy": Caches assets only when first accessed (for non-critical assets like images).
  • dataGroups: Caches dynamic content (e.g., API responses). Use strategy: "freshness" (network-first) or strategy: "performance" (cache-first).

Implementing Offline Functionality

The Angular Service Worker automatically caches assets defined in ngsw-config.json, enabling offline access. To test this:

  1. Build the app in production mode (service workers only work in production):

    ng build --prod
  2. Serve the app locally using a static server (e.g., http-server):

    npm install -g http-server
    http-server -p 8080 dist/angular-pwa-demo
  3. Test offline mode:

    • Open http://localhost:8080 in Chrome.
    • Go to Chrome DevTools > Application > Service Workers and check “Offline”.
    • Refresh the page—the app should load from the cache!

Adding Installability Features

To enable “Add to Home Screen” prompts, ensure your PWA meets these criteria:

  • Served over HTTPS (or localhost for development).
  • Has a valid manifest.json with name, short_name, start_url, and display.
  • Registers a service worker with a fetch event listener.

Custom Install Button

You can override the default browser prompt by listening to the beforeinstallprompt event. Add this to your root component:

// src/app/app.component.ts
import { Component, HostListener } from '@angular/core';

@Component({
  selector: 'app-root',
  templateUrl: './app.component.html',
  styleUrls: ['./app.component.css']
})
export class AppComponent {
  installPrompt: any;
  showInstallButton = false;

  @HostListener('window:beforeinstallprompt', ['$event'])
  onBeforeInstallPrompt(event: Event) {
    // Prevent the default prompt
    event.preventDefault();
    // Store the event for later use
    this.installPrompt = event;
    // Show custom install button
    this.showInstallButton = true;
  }

  installApp() {
    // Trigger the install prompt
    this.installPrompt.prompt();
    // Wait for the user to respond
    this.installPrompt.userChoice.then((choiceResult: { outcome: string }) => {
      if (choiceResult.outcome === 'accepted') {
        console.log('User installed the app');
      } else {
        console.log('User declined the install');
      }
      // Reset the prompt
      this.installPrompt = null;
      this.showInstallButton = false;
    });
  }
}

Add a button in your template (app.component.html):

<button *ngIf="showInstallButton" (click)="installApp()">
  Install Angular PWA
</button>

Testing and Debugging Your PWA

Lighthouse Audit

Use Google’s Lighthouse tool to validate PWA compliance:

  1. Open Chrome DevTools > Lighthouse tab.
  2. Check “Progressive Web App” and click “Generate report”.
  3. Fix any failed audits (e.g., missing icons, HTTPS issues).

Chrome DevTools

  • Application > Service Workers: Inspect active service workers, update them, or clear storage.
  • Application > Cache Storage: View cached assets and API responses.
  • Network > Throttling: Simulate slow/offline networks to test performance.

Advanced PWA Features with Angular

Push Notifications

Angular supports push notifications via the Web Push Protocol. Use the SwPush service from @angular/service-worker:

import { SwPush } from '@angular/service-worker';

@Component({ ... })
export class NotificationComponent {
  constructor(private swPush: SwPush) {}

  subscribeToNotifications() {
    if (this.swPush.isEnabled) {
      this.swPush.requestSubscription({
        serverPublicKey: 'YOUR_VAPID_PUBLIC_KEY' // Generate via web-push library
      }).then(sub => {
        // Send subscription to your backend to trigger notifications
        console.log('Push subscription:', sub);
      });
    }
  }
}

App Updates

Notify users when a new version is available using SwUpdate:

import { SwUpdate } from '@angular/service-worker';

@Component({ ... })
export class AppComponent {
  constructor(private swUpdate: SwUpdate) {
    if (this.swUpdate.isEnabled) {
      this.swUpdate.versionUpdates.subscribe(event => {
        if (event.type === 'VERSION_AVAILABLE') {
          if (confirm('Update available! Refresh now?')) {
            window.location.reload();
          }
        }
      });
    }
  }
}

Deploying Your Angular PWA

Deploy your PWA to a hosting service that supports HTTPS (required for service workers). Popular options:

Firebase Hosting

  1. Install Firebase CLI: npm install -g firebase-tools
  2. Initialize Firebase: firebase init (select “Hosting”)
  3. Deploy: firebase deploy

Netlify/Vercel

  1. Push your code to GitHub.
  2. Connect your repo to Netlify/Vercel.
  3. Set the build command to ng build --prod and publish directory to dist/angular-pwa-demo.

Conclusion

Angular makes building PWAs accessible with its built-in service worker, manifest support, and tooling. By following this guide, you’ve learned to:

  • Set up PWA support in Angular.
  • Configure caching for static assets and dynamic API data.
  • Enable offline access and installability.
  • Test, debug, and deploy your PWA.

PWAs offer a cost-effective way to deliver native-like experiences across devices—start building yours today!

References