Sofortige Verarbeitung von Service Worker-Updates

Der Service Worker-Lebenszyklus sieht standardmäßig vor, dass wenn ein aktualisierter Service Worker gefunden und installiert wird, alle geöffneten Tabs, die der aktuelle Service Worker verwaltet, geschlossen oder aufgerufen werden müssen, bevor der aktualisierte Service Worker aktiviert wird und die Kontrolle übernimmt.

In vielen Fällen kann dies im Lauf der Zeit erlaubt sein, aber in einigen Fällen kann es sinnvoll sein, den Nutzer über ein ausstehendes Service Worker-Update zu informieren und den Wechsel zum neuen Service Worker zu automatisieren. Dazu müssen Sie Ihrer Seite und Ihrem Service Worker Code hinzufügen.

Code, der auf Ihrer Seite eingefügt werden soll

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

<!-- 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 die Anfrage akzeptiert wird, weist messageSkipWaiting() den wartenden Service Worker an, self.skipWaiting() aufzurufen. Das bedeutet, dass die Aktivierung beginnt. Nach der Aktivierung übernimmt der neue Service Worker die Kontrolle über alle vorhandenen Clients und löst das Ereignis controlling in workbox-window aus. In diesem Fall wird die aktuelle Seite mit der neuesten Version aller vorab im Cache gespeicherten Assets und der neuen Routinglogik neu geladen, die im aktualisierten Service Worker gefunden wurde.

Code, den Sie in den Service Worker einfügen müssen

Sobald Sie den Code aus dem vorherigen Abschnitt auf Ihrer Seite erhalten haben, müssen Sie Ihrem Service Worker Code hinzufügen, der angibt, wann die Wartephase übersprungen werden soll. Wenn Sie generateSW in workbox-build verwenden und die skipWaiting-Option auf false (Standardeinstellung) gesetzt ist, brauchen Sie nichts zu tun, da der folgende Code automatisch in die generierte Service Worker-Datei eingefügt wird.

Wenn Sie einen eigenen Service Worker schreiben, beispielsweise in Verbindung 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();
  }
});

Dadurch werden Nachrichten erfasst, die von workbox-window an den Service Worker mit dem type-Wert SKIP_WAITING gesendet wurden. In diesem Fall wird self.skipWaiting() aufgerufen. Die im vorherigen Codebeispiel gezeigte Methode messageSkipWaiting() in workbox-window ist für das Senden dieser Nachricht verantwortlich.

Muss eine Aufforderung eingeblendet werden?

Dabei handelt es sich nicht um ein Muster, dem jede Anwendung zum Bereitstellen eines Service Workers folgen muss. Sie ist für bestimmte Szenarien vorgesehen, bei denen die Möglichkeit zum Aktualisieren einer Seite bei einem Service Worker-Update zu unerwartetem Verhalten führen kann. Es gibt keine festen Regeln dafür, ob Sie eine Aktualisierungsaufforderung anzeigen sollten, aber die folgenden Situationen können sinnvoll sein:

  • Sie verwenden das Precaching in großem Umfang. Bei statischen Assets können später Probleme auftreten, wenn Sie für Navigationsanfragen eine Strategie mit Fokus auf das Netzwerk oder nur auf das Netzwerk anwenden, aber Lazy Loading für statische Assets verwenden. Dies kann zu Situationen führen, in denen sich versionierte Assets ändern können und ein Service Worker sie nicht vorab im Cache gespeichert hat. Wenn du hier eine Schaltfläche zum Aktualisieren anbietest, kannst du unerwartetes Verhalten vermeiden.
  • Wenn Sie vorab im Cache gespeichertes HTML bereitstellen. In diesem Fall sollten Sie bei Service Worker-Updates dringend eine Schaltfläche zum Aktualisieren anbieten, da Aktualisierungen dieses HTML-Codes erst erkannt werden, wenn der aktualisierte Service Worker die Kontrolle übernimmt.
  • Wenn Sie das Laufzeit-Caching nicht hauptsächlich nutzen, Wenn Sie Ressourcen zur Laufzeit im Cache speichern, müssen Sie dem Nutzer nicht mitteilen, dass er neu laden soll. Wenn sich versionierte Assets ändern, werden sie im Laufe der Zeit dem Laufzeitcache hinzugefügt, vorausgesetzt, für die Navigationsanfragen wird eine Strategie verwendet, die sich hauptsächlich auf das Netzwerk oder nur auf das Netzwerk bezieht.
  • Wenn Sie die Strategie stale-while-revalidate verwenden, können Sie die Nutzer mit dem workbox-broadcast-update-Modul über Service Worker-Updates informieren.

Ob Sie den Nutzer über Updates für einen Service Worker informieren müssen, hängt von Ihrer Anwendung und deren individuellen Anforderungen ab. Wenn Sie feststellen, dass Ihre Nutzer bei der Bereitstellung eines neuen Service Workers merkwürdiges Verhalten zeigen, ist dies wahrscheinlich das beste Signal, dass Sie die Nutzer benachrichtigen sollten.