Workbox предоставляет удобный набор инструментов для управления кешированием и обновлениями сервис-воркеров в приложениях на JavaScript. Один из ключевых аспектов современного веб-приложения — уведомление пользователя о доступности новой версии сайта, чтобы он мог обновиться без неожиданного поведения или потери данных.
Первый шаг — корректная регистрация сервис-воркера. Workbox упрощает
этот процесс через стандартный API
navigator.serviceWorker.register. Важно сразу подписаться
на события, сигнализирующие о новой версии.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js')
.then(registration => {
registration.addEventListener('updatefound', () => {
const newWorker = registration.installing;
newWorker.addEventListener('statechange', () => {
if (newWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// Существующий воркер обновлен, доступно уведомление
console.log('Новая версия доступна');
} else {
// Первичная установка сервис-воркера
console.log('Сервис-воркер установлен впервые');
}
}
});
});
});
}
Ключевой момент: проверка
navigator.serviceWorker.controller позволяет определить,
что это не первичная установка, а именно обновление существующего
воркера.
Для уведомления о доступности новой версии используется
взаимодействие между сервис-воркером и клиентом через
postMessage. В сервис-воркере можно добавить следующий
код:
self.addEventListener('install', event => {
self.skipWaiting(); // Принудительное ожидание следующей активной версии
});
self.addEventListener('activate', event => {
clients.matchAll({ type: 'window' }).then(allClients => {
allClients.forEach(client => client.postMessage({ type: 'NEW_VERSION_AVAILABLE' }));
});
});
На стороне клиента нужно подписаться на сообщения от воркера:
navigator.serviceWorker.addEventListener('message', event => {
if (event.data.type === 'NEW_VERSION_AVAILABLE') {
// Показ уведомления пользователю
showUpdateNotification();
}
});
function showUpdateNotification() {
const updateBanner = document.createElement('div');
updateBanner.textContent = 'Доступна новая версия сайта. Обновить?';
const reloadButton = document.createElement('button');
reloadButton.textContent = 'Обновить';
reloadButton.oncl ick = () => window.location.reload();
updateBanner.appendChild(reloadButton);
document.body.appendChild(updateBanner);
}
Особенность: использование
clients.matchAll позволяет уведомить все открытые вкладки
приложения, а skipWaiting() гарантирует, что новый воркер
начнет управление сразу после установки, а не после закрытия всех
вкладок.
Workbox предлагает встроенные методы для управления стратегиями
кеширования и обновления ресурсов, включая workbox-window
для клиентской части. С помощью Workbox можно подписываться
на события жизненного цикла воркера:
import { Workbox } from 'workbox-window';
const wb = new Workbox('/service-worker.js');
wb.addEventListener('waiting', () => {
// Новый воркер готов к активации
notifyUserAboutUpdate(wb);
});
wb.register();
function notifyUserAboutUpdate(wbInstance) {
const updateBanner = document.createElement('div');
updateBanner.textContent = 'Доступна новая версия сайта';
const reloadButton = document.createElement('button');
reloadButton.textContent = 'Обновить';
reloadButton.oncl ick = () => wbInstance.messageSkipWaiting();
updateBanner.appendChild(reloadButton);
document.body.appendChild(updateBanner);
}
Преимущество: использование
wb.messageSkipWaiting() позволяет активировать новый воркер
без полной перезагрузки вкладки, сохраняя пользовательский контекст,
если приложение поддерживает работу с данными в фоне.
Чтобы обновление происходило безопасно и минимально заметно для пользователя, Workbox рекомендует использовать стратегии кеширования:
Пример использования для статических файлов:
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
registerRoute(
({ request }) => request.destination === 'script' || request.destination === 'style',
new StaleWhileRevalidate({
cacheName: 'static-resources',
})
);
Такой подход обеспечивает быстрое отображение старой версии и бесшовное получение новой версии, что делает уведомление о обновлении актуальным именно тогда, когда новый контент действительно готов к показу.
В приложениях с несколькими открытыми вкладками важно синхронизировать уведомления:
navigator.serviceWorker.addEventListener('controllerchange', () => {
window.location.reload();
});
Это гарантирует, что все вкладки будут работать с одной и той же версией приложения после обновления сервис-воркера.
В совокупности, использование Workbox для уведомления о новой версии включает три ключевых аспекта:
install, activate и waiting.Этот подход позволяет реализовать контролируемое и прогнозируемое обновление веб-приложений без неожиданной потери данных и с минимальными неудобствами для пользователя.