Rozgłaszaj aktualizacje stron z skryptami service worker

Andrew Guan
Andrew Guan

W niektórych sytuacjach skrypt service worker może wymagać aktywnej komunikacji z dowolnymi aktywnymi kartami, które kontroluje, aby informować o konkretnych zdarzeniach. Przykłady:

  • Informowanie strony o zainstalowaniu nowej wersji pracownika usługi, aby mogła ona wyświetlić użytkownikowi przycisk „Aktualizuj, aby odświeżyć”, umożliwiający natychmiastowy dostęp do nowej funkcji.
  • Poinformowanie użytkownika o zmianie danych w pamięci podręcznej, która nastąpiła po stronie service workera, przez wyświetlenie komunikatu, takiego jak „Aplikacja jest teraz gotowa do pracy w trybie offline” lub „Dostępna nowa wersja treści”.
Diagram pokazujący, jak serwis worker komunikuje się ze stroną, aby wysłać aktualizację.

Tego typu przypadki użycia będziemy nazywać „aktualizacjami transmisji”, które nie muszą otrzymywać wiadomości ze strony, aby rozpocząć komunikację. W tym przewodniku omówimy różne sposoby implementowania tego typu komunikacji między stronami a usługami w tle, korzystając ze standardowych interfejsów API przeglądarki i biblioteki Workbox.

Przypadki produkcyjne

Tinder

Tinder PWA używa workbox-window do nasłuchiwania ważnych momentów cyklu życia usługi na stronie (np. „zainstalowana”, „kontrolowana” i „aktywowana”). Gdy nowy serwis działający w tle zostanie uruchomiony, wyświetli się baner „Dostępna aktualizacja”, aby użytkownicy mogli odświeżyć PWA i uzyskać dostęp do najnowszych funkcji:

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

Squoosh

Gdy skrypt Squoosh PWA zapisze w pamięci podręcznej wszystkie zasoby niezbędne do pracy w trybie offline, wysyła na stronę komunikat „Gotowa do pracy offline” z informacją o tej funkcji:

Zrzut ekranu z funkcją „Gotowy do pracy offline” w aplikacji internetowej Squoosh.
W PWA Squoosh usługa workera rozgłasza na stronie aktualizację, gdy pamięć podręczna jest gotowa, a strona wyświetla komunikat „Gotowe do pracy offline”.

Korzystanie z Workbox

Nasłuchiwanie zdarzeń cyklu życia usługi workera

workbox-window udostępnia prosty interfejs do nasłuchiwania ważnych zdarzeń cyklu życia skryptu service worker. Biblioteka korzysta z interfejsów API po stronie klienta, takich jak updatefoundstatechange, oraz udostępnia obiekt workbox-window z odbiorcami zdarzeń wyższego poziomu, co ułatwia użytkownikowi korzystanie z tych zdarzeń.

Ten kod strony pozwala wykryć każdą nową wersję skryptu service worker, aby można było przekazać tę informację użytkownikowi:

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 pamięci podręcznej

Pakiet Workbox workbox-broadcast-update zapewnia standardowy sposób powiadamiania klientów okien o zaktualizowaniu odpowiedzi z pamięci podręcznej. Jest ona najczęściej używana razem ze strategią StaleWhileRevalidate.

Aby przesyłać aktualizacje, dodaj opcję broadcastUpdate.BroadcastUpdatePlugin do opcji strategii po stronie pracownika:

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ądarek

Jeśli funkcje Workbox nie wystarczają do Twoich potrzeb, użyj tych interfejsów API przeglądarki, aby zaimplementować „aktualizacje rozsyłane”:

Interfejs Broadcast Channel API

Skrypt service worker tworzy obiekt BroadcastChannel i zaczyna wysyłać do niego wiadomości. Dowolny kontekst (np. strona) zainteresowany otrzymywaniem tych wiadomości może utworzyć wystąpienie obiektu BroadcastChannel i zaimplementować moduł obsługi wiadomości do odbierania wiadomości.

Aby poinformować stronę o zainstalowaniu nowego pracownika usługi, 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 te zdarzenia:

// 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.
  }
};

To prosta metoda, ale jej ograniczeniem jest obsługa przez przeglądarki: w momencie pisania tego artykułu Safari nie obsługuje tego interfejsu API.

Client API

Interfejs API klienta zapewnia prosty sposób komunikowania się z wieloma klientami z poziomu service workera przez iterowanie w tablicy obiektów Client.

Aby wysłać wiadomość do ostatniej aktywnej karty, użyj tego kodu usługi:

// 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, aby przechwytywać te wiadomości:

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

Interfejs Client API to świetna opcja w przypadku rozpowszechniania informacji na wielu aktywnych kartach. Interfejs API jest obsługiwany przez wszystkie główne przeglądarki, ale nie wszystkie jego metody. Zanim go użyjesz, sprawdź jej obsługę.

Kanał wiadomości

Kanał wiadomości wymaga wstępnej konfiguracji polegającej na przekazaniu portu ze strony do usługi internetowej, aby ustanowić kanał komunikacji między nimi. Strona tworzy instancję obiektu MessageChannel i przekazuje skryptowi service worker interfejs 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 uchwyt za pomocą metody „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 z użyciem okna dla usług: „aktualizacje w ramach transmisji”. W przykładach omawianych w tym artykule uwzględniono m.in. słuchanie ważnych zdarzeń cyklu życia usługi oraz komunikowanie się z stroną o zmianach w treści lub danych w pamięci podręcznej. Można wymyślić ciekawsze przypadki użycia, w których skrypt service worker aktywnie komunikuje się ze stroną, nie otrzymując wcześniej żadnych komunikatów.

Więcej wzorców komunikacji okien i skryptów usługi znajdziesz tutaj:

Dodatkowe materiały