Работа с Service Workers

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

Регистрация Service Worker

Регистрация Service Worker осуществляется через стандартный API браузера. В контексте Stimulus это удобно делать в контроллере, который инициализируется при загрузке страницы. Пример базовой регистрации:

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  connect() {
    if ('serviceWorker' in navigator) {
      navigator.serviceWorker.register('/service-worker.js')
        .then(registration => {
          console.log('Service Worker зарегистрирован с областью:', registration.scope);
        })
        .catch(error => {
          console.error('Ошибка при регистрации Service Worker:', error);
        });
    }
  }
}

Ключевые моменты:

  • Проверка 'serviceWorker' in navigator необходима для обеспечения совместимости с браузерами, которые не поддерживают Service Workers.
  • Метод register возвращает промис с объектом регистрации, который содержит информацию о scope и состоянии Service Worker.

Основные события Service Worker

Service Worker поддерживает несколько жизненно важных событий:

  • install — выполняется при первой установке или обновлении Service Worker. Здесь обычно происходит кэширование статических ресурсов.
  • activate — вызывается после установки, позволяет очищать старые кэши и готовить новый Service Worker к работе.
  • fetch — перехватывает сетевые запросы, что позволяет реализовать офлайн-режим и динамическое кэширование.

Пример Service Worker с кэшированием:

const CACHE_NAME = 'my-app-cache-v1';
const URLS_TO_CACHE = [
  '/',
  '/styles.css',
  '/script.js',
  '/logo.png'
];

self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(URLS_TO_CACHE))
  );
});

self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.filter(name => name !== CACHE_NAME)
          .map(name => caches.delete(name))
      );
    })
  );
});

self.addEventListener('fetch', event => {
  event.respondWith(
    caches.match(event.request)
      .then(response => response || fetch(event.request))
  );
});

Особенности:

  • Метод event.waitUntil гарантирует, что установка или активация завершится только после выполнения всех асинхронных задач.
  • Использование caches.match позволяет вернуть закэшированную версию ресурса или обратиться к сети при его отсутствии.

Интеграция с Stimulus

Stimulus контроллер может взаимодействовать с Service Worker, например, для уведомления пользователей о доступности обновлений:

import { Controller } from "@hotwired/stimulus";

export default class extends Controller {
  connect() {
    if (navigator.serviceWorker.controller) {
      navigator.serviceWorker.addEventListener('message', event => {
        if (event.data === 'update-available') {
          console.log('Доступно обновление приложения');
          // Можно показать уведомление или автоматически обновить страницу
        }
      });
    }
  }

  triggerUpdate() {
    if (navigator.serviceWorker.controller) {
      navigator.serviceWorker.controller.postMessage('skipWaiting');
    }
  }
}

Важные детали:

  • Связь между контроллером Stimulus и Service Worker осуществляется через postMessage и обработку события message.
  • Использование сообщений позволяет динамически управлять поведением страницы без полной перезагрузки.

Работа с кэшированием динамических данных

Для динамических данных, таких как API-запросы, Service Worker может применять стратегию stale-while-revalidate:

self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      caches.open('dynamic-cache').then(cache => {
        return cache.match(event.request).then(response => {
          const fetchPromise = fetch(event.request).then(networkResponse => {
            cache.put(event.request, networkResponse.clone());
            return networkResponse;
          });
          return response || fetchPromise;
        });
      })
    );
  }
});

Принципы работы:

  • Сначала возвращается закэшированный ответ, если он есть.
  • Параллельно выполняется сетевой запрос для обновления кэша.
  • Такой подход обеспечивает быстрый отклик и актуальные данные.

Отладка и обновление Service Worker

Для разработки и отладки важно управлять обновлением Service Worker:

  • В Chrome DevTools можно принудительно остановить и удалить старый Service Worker.
  • Для автоматического применения нового Service Worker используется метод skipWaiting() внутри Service Worker и сообщение от контроллера Stimulus для перезагрузки страницы.

Рекомендации по структуре проекта

  • Разделение логики Service Worker и контроллеров Stimulus. Контроллеры не должны содержать сложной логики кэширования.
  • Все статические ресурсы, необходимые для офлайн-режима, лучше перечислять в отдельном массиве при установке Service Worker.
  • Динамические данные кэшировать в отдельном кэше, чтобы избежать конфликта с основными ресурсами.

Интеграция Stimulus с Service Worker позволяет создавать быстрые, отзывчивые веб-приложения с поддержкой офлайн-режима и эффективным кэшированием ресурсов, сохраняя при этом простую и модульную архитектуру.