Natychmiastowa obsługa aktualizacji skryptu service worker

Domyślnie cykl życia skryptu service worker wymaga, aby po znalezieniu i zainstalowaniu zaktualizowanego skryptu service worker wszystkie otwarte karty kontrolowane przez bieżący skrypt service worker były zamknięte lub poddawane nawigacji, zanim zaktualizowany skrypt service worker aktywuje się i przejmie kontrolę.

W wielu przypadkach możesz zezwolić na wykonanie tego z odpowiednim czasem, ale w niektórych przypadkach warto powiadomić użytkownika o oczekującej aktualizacji skryptu service worker, a następnie zautomatyzować proces przełączania się na nowy skrypt service worker. Aby to zrobić, dodaj kod na stronie i skrypt service worker.

Kod, który należy umieścić na stronie

Poniższy kod jest uruchamiany we wbudowanym elemencie <script> za pomocą modułów JavaScript zaimportowanych z wersji workbox-window hostowanej w sieci CDN. Rejestruje skrypt service worker za pomocą workbox-window i reaguje, jeśli utknie na etapie oczekiwania. Po znalezieniu oczekującego skryptu service worker użytkownik jest informowany o dostępności zaktualizowanej wersji witryny oraz proponuje ponowne załadowanie strony.

<!-- This script tag uses JavaScript modules, so the proper `type` attribute value is required -->
<script type="module">
  // This code sample uses features introduced in Workbox v6.
  import {Workbox} from 'https://storage.googleapis.com/workbox-cdn/releases/6.4.1/workbox-window.prod.mjs';

  if ('serviceWorker' in navigator) {
    const wb = new Workbox('/sw.js');
    let registration;

    const showSkipWaitingPrompt = async (event) => {
      // Assuming the user accepted the update, set up a listener
      // that will reload the page as soon as the previously waiting
      // service worker has taken control.
      wb.addEventListener('controlling', () => {
        // At this point, reloading will ensure that the current
        // tab is loaded under the control of the new service worker.
        // Depending on your web app, you may want to auto-save or
        // persist transient state before triggering the reload.
        window.location.reload();
      });

      // When `event.wasWaitingBeforeRegister` is true, a previously
      // updated service worker is still waiting.
      // You may want to customize the UI prompt accordingly.

      // This code assumes your app has a promptForUpdate() method,
      // which returns true if the user wants to update.
      // Implementing this is app-specific; some examples are:
      // https://open-ui.org/components/alert.research or
      // https://open-ui.org/components/toast.research
      const updateAccepted = await promptForUpdate();

      if (updateAccepted) {
        wb.messageSkipWaiting();
      }
    };

    // Add an event listener to detect when the registered
    // service worker has installed but is waiting to activate.
    wb.addEventListener('waiting', (event) => {
      showSkipWaitingPrompt(event);
    });

    wb.register();
  }
</script>

Jeśli je zaakceptuje, messageSkipWaiting() nakazuje czekającemu skryptowi service worker wywołanie self.skipWaiting(), co oznacza, że rozpocznie się aktywacja. Po aktywowaniu nowy skrypt service worker przejmie kontrolę nad wszystkimi istniejącymi klientami, aktywując zdarzenie controlling w workbox-window. W takim przypadku bieżąca strona załaduje się ponownie przy użyciu najnowszej wersji wszystkich zasobów wstępnie zapisanych w pamięci podręcznej oraz nowej logiki routingu wykrytej w zaktualizowanym mechanizmie Service Worker.

Kod, który należy umieścić w skrypcie service worker

Po otrzymaniu kodu z poprzedniej sekcji na stronie musisz dodać do skryptu service worker kod, który poinformuje go, kiedy pominąć fazę oczekiwania. Jeśli używasz generateSW z workbox-build i masz ustawioną opcję skipWaiting na false (domyślną), nie musisz nic robić, ponieważ poniższy kod zostanie automatycznie dołączony do wygenerowanego pliku skryptu service worker.

Jeśli tworzysz własny skrypt service worker – być może w połączeniu z jednym z narzędzi do kompilacji Workbox w trybie injectManifest – musisz samodzielnie dodać ten kod:

addEventListener('message', (event) => {
  if (event.data && event.data.type === 'SKIP_WAITING') {
    self.skipWaiting();
  }
});

Spowoduje to nasłuchiwanie wiadomości wysyłanych z systemu workbox-window do skryptu service worker o wartości type o wartości SKIP_WAITING, a gdy to nastąpi, wywołuje metodę self.skipWaiting(). Za wysłanie tej wiadomości odpowiada metoda messageSkipWaiting() w interfejsie workbox-window, widoczna we wcześniejszym przykładowym kodzie.

Czy chcesz pokazać komunikat?

Nie jest to wzorzec, z którego musi korzystać każda aplikacja wdrażająca mechanizm Service Worker. Jest on używany w wybranych scenariuszach, w których brak możliwości ponownego załadowania strony po aktualizacji skryptu service worker może spowodować nieoczekiwane zachowania. Nie ma sztywnych i szybkich reguł, które określają, czy polecenie ponownego załadowania warto wyświetlić. Oto kilka sytuacji, w których takie polecenie może mieć sens:

  • Intensywnie korzystasz z pamięci podręcznej. Jeśli chodzi o zasoby statyczne, później możesz mieć problemy, jeśli do obsługi żądań nawigacji będziesz wykorzystywać strategię ukierunkowaną na sieć lub sieć, ale leniwe ładowanie zasobów statycznych. Może to powodować sytuacje, w których zasoby z obsługą wersji mogą ulec zmianie, a skrypt service worker nie umieścił ich w pamięci podręcznej. Użycie przycisku ponownego załadowania pozwala uniknąć niektórych nieoczekiwanych zachowań.
  • Jeśli używasz kodu HTML w pamięci podręcznej, W takim przypadku zdecydowanie zalecamy udostępnienie przycisku ponownego załadowania przy aktualizacjach skryptu service worker, ponieważ aktualizacje kodu HTML nie zostaną rozpoznane, dopóki zaktualizowany skrypt Service nie przejmie kontroli.
  • Jeśli nie używasz zwykle buforowania w czasie działania. Podczas buforowania zasobów w czasie działania nie musisz informować użytkownika o konieczności ponownego załadowania. Zasoby z obsługą wersji będą w przyszłości dodawane do pamięci podręcznej środowiska wykonawczego, o ile w żądaniach nawigacyjnych jest stosowana strategia ukierunkowana na sieć lub tylko sieć.
  • Jeśli używasz strategii stale podczas ponownej weryfikacji, możesz użyć modułu workbox-broadcast-update, aby powiadamiać użytkowników o aktualizacjach skryptu service worker.

To, czy musisz powiadamiać użytkownika o aktualizacjach skryptu service worker, zależy od Twojej aplikacji i jej unikalnych wymagań. Jeśli stwierdzisz, że po uruchomieniu nowego skryptu service worker użytkownicy zachowują się dziwnie, jest to najlepszy sygnał, że należy ich powiadomić.