Workbox — это набор библиотек и инструментов для создания сервис-воркеров, позволяющих реализовать продвинутые стратегии кэширования и офлайн-поддержку в веб-приложениях. В контексте Next.js Workbox используется для управления кэшированием статических ресурсов, страниц и API-запросов, обеспечивая быстрый отклик и снижение нагрузки на сервер.
Next.js по умолчанию поддерживает серверный рендеринг (SSR) и статическую генерацию (SSG), что накладывает свои особенности на работу сервис-воркеров. Для корректного кэширования необходимо учитывать структуру сборки, динамические маршруты и публичные файлы.
Установка Workbox в проект на Next.js производится через npm:
npm install workbox-webpack-plugin --save-dev
или через yarn:
yarn add workbox-webpack-plugin --dev
Workbox интегрируется с Webpack через плагин GenerateSW
или InjectManifest. В Next.js для этого используется
модификация конфигурации Webpack через next.config.js:
const { GenerateSW } = require('workbox-webpack-plugin');
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.plugins.push(
new GenerateSW({
clientsClaim: true,
skipWaiting: true,
runtimeCaching: [
{
urlPattern: /\.(?:png|jpg|jpeg|svg|gif)$/,
handler: 'CacheFirst',
options: {
cacheName: 'images',
expiration: { maxEntries: 60, maxAgeSeconds: 30 * 24 * 60 * 60 },
},
},
{
urlPattern: /^https:\/\/api\.example\.com\/.*$/,
handler: 'NetworkFirst',
options: {
cacheName: 'api',
networkTimeoutSeconds: 10,
expiration: { maxEntries: 50, maxAgeSeconds: 5 * 60 },
},
},
],
})
);
}
return config;
},
};
Workbox предоставляет несколько ключевых стратегий кэширования, каждая из которых имеет свои сценарии использования:
Next.js поддерживает SSR и SSG, поэтому страницы генерируются на
сервере и имеют динамические URL. Для работы Workbox с динамическими
маршрутами рекомендуется использовать регулярные выражения в
runtimeCaching:
{
urlPattern: /^\/blog\/.*$/,
handler: 'NetworkFirst',
options: {
cacheName: 'blog-pages',
networkTimeoutSeconds: 5,
expiration: { maxEntries: 100, maxAgeSeconds: 24 * 60 * 60 },
},
}
Такой подход позволяет кэшировать страницы блога, подгружая их из сети в первую очередь, но обеспечивая офлайн-доступ, если сеть недоступна.
Все файлы из папки public автоматически становятся
доступными по URL и могут кэшироваться через Workbox. Для этого
достаточно задать соответствующий urlPattern:
{
urlPattern: /^\/_next\/static\/.*/,
handler: 'CacheFirst',
options: {
cacheName: 'next-static',
expiration: { maxEntries: 100, maxAgeSeconds: 7 * 24 * 60 * 60 },
},
}
Важно учитывать версионирование Next.js
(/_next/static/), чтобы кэш автоматически обновлялся после
деплоя новой сборки.
Для более гибкого управления сервис-воркером применяется
InjectManifest. В этом режиме создается кастомный
сервис-воркер с вашей логикой, в который Workbox внедряет стратегию
кэширования.
Пример настройки next.config.js:
const { InjectManifest } = require('workbox-webpack-plugin');
const path = require('path');
module.exports = {
webpack: (config, { isServer }) => {
if (!isServer) {
config.plugins.push(
new InjectManifest({
swSrc: path.join(__dirname, 'src', 'service-worker.js'),
swDest: 'service-worker.js',
maximumFileSizeToCacheInBytes: 5 * 1024 * 1024,
})
);
}
return config;
},
};
В src/service-worker.js можно определить кастомные
стратегии:
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { NetworkFirst, CacheFirst } from 'workbox-strategies';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
({ request }) => request.destination === 'image',
new CacheFirst({ cacheName: 'images' })
);
registerRoute(
({ url }) => url.pathname.startsWith('/api/'),
new NetworkFirst({ cacheName: 'api' })
);
API маршруты Next.js можно кэшировать через стратегию
NetworkFirst с небольшим временем жизни кэша. Для сложных
сценариев, где данные чувствительны к времени, используется
StaleWhileRevalidate с коротким TTL.
Workbox автоматически добавляет хэш к файлам при сборке
(precacheManifest). Для ручного контроля версий важно:
skipWaiting() и
clientsClaim() для немедленного обновления сервис-воркера
после деплоя.self.addEventListener('activate', event => {
event.waitUntil(
caches.keys().then(keys =>
Promise.all(keys.map(key => caches.delete(key)))
)
);
});
Это позволяет избегать проблем с устаревшими кэшами и гарантирует, что пользователи получают актуальную версию приложения.