Обслуживание App Shell из кэша

App Shell представляет собой минимальный набор статических ресурсов, необходимых для отображения пользовательского интерфейса веб-приложения. Обычно это HTML-шаблон, CSS-стили, JavaScript-файлы и базовые изображения. Основная цель App Shell — обеспечить мгновенную загрузку интерфейса и сделать веб-приложение похожим на нативное, даже при медленном соединении.

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


Регистрация сервис-воркера

Для работы с Workbox сначала необходимо зарегистрировать сервис-воркер в основном JavaScript-файле приложения:

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
    .then(reg => console.log('Service Worker зарегистрирован', reg))
    .catch(err => console.error('Ошибка регистрации Service Worker', err));
}

Файл sw.js станет точкой конфигурации кэширования App Shell.


Импорт библиотек Workbox

Workbox можно подключать как через CDN, так и через npm. Для CDN достаточно добавить в сервис-воркер:

importScripts('https://storage.googleapis.com/workbox-cdn/releases/6.6.0/workbox-sw.js');

После этого объект workbox становится доступным для конфигурации стратегий кэширования.


Применение стратегии Cache First для App Shell

Cache First — оптимальная стратегия для App Shell, так как позволяет всегда быстро загружать интерфейс из кэша и обновлять ресурсы по мере необходимости в фоновом режиме.

Пример реализации с Workbox:

workbox.routing.registerRoute(
  ({request}) => request.destination === 'document' || request.destination === 'script' || request.destination === 'style',
  new workbox.strategies.CacheFirst({
    cacheName: 'app-shell-cache',
    plugins: [
      new workbox.expiration.ExpirationPlugin({
        maxEntries: 50,
        maxAgeSeconds: 7 * 24 * 60 * 60, // 7 дней
      }),
    ],
  })
);

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

  • request.destination фильтрует типы ресурсов (HTML, JS, CSS).
  • cacheName задаёт отдельный кэш для App Shell.
  • ExpirationPlugin управляет временем хранения и количеством элементов в кэше.

Предварительное кэширование ресурсов

Workbox поддерживает precache, что позволяет кэшировать все ресурсы App Shell при установке сервис-воркера. Это гарантирует мгновенный доступ к интерфейсу при первой загрузке:

workbox.precaching.precacheAndRoute([
  { url: '/', revision: '1' },
  { url: '/index.html', revision: '1' },
  { url: '/styles/main.css', revision: '1' },
  { url: '/scripts/main.js', revision: '1' },
  { url: '/images/logo.png', revision: '1' },
]);

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

  • revision используется для контроля версий ресурсов. При изменении файла сервис-воркер обновит кэш автоматически.
  • Все файлы, добавленные в precache, будут обслуживаться даже при оффлайн-доступе.

Обновление App Shell

Для поддержания актуальности интерфейса применяют стратегию stale-while-revalidate для некоторых ресурсов App Shell, позволяя сразу показывать старую версию, а новую загружать в фоне:

workbox.routing.registerRoute(
  ({request}) => request.destination === 'script' || request.destination === 'style',
  new workbox.strategies.StaleWhileRevalidate({
    cacheName: 'app-shell-stale-cache',
  })
);

Преимущества:

  • Мгновенная загрузка интерфейса из кэша.
  • Фоновое обновление ресурсов.
  • Снижение задержек при первой загрузке.

Управление версиями и очистка старых кэшей

При изменении App Shell важно удалять устаревшие версии кэша. Workbox предоставляет плагины и API для этого:

self.addEventListener('activate', (event) => {
  const currentCaches = ['app-shell-cache', 'app-shell-stale-cache'];
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      return Promise.all(
        cacheNames.map((cacheName) => {
          if (!currentCaches.includes(cacheName)) {
            return caches.delete(cacheName);
          }
        })
      );
    })
  );
});

Это предотвращает накопление старых версий ресурсов и уменьшает потребление памяти.


Кэширование с учетом оффлайн-доступа

Все ресурсы App Shell, закэшированные через precache или Cache First, становятся доступными при отсутствии сети. Сервис-воркер перехватывает запросы и возвращает кэшированные файлы, обеспечивая работу интерфейса оффлайн:

self.addEventListener('fetch', (event) => {
  // Workbox автоматически обрабатывает precache и routing
});

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


Оптимизация производительности

  • Разделение кэшей: отдельный кэш для App Shell, отдельный для динамических данных.
  • Контроль версий через revision для эффективного обновления.
  • Использование стратегий Cache First для статических ресурсов и Stale-While-Revalidate для часто обновляемых скриптов и стилей.
  • Ограничение количества записей и времени хранения через ExpirationPlugin.

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