Rozgłaszaj aktualizacje stron z skryptami service worker

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

W niektórych przypadkach service worker może potrzebować aktywnie komunikować się z dowolną z aktywnych kart, które kontroluje, aby poinformować o określonym zdarzeniu. Przykłady:

  • Informowanie strony o zainstalowaniu nowej wersji skryptu service worker, aby mogła wyświetlać użytkownikowi przycisk „Odśwież, aby zaktualizować”, który umożliwia natychmiastowe korzystanie z nowych funkcji.
  • Informowanie użytkownika o zmianie w danych przechowywanych w pamięci podręcznej, która nastąpiła po stronie skryptu service worker, poprzez wyświetlanie informacji, np. „Aplikacja jest teraz gotowa do pracy w trybie offline” lub „Dostępna jest nowa wersja treści”.
Diagram przedstawiający proces komunikacji między skryptem service worker a stroną w celu wysłania aktualizacji.

Takie przypadki użycia, w których skrypt service worker nie musi otrzymywać wiadomości ze strony, aby rozpocząć komunikację, będziemy nazywać „aktualizacjami rozgłoszeniowymi”. W tym przewodniku omówimy różne sposoby implementowania tego typu komunikacji między stronami a procesami service worker przy użyciu standardowych interfejsów API przeglądarki i biblioteki Workbox.

Przypadki produkcyjne

Tinder

Aplikacja PWA Tinder korzysta z workbox-window, aby nasłuchiwać ważnych momentów cyklu życia skryptu service worker na stronie („zainstalowany”, „kontrolowany” i „aktywowany”). Dzięki temu, gdy pojawi się nowy skrypt service worker, wyświetli się baner „Dostępna aktualizacja”, aby użytkownik mógł odświeżyć aplikację PWA i uzyskać dostęp do najnowszych funkcji:

Zrzut ekranu przedstawiający funkcję „Dostępna aktualizacja” w aplikacji internetowej Tinder.
W progresywnej aplikacji internetowej Tinder skrypt service worker informuje stronę, że nowa wersja jest gotowa, a strona wyświetla użytkownikom baner „Dostępna aktualizacja”.

Squoosh

W Squoosh PWA, gdy skrypt service worker zapisze w pamięci podręcznej wszystkie niezbędne zasoby, aby aplikacja działała w trybie offline, wysyła do strony komunikat z informacją o gotowości do pracy w trybie offline. Dzięki temu użytkownik dowiaduje się o tej funkcji:

Zrzut ekranu aplikacji internetowej Squoosh z funkcją „Gotowa do pracy w trybie offline”.
W aplikacji Squoosh PWA skrypt service worker wysyła do strony komunikat o aktualizacji, gdy pamięć podręczna jest gotowa, a strona wyświetla komunikat „Gotowa do pracy w trybie offline”.

Korzystanie z Workbox

Nasłuchiwanie zdarzeń cyklu życia skryptu service worker

workbox-window udostępnia prosty interfejs do słuchania ważnych zdarzeń związanych z cyklem życia skryptu service worker. Biblioteka korzysta z interfejsów API po stronie klienta, takich jak updatefoundstatechange, oraz udostępnia słuchaczy zdarzeń wyższego poziomu w obiekcie workbox-window, co ułatwia użytkownikowi korzystanie z tych zdarzeń.

Poniższy kod strony umożliwia wykrywanie każdej instalacji nowej wersji skryptu service worker, dzięki czemu możesz informować o tym użytkownika:

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

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

wb.register();

Informowanie strony o zmianach w danych z pamięci podręcznej

Pakiet Workbox workbox-broadcast-update zapewnia standardowy sposób powiadamiania klientów okien o zaktualizowaniu odpowiedzi w pamięci podręcznej. Jest to najczęściej używane w połączeniu ze strategią StaleWhileRevalidate.

Aby transmitować aktualizacje, dodaj broadcastUpdate.BroadcastUpdatePlugin do opcji strategii po stronie skryptu 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(),
    ],
  })
);

W aplikacji internetowej możesz nasłuchiwać tych zdarzeń w ten sposób:

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();
  }
});

Korzystanie z interfejsów API przeglądarki

Jeśli funkcje udostępniane przez Workbox nie są wystarczające, użyj tych interfejsów API przeglądarki, aby zaimplementować „aktualizacje rozgłoszeniowe”:

Broadcast Channel API

Skrypt service worker tworzy obiekt BroadcastChannel i zaczyna wysyłać do niego wiadomości. Każdy kontekst (np. strona), który jest zainteresowany otrzymywaniem tych wiadomości, może utworzyć instancję obiektu BroadcastChannel i wdrożyć procedurę obsługi wiadomości, aby je odbierać.

Aby poinformować stronę o zainstalowaniu nowego skryptu service worker, użyj tego kodu:

// 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'});
});

Strona nasłuchuje tych zdarzeń, subskrybując 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.
  }
};

Jest to prosta metoda, ale ma ograniczenie w postaci obsługi przez przeglądarki: w momencie pisania tego artykułu Safari nie obsługuje tego interfejsu API.

Client API

Interfejs Client API zapewnia prosty sposób komunikacji z wieloma klientami z poziomu skryptu service worker przez iterację po tablicy obiektów Client.

Aby wysłać wiadomość do ostatniej aktywnej karty, użyj tego kodu skryptu service worker:

// 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'});
  }
});

Strona implementuje moduł obsługi wiadomości, który przechwytuje te wiadomości:

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

Interfejs Client API to świetne rozwiązanie w przypadku takich działań jak przesyłanie informacji do wielu aktywnych kart. Interfejs API jest obsługiwany przez wszystkie główne przeglądarki, ale nie wszystkie jego metody. Zanim zaczniesz z niej korzystać, sprawdź, czy jest obsługiwana przez Twoją przeglądarkę.

Kanał wiadomości

Message Channel wymaga początkowego kroku konfiguracji, polegającego na przekazaniu portu ze strony do skryptu service worker, aby utworzyć między nimi kanał komunikacji. Strona tworzy obiekt MessageChannel i przekazuje port do skryptu service worker za pomocą interfejsu postMessage():

const messageChannel = new MessageChannel();

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

Strona nasłuchuje wiadomości, implementując na tym porcie procedurę obsługi „onmessage”:

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

Skrypt service worker odbiera port i zapisuje do niego odwołanie:

// Initialize
let communicationPort;

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

Od tego momentu może wysyłać wiadomości do strony, wywołując postMessage() w odniesieniu do portu:

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

MessageChannel może być trudniejszy do wdrożenia ze względu na konieczność inicjowania portów, ale jest obsługiwany przez wszystkie główne przeglądarki.

Dalsze kroki

W tym przewodniku omówiliśmy jeden konkretny przypadek komunikacji między oknem a skryptem service worker: „przesyłanie aktualizacji”. Przykłady obejmują nasłuchiwanie ważnych zdarzeń cyklu życia skryptów service worker i informowanie strony o zmianach treści lub danych przechowywanych w pamięci podręcznej. Możesz wymyślić ciekawsze przypadki użycia, w których service worker aktywnie komunikuje się ze stroną bez wcześniejszego otrzymania żadnej wiadomości.

Więcej wzorców komunikacji między oknem a skryptem service worker znajdziesz w tych materiałach:

Dodatkowe materiały