Plug-ins verwenden

Wenn Sie Workbox verwenden, können Sie eine Anfrage und eine Antwort bearbeiten, während sie abgerufen oder im Cache gespeichert wird. Mit Workbox-Plug-ins können Sie Ihrem Service Worker mit minimalem zusätzlichen Boilerplate-Code zusätzliche Verhaltensweisen hinzufügen. Sie können gepackt und in Ihren eigenen Projekten wiederverwendet oder auch von anderen Nutzern zur Nutzung veröffentlicht werden.

Workbox bietet eine Reihe von Plug-ins, die direkt verwendet werden können. Wenn Sie handwerklich begabt sind, können Sie auch benutzerdefinierte Plug-ins erstellen, die auf die Anforderungen Ihrer Anwendung zugeschnitten sind.

Verfügbare Workbox-Plug-ins

Workbox bietet die folgenden offiziellen Plug-ins für die Verwendung in Ihrem Service Worker:

Workbox-Plug-ins – ob eines der oben aufgeführten oder ein benutzerdefiniertes Plug-in – werden mit einer Workbox-Strategie verwendet. Dazu fügen Sie der plugins-Eigenschaft der Strategie eine Instanz des Plug-ins hinzu:

import {registerRoute} from 'workbox-routing';
import {CacheFirst} from 'workbox-strategies';
import {ExpirationPlugin} from 'workbox-expiration';

registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst({
    cacheName: 'images',
    plugins: [
      new ExpirationPlugin({
        maxEntries: 60,
        maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
      }),
    ],
  })
);

Methoden für benutzerdefinierte Plug-ins

Ein Workbox-Plug-in muss eine oder mehrere Rückruffunktionen implementieren. Wenn Sie einer Strategie ein Plug-in hinzufügen, werden die Rückruffunktionen automatisch zur richtigen Zeit ausgeführt. Die Strategie gibt deiner Callback-Funktion relevante Informationen zur aktuellen Anfrage und/oder Antwort weiter, sodass dein Plug-in den erforderlichen Kontext für eine Aktion hat. Die folgenden Rückruffunktionen werden unterstützt:

  • cacheWillUpdate: Wird aufgerufen, bevor ein Response zum Aktualisieren eines Caches verwendet wird. Bei dieser Methode kann die Antwort geändert werden, bevor sie dem Cache hinzugefügt wird. Alternativ können Sie null zurückgeben, um eine vollständige Aktualisierung des Caches zu vermeiden.
  • cacheDidUpdate: Wird aufgerufen, wenn einem Cache ein neuer Eintrag hinzugefügt oder ein vorhandener Eintrag aktualisiert wird. Plug-ins, die diese Methode verwenden, können nützlich sein, wenn Sie nach einer Cache-Aktualisierung eine Aktion ausführen möchten.
  • cacheKeyWillBeUsed: Wird aufgerufen, bevor eine Anfrage als Cache-Schlüssel verwendet wird. Dies gilt sowohl für Cache-Suchanfragen (wenn mode = 'read') als auch für Cache-Schreibvorgänge (wenn mode = 'write'). Dieser Rückruf ist praktisch, wenn Sie URLs überschreiben oder normalisieren müssen, bevor Sie sie zum Zugriff auf Caches verwenden.
  • cachedResponseWillBeUsed: Diese Funktion wird kurz vor der Verwendung einer Antwort aus einem Cache aufgerufen. So können Sie diese Antwort prüfen. An dieser Stelle kannst du entweder eine andere Antwort oder null zurückgeben.
  • requestWillFetch: Wird aufgerufen, wenn eine Anfrage an das Netzwerk gesendet werden soll. Dies ist nützlich, wenn Sie den Request ändern müssen, kurz bevor er mit dem Netzwerk verbunden wird.
  • fetchDidFail: Wird aufgerufen, wenn eine Netzwerkanfrage fehlschlägt, höchstwahrscheinlich aufgrund einer fehlenden Netzwerkverbindung. Wird nicht ausgelöst, wenn der Browser eine Netzwerkverbindung hat, aber einen Fehler erhält (z. B. 404 Not Found).
  • fetchDidSucceed: Wird immer dann aufgerufen, wenn eine Netzwerkanfrage erfolgreich ist, unabhängig vom HTTP-Antwortcode.
  • handlerWillStart: Wird aufgerufen, bevor die Handlerlogik gestartet wird. Das ist nützlich, wenn Sie den anfänglichen Handlerstatus festlegen müssen. Wenn Sie beispielsweise wissen möchten, wie lange der Handler für die Generierung einer Antwort benötigt hat, können Sie sich in diesem Rückruf die Startzeit notieren.
  • handlerWillRespond: Wird aufgerufen, bevor die handle()-Methode der Strategie eine Antwort zurückgibt. Dies ist hilfreich, wenn Sie eine Antwort ändern müssen, bevor sie an eine RouteHandler oder andere benutzerdefinierte Logik zurückgegeben wird.
  • handlerDidRespond: Wird aufgerufen, nachdem die handle()-Methode der Strategie eine Antwort zurückgegeben hat. In diesem Fall kann es hilfreich sein, alle Details zur endgültigen Antwort aufzuzeichnen, z. B. nach Änderungen, die von anderen Plugins vorgenommen wurden.
  • handlerDidComplete: Wird aufgerufen, nachdem alle Versprechen zur Verlängerung der Lebensdauer, die dem Ereignis durch die Aufrufung der Strategie hinzugefügt wurden, abgelaufen sind. Das ist hilfreich, wenn Sie Berichte zu Daten erstellen möchten, für die gewartet werden muss, bis der Handler fertig ist, um beispielsweise den Cache-Trefferstatus, die Cache-Latenz, die Netzwerklatenz und andere nützliche Informationen zu berechnen.
  • handlerDidError: Wird aufgerufen, wenn der Handler keine gültige Antwort von einer beliebigen Quelle liefern kann. Dies ist der optimale Zeitpunkt, um eine Art Fallback-Antwort als Alternative zum sofortigen Fehler zu liefern.

Alle diese Callbacks sind async. Daher muss await verwendet werden, wenn ein Cache- oder Abrufereignis den relevanten Punkt für den betreffenden Callback erreicht.

Wenn ein Plug-in alle oben genannten Rückrufe verwendet, würde der Code so aussehen:

const myPlugin = {
  cacheWillUpdate: async ({request, response, event, state}) => {
    // Return `response`, a different `Response` object, or `null`.
    return response;
  },
  cacheDidUpdate: async ({
    cacheName,
    request,
    oldResponse,
    newResponse,
    event,
    state,
  }) => {
    // No return expected
    // Note: `newResponse.bodyUsed` is `true` when this is called,
    // meaning the body has already been read. If you need access to
    // the body of the fresh response, use a technique like:
    // const freshResponse = await caches.match(request, {cacheName});
  },
  cacheKeyWillBeUsed: async ({request, mode, params, event, state}) => {
    // `request` is the `Request` object that would otherwise be used as the cache key.
    // `mode` is either 'read' or 'write'.
    // Return either a string, or a `Request` whose `url` property will be used as the cache key.
    // Returning the original `request` will make this a no-op.
    return request;
  },
  cachedResponseWillBeUsed: async ({
    cacheName,
    request,
    matchOptions,
    cachedResponse,
    event,
    state,
  }) => {
    // Return `cachedResponse`, a different `Response` object, or null.
    return cachedResponse;
  },
  requestWillFetch: async ({request, event, state}) => {
    // Return `request` or a different `Request` object.
    return request;
  },
  fetchDidFail: async ({originalRequest, request, error, event, state}) => {
    // No return expected.
    // Note: `originalRequest` is the browser's request, `request` is the
    // request after being passed through plugins with
    // `requestWillFetch` callbacks, and `error` is the exception that caused
    // the underlying `fetch()` to fail.
  },
  fetchDidSucceed: async ({request, response, event, state}) => {
    // Return `response` to use the network response as-is,
    // or alternatively create and return a new `Response` object.
    return response;
  },
  handlerWillStart: async ({request, event, state}) => {
    // No return expected.
    // Can set initial handler state here.
  },
  handlerWillRespond: async ({request, response, event, state}) => {
    // Return `response` or a different `Response` object.
    return response;
  },
  handlerDidRespond: async ({request, response, event, state}) => {
    // No return expected.
    // Can record final response details here.
  },
  handlerDidComplete: async ({request, response, error, event, state}) => {
    // No return expected.
    // Can report any data here.
  },
  handlerDidError: async ({request, event, error, state}) => {
    // Return a `Response` to use as a fallback, or `null`.
    return fallbackResponse;
  },
};

Das event-Objekt, das in den oben aufgeführten Callbacks verfügbar ist, ist das ursprüngliche Ereignis, das die Abruf- oder Cache-Aktion ausgelöst hat. Manchmal gibt es kein ursprüngliches Ereignis. Ihr Code sollte daher prüfen, ob es vorhanden ist, bevor es referenziert wird.

Alle Plugin-Callbacks erhalten außerdem ein state-Objekt, das für ein bestimmtes Plugin und die aufgerufene Strategie eindeutig ist. Das bedeutet, dass Sie Plugins schreiben können, in denen ein Callback eine Aufgabe bedingt ausführen kann, je nachdem, was ein anderer Callback im selben Plug-in getan hat (z. B. den Unterschied zwischen der Ausführung von requestWillFetch() und fetchDidSucceed() oder fetchDidFail() berechnen).

Drittanbieter-Plug-ins

Wenn Sie ein Plug-in entwickeln und glauben, dass es außerhalb Ihres Projekts verwendet wird, empfehlen wir Ihnen, es als Modul zu veröffentlichen. Im Folgenden finden Sie eine kurze Liste der von der Community bereitgestellten Workbox-Plug-ins:

Im npm-Repository finden Sie möglicherweise weitere von der Community bereitgestellte Workbox-Plug-ins.

Wenn Sie ein Workbox-Plug-in erstellt haben, das Sie freigeben möchten, fügen Sie schließlich bei der Veröffentlichung das Keyword workbox-plugin hinzu. Wenn ja, lasst es uns auf Twitter unter @WorkboxJS wissen.