Angular. Progressive Web Apps (PWA)

Home » Tutorials » JavaScript » Angular. Progressive Web Apps (PWA)
Progressive Web Apps (PWAs) are one of Angular’s most powerful built-in features. With the help of the Angular Service Worker, you can transform a regular Single Page Application (SPA) into a fast, installable, offline-capable web application that automatically updates when a new version is deployed.

In this tutorial, you’ll learn how to build a Progressive Web App in Angular, configure the Service Worker, cache HTTP requests, and implement automatic update detection.

What is a Progressive Web App (PWA)?

A Progressive Web App (PWA) is a web application that delivers a user experience similar to a native mobile app.

Some of the main benefits of a PWA include:

  • Offline support
  • Faster loading times
  • Resource caching
  • Installable on desktop and mobile devices
  • Automatic updates
  • Push notification support

At the heart of every PWA is the Service Worker

Configuring ngsw-config.json

The behavior of Angular’s Service Worker is defined inside the ngsw-config.json file (see the code below).

The assetGroups section defines which static resources should be cached.

In this example, Angular caches:

  • index.html
  • manifest.webmanifest
  • CSS files
  • JavaScript bundles
  • favicon

After the initial visit, these files are served directly from the cache, resulting in significantly faster page loads.

Caching HTTP API Requests

Angular Service Worker can cache more than just application assets—it can also cache HTTP API responses.

This is done using the dataGroups section.

Detecting Application Updates

One of the biggest advantages of PWAs is automatic application updates.

Angular provides the SwUpdate service for this purpose.

Testing Your PWA with Lighthouse

Once your PWA is configured, it’s a good idea to analyze it using Lighthouse in Chrome DevTools.

Lighthouse evaluates several important aspects of your application, including:

  • Performance
  • Accessibility
  • Best Practices
  • SEO
  • Progressive Web App compliance
  • Service Worker configuration
  • Web App Manifest
  • Installability

A properly configured Angular PWA should achieve an excellent Lighthouse score.

Angular provides almost everything you need to build a modern Progressive Web App out of the box. By configuring the Service Worker and the ngsw-config.json file, your application gains several powerful features:

  • Offline support
  • HTML, CSS, and JavaScript caching
  • HTTP API response caching
  • Automatic application updates
  • Faster loading times
  • Installability on desktop and mobile devices
  • Better Lighthouse scores and improved user experience

If you’re building a modern Angular application, adding PWA support is one of the easiest ways to improve performance, reliability, and the overall user experience—all without relying on third-party libraries.

ngsw-config.json

{
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.csr.html",
          "/index.html",
          "/manifest.webmanifest",
          "/*.css",
          "/*.js"
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": ["/**/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"]
      }
    }
  ],
  "dataGroups": [
    {
      "name": "users-api",
      "urls": ["https://jsonplaceholder.typicode.com/users/"],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "1h",
        "timeout": "3s"
      }
    }
  ]
}

app.ts

import { Component, inject, Signal, signal } from '@angular/core';
import { HttpClient } from '@angular/common/http';
import { toSignal } from '@angular/core/rxjs-interop';
import { SwUpdate, VersionEvent } from '@angular/service-worker';

@Component({
  selector: 'app-root',
  imports: [],
  templateUrl: './app.html',
  styleUrl: './app.css',
})
export class App {
  protected users: Signal<any> = signal([]);

  private http = inject(HttpClient);

  constructor(private swUpdate: SwUpdate) {
    this.users = toSignal(this.http.get('https://jsonplaceholder.typicode.com/users/'));
    if (swUpdate.isEnabled) {
      this.swUpdate.versionUpdates.subscribe((event: VersionEvent) => {
        console.log('Event type', event.type);
      });

      this.swUpdate.checkForUpdate().then((hasUpdate) => {
        if (hasUpdate) {
          console.log('New version available, click ok to refresh');
          window.location.reload();
        }
      });
    }
  }
}

0 Comments

Submit a Comment

Your email address will not be published. Required fields are marked *


The reCAPTCHA verification period has expired. Please reload the page.

Pin It on Pinterest

Share This