Workbox предоставляет мощный набор инструментов для организации
сервис-воркеров, кэширования ресурсов и управления сетевыми запросами.
Один из ключевых аспектов расширяемости Workbox — возможность
использования плагинов. Плагины позволяют внедрять пользовательскую
логику на разных этапах обработки запросов и ответов, таких как
fetchDidSucceed, cacheDidUpdate,
requestWillFetch и другие. Для эффективного использования
плагинов важно понимать, как можно передавать контекст между ними,
сохраняя состояние и данные.
context и его
рольКаждый плагин в Workbox может получать объект контекста, который предоставляет доступ к данным, общим для всего жизненного цикла запроса. Контекст позволяет:
Пример структуры объекта контекста:
{
request: Request,
response: Response | undefined,
cacheKey: string,
timestamp: number,
metadata: {}
}
Поле metadata обычно используется для передачи
произвольных данных между плагинами. Это ключевое место, где хранится
состояние конкретного запроса или кэширования.
Чтобы плагин мог работать с контекстом, необходимо реализовать
соответствующие методы и использовать объект context:
const loggingPlugin = {
cacheDidUpdate: async ({cacheName, request, oldResponse, newResponse, metadata}) => {
if (!metadata) metadata = {};
metadata.cacheUpdatedAt = Date.now();
console.log(`Cache "${cacheName}" обновлен для URL: ${request.url}`);
},
fetchDidSucceed: async ({request, response, metadata}) => {
metadata.fetchTimestamp = Date.now();
return response;
}
};
Здесь metadata используется для сохранения временных
меток и передачи информации между этапами обработки. Если другой плагин
обрабатывает тот же объект metadata, он сможет получить эти
данные:
const analyticsPlugin = {
cacheDidUpdate: async ({metadata}) => {
if (metadata && metadata.cacheUpdatedAt) {
console.log(`Отправка метрик: кэш обновлен в ${metadata.cacheUpdatedAt}`);
}
}
};
Workbox гарантирует, что объект context создается для
каждого запроса и передается всем плагинам, зарегистрированным для
соответствующего события. Основные принципы передачи:
context. Данные одного запроса не
смешиваются с данными другого.metadata,
следующий плагин в цепочке увидит эти изменения.const timingPlugin = {
requestWillFetch: async ({request, metadata}) => {
metadata.startTime = performance.now();
return request;
},
fetchDidSucceed: async ({response, metadata}) => {
metadata.endTime = performance.now();
metadata.duration = metadata.endTime - metadata.startTime;
return response;
}
};
const metricsPlugin = {
cacheDidUpdate: async ({metadata}) => {
if (metadata && metadata.duration !== undefined) {
console.log(`Время обработки запроса: ${metadata.duration.toFixed(2)} мс`);
}
}
};
workbox.routing.registerRoute(
({url}) => url.origin === self.location.origin,
new workbox.strategies.NetworkFirst({
cacheName: 'dynamic-cache',
plugins: [timingPlugin, metricsPlugin]
})
);
В этом примере timingPlugin фиксирует время запроса и
передачи данных, а metricsPlugin использует эти данные для
логирования метрик. Объект metadata является единым каналом
передачи данных между плагинами.
Помимо стандартного поля metadata, можно создавать свои
структурированные объекты внутри context для специфических
нужд:
const authPlugin = {
requestWillFetch: async ({request, metadata}) => {
if (!metadata.auth) metadata.auth = {};
metadata.auth.token = await getAuthToken();
return new Request(request, {
headers: { ...request.headers, 'Authorization': `Bearer ${metadata.auth.token}` }
});
}
};
const auditPlugin = {
fetchDidSucceed: async ({response, metadata}) => {
if (metadata.auth?.token) {
console.log('Запрос выполнен с токеном:', metadata.auth.token.slice(0, 8));
}
return response;
}
};
Такой подход обеспечивает изоляцию логики плагинов, предотвращает конфликты имен и позволяет безопасно обмениваться данными.
metadata.auth,
metadata.timing, metadata.analytics делает код
читаемым и поддерживаемым.Передача контекста между плагинами Workbox — мощный инструмент для
построения расширяемой и гибкой логики обработки запросов и кэширования.
Использование поля metadata и структурированных объектов в
контексте позволяет организовать комплексные цепочки плагинов,
отслеживать состояние, собирать метрики и делиться данными между разными
этапами жизненного цикла запроса без глобальных переменных.