Типизация собственных плагинов

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

Интерфейс плагина

Собственный плагин в Workbox создаётся как объект с методами, соответствующими жизненному циклу обработки запроса и кэша. Основные интерфейсы:

  • cacheWillUpdate — вызывается перед сохранением ответа в кэш. Позволяет изменить или отклонить сохранение.
  • cacheDidUpdate — вызывается после успешного обновления кэша.
  • cachedResponseWillBeUsed — позволяет модифицировать возвращаемый из кэша ответ.
  • fetchDidFail — вызывается при сбое сетевого запроса.
  • requestWillFetch — позволяет модифицировать Request перед отправкой в сеть.
  • fetchDidSucceed — вызывается после успешного получения ответа из сети.

Каждый метод принимает объект с определёнными свойствами и должен возвращать строго определённый тип.

Типизация с TypeScript

Для корректной работы с типами можно использовать встроенные интерфейсы из пакета workbox-core и workbox-strategies:

import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { RouteMatchCallbackOptions } from 'workbox-core/types';

interface MyPluginOptions {
  ignoreStatus?: number[];
  transformResponse?: (response: Response) => Promise<Response>;
}

class MyCustomPlugin implements CacheableResponsePlugin {
  private options: MyPluginOptions;

  constructor(options: MyPluginOptions) {
    this.options = options;
  }

  async cacheWillUpdate({ response }: { response: Response }): Promise<Response | null> {
    if (this.options.ignoreStatus?.includes(response.status)) {
      return null;
    }
    if (this.options.transformResponse) {
      return await this.options.transformResponse(response.clone());
    }
    return response;
  }

  cacheDidUpdate({ cacheName, request, oldResponse, newResponse }: 
    { cacheName: string; request: Request; oldResponse: Response | null; newResponse: Response }
  ): void {
    console.log(`Cache ${cacheName} updated for ${request.url}`);
  }
}

В этом примере:

  • cacheWillUpdate строго ожидает объект с полем response типа Response и возвращает либо модифицированный Response, либо null.
  • cacheDidUpdate принимает объект с информацией о кэше и обновлённом ресурсе.
  • Использование типов из Workbox обеспечивает совместимость с остальной экосистемой Workbox.

Передача плагина в стратегию

Плагины передаются в стратегии через массив plugins:

import { CacheFirst } from 'workbox-strategies';

const myPlugin = new MyCustomPlugin({
  ignoreStatus: [404, 500],
  transformResponse: async (response) => {
    const clone = response.clone();
    // Можно модифицировать тело ответа, например, обрезать JSON
    return clone;
  }
});

const cacheFirstStrategy = new CacheFirst({
  cacheName: 'my-cache',
  plugins: [myPlugin]
});

TypeScript проверяет, что объект myPlugin соответствует интерфейсу CacheableResponsePlugin. Любое несоответствие типов будет обнаружено на этапе компиляции, что предотвращает ошибки во время выполнения сервис-воркера.

Особенности типизации методов

  • cacheWillUpdate — может вернуть null, что указывает Workbox не кэшировать данный ответ.
  • cachedResponseWillBeUsed — позволяет модифицировать кэшированный ответ перед выдачей.
  • requestWillFetch — возвращает Request или Promise<Request> для асинхронных изменений.
  • fetchDidFail — полезен для логирования или повторных попыток при сетевых ошибках.

Все методы имеют строгую типизацию, совместимую с оригинальными интерфейсами Workbox, что гарантирует корректную работу при интеграции с другими плагинами и стратегиями.

Расширение базовых интерфейсов

Для сложных сценариев можно создавать собственные интерфейсы, расширяя базовые типы Workbox:

import { CacheWillUpdatePlugin } from 'workbox-core/types';

interface ExtendedPluginOptions extends MyPluginOptions {
  logUpdates?: boolean;
}

class ExtendedPlugin implements CacheWillUpdatePlugin {
  constructor(private options: ExtendedPluginOptions) {}

  async cacheWillUpdate({ response }: { response: Response }): Promise<Response | null> {
    if (this.options.logUpdates) {
      console.log('Response status:', response.status);
    }
    return response.status === 200 ? response : null;
  }
}

Такое расширение позволяет добавлять новые поля в конфигурацию плагина без потери типовой безопасности.

Преимущества строгой типизации

  1. Автодополнение методов и параметров в редакторе кода.
  2. Предотвращение ошибок при неверном типе возвращаемого значения.
  3. Возможность безопасно комбинировать пользовательские плагины с официальными стратегиями Workbox.
  4. Поддержка асинхронных операций с полным контролем типов Promise<Response>.

Строгая типизация пользовательских плагинов Workbox обеспечивает надёжность и предсказуемость поведения сервис-воркеров, минимизируя ошибки на этапе разработки и повышая качество архитектуры фронтенд-приложений.