Типизация обработчиков маршрутов

В Workbox обработчики маршрутов (route handlers) являются ключевым элементом построения сервис-воркера. Они определяют, каким образом будет обрабатываться каждый запрос: кэшироваться, получать обновления с сервера или комбинировать различные стратегии. Для эффективной работы с ними критически важно понимать типизацию обработчиков, особенно в TypeScript, где строгие типы помогают предотвратить ошибки на этапе компиляции.


Основные типы обработчиков

В Workbox выделяют несколько способов определения обработчиков:

  1. Function Handler (RouteHandlerCallback) Функция, которая принимает объект запроса и возвращает Promise<Response>:
import { RouteHandlerCallback } from 'workbox-core/types';

const handler: RouteHandlerCallback = async ({ request, event, params }) => {
  const response = await fetch(request);
  return response;
};

Ключевые моменты:

  • request: Request – объект запроса, переданный браузером.
  • event: FetchEvent – событие fetch, позволяющее использовать event.waitUntil().
  • params: Record<string, string> – объект с параметрами маршрута, если используются динамические сегменты (:id, :slug и т.д.).
  • Возвращаемое значение должно быть Promise<Response>.

  1. Class-based Handler (RouteHandler) Классы-обработчики предоставляют интерфейс handle для работы с запросами:
import { RouteHandler } from 'workbox-core/types';

class CustomHandler implements RouteHandler {
  async handle({ request, event, params }: Parameters<RouteHandler['handle']>[0]) {
    return fetch(request);
  }
}

Особенности:

  • Позволяет инкапсулировать логику кэширования и других стратегий внутри класса.
  • Может хранить состояние между вызовами, например, счетчик обращений или локальные настройки.
  • Интерфейс гарантирует правильную сигнатуру метода handle, что снижает риск ошибок типизации.

Типизация параметров маршрута

Маршруты с динамическими сегментами (/users/:userId/posts/:postId) позволяют автоматически получать параметры из URL. Workbox поддерживает типизацию параметров:

interface Params {
  userId: string;
  postId: string;
}

const handler: RouteHandlerCallback<Params> = ({ params }) => {
  console.log(params.userId, params.postId);
  return fetch(`/api/users/${params.userId}/posts/${params.postId}`);
};
  • Параметры маршрута строго типизированы, что исключает опечатки и неправильное использование ключей.
  • Можно комбинировать с типами запроса и ответа, например RequestInit и Response.

Стратегии как типизированные обработчики

Workbox предоставляет готовые стратегии (CacheFirst, NetworkFirst, StaleWhileRevalidate), каждая из которых реализует интерфейс RouteHandler:

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

const cacheFirstHandler = new CacheFirst({
  cacheName: 'images-cache',
});

registerRoute(
  ({ request }) => request.destination === 'image',
  cacheFirstHandler
);

Типы обеспечивают:

  • Проверку корректности конфигурации (cacheName, plugins).
  • Гарантию того, что handle() вернет Promise<Response>.
  • Совместимость с TypeScript при создании кастомных стратегий.

Комбинированные обработчики и middleware

Workbox позволяет комбинировать обработчики через цепочку middleware. Для типизации используется RouteHandlerCallback:

import { Router } from 'workbox-routing';

const router = new Router();

const logger: RouteHandlerCallback = async ({ request }, next) => {
  console.log('Запрос:', request.url);
  return next ? next() : fetch(request);
};

const cacheHandler: RouteHandlerCallback = async ({ request }) => {
  return caches.match(request) || fetch(request);
};

router.registerRoute('/api/:endpoint', [logger, cacheHandler]);
  • Каждая функция в цепочке получает request, event и params.
  • Типизация позволяет определить точные типы для params и аргумента next().
  • Упрощает обработку сложных сценариев без потери безопасности типов.

Взаимодействие с WorkboxPlugin и типами

Обработчики маршрутов часто используют плагины (WorkboxPlugin) для кэширования, повторных запросов или логирования. Типизация помогает:

import { CacheableResponsePlugin } from 'workbox-cacheable-response';
import { CacheFirst } from 'workbox-strategies';

const handler = new CacheFirst({
  cacheName: 'api-cache',
  plugins: [
    new CacheableResponsePlugin({
      statuses: [0, 200],
    }),
  ],
});
  • Плагин имеет строгие типы конфигурации (statuses, headers, cacheWillUpdate и т.д.).
  • CacheFirst гарантирует, что возвращаемый объект соответствует Promise<Response>.

Выводы по типизации

Типизация обработчиков маршрутов в Workbox позволяет:

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

Правильная типизация — это не только инструмент компиляции, но и архитектурный подход к построению надежных маршрутов и стратегий работы с сетью и кэшем.