Использование плагинов

При использовании Workbox вам может потребоваться манипулировать запросом и ответом во время его выборки или кэширования. Плагины Workbox позволяют добавлять дополнительные варианты поведения к вашему сервис-воркеру с минимальными дополнительными шаблонами. Их можно упаковать и повторно использовать в ваших собственных проектах или опубликовать публично для использования другими.

Workbox предоставляет нам ряд готовых плагинов, и — если вы умеете — вы можете написать собственные плагины, адаптированные к требованиям вашего приложения.

Доступные плагины Workbox

Workbox предлагает следующие официальные плагины для использования в сервис-воркере:

  • BackgroundSyncPlugin : если сетевой запрос не удался, этот плагин позволяет добавить его в очередь фоновой синхронизации, чтобы он был запрошен снова при запуске следующего события синхронизации .
  • BroadcastUpdatePlugin : позволяет отправлять сообщение по широковещательному каналу или через postMessage() при каждом обновлении кеша.
  • CacheableResponsePlugin : кэширует только те запросы, которые соответствуют определенным критериям.
  • ExpirationPlugin : управляет количеством и максимальным возрастом элементов в кэше.
  • RangeRequestsPlugin : отвечает на запросы, которые включают заголовок HTTP-запроса Range .

Плагины Workbox — будь то один из перечисленных выше плагинов или пользовательский плагин — используются со стратегией Workbox путем добавления экземпляра плагина в свойство plugins стратегии:

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

Методы для пользовательских плагинов

Плагин Workbox должен реализовать одну или несколько функций обратного вызова. Когда вы добавляете плагин в стратегию, функции обратного вызова автоматически запускаются в нужное время. Стратегия передает вашей функции обратного вызова соответствующую информацию о текущем запросе и/или ответе, предоставляя вашему плагину контекст, необходимый для принятия мер. Поддерживаются следующие функции обратного вызова:

  • cacheWillUpdate : вызывается перед использованием Response для обновления кеша. В этом методе ответ можно изменить до того, как он будет добавлен в кеш, или вы можете вернуть null , чтобы избежать полного обновления кеша.
  • cacheDidUpdate : вызывается, когда в кэш добавляется новая запись или обновляется существующая запись. Плагины, использующие этот метод, могут быть полезны, если вы хотите выполнить действие после обновления кэша.
  • cacheKeyWillBeUsed : вызывается перед использованием запроса в качестве ключа кэша. Это происходит как при поиске в кэше (когда mode 'read' ), так и при записи в кэш (когда mode 'write' ). Этот обратный вызов удобен, если вам нужно переопределить или нормализовать URL-адреса перед их использованием для доступа к кешам.
  • cachedResponseWillBeUsed : вызывается непосредственно перед использованием ответа из кэша, что позволяет вам проверить этот ответ. На этом этапе вы можете либо вернуть другой ответ, либо вернуть null .
  • requestWillFetch : вызывается всякий раз, когда запрос собирается отправить в сеть. Полезно, когда вам нужно изменить Request непосредственно перед его отправкой в ​​сеть.
  • fetchDidFail : вызывается при сбое сетевого запроса, скорее всего, из-за отсутствия сетевого подключения, и не срабатывает, когда браузер имеет сетевое подключение, но получает ошибку (например, 404 Not Found ).
  • fetchDidSucceed : вызывается при успешном выполнении сетевого запроса, независимо от кода ответа HTTP.
  • handlerWillStart : вызывается перед запуском какой-либо логики обработчика, что полезно, если вам нужно установить начальное состояние обработчика. Например, если вы хотите узнать, сколько времени потребовалось обработчику для генерации ответа, вы можете записать время начала в этом обратном вызове.
  • handlerWillRespond : вызывается до того, как метод handle() стратегии вернет ответ, что полезно, если вам нужно изменить ответ перед его возвратом в RouteHandler или другую пользовательскую логику.
  • handlerDidRespond : вызывается после того, как метод handle() стратегии возвращает ответ. В этом случае может быть полезно записать окончательные детали ответа (например, после изменений, внесенных другими плагинами).
  • handlerDidComplete : вызывается после того, как все обещания продления срока действия , добавленные к событию при вызове стратегии, выполнены. Это полезно, если вам нужно сообщить о любых данных, которым необходимо дождаться завершения работы обработчика, чтобы вычислить такие вещи, как статус попадания в кэш, задержку кэша, задержку сети и другую полезную информацию.
  • handlerDidError : вызывается, если обработчик не может предоставить действительный ответ из любого источника, что является оптимальным временем для предоставления какого-либо резервного ответа в качестве альтернативы прямому сбою.

Все эти обратные вызовы являются async и, следовательно, потребуют использования await всякий раз, когда событие кэширования или выборки достигает соответствующей точки для соответствующего обратного вызова.

Если бы плагин использовал все вышеперечисленные обратные вызовы, результирующий код был бы таким:

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

Объект event , доступный в перечисленных выше обратных вызовах, является исходным событием, которое инициировало действие выборки или кэширования. Иногда исходного события не будет, поэтому ваш код должен проверить, существует ли оно, прежде чем ссылаться на него.

Всем обратным вызовам плагинов также передается объект state , который уникален для конкретного плагина и стратегии, которую он вызывает. Это означает, что вы можете писать плагины, в которых один обратный вызов может условно выполнять задачу на основе того, что делал другой обратный вызов в том же плагине (например, вычислять разницу между запуском requestWillFetch() и fetchDidSucceed() или fetchDidFail() ).

Сторонние плагины

Если вы разрабатываете плагин и считаете, что его можно использовать за пределами вашего проекта, мы рекомендуем вам опубликовать его как модуль! Ниже приведен краткий список плагинов Workbox, предоставленных сообществом:

Возможно, вы сможете найти дополнительные плагины Workbox, предоставленные сообществом , выполнив поиск в репозитории npm.

Наконец, если вы создали плагин Workbox, которым хотите поделиться, добавьте ключевое слово workbox-plugin при его публикации. Если да, сообщите нам об этом в Твиттере @WorkboxJS !