Работа с Service Workers

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


Подключение Service Worker

Первым шагом является регистрация Service Worker в приложении. Обычно это выполняется в основном файле Jav * aScript:

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

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

  • Проверка if ('serviceWorker' in navigator) необходима для поддержки старых браузеров.
  • Регистрация происходит после события load, чтобы страница и все ресурсы были загружены.
  • Метод register возвращает объект Promise, который можно использовать для отслеживания состояния регистрации.

Создание Service Worker

Файл service-worker.js располагается в корне проекта и содержит логику обработки запросов. Простейший пример кеширования ресурсов:

const CACHE_NAME = 'hyperapp-cache-v1';
const ASSETS = [
  '/',
  '/index.html',
  '/style.css',
  '/bundle.js'
];

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

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

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

Особенности работы:

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

Интеграция со стейтом Hyperapp

Hyperapp использует централизованный стейт, который можно синхронизировать с Service Worker. Например, для уведомления о доступной новой версии приложения:

const state = {
  updateAvailable: false
};

const actions = {
  setUpdate: value => state => ({ updateAvailable: value })
};

const view = (state, actions) => (
  h('div', {}, [
    state.updateAvailable && h('div', { class: 'update-notice' }, 'Доступна новая версия')
  ])
);

app({ init: state, view, node: document.getElementById('app'), actions });

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.addEventListener('controllerchange', () => {
    actions.setUpdate(true);
  });
}

Важные моменты:

  • controllerchange срабатывает, когда новая версия Service Worker берёт контроль над страницей.
  • Состояние Hyperapp можно использовать для управления отображением уведомлений о обновлении.

Кеширование динамических данных

Для API-запросов можно использовать стратегию «сначала сеть, потом кеш»:

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

Пояснения:

  • API-запросы сначала отправляются в сеть, чтобы получить актуальные данные.
  • Ответ клонируется и сохраняется в кеш для офлайн-доступа.
  • При отсутствии сети возвращается закешированный ответ.

Автообновление Service Worker

Для автоматического обновления и активации нового Service Worker можно использовать стратегию «skipWaiting»:

self.addEventListener('install', event => {
  self.skipWaiting();
});

self.addEventListener('activate', event => {
  clients.claim();
});
  • skipWaiting() позволяет новому Service Worker сразу перейти в активное состояние.
  • clients.claim() гарантирует, что текущие страницы начнут использовать нового Service Worker без перезагрузки.

Советы по оптимизации

  • Разделять статические ресурсы и динамические данные в разных кешах.
  • Использовать версии кеша (CACHE_NAME = 'v1') для безопасного обновления.
  • Минимизировать логику в Service Worker, чтобы не блокировать основное приложение.
  • Логи и уведомления об обновлениях удобно интегрировать через состояние Hyperapp для визуальной обратной связи.

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