Creazione di script per il service worker

Questo codelab fa parte del corso di formazione Developing Progressive Web Apps, sviluppato dal team Google Training Training. Otterrai il massimo valore da questo corso se lavori in sequenza nei codelab.

Per i dettagli completi sul corso, consulta la panoramica sullo sviluppo di app web progressive.

Introduzione

Questo lab illustra come creare un service worker semplice e spiega il ciclo di vita del service worker.

Obiettivi didattici

  • Crea uno script service worker di base, installalo ed esegui il debug semplice

Che cosa devi sapere

  • JavaScript e HTML di base
  • Concetti e sintassi di base di ES2015 Promi
  • Come attivare la Console per gli sviluppatori

Cosa ti serve prima di iniziare

Scarica o clona il repository pwa-training-labs da github e installa la versione LTS di Node.js, se necessario.

Accedi alla directory service-worker-lab/app/ e avvia un server di sviluppo locale:

cd service-worker-lab/app
npm install
node server.js

Puoi arrestare il server in qualsiasi momento con Ctrl-c.

Apri il browser e vai alla pagina localhost:8081/.

Nota: annulla la registrazione di tutti i service worker e cancella tutte le cache di service worker per localhost, in modo da non interferire con il lab. In Chrome DevTools, puoi accedere a Cancella dati sito dalla sezione Cancella spazio di archiviazione della scheda Applicazione.

Apri la cartella service-worker-lab/app/ nell'editor di testo che preferisci. La cartella app/ è il luogo in cui creerai il lab.

Questa cartella contiene:

  • below/another.html, js/another.js, js/other.js e other.html sono risorse di esempio che utilizziamo per sperimentare l'ambito del service worker
  • La cartella styles/ contiene i fogli di stile a cascata per questo lab
  • La cartella test/ contiene file che consentono di verificare l'avanzamento
  • index.html è la pagina HTML principale del nostro sito/applicazione di esempio
  • service-worker.js è il file JavaScript utilizzato per creare il nostro service worker
  • package.json e package-lock.json monitorano i pacchetti di nodi utilizzati in questo progetto
  • server.js è un semplice server espresso che utilizziamo per ospitare la nostra app

Apri service-worker.js nell'editor di testo. Tieni presente che il file è vuoto. Non abbiamo ancora aggiunto alcun codice da eseguire all'interno del service worker.

Apri index.html nell'editor di testo.

All'interno dei tag <script>, aggiungi il codice seguente per registrare il service worker:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('Service Worker is registered', registration);
    })
    .catch(err => {
      console.error('Registration failed:', err);
    });
  });
}

Salva lo script e aggiorna la pagina. La console dovrebbe restituire un messaggio che indica che il service worker è stato registrato. In Chrome, puoi verificare che un service worker sia registrato aprendo DevTools (Ctrl + Maiusc + I su Windows e Linux o ⌘ + Alt + I su Mac), facendo clic sulla scheda Applicazione e quindi sull'opzione Service worker. Il risultato dovrebbe essere simile al seguente:

(Facoltativo) Apri il sito su un browser non supportato e verifica che il controllo di supporto condizionale.

Spiegazione

Il codice riportato sopra registra il file service-worker.js come service worker. Verifica innanzitutto se il browser supporta i service worker. Questa operazione deve essere eseguita ogni volta che registri un service worker perché alcuni browser potrebbero non supportare i service worker. Il codice registra quindi il service worker utilizzando il metodo register dell'API ServiceWorkerContainer, presente nell'interfaccia di Navigator di Windows.

navigator.serviceWorker.register(...) restituisce una promessa che si risolve con un oggetto registration una volta registrato il service worker. In caso contrario, la promessa verrà rifiutata.

Le modifiche allo stato del service worker attivano gli eventi nel service worker.

Aggiungi listener di eventi

Apri service-worker.js nell'editor di testo.

Aggiungi i seguenti listener di eventi per il service worker:

self.addEventListener('install', event => {
  console.log('Service worker installing...');
  // Add a call to skipWaiting here
});

self.addEventListener('activate', event => {
  console.log('Service worker activating...');
});

Salva il file.

Annulla manualmente la registrazione del service worker e aggiorna la pagina per installare e attivare il service worker aggiornato. Il log della console dovrebbe indicare che il nuovo service worker è stato registrato, installato e attivato.

Nota: il log di registrazione potrebbe risultare non conforme agli altri log (installazione e attivazione). Il service worker viene eseguito contemporaneamente alla pagina, quindi non possiamo garantire l'ordine dei log (il log di registrazione proviene dalla pagina, mentre i log di installazione e attivazione provengono dal service worker). Tuttavia, l'installazione, l'attivazione e altri eventi del service worker avvengono in un ordine definito all'interno del service worker, che dovrebbe sempre comparire nell'ordine previsto.

Spiegazione

Il service worker emette un evento install al termine della registrazione. Nel codice riportato sopra, viene registrato un messaggio all'interno del listener di eventi install, ma in un'app reale è l'ideale per memorizzare nella cache gli asset statici.

Quando viene registrato un service worker, il browser rileva se è un nuovo service worker (perché è diverso da quello installato in precedenza o perché non è presente alcun service worker registrato per questo sito). Se il service worker è nuovo (come in questo caso), allora il browser lo installa.

Quando prende il controllo della pagina, il service worker emette un evento activate. Il codice riportato sopra registra un messaggio qui, ma questo evento viene spesso utilizzato per aggiornare le cache.

È possibile attivare un solo service worker alla volta per un determinato ambito (vedi Esplorazione del service worker). Di conseguenza, un service worker appena installato non viene attivato finché il service worker esistente non è più in uso. Questo è il motivo per cui tutte le pagine controllate da un service worker devono essere chiuse prima che un nuovo service worker possa prendere il controllo. Poiché abbiamo annullato la registrazione del service worker esistente, questo è stato attivato immediatamente.

Nota: l'aggiornamento della pagina non è sufficiente per trasferire il controllo a un nuovo service worker, perché la nuova pagina verrà richiesta prima dell'unload della pagina corrente e non ci sarà un momento in cui il vecchio service worker non sarà in uso.

Nota:puoi anche attivare manualmente un nuovo service worker utilizzando alcuni browser e strumenti per sviluppatori e in modo programmatico con skipWaiting(), illustrato nella sezione 3.4.

Aggiorna il service worker

Aggiungi il seguente commento in service-worker.js:

// I'm a new service worker

Salva il file e aggiorna la pagina. Esamina i log nella console. Tieni presente che il nuovo service worker viene installato ma non attivato. In Chrome, puoi visualizzare il service worker in attesa nella scheda Application di DevTools.

Chiudi tutte le pagine associate al service worker. Dopodiché, riapri il localhost:8081/. Il log della console dovrebbe indicare che il nuovo service worker è stato attivato.

Nota: se ricevi risultati imprevisti, assicurati che la cache HTTP sia disattivata negli strumenti per sviluppatori.

Spiegazione

Il browser rileva una differenza di byte tra il file del nuovo service worker e quello esistente (a causa del commento aggiunto), quindi è installato il nuovo service worker. Poiché può essere attivo un solo service worker alla volta (per un determinato ambito), anche se il nuovo service worker è installato, non può essere attivato finché il service worker esistente non è più in uso. Chiudendo tutte le pagine sotto il controllo del vecchio service worker, possiamo attivare il nuovo service worker.

Ignorare la fase di attesa

È possibile che un nuovo service worker venga attivato immediatamente, anche se è presente un service worker esistente, saltando la fase di attesa.

In service-worker.js, aggiungi una chiamata a skipWaiting nel listener di eventi install:

self.skipWaiting();

Salva il file e aggiorna la pagina. Nota che il nuovo service worker viene installato e attivato immediatamente, anche se era sotto il controllo di un precedente service worker.

Spiegazione

Il metodo skipWaiting() consente a un service worker di attivarsi non appena termina l'installazione. Il listener di eventi di installazione è un punto comune per chiamare skipWaiting(), ma può essere chiamato ovunque durante o prima della fase di attesa. Consulta questa documentazione per ulteriori informazioni su quando e come utilizzare skipWaiting(). Per il resto del lab, possiamo testare il nuovo codice del service worker senza annullare manualmente la registrazione del service worker.

Per avere ulteriori informazioni

I service worker possono fungere da proxy tra l'app web e la rete.

Aggiungi un listener di recupero per intercettare le richieste del nostro dominio.

Aggiungi il seguente codice a service-worker.js:

self.addEventListener('fetch', event => {
  console.log('Fetching:', event.request.url);
});

Salva lo script e aggiorna la pagina per installare e attivare il service worker aggiornato.

Controlla la console e osserva che non sono stati registrati eventi di recupero. Aggiorna la pagina e controlla nuovamente la console. Questa volta dovresti visualizzare gli eventi di recupero della pagina e dei relativi asset (ad esempio il codice CSS).

Fai clic sui link Altre pagine, Altra pagina e Indietro.

Nella console, vedrai gli eventi di recupero per ciascuna delle pagine e le relative risorse. Tutti i log hanno senso?

Nota: se visiti una pagina e non hai disattivato la cache HTTP, gli asset CSS e JavaScript potrebbero essere memorizzati nella cache locale. In questo caso, non vedrai gli eventi di recupero per queste risorse.

Spiegazione

Il service worker riceve un evento fetch per ogni richiesta HTTP effettuata dal browser nell'ambito. L'oggetto evento di recupero contiene la richiesta. L'ascolto degli eventi di recupero nel service worker è simile all'ascolto degli eventi di clic nel DOM. Nel nostro codice, quando si verifica un evento di recupero, registriamo l'URL richiesto alla console (in pratica possiamo anche creare e restituire la nostra risposta personalizzata con risorse arbitrarie).

Perché gli eventi di recupero non vengono registrati al primo aggiornamento? Per impostazione predefinita, il recupero degli eventi da una pagina non viene eseguito da un service worker se non riceve la richiesta stessa. Ciò garantisce coerenza nel sito; se una pagina viene caricata senza il service worker, lo fa anche le relative risorse secondarie.

Per avere ulteriori informazioni

Codice soluzione

Per recuperare una copia del codice funzionante, vai alla cartella 04-intercepting-network-requests/.

I service worker hanno l'ambito. L'ambito del service worker determina da quali percorsi intercetta le richieste.

Trova l'ambito

Aggiorna il codice di registrazione in index.html con:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('service-worker.js')
    .then(registration => {
      console.log('SW registered with scope:', registration.scope);
    })
    .catch(err => {
      console.error('Registration failed:', err);
    });
  });
}

Aggiorna il browser. Tieni presente che la console mostra l'ambito del service worker (in questo caso http://localhost:8081/).

Spiegazione

La promessa restituita da register() si risolve nell'oggetto di registrazione, che contiene l'ambito del service worker.

L'ambito predefinito è il percorso del file del service worker e si estende a tutte le directory inferiori. Di conseguenza, un service worker nella directory principale di un'app controlla le richieste di tutti i file al suo interno.

Spostamento del service worker

Sposta service-worker.js nella directory below/ e aggiorna l'URL del service worker nel codice di registrazione in index.html.

Annulla la registrazione dell'attuale service worker nel browser e aggiorna la pagina.

La console mostra che l'ambito del service worker è ora http://localhost:8081/below/. In Chrome, puoi anche visualizzare l'ambito del service worker nella scheda Application di DevTools:

Torna alla pagina principale e fai clic su Altra pagina, Altra pagina e Indietro. Quali richieste di recupero vengono registrate? Quali non sono?

Spiegazione

L'ambito predefinito del service worker è il percorso del file del service worker. Poiché il file del service worker ora si trova in below/, questo è il suo ambito. Ora la console registra solo gli eventi di recupero per another.html, another.css e another.js, perché queste sono le uniche risorse presenti nell'ambito del service worker.

Imposta un ambito arbitrario

Sposta di nuovo il service worker nella directory radice del progetto (app/) e aggiorna l'URL del service worker nel codice di registrazione in index.html.

Utilizza il riferimento su MDN per impostare l'ambito del service worker alla directory below/ utilizzando il parametro facoltativo in register().

Annulla la registrazione del service worker e aggiorna la pagina. Fai clic su Altra pagina, Un'altra pagina e Indietro.

Ancora una volta la console mostra che l'ambito del service worker è ora http://localhost:8081/below/ e i log recuperano solo gli eventi per another.html, another.css e another.js.

Spiegazione

È possibile impostare un ambito arbitrario passando a un parametro aggiuntivo durante la registrazione, ad esempio:

navigator.serviceWorker.register('/service-worker.js', {
  scope: '/kitten/'
});

Nell'esempio precedente, l'ambito del service worker è impostato su /kitten/. Il service worker intercetta le richieste dalle pagine di /kitten/ e /kitten/lower/, ma non quelle di pagine come /kitten o /.

Nota: non puoi impostare un ambito arbitrario sopra la posizione effettiva del service worker. Tuttavia, se il server worker è attivo su un client utilizzato con l'intestazione Service-Worker-Allowed, puoi specificare un ambito massimo per il service worker sopra la località del service worker.

Per avere ulteriori informazioni

Codice soluzione

Per recuperare una copia del codice funzionante, vai alla cartella solution/.

Ora un service worker semplice è in funzione e comprende il ciclo di vita del service worker.

Per avere ulteriori informazioni

Ciclo di vita dei service worker

Per visualizzare tutti i codelab nel corso di formazione per PWA, vedi il codelab di benvenuto per il corso/