Transformez votre app Angular en PWA performante : service worker, stratégies de cache, mode offline et mise à jour sans friction.
Activer le Service Worker Angular
Angular fournit le package @angular/service-worker qui génère un service worker optimisé à partir d'un fichier de configuration JSON — pas besoin d'écrire le worker à la main.
ng add @angular/pwa
Le CLI crée automatiquement :
ngsw-config.json— configuration du cache et des stratégies.manifest.webmanifest— icônes, couleurs et nom pour l'installation sur l'écran d'accueil.- L'enregistrement du service worker dans
app.config.ts.
// app.config.ts (Angular 17+ standalone)
import { provideServiceWorker } from '@angular/service-worker';
import { isDevMode } from '@angular/core';
export const appConfig: ApplicationConfig = {
providers: [
provideServiceWorker('ngsw-worker.js', {
enabled: !isDevMode(), // désactivé en dev
registrationStrategy: 'registerWhenStable:30000'
})
]
};
ng build + http-server dist/ — jamais ng serve qui désactive le SW.
Configuration ngsw-config.json
Le fichier ngsw-config.json déclare quels assets mettre en cache, avec quelle stratégie, et quelles API intercepter.
{
"$schema": "./node_modules/@angular/service-worker/config/schema.json",
"index": "/index.html",
"assetGroups": [
{
"name": "app-shell",
"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|gif|otf|ttf|woff|woff2)"]
}
}
],
"dataGroups": [
{
"name": "api-freshness",
"urls": ["/api/articles"],
"cacheConfig": {
"strategy": "freshness",
"maxSize": 100,
"maxAge": "3d",
"timeout": "10s"
}
}
]
}
installMode vs updateMode
prefetch— télécharge les ressources immédiatement lors de l'installation du SW. Idéal pour le shell applicatif.lazy— télécharge uniquement quand la ressource est demandée la première fois. Idéal pour les images et assets secondaires.
Stratégies de cache
Pour les dataGroups (appels API), deux stratégies principales s'opposent :
- freshness — essaie le réseau en premier, utilise le cache si le réseau ne répond pas dans le
timeout. Idéal pour les données qui changent fréquemment (flux, prix, stocks). - performance — utilise le cache en premier, interroge le réseau uniquement si la donnée est expirée (
maxAge). Idéal pour les données stables (config, catalogue, profil).
{
"dataGroups": [
{
"name": "api-config",
"urls": ["/api/config", "/api/categories"],
"cacheConfig": {
"strategy": "performance",
"maxSize": 20,
"maxAge": "1d"
}
},
{
"name": "api-live",
"urls": ["/api/prices/**"],
"cacheConfig": {
"strategy": "freshness",
"maxSize": 50,
"maxAge": "1m",
"timeout": "5s"
}
}
]
}
Mode offline et fallback
Quand l'utilisateur perd la connexion, le service worker sert les assets depuis le cache. Pour les routes dynamiques sans cache, il faut prévoir un fallback explicite.
// Détecter l'état de connexion dans l'application
import { Injectable, signal } from '@angular/core';
@Injectable({ providedIn: 'root' })
export class ConnectivityService {
readonly isOnline = signal(navigator.onLine);
constructor() {
window.addEventListener('online', () => this.isOnline.set(true));
window.addEventListener('offline', () => this.isOnline.set(false));
}
}
// Dans un composant
@Component({
template: `
@if (!connectivity.isOnline()) {
<div class="alert alert-warning" role="alert">
Vous êtes hors ligne. Certaines données peuvent ne pas être à jour.
</div>
}
`
})
export class AppComponent {
connectivity = inject(ConnectivityService);
}
/offline avec un composant simplifié qui s'affiche quand une navigation vers une page non cachée échoue. Configure-la dans ngsw-config.json comme fallback de navigation.
Gestion des mises à jour
Quand un nouveau build est déployé, le service worker le détecte en arrière-plan. Angular expose le service SwUpdate pour informer l'utilisateur et appliquer la mise à jour au bon moment.
import { Component, inject, OnInit } from '@angular/core';
import { SwUpdate, VersionReadyEvent } from '@angular/service-worker';
import { filter } from 'rxjs/operators';
@Component({ ... })
export class AppComponent implements OnInit {
private swUpdate = inject(SwUpdate);
ngOnInit(): void {
if (!this.swUpdate.isEnabled) return;
// Écouter quand une nouvelle version est prête
this.swUpdate.versionUpdates.pipe(
filter((evt): evt is VersionReadyEvent => evt.type === 'VERSION_READY')
).subscribe(() => {
if (confirm('Une nouvelle version est disponible. Recharger ?')) {
this.swUpdate.activateUpdate().then(() =>
document.location.reload()
);
}
});
// Vérifier manuellement (ex: au focus de l'onglet)
document.addEventListener('visibilitychange', () => {
if (!document.hidden) this.swUpdate.checkForUpdate();
});
}
}
Checklist PWA
- Activer le SW uniquement en production avec
enabled: !isDevMode()— évite les conflits de cache en développement. - Tester avec
ng build+ serveur local HTTPS — jamais avecng serve. - Configurer
manifest.webmanifest: icônes 192px et 512px,display: standalone,theme_color. - Utiliser
installMode: prefetchpour le shell etlazypour les assets secondaires. - Choisir la stratégie
freshnesspour les API temps réel etperformancepour les données stables. - Implémenter un banner de mise à jour avec
SwUpdate.versionUpdates— ne pas forcer le rechargement sans confirmation. - Afficher un message clair quand l'utilisateur est hors ligne via
navigator.onLineet les événementsonline/offline. - Auditer avec Lighthouse (score PWA) après le build de production — viser 90+ sur mobile.