Синхронизация версий между вкладками

Workbox предоставляет мощные инструменты для управления кэшированием и стратегиями загрузки ресурсов, однако при работе с несколькими вкладками одного приложения возникает задача синхронизации версий сервис-воркера. Без корректной синхронизации новые версии приложения могут быть доступны в одной вкладке, но другие вкладки будут использовать старые ресурсы. Это может приводить к рассинхронизации состояния интерфейса и неконсистентности данных.

Механизм уведомления о новой версии

Для отслеживания обновлений Workbox использует события жизненного цикла сервис-воркера: install, activate, waiting, controlling. Ключевое событие для синхронизации версий между вкладками — waiting. Когда новая версия сервис-воркера установлена, но ещё не активирована, она попадает в состояние waiting. Это сигнализирует о том, что есть новая версия приложения, и все открытые вкладки должны быть оповещены.

self.addEventListener('install', (event) => {
  console.log('Service Worker: установлен');
});

self.addEventListener('activate', (event) => {
  console.log('Service Worker: активирован');
});

self.addEventListener('waiting', () => {
  console.log('Service Worker: новая версия готова к активации');
});

Использование BroadcastChannel для уведомлений

Для синхронизации вкладок эффективно применять API BroadcastChannel. Он позволяет открытым вкладкам обмениваться сообщениями в реальном времени. При обнаружении новой версии сервис-воркера одна вкладка может отправить уведомление другим вкладкам.

const channel = new BroadcastChannel('sw-messages');

channel.addEventListener('message', (event) => {
  if (event.data.type === 'NEW_VERSION_AVAILABLE') {
    console.log('Обнаружена новая версия приложения');
    // Логика обновления интерфейса или перезагрузки вкладки
  }
});

Сервис-воркер может отправлять сообщения всем вкладкам через clients.matchAll:

self.addEventListener('install', (event) => {
  self.skipWaiting(); // пропускаем фазу ожидания при необходимости
});

self.addEventListener('activate', async () => {
  const clientsList = await self.clients.matchAll({ type: 'window' });
  clientsList.forEach(client => {
    client.postMessage({ type: 'NEW_VERSION_AVAILABLE' });
  });
});

Автоматическое обновление вкладок

Для минимизации рассинхронизации можно реализовать автоматическое обновление вкладки при обнаружении новой версии. После получения события NEW_VERSION_AVAILABLE вкладка может показать уведомление пользователю или перезагрузить страницу автоматически:

channel.addEventListener('message', (event) => {
  if (event.data.type === 'NEW_VERSION_AVAILABLE') {
    window.location.reload();
  }
});

Использование Workbox Versioned Cache

Workbox поддерживает версионированные кэши через cacheNameDetails. Это позволяет создать отдельный кэш для каждой версии приложения. При активации новой версии сервис-воркера старый кэш можно удалить:

workbox.core.setCacheNameDetails({
  prefix: 'my-app',
  suffix: 'v1', // изменяется при выпуске новой версии
  precache: 'precache',
  runtime: 'runtime'
});

self.addEventListener('activate', async () => {
  const cacheNames = await caches.keys();
  await Promise.all(
    cacheNames
      .filter(name => !name.includes('v1'))
      .map(name => caches.delete(name))
  );
});

Стратегии управления версиями и вкладками

  1. Принудительная активация новой версии (skipWaiting) – обеспечивает немедленное обновление, но может прервать активные сессии.
  2. Уведомление пользователя – позволяет сохранить текущее состояние и дать возможность пользователю обновить вкладку самостоятельно.
  3. Сочетание BroadcastChannel и versioned caches – гарантирует, что все вкладки узнают о новой версии и смогут загрузить актуальные ресурсы.

Практические рекомендации

  • Обновления кэша должны происходить асинхронно, чтобы не блокировать интерфейс.
  • Не использовать window.location.reload() без уведомления пользователя в критически важных приложениях, где потеря состояния недопустима.
  • Тестировать синхронизацию в условиях множества открытых вкладок и нестабильного соединения.
  • Использовать уникальные идентификаторы версий (hash сборки) для контроля состояния кэшей.

Синхронизация версий между вкладками позволяет поддерживать консистентное состояние приложения и предотвращает ошибки из-за использования старых ресурсов. Комбинация возможностей Workbox, событий жизненного цикла сервис-воркера и BroadcastChannel обеспечивает надежный и масштабируемый механизм обновления.