Le PWA, ovvero le Progressive Web Apps, sono uno strumento moderno da cui molti siti web possono trarre vantaggio, sia in termini di tempi di caricamento che per l’interazione con funzionalità native. Nel presente articolo andremo a creare una piccola PWA di test utilizzando Angular.
Cos’è una PWA?
Una PWA è un tipo di applicazione scritta utilizzando, di base, HTML, Javascript e CSS, e distribuita sul web, che può essere eseguita su qualunque dispositivo (o quasi) che utilizza un browser con funzionalità standard in termini di compatibilità di motori JS.
Le Progressive Web Apps fanno largo uso dei service workers, o meglio, delle loro API messe a disposizione dai browser, al fine di ottenere meccanismi di caching, accesso a funzionalità native e, inoltre, fanno si che l’utente abbia la percezione di stare interagendo con un’applicazione.
Creiamo una PWA in Angular
Il primo passo da compiere è la creazione di un’applicazione Angular, utilizzando il classico comando
ng new angular-pwa-testPer quel che dobbiamo fare può essere opportuno installare già in questa fase il routing di Angular; infine, durante il wizard di creazione dell’applicazione, a meno di casi particolari, seleziono SCSS come motore per gli stili.
NOTA: Per poter utilizzare la CLI di Angular è necessario predisporre preventivamente l’ambiente di sviluppo. Consiglio sempre di installare nvm [node version manager] per poter gestire diverse versioni di node sulla stessa macchina e quindi poter gestire anche differenti versioni di Angular CLI [ma anche Cordova, Ionic, etc etc]
L’esecuzione del comando precedente, quindi, va a creare l’applicazione Angular.

Una volta creata l’applicazione dobbiamo procedere ad installare @angular/pwa, uno schematic che, tra le altre cose, installa @angular/service-worker come dipendenza, genera dei files per la configurazione della cache e per il manifest della web app.
npx -p @angular/cli@14.0.3 ng add @angular/pwa@14.2.10NOTA: Per poter utilizzare la CLI di Angular è necessario predisporre preventivamente l’ambiente di sviluppo. Consiglio sempre di installare nvm [node version manager] per poter gestire diverse versioni di node sulla stessa macchina e quindi poter gestire anche differenti versioni di Angular CLI [ma anche Cordova, Ionic, etc etc]
Il comando precedente ha avuto il seguente output.

Dall’output dell’esecuzione si comprende che, oltre ad installare alcune dipendenze, è stato creato il file ngsw-config.json, il manifest della webapp, alcune icone e, infine sono stati aggiornati angular.json, package.json, index.html e app.module.ts.
Il file ngsw-config.json contiene, in formato JSON, la configurazione per la generazione del service worker. In esso vanno configurati l’entry point HTML dell’applicativo e la modalità di caching per le risorse [es. gli assets].

Il file manifest.webmanifest contiene, sostanzialmente, le informazioni su come dovrà apparire la nostra Progressive Web App quando verrà lanciata: è il file nel quale poter impostare, ad esempio, il logo e i colori di background.

Molto importanti sono inoltre le modifiche apportate al file angular.json. Tali modifiche infatti, sono necessarie per indicare che dovrà essere abilitato il service worker la cui configurazione è il file ngsw-config.json.

Infine all’interno del modulo dell’applicazione viene importato il ServiceWorkerModule e registrato il service worker ngsw-config.js in ambiente di produzione.

Esecuzione della PWA
Normalmente un’applicazione Angular viene eseguita lanciando il comando ng serve, ma in questo caso, il server interno di Angular non risulta essere sufficiente. Inoltre c’è da tenere in considerazione che, qualora non si voglia/possa utilizzare HTTPS il service worker verrà registrato solamente su localhost.
NOTA: Per poter utilizzare la CLI di Angular è necessario predisporre preventivamente l’ambiente di sviluppo. Consiglio sempre di installare nvm [node version manager] per poter gestire diverse versioni di node sulla stessa macchina e quindi poter gestire anche differenti versioni di Angular CLI [ma anche Cordova, Ionic, etc etc]
A questo punto si può procedere effettuando la build dell’applicazione, ricordando che il service worker viene abilitato per la sola modalità di prod, pertanto dobbiamo utilizzare il comando
ng build --configuration productionIl comando ha generato, come di consueto, nella cartella dist/angular-pwa-test la versione dell’applicazione che dovremo andare ad utilizzare. Per fare ciò entriamo da terminale all’interno di questa cartella e lanciamo il comando
http-serverQuesto comando farà partire un web server per servire i files contenuti nella cartella corrente, sulla porta 8080. E’ uno strumento abbastanza utile e potente che, con delle opportune configurazioni, permette di servire anche in HTTPS oppure di abilitare il CORS. Qualora dovessimo avere un errore per mancanza dell’applicativo possiamo procedere alla sua installazione con il comando npm i -g http-server.
Accedendo alla pagina http://localhost:8080 vediamo che l’applicazione è correttamente partita.

Utilizzando gli strumenti di ispezione messi a disposizione dal browser, accedendo alle risorse dell’applicazione quindi al path Application>ServiceWorkers vediamo come il service worker ngsw-worker.js è stato correttamente caricato.

Per dimostrare che sia funzionante possiamo anche ricaricare la pagina e verificare negli strumenti di rete che le risorse non vengono richieste al server ma gestite direttamente dal service worker.

Come suggerito dalla documentazione ufficiale possiamo provare a creare un disservizio di rete e verificare il comportamento della nostra PWA. Per fare questo possiamo modificare il valore della select accanto alla label “Disable cache” dal valore No Throttling al valore Offline, in questo modo al caricamento della pagina l’applicazione non avrà accesso ad internet. Cosa accade alla nostra applicazione? Nel caso di un’applicazione normale il browser mostrerà un messaggio per indicare che si è disconnessi dalla rete, mentre nel caso del service worker l’applicazione verrà caricata normalmente.

Visualizzazione dello stato nell’applicazione
Cerchiamo di effettuare delle piccole modifiche al codice della nostra applicazione per interagire con il service worker. Per fare questo dobbiamo andare a modificare il componente (l’unico attualmente) contenuto all’interno della nostra applicazione.
Modifichiamo il file app.component.ts andando ad inserire una variabile che indichi se il sistema è online che verrà inizializzata ad un valore di default; procediamo anche a implementare un metodo che, accedendo alla proprietà window.navigator.onLine va ad aggiornare questa variabile. Infine procediamo a metterci in ascolto su due eventi che chiameranno il metodo per l’aggiornamento dello stato.
import { Component, OnInit } from '@angular/core';
@Component({
selector: 'app-root',
templateUrl: './app.component.html',
styleUrls: ['./app.component.scss'],
})
export class AppComponent implements OnInit {
isOnline: boolean;
constructor() {
this.isOnline = false;
}
public ngOnInit(): void {
this.updateOnlineStatus();
window.addEventListener('online', this.updateOnlineStatus.bind(this));
window.addEventListener('offline', this.updateOnlineStatus.bind(this));
}
private updateOnlineStatus(): void {
this.isOnline = window.navigator.onLine;
console.info(`isOnline=[${this.isOnline}]`);
}
}Andiamo ora a modificare la parte html per contenuto nel file app.component.html per mostrare lo stato.
<div class="container-fluid py-3">
<h1>Angular PWA Test</h1>
<div class="row">
<div class="col text-end">
Status:
</div>
<div class="col">
<span class="badge bg-success" *ngIf="isOnline; else offlineBlock">Online</span>
<ng-template #offlineBlock>
<span class="badge bg-danger" >Offline</span>
</ng-template>
</div>
</div>
</div>Possiamo procedere ad una nuova build e rilanciare il server per verificare il nuovo comportamento. Per evitare di dover rilanciare i comandi manualmente possiamo aggiungere la seguente riga nella sezione scripts del file package.json
"pwa": "ng build --configuration production && http-server ./dist/angular-pwa-test -p 8080"Possiamo così lanciare il comando npm run pwa e vediamo come l’esecuzione della PWA mostra nell’interfaccia lo stato corrente.


Caching delle chiamate API
La nostra PWA è quindi correttamente funzionante e quindi possiamo concentrarci sull’utilizzare le funzionalità messe a disposizione dai service workers.
Per poter testare il caching delle chiamate API prima di tutto andiamo ad inserire nella nostra applicazione di test due pulsanti che serviranno per effettuare due distinte chiamate API a dei servizi mock. Per fare questo iniziamo con il creare un service con il comando
ng generate service apiAll’interno del service andiamo ad implementare i due metodi che effettueranno le due chiamate API; chiaramente per effettuare questa operazione sarà necessario importare nell’app.module il modulo HttpClientModule e utilizzarlo all’interno del nostro service. Per semplicità all’interno dell’environment ho anche aggiunto un baseUrl a cui puntare per poter eventualmente modificare il puntamento da servizi mock a servizi reali.

Nel app.component.ts possiamo implementare due metodi che andranno a chiamare i servizi.
test1Perform() {
this.service.test1().subscribe(x => console.log(x));
}
test2Perform() {
this.service.test2().subscribe(x => console.log(x));
} 

