Уведомление пользователя о доступном обновлении

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 предлагает встроенные методы для управления стратегиями кеширования и обновления ресурсов, включая 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 рекомендует использовать стратегии кеширования:

  • StaleWhileRevalidate — быстрый отклик из кеша, одновременно обновляя ресурсы в фоне.
  • NetworkFirst — попытка получить свежие данные из сети, fallback на кеш при недоступности.
  • CacheFirst — преимущественно кеш с редкой проверкой обновлений.

Пример использования для статических файлов:

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 для уведомления о новой версии включает три ключевых аспекта:

  1. Отслеживание жизненного цикла воркера через события install, activate и waiting.
  2. Коммуникацию клиент–воркер для информирования пользователя о новой версии.
  3. Выбор стратегии кеширования, обеспечивающей быстрый отклик и безопасное обновление ресурсов.

Этот подход позволяет реализовать контролируемое и прогнозируемое обновление веб-приложений без неожиданной потери данных и с минимальными неудобствами для пользователя.