Korzystanie z wtyczek

Podczas korzystania ze skrzynki roboczej możesz manipulować żądaniami i odpowiedziami podczas ich pobierania lub przechowywania w pamięci podręcznej. Wtyczki skrzynki roboczej pozwalają dodać do skryptu service worker dodatkowe zachowania przy minimalnej ilości dodatkowych informacji. Można je tworzyć w pakietach i ponownie używać w swoich projektach. Można też udostępnić je publicznie do użytku innych osób.

Workbox udostępnia wiele wtyczek, które są od razu dostępne w pudełku. Jeśli lubisz działać na polubieniu, możesz tworzyć niestandardowe wtyczki dostosowane do wymagań Twojej aplikacji.

Dostępne wtyczki Workbox

Workbox udostępnia te oficjalne wtyczki, których można używać w skrypcie service worker:

Wtyczki Workspace – niezależnie od tego, czy są to wtyczki wymienione powyżej czy wtyczka niestandardowa – są używane ze strategią skrzynki roboczej po dodaniu jej wystąpienia do właściwości plugins strategii:

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
      }),
    ],
  })
);

Metody wtyczek niestandardowych

Wtyczka Workbox musi zaimplementować co najmniej 1 funkcję wywołania zwrotnego. Gdy dodasz wtyczkę do strategii, funkcje wywołań zwrotnych będą automatycznie uruchamiane w odpowiednim momencie. Strategia przekazuje do funkcji wywołania zwrotnego istotne informacje o bieżącym żądaniu lub odpowiedzi, dostarczając wtyczce kontekstu potrzebnego do podjęcia działania. Obsługiwane są te funkcje wywołania zwrotnego:

  • cacheWillUpdate: wywoływane przed wywołaniem Response do aktualizacji pamięci podręcznej. W ramach tej metody odpowiedź można zmienić, zanim zostanie dodana do pamięci podręcznej, lub zwrócić dyrektywę null, aby całkowicie uniknąć aktualizacji pamięci podręcznej.
  • cacheDidUpdate: wywoływane po dodaniu nowego wpisu do pamięci podręcznej lub zaktualizowaniu istniejącego wpisu. Wtyczki korzystające z tej metody mogą być przydatne, gdy chcesz wykonać działanie po zaktualizowaniu pamięci podręcznej.
  • cacheKeyWillBeUsed: wywoływane, zanim żądanie zostanie użyte jako klucz pamięci podręcznej. Dotyczy to zarówno wyszukiwań w pamięci podręcznej (gdy mode ma wartość 'read'), jak i zapisów w pamięci podręcznej (gdy mode ma wartość 'write'). To wywołanie zwrotne jest przydatne, jeśli musisz zastąpić lub znormalizować adresy URL, zanim użyjesz ich do uzyskania dostępu do pamięci podręcznych.
  • cachedResponseWillBeUsed: jest wywoływane tuż przed wykorzystaniem odpowiedzi z pamięci podręcznej, co umożliwia jej sprawdzenie. W takiej sytuacji możesz zwrócić inną odpowiedź lub zwrócić wartość null.
  • requestWillFetch: wywoływane za każdym razem, gdy żądanie ma trafić do sieci. Ta opcja jest przydatna, gdy musisz zmienić Request tuż przed połączeniem go z siecią.
  • fetchDidFail: wywoływane, gdy żądanie sieciowe nie powiedzie się, najprawdopodobniej z powodu braku połączenia z siecią. Nie uruchomi się, gdy przeglądarka ma połączenie z siecią, ale otrzyma błąd (na przykład 404 Not Found).
  • fetchDidSucceed: wywoływane za każdym razem, gdy żądanie sieciowe zostanie zrealizowane, niezależnie od kodu odpowiedzi HTTP.
  • handlerWillStart: wywoływane przed uruchomieniem jakiejkolwiek logiki modułu obsługi. Jest to przydatne, gdy trzeba ustawić początkowy stan modułu obsługi. Jeśli na przykład chcesz się dowiedzieć, ile czasu moduł obsługi zajęło wygenerowanie odpowiedzi, możesz w wywołaniu zwrotnym zapisać czas rozpoczęcia.
  • handlerWillRespond: wywołanie, zanim metoda handle() strategii zwróci odpowiedź. Jest to przydatne, jeśli musisz zmodyfikować odpowiedź, zanim zwrócisz ją do RouteHandler lub innej niestandardowej logiki.
  • handlerDidRespond: wywoływane po zwróceniu odpowiedzi przez metodę handle() strategii. Warto wtedy zarejestrować szczegóły końcowej odpowiedzi (np. po zmianach wprowadzonych przez inne wtyczki).
  • handlerDidComplete: wywoływane po upływie wszystkich obietnic dotyczących przedłużenia ważności dodanych do zdarzenia w wyniku wywołania strategii. Jest to przydatne, gdy musisz wygenerować raport dotyczący danych, które muszą czekać na zakończenie działania modułu, aby obliczać takie rzeczy jak stan trafień w pamięci podręcznej, czas oczekiwania w pamięci podręcznej, opóźnienie sieci i inne przydatne informacje.
  • handlerDidError: wywoływany, jeśli moduł obsługi nie może odpowiedzieć z żadnego źródła. Jest to optymalny czas na uzyskanie odpowiedzi zastępczej jako alternatywy dla bezpośredniego niepowodzenia.

Wszystkie te wywołania zwrotne mają wartość async i dlatego wymagają użycia await za każdym razem, gdy zdarzenie pamięci podręcznej lub zdarzenia pobierania dotrze do odpowiedniego punktu dla danego wywołania zwrotnego.

Jeśli wtyczka wykorzystywała wszystkie z powyższych wywołań zwrotnych, powstanie ten kod:

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;
  },
};

Obiekt event dostępny w wywołaniach zwrotnych wymienionych powyżej to pierwotne zdarzenie, które wywołało działanie pobierania lub pamięci podręcznej. Czasami nie ma pierwotnego zdarzenia, więc przed odwołaniem się do niego w kodzie należy sprawdzić, czy istnieje.

Wszystkie wywołania zwrotne wtyczki przekazują też obiekt state, który jest unikalny dla konkretnej wtyczki i wywołanej przez nią strategii. Oznacza to, że możesz napisać wtyczki, w których jedno wywołanie zwrotne może warunkowo wykonać zadanie na podstawie tego, co zrobiło inne wywołanie zwrotne tej samej wtyczki (np. obliczyć różnicę między uruchomieniem funkcji requestWillFetch() a fetchDidSucceed() lub fetchDidFail()).

Wtyczki innych firm

Jeśli uważasz, że stworzona przez Ciebie wtyczka może być wykorzystywana poza Twoim projektem, zachęcamy do opublikowania jej jako modułu. Poniżej znajdziesz krótką listę wtyczek Workbox dostarczanych przez społeczność:

Możesz znaleźć więcej wtyczek Workbox dostarczonych przez społeczność, przeszukując repozytorium npm.

Jeśli masz już wtyczkę Workbox, którą chcesz udostępnić, dodaj słowo kluczowe workbox-plugin podczas jej publikowania. Jeśli tak, daj nam znać na Twitterze: @WorkboxJS.