Skip to content

Vous souhaitez recevoir de l'aide sur ce sujet ? rejoignez la communauté Angular.fr sur Discord.

Progressive Web App (PWA) avec Angular

Dans ce tutoriel, nous allons découvrir comment transformer votre application Angular en Progressive Web App (PWA). Vous apprendrez à rendre votre application installable, fonctionnelle hors ligne, et à offrir une expérience utilisateur comparable à une application native mobile ou desktop.

Qu'est-ce qu'une PWA ?

Imaginez que vous utilisez une application mobile comme Instagram ou Twitter. Ces applications sont installées sur votre téléphone, fonctionnent même sans connexion Internet (pour consulter du contenu déjà chargé), et se lancent rapidement. Une Progressive Web App (PWA) permet de transformer votre site web en une application qui se comporte de la même manière.

Concrètement, une PWA peut :

  • Se charger rapidement grâce à la mise en cache des ressources
  • Fonctionner sans connexion Internet (mode offline) pour consulter du contenu déjà chargé
  • Être installable : on peut l'ajouter à l'écran d'accueil d'un téléphone ou d'un ordinateur, avec une icône, un démarrage en plein écran, comme une application classique
  • Offrir une expérience fluide et fiable, comparable à une application native

Les composants techniques d'une PWA

Pour qu'un site soit reconnu comme PWA, il faut au minimum :

  1. HTTPS : Le site doit être servi en HTTPS (sécurité et intégrité)
  2. Service Worker : Un script spécial chargé par le navigateur pour intercepter les requêtes réseau, gérer un cache, etc.
  3. Manifest : Un fichier (souvent manifest.json ou manifest.webmanifest) qui décrit l'application : nom, icônes, URL de démarrage, mode d'affichage... ce qui rend l'app installable

Pourquoi utiliser une PWA ?

Fonctionne hors connexion

Grâce au service worker, l'utilisateur peut accéder à l'application même sans connexion Internet ou avec une connexion dégradée. Par exemple, si vous avez déjà consulté la liste des utilisateurs, vous pourrez toujours la voir même si vous perdez la connexion.

Rapidité et performance

Les ressources (HTML, JS, CSS, images...) peuvent être mises en cache, donc le chargement est plus rapide après la première visite. L'utilisateur n'a pas besoin de recharger toutes les ressources à chaque fois.

Expérience utilisateur proche d'une application native

Installation sur l'écran d'accueil, plein écran, icônes personnalisées, notifications, usage fluide... L'utilisateur a l'impression d'utiliser une vraie application, pas juste un site web.

Compatibilité web et simplicité

C'est encore du web (URL, navigateurs), l'utilisateur peut simplement installer depuis le navigateur sans passer par un store. Cependant, il est aussi possible de publier une PWA sur les stores si vous le souhaitez (voir la section dédiée ci-dessous).

Ce qu'offre Angular pour les PWA

Angular intègre une implémentation de service worker complète. Cela signifie qu'Angular fournit tout le nécessaire pour transformer une application Angular en PWA, sans partir de zéro.

Grâce à Angular, vous n'avez pas besoin d'écrire manuellement les bas-niveaux du service worker : l'infrastructure, le cache, l'installation, etc. sont automatisés.

Angular gère aussi :

  • La génération du manifest
  • La génération des icônes
  • L'enregistrement du service worker
  • La configuration de base pour le cache

Comment activer une PWA dans Angular

Voici les étapes pour transformer votre application Angular en PWA.

Étape 1 : Ajouter le support PWA

Dans votre projet Angular, lancez la commande suivante :

bash
ng add @angular/pwa

Cette commande fait plusieurs choses automatiquement :

  • Ajoute le paquet @angular/service-worker
  • Configure le build pour supporter le service worker
  • Modifie index.html pour ajouter les références nécessaires (manifest, meta, icônes...)
  • Crée un fichier ngsw-config.json, qui définit comment et quoi mettre en cache

Regardons ce qui a été modifié dans votre projet :

Le fichier app.config.ts

Le service worker est ajouté aux providers de l'application. Voici ce qui est ajouté :

typescript
import { provideServiceWorker } from '@angular/service-worker';
import { isDevMode } from '@angular/core';

export const appConfig: ApplicationConfig = {
  providers: [
    provideRouter(routes),
    provideHttpClient(),
    // Enregistre le service worker pour gérer le cache et le mode offline
    provideServiceWorker('ngsw-worker.js', {
      enabled: !isDevMode(),
      registrationStrategy: 'registerWhenStable:30000'
    })
  ]
};

Le service worker est activé uniquement en production (!isDevMode()). En développement, il est désactivé pour faciliter le débogage. La stratégie d'enregistrement registerWhenStable:30000 signifie que le service worker sera enregistré 30 secondes après que l'application soit stable.

Le fichier ngsw-config.json

Ce fichier configure ce qui doit être mis en cache. Voici un exemple de configuration par défaut :

json
{
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
    {
      "name": "app",
      "installMode": "prefetch",
      "resources": {
        "files": [
          "/favicon.ico",
          "/index.html",
          "/manifest.webmanifest",
          "/*.css",
          "/*.js"
        ]
      }
    },
    {
      "name": "assets",
      "installMode": "lazy",
      "updateMode": "prefetch",
      "resources": {
        "files": [
          "/assets/**",
          "/*.(svg|cur|jpg|jpeg|png|apng|webp|avif|gif|otf|ttf|woff|woff2)"
        ]
      }
    }
  ]
}

Cette configuration définit deux groupes de ressources :

  • app : Les fichiers de l'application (HTML, CSS, JS) qui sont préchargés (prefetch)
  • assets : Les ressources statiques (images, polices) qui sont chargées à la demande (lazy)

Le fichier index.html

Le fichier index.html est modifié pour inclure les références au manifest et aux icônes :

html
<link rel="manifest" href="/manifest.webmanifest">
<meta name="theme-color" content="#1976d2">

Le fichier manifest.webmanifest

Un fichier manifest est créé avec les informations de base de votre application :

json
{
  "name": "Mon Application Angular",
  "short_name": "Mon App",
  "theme_color": "#1976d2",
  "background_color": "#ffffff",
  "display": "standalone",
  "scope": "/",
  "start_url": "/",
  "icons": [
    {
      "src": "icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    }
    // ... autres icônes
  ]
}

Étape 2 : Construire l'application en production

Pour que le service worker soit généré, vous devez construire l'application en mode production :

bash
ng build

Cela génère le dossier dist/ avec la configuration PWA, y compris le fichier ngsw-worker.js (le service worker compilé) et ngsw.json (la configuration du cache).

Étape 3 : Servir l'application

Le service worker ne fonctionne que si l'application est servie via HTTP(S). En production, utilisez HTTPS de préférence.

Pour tester localement, vous pouvez utiliser un serveur HTTP simple. Par exemple, avec http-server :

bash
npm install -g http-server
cd dist/votre-projet
http-server -p 8080

Ou avec Angular CLI :

bash
ng serve --configuration production

Service Worker et HTTPS

Le service worker ne fonctionnera que si l'application est servie via HTTPS — sinon il ne sera pas enregistré (sauf peut-être en local avec localhost). En production, HTTPS est obligatoire.

Étape 4 : Tester le comportement offline

Voici comment tester que votre PWA fonctionne hors ligne :

  1. Première visite : Ouvrez l'application dans votre navigateur. Le service worker va mettre en cache les fichiers critiques (HTML, JS, CSS, etc.).

  2. Vérifier l'enregistrement : Ouvrez les outils de développement (F12), allez dans l'onglet "Application" (Chrome) ou "Stockage" (Firefox), puis "Service Workers". Vous devriez voir votre service worker enregistré.

  3. Tester offline : Dans les outils de développement, activez l'option "Offline" dans l'onglet "Network". Rechargez la page. L'application doit toujours afficher son contenu — elle fonctionne "offline", grâce au cache.

  4. Tester l'installation : Sur mobile ou dans Chrome desktop, vous devriez voir une icône d'installation dans la barre d'adresse. Cliquez dessus pour installer l'application sur l'écran d'accueil.

Personnaliser la configuration du cache

Si vous avez des besoins spécifiques (assets externes, lazy loading, mises à jour, push notifications, etc.), vous pouvez personnaliser le fichier ngsw-config.json.

Exemple : Ajouter des données API au cache

Supposons que vous voulez mettre en cache les réponses de votre API pour les utilisateurs :

json
{
  "$schema": "./node_modules/@angular/service-worker/config/schema.json",
  "index": "/index.html",
  "assetGroups": [
    // ... groupes existants
  ],
  "dataGroups": [
    {
      "name": "api-users",
      "urls": ["/api/users/**"],
      "cacheConfig": {
        "strategy": "freshness",
        "maxSize": 100,
        "maxAge": "1h",
        "timeout": "5s"
      }
    }
  ]
}

Cette configuration :

  • Met en cache les réponses de l'API /api/users/**
  • Utilise la stratégie freshness : essaie d'abord le réseau, puis le cache si le réseau échoue
  • Limite le cache à 100 entrées maximum
  • Conserve les données pendant 1 heure
  • Timeout de 5 secondes pour les requêtes réseau

Exemple : Gérer les mises à jour

Par défaut, Angular gère les mises à jour automatiquement. Mais vous pouvez personnaliser le comportement dans votre composant :

typescript
import { Component, inject, OnInit } from '@angular/core';
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
import { filter } from 'rxjs/operators';

@Component({
  selector: 'app-root',
  standalone: true,
  template: `
    <div>
      <h1>Gestion des utilisateurs</h1>
      @if (updateAvailable) {
        <button (click)="reloadPage()">
          Une nouvelle version est disponible. Cliquez pour mettre à jour.
        </button>
      }
    </div>
  `
})
export class AppComponent implements OnInit {
  // Service pour gérer les mises à jour du service worker
  private swUpdate = inject(SwUpdate);
  updateAvailable = false;

  ngOnInit() {
    // Vérifie si une nouvelle version est disponible
    if (this.swUpdate.isEnabled) {
      this.swUpdate.versionUpdates
        .pipe(
          filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY')
        )
        .subscribe(() => {
          this.updateAvailable = true;
        });
    }
  }

  // Recharge la page pour activer la nouvelle version
  reloadPage() {
    window.location.reload();
  }
}

Cette implémentation :

  • Vérifie si le service worker est activé
  • Écoute les événements de mise à jour
  • Affiche un bouton quand une nouvelle version est disponible
  • Permet à l'utilisateur de recharger la page pour activer la nouvelle version

Limites et considérations

Service worker simple mais efficace

Le service worker fourni par Angular est utile pour le cache basique et le mode offline, mais il est assez simple. Pour des besoins complexes (caching dynamique avancé, synchronisation en arrière-plan, logique offline poussée...), il faudra peut-être compléter ou coder vous-même certaines parties.

HTTPS obligatoire

Le service worker ne fonctionnera que si l'application est servie via HTTPS — sinon il ne sera pas enregistré (sauf peut-être en local avec localhost). En production, HTTPS est obligatoire.

Stratégie de mise à jour

Il faut prévoir une stratégie de mise à jour : quand vous modifiez votre application, le service worker/cache doit savoir qu'il y a du nouveau. Angular gère ça via le fichier de configuration et via le manifest/ngsw.json, mais vous devez informer l'utilisateur qu'une mise à jour est disponible.

Bonne pratique

Informez toujours l'utilisateur lorsqu'une nouvelle version est disponible. Ne rechargez pas automatiquement la page sans son consentement, car cela pourrait interrompre son travail.

Publier une PWA sur les stores

Une question fréquente est de savoir si on peut mettre une PWA sur les stores (App Store, Google Play, etc.). La réponse est : oui, mais cela dépend du store et nécessite souvent un "packaging" supplémentaire.

Installation depuis le navigateur (sans store)

Avant tout, rappelons qu'une PWA reste toujours installable "à la main" depuis le navigateur (sur mobile ou desktop) — sans passer par un store. L'utilisateur peut simplement cliquer sur l'icône d'installation dans la barre d'adresse du navigateur.

Google Play Store (Android)

Pour le store Android (Google Play Store), c'est possible : on peut publier une PWA si on l'« emboîte » dans un conteneur compatible, typiquement via une Trusted Web Activity (TWA). Cette approche encapsule votre PWA dans une application Android native qui affiche votre site web en plein écran, sans barre de navigateur.

Apple App Store (iOS)

Pour l'iOS store (Apple App Store), c'est plus délicat. Les PWAs pures ne sont généralement pas acceptées ; il faut les « wrapper » dans une application native (webview, conteneur natif…) pour avoir une chance de soumission. Apple exige que l'application offre une expérience utilisateur de qualité, et si l'app ressemble trop à un simple site web "emballé", elle risque d'être rejetée.

Autres stores

En plus d'Android et iOS, certains stores et plateformes — comme le Microsoft Store — supportent aussi les PWAs de manière plus directe.

Résumé

Oui, vous pouvez viser les stores, mais cela implique souvent de "transformer" la PWA en package compatible store — ce n'est pas automatique. Vous devrez utiliser des outils de packaging (voir section suivante).

Solutions pour packager une PWA et la publier dans un store

Voici quelques solutions et approches populaires pour rendre une PWA "store-ready" :

Capacitor

Capacitor permet de prendre votre PWA + code web, et de la "wrapper" en application native/hybride (iOS & Android). Vous pouvez garder le même code web, mais l'emballer dans un conteneur natif.

Avantages :

  • Support iOS et Android
  • Accès aux APIs natives (caméra, géolocalisation, notifications push natives, etc.)
  • Vous gardez votre code web Angular
  • Intégration facile avec Angular

Installation basique :

bash
npm install @capacitor/core @capacitor/cli
npx cap init
npx cap add android
npx cap add ios

PWABuilder

PWABuilder est un outil qui automatise la génération de packages pour différents stores (Android, Windows/Microsoft, iOS, …). Il analyse votre site/PWA, vous dit ce qu'il manque, puis génère les "wrappers" nécessaires.

Avantages :

  • Automatisation complète du processus
  • Support de plusieurs plateformes
  • Analyse de votre PWA pour identifier les manques
  • Génération des packages prêts à soumettre

Vous pouvez l'utiliser en ligne sur pwabuilder.com ou via l'outil en ligne de commande.

TWA (Trusted Web Activity) via Bubblewrap

Pour Android spécifiquement, Bubblewrap permet de "convertir" une PWA en application Android (APK), en encapsulant la PWA dans une vue web fullscreen, sans barre de navigateur — ce qui la rend acceptable sur Google Play.

Avantages :

  • Spécialement conçu pour Android
  • Simple à utiliser
  • Génère un APK directement utilisable

Installation :

bash
npm install -g @bubblewrap/cli
bubblewrap init
bubblewrap build

Services commerciaux (ex : MobiLoud)

Des services commerciaux comme MobiLoud fournissent un service "clé en main" : ils prennent votre PWA, la packagent et s'occupent de la soumission au store. Utile si vous ne voulez pas gérer la complexité vous-même.

Avantages :

  • Service complet (packaging + soumission)
  • Support et assistance
  • Moins de travail technique de votre côté

Inconvénients :

  • Coût (service payant)
  • Moins de contrôle sur le processus

Points à garder en tête

Quelle que soit la solution choisie :

  • Compte développeur requis : Vous aurez besoin d'un compte développeur (Google, Apple, ou autre) comme pour toute app native — donc des coûts possibles (ex. 99$/an pour Apple, 25$ une fois pour Google).

  • Expérience utilisateur : Même avec un wrapper, il faut soigner l'expérience utilisateur. Pour iOS notamment, si l'app ressemble trop à un simple site web "emballé", elle risque d'être rejetée.

  • Vous gardez votre code web : Si vous utilisez un wrapper comme Capacitor, l'app soumise ressemble à une application native ou hybride — mais vous gardez votre code web Angular. C'est un avantage majeur : un seul codebase pour web et mobile.

Recommandation

Pour un projet Angular, Capacitor est souvent le choix le plus adapté car il s'intègre parfaitement avec Angular et vous donne accès aux fonctionnalités natives tout en gardant votre code web.