Progressive Web App with Angular 16

Updated : 08/09/2023 danny

We are going to make our standard Web Application a PWA ( Progressive Web App )

We will use the Angular javascript framework version 16.2.4

Progressive Web App avec Angular

What are we going to do ?

This is step 7 of our Angular guide which will allow us to obtain a PWA type Web Application . The basic Angular project that we will use already has the following characteristics

  • Generated with Angular CLI
  • Routing
  • Lazy Loading
  • The Bootstrap CSS framework
  • Module management
  • Server Side Rendering

All the sources created are indicated at the end of the tutorial.

The application is at the following address

Before you start

2008 App Store is an application store distributed by Apple on mobile devices running iOS.
2012 Google Play Store is an online application store created by Google.

2014 , annual global sales of smartphones exceed one billion units.

2017 two mobile operating systems share the global smartphone market.
Android 85.1% and IOS 14.8%

More than 50% of internet searches are now carried out on mobile in France.

Android and iOS operating systems are written in different programming languages.
So iOS apps run on Objective-C/Swift , while Android apps run on Java .

If you want to develop a mobile application, you can either develop a specific version for each platform or use a cross platform tool that will allow you to have only one source for both OS.
It will nevertheless be necessary to manage registration on the app stores.
In all cases, users must go to a download platform to install an app.

In 2015, Frances Berriman and Google engineer Alex Russell proposed the term “progressive web apps”

A PWA can be consulted like a classic website, from a secure URL but allows a user experience similar to that of a mobile application, without the constraints of the latter (submission to App-Stores, significant use of the device's memory …).


We will use the Angular documentation to apply this technique.

We will use the angular-cli command
ng add

# Adding the pwa library
ng add @angular/pwa --project angular-starter

Angular-cli automatically made a number of changes to our project.

  • modification of the package.json file (in this example we will update the dependencies and the descriptors)
  • editing angular.json file
  • creating the ngsw-config.json file
  • creation of the src/manifest.webmanifest file
  • modifying the src/index.html file
  • modifying the src/app.module.ts file
  • creating icons src/app/assets/icons
    Auto-created icons do not work during deployment.
    ​​​​​​​Get the ones that are available on the final repo.
  "dependencies": {
    "@angular/animations": "16.2.4",
    "@angular/common": "16.2.4",
    "@angular/compiler": "16.2.4",
    "@angular/core": "16.2.4",
    "@angular/forms": "16.2.4",
    "@angular/platform-browser": "16.2.4",
    "@angular/platform-browser-dynamic": "16.2.4",
    "@angular/platform-server": "16.2.4",
    "@angular/router": "16.2.4",
    "@angular/service-worker": "16.2.4",
    "@fortawesome/fontawesome-free": "6.4.2",
    "@nguniversal/express-engine": "16.2.0",
    "bootstrap": "5.3.1",
    "express": "4.18.2",
    "rxjs": "7.8.1",
    "tslib": "2.6.2",
    "zone.js": "0.13.1"
  "devDependencies": {
    "@angular-devkit/build-angular": "16.2.1",
    "@angular-eslint/builder": "16.1.2",
    "@angular-eslint/eslint-plugin": "16.1.2",
    "@angular-eslint/eslint-plugin-template": "16.1.2",
    "@angular-eslint/schematics": "16.1.2",
    "@angular-eslint/template-parser": "16.1.2",
    "@angular/cli": "16.2.1",
    "@angular/compiler-cli": "16.2.4",
    "@nguniversal/builders": "16.2.0",
    "@types/express": "4.17.17",
    "@types/jasmine": "4.3.5",
    "@types/node": "20.5.9",
    "@typescript-eslint/eslint-plugin": "6.6.0",
    "@typescript-eslint/parser": "6.6.0",
    "eslint": "8.48.0",
    "jasmine-core": "5.1.1",
    "karma": "6.4.2",
    "karma-chrome-launcher": "3.2.0",
    "karma-coverage": "2.2.1",
    "karma-jasmine": "5.1.0",
    "karma-jasmine-html-reporter": "2.1.0",
    "typescript": "5.0.4"

"assets": [


        "build": {
          "builder": "@angular-devkit/build-angular:browser",
          "options": {
            "outputPath": "dist/angular-starter/browser",
            "index": "src/index.html",
            "main": "src/main.ts",
            "polyfills": "src/polyfills.ts",
            "tsConfig": "",
            "assets": [
            "styles": [
            "scripts": [
            "serviceWorker": true,
            "ngswConfigPath": "ngsw-config.json"
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
  "name": "angular-starter",
  "short_name": "angular-starter",
  "theme_color": "#1976d2",
  "background_color": "#fafafa",
  "display": "standalone",
  "scope": "./",
  "start_url": "./",
  "icons": [
      "src": "assets/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-96x96.png",
      "sizes": "96x96",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-384x384.png",
      "sizes": "384x384",
      "type": "image/png",
      "purpose": "maskable any"
      "src": "assets/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable any"
<!doctype html>
<html lang="en">
  <meta charset="utf-8">
  <base href="/">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <link rel="icon" type="image/x-icon" href="favicon.ico">

  <!-- Global site tag (gtag.js) - Google Analytics -->
  <script async="" src=""></script>
    window.dataLayer = window.dataLayer || [];
    function gtag() { dataLayer.push(arguments); }
    gtag('js', new Date());

    gtag('config', 'YOUR-ID');

  <link rel="manifest" href="manifest.webmanifest">
  <meta name="theme-color" content="#1976d2">
  <noscript>Please enable JavaScript to continue using this application.</noscript>
import { BrowserModule } from '@angular/platform-browser';
import { NgModule, isDevMode } from '@angular/core';

import { AppComponent } from './app.component';
import { HomeComponent } from './modules/general/home/home.component';
import { NotFoundComponent } from './modules/general/not-found/not-found.component';
import { AppRoutingModule } from './app-routing.module';
import { ServiceWorkerModule } from '@angular/service-worker';

  declarations: [
  imports: [
    ServiceWorkerModule.register('ngsw-worker.js', {
      enabled: !isDevMode(),
      // Register the ServiceWorker as soon as the application is stable
      // or after 30 seconds (whichever comes first).
      registrationStrategy: 'registerWhenStable:30000'
  providers: [],
  bootstrap: [AppComponent]
export class AppModule { }


We will test how the PWA works

The npm run start script executes the ng serve command
ng serve not working with service workers

To test you must use an http server.

The following scripts therefore allow us to test our pwa

  • npm run build:ssr
  • npm run serve:ssr
  • http://localhost:4000/


All that remains is to open Chrome Developer Tools with Ctrl + Shift + J
And run a test of the Lighthouse tool

  • Audits
  • Run audits

Source Code

The source code used at the beginning of the tutorial is available on github

The source code obtained at the end of this tutorial is available on github

The following steps will allow you to obtain a prototype application

The last step provides an example application

The source code of this final application is available on GitHub