Библиотека Sw-precache создаёт сервис-воркеры, которые автоматически кэшируют ресурсы веб-приложения для оффлайн-доступа и ускоренной загрузки. Одной из важных задач при использовании сервис-воркеров является информирование пользователя о доступности новой версии приложения. Без уведомлений пользователи могут продолжать работать с устаревшими данными, что приводит к рассинхронизации и проблемам в интерфейсе.
Sw-precache не предоставляет встроенных UI-элементов для уведомлений, но даёт инструменты для отслеживания обновлений сервис-воркера и вызова кастомных обработчиков.
Для отслеживания обновлений сервис-воркера используется событие
updatefound у регистрационного объекта. Регистрация
сервис-воркера выглядит следующим образом:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/service-worker.js').then(registration => {
registration.onupdatefo und = () => {
const installingWorker = registration.installing;
installingWorker.onstatecha nge = () => {
if (installingWorker.state === 'installed') {
if (navigator.serviceWorker.controller) {
// Новая версия доступна
showUpdateNotification();
}
}
};
};
}).catch(error => {
console.error('Service Worker registration failed:', error);
});
}
Ключевые моменты:
navigator.serviceWorker.controller указывает на
активный воркер. Если он присутствует при событии
installed, значит обновление загрузилось, но ещё не
активировалось.installingWorker.state проходит через состояния:
installing, installed,
activating, activated, redundant.
Событие installed — основной сигнал для уведомления о новой
версии.Можно автоматически активировать новую версию сервис-воркера и перезагрузить страницу:
function showUpdateNotification() {
navigator.serviceWorker.getRegistration().then(reg => {
if (reg.waiting) {
reg.waiting.postMessage({ action: 'skipWaiting' });
}
});
window.location.reload();
}
Более безопасная стратегия — показать баннер или диалог с предложением обновить приложение:
function showUpdateNotification() {
const updateBanner = document.createElement('div');
updateBanner.textContent = 'Доступна новая версия приложения. Обновить сейчас?';
const updateButton = document.createElement('button');
updateButton.textContent = 'Обновить';
updateButton.oncl ick = () => {
navigator.serviceWorker.getRegistration().then(reg => {
if (reg.waiting) {
reg.waiting.postMessage({ action: 'skipWaiting' });
}
});
window.location.reload();
};
updateBanner.appendChild(updateButton);
document.body.appendChild(updateBanner);
}
Sw-precache позволяет передавать сообщения между воркером и основной
страницей. В сервис-воркере можно добавить обработчик для команды
skipWaiting:
self.addEventListener('message', event => {
if (event.data.action === 'skipWaiting') {
self.skipWaiting();
}
});
skipWaiting гарантирует немедленную
активацию обновлённого воркера без ожидания закрытия всех вкладок.Для минимизации риска неожиданной перезагрузки можно реализовать подход “soft update”:
localStorage или
IndexedDB.function scheduleUpdateNotification() {
navigator.serviceWorker.getRegistration().then(reg => {
if (reg.waiting) {
localStorage.setItem('updateReady', 'true');
}
});
}
window.addEventListener('load', () => {
if (localStorage.getItem('updateReady') === 'true') {
showUpdateNotification();
localStorage.removeItem('updateReady');
}
});
Sw-precache генерирует манифест кэша с файлами, каждая версия воркера сопровождается уникальным хэшем. Это позволяет:
// Пример конфигурации sw-precache
swPrecache.write('service-worker.js', {
staticFileGlobs: [
'index.html',
'scripts/**/*.js',
'styles/**/*.css',
'images/**/*.{png,jpg,gif}'
],
stripPrefix: 'dist/',
runtimeCaching: [{
urlPattern: /\/api\/.*$/,
handler: 'networkFirst'
}]
});
staticFileGlobs — список файлов для предзагрузки.runtimeCaching — стратегия для динамических
ресурсов.Объединение этих возможностей с механизмами уведомлений обеспечивает надёжное и контролируемое обновление веб-приложения.
localStorage/IndexedDB) для контроля процесса.updatefound и
statechange должна быть стабильной и отлаженной.Сочетание этих методов обеспечивает гибкое управление обновлениями и позволяет поддерживать актуальность приложения без ущерба для пользовательского опыта.