Sofortige Verarbeitung von Service Worker-Updates

Standardmäßig erfordert der Service Worker-Lebenszyklus, dass wenn ein aktualisierter Service Worker gefunden und installiert wird, alle geöffneten Tabs, die der aktuelle Service Worker steuert, geschlossen werden oder einer Navigation unterzogen werden müssen, bevor der aktualisierte Service Worker aktiviert und die Kontrolle übernimmt.

In vielen Fällen kann es in Ordnung sein, dies zu einem bestimmten Zeitpunkt zuzulassen. In einigen Fällen kann es jedoch sinnvoll sein, den Nutzer über ein ausstehendes Service Worker-Update zu informieren und dann den Wechsel zum neuen Service Worker zu automatisieren. Dazu müssen Sie Ihrer Seite und Ihrem Service Worker Code hinzufügen.

Code für Ihre Seite

Der folgende Code wird in einem Inline-<script>-Element ausgeführt. Dabei werden JavaScript-Module verwendet, die aus einer CDN-gehosteten Version von workbox-window importiert wurden. Er registriert einen Service Worker mit workbox-window und reagiert, wenn er in der Wartephase hängen bleibt. Wenn ein wartender Service Worker gefunden wird, informiert dieser Code den Nutzer darüber, dass eine aktualisierte Version der Website verfügbar ist, und fordert ihn auf, die Website neu zu laden.

<!-- 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>

Wenn sie dies akzeptieren, weist messageSkipWaiting() den wartenden Service Worker an, self.skipWaiting() aufzurufen. Damit beginnt die Aktivierung. Nach der Aktivierung übernimmt der neue Service Worker die Kontrolle über alle vorhandenen Clients und löst das controlling-Ereignis in workbox-window aus. In diesem Fall wird die aktuelle Seite mit der neuesten Version aller vorab im Cache gespeicherten Assets und jeder neuen Routinglogik, die im aktualisierten Service Worker gefunden wurde, neu geladen.

Code für den Service Worker

Sobald Sie den Code aus dem vorherigen Abschnitt auf Ihrer Seite haben, müssen Sie Ihrem Service Worker Code hinzufügen, der ihm weiß, wann die Wartephase übersprungen werden soll. Wenn Sie generateSW aus workbox-build verwenden und die Option skipWaiting auf false (Standardeinstellung) festgelegt ist, ist das kein Problem, da der unten stehende Code automatisch in die generierte Service Worker-Datei eingefügt wird.

Wenn Sie Ihren eigenen Service Worker schreiben – möglicherweise zusammen mit einem der Build-Tools von Workbox im injectManifest-Modus – müssen Sie den folgenden Code selbst hinzufügen:

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

Damit wird auf Nachrichten gewartet, die von workbox-window mit dem type-Wert SKIP_WAITING an den Service Worker gesendet wurden. In diesem Fall wird self.skipWaiting() aufgerufen. Das Senden dieser Nachricht erfolgt über die Methode messageSkipWaiting() in workbox-window, die im vorherigen Codebeispiel gezeigt wurde.

Muss eine Aufforderung angezeigt werden?

Dies ist kein Muster, das jede Anwendung, die einen Service Worker bereitstellt, folgen muss. Dies gilt für bestimmte Szenarien, in denen es zu unerwartetem Verhalten kommen kann, wenn bei einem Service Worker-Update keine Möglichkeit zum Aktualisieren einer Seite bereitgestellt wird. Es gibt keine festen Regeln dazu, ob eine Aufforderung zum Aktualisieren angezeigt werden soll. Hier sind einige Situationen, in denen dies sinnvoll sein kann:

  • Sie nutzen Precaching ausgiebig. Bei statischen Assets können später Probleme auftreten, wenn Sie für Navigationsanfragen eine Strategie des Typs „Network-first“ oder „Nur Netzwerk“ verwenden, aber Lazy Loading für statische Assets verwenden. Dies kann dazu führen, dass sich versionierte Assets ändern und ein Service Worker sie nicht vorab im Cache gespeichert hat. Wenn Sie hier eine Schaltfläche zum Aktualisieren anbieten, können unerwartete Verhaltensweisen vermieden werden.
  • Wenn Sie vorab im Cache gespeicherte HTML-Inhalte bereitstellen. In diesem Fall sollten Sie dringend eine Schaltfläche zum Aktualisieren für Service Worker-Updates anbieten, da Aktualisierungen dieses HTML-Codes erst erkannt werden, wenn der aktualisierte Service Worker die Kontrolle übernimmt.
  • Wenn Sie sich nicht hauptsächlich auf Laufzeit-Caching verlassen. Wenn Ressourcen zur Laufzeit im Cache gespeichert werden, müssen Sie dem Nutzer nicht mitteilen, dass sie neu geladen werden sollen. Wenn sich die versionierten Assets ändern, werden sie im Laufe der Zeit dem Laufzeitcache hinzugefügt. Dabei wird davon ausgegangen, dass Navigationsanfragen eine netzwerk- oder nur netzwerkbasierte Strategie verwenden.
  • Wenn Sie eine Strategie des Typs veraltete Überprüfung während der Überprüfung verwenden, können Sie Nutzer mit dem Modul workbox-broadcast-update über Service Worker-Updates informieren.

Ob Sie den Nutzer über Updates für einen Service Worker benachrichtigen müssen, hängt von Ihrer Anwendung und ihren individuellen Anforderungen ab. Wenn Sie feststellen, dass Ihre Nutzer beim Bereitstellen eines neuen Service Workers ein ungewöhnliches Verhalten feststellen, ist dies wahrscheinlich das beste Signal dafür, den Nutzer zu benachrichtigen.