Trasmissione di aggiornamenti alle pagine con i service worker

Andrew Guan
Andrew Guan
Demián Renzulli
Demián Renzulli

In alcuni scenari, il worker di servizio potrebbe dover comunicare in modo proattivo con una delle schede attive che controlla per informare di un determinato evento. Ecco alcuni esempi:

  • Informa la pagina quando è stata installata una nuova versione del servizio worker, in modo che possa mostrare all'utente un pulsante "Aggiorna per aggiornare" per accedere immediatamente alla nuova funzionalità.
  • Comunicare all'utente una modifica ai dati memorizzati nella cache avvenuta lato service worker, mostrando un'indicazione, ad esempio: "L'app è ora pronta per il funzionamento offline" o "Nuova versione dei contenuti disponibile".
Diagramma che mostra un worker di servizio che comunica con la pagina per inviare un aggiornamento.

Chiameremo "aggiornamento di trasmissione" questi tipi di casi d'uso in cui il service worker non deve ricevere un messaggio dalla pagina per avviare una comunicazione. In questa guida esamineremo diversi modi per implementare questo tipo di comunicazione tra pagine e worker di servizio utilizzando le API browser standard e la libreria Workbox.

Casi di produzione

Tinder

Tinder PWA utilizza workbox-window per ascoltare i momenti importanti del ciclo di vita dei service worker dalla pagina ("installati", "controllati" e "attivati"). In questo modo, quando viene attivato un nuovo worker di servizio, viene visualizzato un banner "Aggiornamento disponibile", in modo che l'utente possa aggiornare la PWA e accedere alle ultime funzionalità:

Uno screenshot della funzionalità "Aggiornamento disponibile" della web app di Tinder.
Nella PWA di Tinder, il service worker comunica alla pagina che è disponibile una nuova versione e la pagina mostra agli utenti un banner "Aggiornamento disponibile".

Squoosh

Nella PWA Squoosh, quando il service worker ha memorizzato nella cache tutti gli asset necessari per far funzionare il servizio offline, invia un messaggio alla pagina per mostrare un avviso popup "Pronto per lavorare offline", informando l'utente della funzionalità:

Uno screenshot della funzionalità "Pronto per lavorare offline" dell'app web Squoosh.
Nella PWA Squoosh, il service worker trasmette un aggiornamento alla pagina quando la cache è pronta e la pagina mostra il messaggio popup "Pronto per il lavoro offline".

Utilizzo di Workbox

Ascoltare gli eventi del ciclo di vita del worker di servizio

workbox-window fornisce un'interfaccia semplice per ascoltare gli eventi importanti del ciclo di vita dei service worker. Sotto il cofano, la libreria utilizza API lato client come updatefound e statechange e fornisce ascoltatori di eventi di livello superiore nell'oggetto workbox-window, semplificando per l' utente l'utilizzo di questi eventi.

Il seguente codice pagina consente di rilevare ogni volta che viene installata una nuova versione del servizio worker, in modo da comunicarlo all'utente:

const wb = new Workbox('/sw.js');

wb.addEventListener('installed', (event) => {
  if (event.isUpdate) {
    // Show "Update App" banner
  }
});

wb.register();

Comunica alla pagina le modifiche ai dati della cache

Il pacchetto Workbox workbox-broadcast-update fornisce un modo standard per notificare ai client Windows che una risposta memorizzata nella cache è stata aggiornata. Viene solitamente utilizzata insieme alla strategia StaleWhileRevalidate.

Per trasmettere gli aggiornamenti, aggiungi un broadcastUpdate.BroadcastUpdatePlugin alle opzioni di strategia nel lato del servizio worker:

import {registerRoute} from 'workbox-routing';
import {StaleWhileRevalidate} from 'workbox-strategies';
import {BroadcastUpdatePlugin} from 'workbox-broadcast-update';

registerRoute(
  ({url}) => url.pathname.startsWith('/api/'),
  new StaleWhileRevalidate({
    plugins: [
      new BroadcastUpdatePlugin(),
    ],
  })
);

Nella tua app web, puoi ascoltare questi eventi nel seguente modo:

navigator.serviceWorker.addEventListener('message', async (event) => {
  // Optional: ensure the message came from workbox-broadcast-update
  if (event.data.meta === 'workbox-broadcast-update') {
    const {cacheName, updatedUrl} = event.data.payload;

    // Do something with cacheName and updatedUrl.
    // For example, get the cached content and update
    // the content on the page.
    const cache = await caches.open(cacheName);
    const updatedResponse = await cache.match(updatedUrl);
    const updatedText = await updatedResponse.text();
  }
});

Utilizzo delle API del browser

Se le funzionalità fornite da Workbox non sono sufficienti per le tue esigenze, utilizza le seguenti API browser per implementare gli "aggiornamenti di trasmissione":

API Broadcast Channel

Il service worker crea un oggetto BroadcastChannel e inizia a inviargli messaggi. Qualsiasi contesto (ad esempio la pagina) interessato a ricevere questi messaggi può creare un'istanza di un oggetto BroadcastChannel e implementare un gestore di messaggi per la ricezione dei messaggi.

Per informare la pagina quando viene installato un nuovo worker di servizio, utilizza il seguente codice:

// Create Broadcast Channel to send messages to the page
const broadcast = new BroadcastChannel('sw-update-channel');

self.addEventListener('install', function (event) {
  // Inform the page every time a new service worker is installed
  broadcast.postMessage({type: 'CRITICAL_SW_UPDATE'});
});

La pagina ascolta questi eventi sottoscrivendo l'sw-update-channel:

// Create Broadcast Channel and listen to messages sent to it
const broadcast = new BroadcastChannel('sw-update-channel');

broadcast.onmessage = (event) => {
  if (event.data && event.data.type === 'CRITICAL_SW_UPDATE') {
    // Show "update to refresh" banner to the user.
  }
};

Si tratta di una tecnica semplice, ma la sua limitazione è il supporto del browser: al momento in cui scriviamo, Safari non supporta questa API.

API client

L'API client offre un modo semplice per comunicare con più client dal service worker tramite l'iterazione su un array di oggetti Client.

Utilizza il seguente codice di worker di servizio per inviare un messaggio all'ultima scheda attivata:

// Obtain an array of Window client objects
self.clients.matchAll(options).then(function (clients) {
  if (clients && clients.length) {
    // Respond to last focused tab
    clients[0].postMessage({type: 'MSG_ID'});
  }
});

La pagina implementa un gestore dei messaggi per intercettare questi messaggi:

// Listen to messages
navigator.serviceWorker.onmessage = (event) => {
     if (event.data && event.data.type === 'MSG_ID') {
         // Process response
   }
};

L'API client è un'ottima opzione per casi come la trasmissione di informazioni a più schede attive. L'API è supportata da tutti i principali browser, ma non tutti i relativi metodi. Verifica la compatibilità del browser prima di usarlo.

Canale messaggi

Canale di messaggio richiede un passaggio di configurazione iniziale, passando una porta dalla pagina al service worker, per stabilire un canale di comunicazione tra i due. La pagina crea un'istanza per un oggetto MessageChannel e passa una porta al service worker tramite l'interfaccia postMessage():

const messageChannel = new MessageChannel();

// Init port
navigator.serviceWorker.controller.postMessage({type: 'PORT_INITIALIZATION'}, [
  messageChannel.port2,
]);

La pagina ascolta i messaggi implementando un gestore "onmessage" su quella porta:

// Listen to messages
messageChannel.port1.onmessage = (event) => {
  // Process message
};

Il service worker riceve la porta e ne salva un riferimento:

// Initialize
let communicationPort;

self.addEventListener('message', (event) => {
  if (event.data && event.data.type === 'PORT_INITIALIZATION') {
    communicationPort = event.ports[0];
  }
});

A questo punto può inviare messaggi alla pagina chiamando postMessage() nel riferimento alla porta:

// Communicate
communicationPort.postMessage({type: 'MSG_ID' });

MessageChannel potrebbe essere più complesso da implementare, a causa della necessità di inizializzare le porte, ma è supportato da tutti i principali browser.

Passaggi successivi

In questa guida abbiamo esplorato un caso particolare di comunicazione tra finestra e worker di servizio: "aggiornamento di trasmissione". Gli esempi esplorati includono l'ascolto di eventi importanti del ciclo di vita del servizio worker e la comunicazione alla pagina delle modifiche ai contenuti o ai dati memorizzati nella cache. Puoi pensare a casi d'uso più interessanti in cui il worker di servizio comunica in modo proattivo con la pagina senza aver ricevuto alcun messaggio in precedenza.

Per ulteriori modelli di comunicazione tra Windows e Service worker, dai un'occhiata qui:

Risorse aggiuntive