Trasmissione di aggiornamenti alle pagine con i service worker

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

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

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

Questi tipi di casi d'uso chiameremo questi tipi di casi d'uso in cui il service worker non deve ricevere un messaggio dalla pagina per avviare una comunicazione "Trasmetti aggiornamenti". In questa guida esamineremo diversi modi per implementare questo tipo di comunicazione tra pagine e service worker, utilizzando le API browser standard e la libreria delle caselle di lavoro.

Casi di produzione

Tinder

La PWA Tinder utilizza workbox-window per ascoltare dalla pagina i momenti importanti del ciclo di vita dei service worker ("installato", "controllato" e "attivato"). In questo modo, quando un nuovo service worker entra in gioco, viene mostrato il banner "Aggiornamento disponibile" che gli consente di aggiornare la PWA e accedere alle funzionalità più recenti:

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

Squoosh

Nella PWA di Squoosh, quando il service worker ha memorizzato nella cache tutti gli asset necessari per far funzionare la funzionalità offline, invia un messaggio alla pagina per mostrare un messaggio popup "Pronto per il funzionamento offline" per informare 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 visualizza il messaggio "Pronto per lavorare offline".

Utilizzo di Workbox

Ascolta gli eventi del ciclo di vita dei service worker

workbox-window offre un'interfaccia semplice per ascoltare importanti eventi del ciclo di vita dei service worker. In background, la libreria utilizza API lato client come updatefound e statechange e fornisce listener di eventi di livello superiore nell'oggetto workbox-window, facilitando il consumo di questi eventi da parte dell'utente.

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

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

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

wb.register();

Informa la pagina delle modifiche ai dati della cache

Il pacchetto Workbox workbox-broadcast-update fornisce un modo standard per notificare ai client finestra che una risposta memorizzata nella cache è stata aggiornata. Questo viene usato più di frequente insieme alla strategia StaleWhenRevalidate.

Per trasmettere gli aggiornamenti, aggiungi un broadcastUpdate.BroadcastUpdatePlugin alle opzioni della tua strategia lato service 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 come questi:

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 la funzionalità fornita da Workbox non è sufficiente per le tue esigenze, usa le seguenti API del browser per implementare gli "aggiornamenti della trasmissione":

API Broadcast Channel

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

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

// 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 iscrivendosi a 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 il suo limite è il supporto del browser: al momento della stesura di questo documento, Safari non supporta questa API.

API client

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

Utilizza il seguente codice del service worker per inviare un messaggio all'ultima scheda attiva:

// 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 suoi metodi lo sono. Verifica il supporto del browser prima di utilizzarlo.

Canale messaggi

Il canale Message richiede un passaggio di configurazione iniziale, che prevede il passaggio di una porta dalla pagina al service worker, per stabilire un canale di comunicazione tra di loro. La pagina crea un'istanza di 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 rimane in ascolto dei messaggi implementando un gestore "onmessage" su quella porta:

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

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

// 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 esaminato un caso specifico di comunicazione da Window to service worker: "Trasmetti aggiornamenti". Gli esempi esplorati includono l'ascolto di importanti eventi del ciclo di vita dei service worker e la comunicazione alla pagina delle modifiche ai contenuti o ai dati memorizzati nella cache. Potresti pensare a casi d'uso più interessanti in cui il service worker comunica in modo proattivo con la pagina, senza ricevere alcun messaggio in precedenza.

Per altri pattern di comunicazione tra Windows e Service worker, consulta:

Altre risorse