Service Worker — это скрипт, работающий в фоновом режиме браузера, который перехватывает сетевые запросы и управляет кэшированием ресурсов. Sw-precache упрощает процесс генерации Service Worker, автоматически создавая кэш для статических файлов веб-приложения. Однако по умолчанию Service Worker обновляется только тогда, когда его скрипт изменился, что может приводить к задержкам при внедрении новых версий приложения. Для решения этой проблемы используется принудительное обновление Service Worker.
Sw-precache генерирует файл service-worker.js, в котором
указаны все ресурсы для кэширования. Каждый раз при генерации Service
Worker создаётся новый хеш содержимого, и браузер распознаёт изменение
скрипта. Однако если изменения происходят редко или разработчик хочет
немедленно обновить кэш, необходимо использовать методы активации нового
Service Worker вручную.
Основные события в Service Worker для обновления:
install – событие установки нового
Service Worker.activate – событие активации, которое
позволяет очистить старый кэш.message – событие, через которое можно
инициировать принудительное обновление из клиентской части.Ключевой подход заключается в том, чтобы использовать метод
skipWaiting() в событии
install и метод
clients.claim() в событии
activate.
skipWaiting() и clients.claim()self.addEventListener('install', function(event) {
event.waitUntil(
self.skipWaiting()
);
});
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.keys().then(function(cacheNames) {
return Promise.all(
cacheNames.map(function(cacheName) {
// Очистка старых кэшей
if (cacheName !== CURRENT_CACHE_NAME) {
return caches.delete(cacheName);
}
})
);
}).then(() => self.clients.claim())
);
});
skipWaiting() принудительно завершает
фазу ожидания нового Service Worker, позволяя ему сразу перейти в
активное состояние.clients.claim() гарантирует, что все
открытые вкладки начнут использовать новый Service Worker без
необходимости перезагрузки страницы.Для инициирования обновления из веб-приложения можно использовать
метод postMessage:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.ready.then(function(registration) {
registration.active.postMessage({ action: 'skipWaiting' });
});
}
В Service Worker необходимо добавить обработчик сообщений:
self.addEventListener('message', function(event) {
if (event.data && event.data.action === 'skipWaiting') {
self.skipWaiting();
}
});
Таким образом, новая версия Service Worker активируется немедленно, и кэш обновляется без ожидания закрытия всех вкладок.
Sw-precache поддерживает стратегию
cacheFirst, когда ресурсы берутся из кэша,
если они доступны. При принудительном обновлении важно корректно
управлять старыми кэшами:
const CURRENT_CACHE_NAME = 'my-app-cache-v2';
self.addEventListener('activate', function(event) {
event.waitUntil(
caches.keys().then(cacheNames =>
Promise.all(
cacheNames.map(cacheName => {
if (cacheName !== CURRENT_CACHE_NAME) {
return caches.delete(cacheName);
}
})
)
).then(() => self.clients.claim())
);
});
Присвоение уникальных имен кэшу (v1, v2,
v3) позволяет отслеживать версии ресурсов и удалять
устаревшие файлы без вмешательства пользователя.
При использовании sw-precache через Gulp или Grunt можно интегрировать генерацию Service Worker в процесс сборки, обеспечивая автоматическое обновление при каждом деплое:
swPrecache.write('service-worker.js', {
staticFileGlobs: [
'index.html',
'css/**/*.css',
'js/**/*.js',
'images/**/*.{png,jpg,gif,svg}'
],
stripPrefix: '/',
navigateFallback: '/index.html',
verbose: true,
});
Каждое изменение файлов в staticFileGlobs изменяет хеш,
и браузер распознаёт новый Service Worker.
skipWaiting() только
после тщательного тестирования, чтобы избежать конфликтов при
одновременном использовании старых и новых ресурсов.Эта стратегия позволяет обеспечить мгновенное внедрение новых версий приложения, минимизировать вероятность использования устаревших кэшей и поддерживать актуальность контента без вмешательства пользователя.