Как добавить Service Worker в React приложение?react-98

Service Worker (Сервис-воркер) — это скрипт, который работает в фоновом режиме браузера и позволяет реализовать возможности PWA (оффлайн-работу, push-уведомления, фоновую синхронизацию).

Основные возможности Service Worker

  1. Кеширование ресурсов (Caching) - для оффлайн-работы
  2. Фоновая синхронизация (Background Sync) - обновление данных
  3. Push-уведомления (Push Notifications) - уведомления пользователя
  4. Перехват запросов (Request Interception) - контроль сетевых запросов

Способы добавления Service Worker в React

1. Использование Create React App

CRA уже включает базовую поддержку Service Worker:

// В файле src/index.js
import * as serviceWorkerRegistration from './serviceWorkerRegistration';

// Регистрация сервис-воркера
serviceWorkerRegistration.register();

Для кастомизации измените src/service-worker.js:

// Пример кеширования
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open('my-cache-v1').then((cache) => {
      return cache.addAll([
        '/',
        '/index.html',
        '/static/js/main.chunk.js',
        '/static/css/main.css'
      ]);
    })
  );
});

2. Ручная настройка Service Worker

Шаг 1: Создание файла Service Worker

public/sw.js:

const CACHE_NAME = 'my-app-cache-v1';
const urlsToCache = [
  '/',
  '/index.html',
  '/manifest.json',
  '/static/media/logo.123456.png'
];

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

Шаг 2: Регистрация в React приложении

src/registerServiceWorker.js:

export function register() {
  if ('serviceWorker' in navigator) {
    window.addEventListener('load', () => {
      navigator.serviceWorker.register('/sw.js')
        .then(registration => {
          console.log('SW registered:', registration);
        })
        .catch(error => {
          console.log('SW registration failed:', error);
        });
    });
  }
}

Шаг 3: Импорт в главном файле

src/index.js:

import { register } from './registerServiceWorker';
register();

3. Использование Workbox

Workbox — это библиотека от Google для работы с Service Workers:

npm install workbox-webpack-plugin --save-dev

webpack.config.js:

const { InjectManifest } = require('workbox-webpack-plugin');

module.exports = {
  plugins: [
    new InjectManifest({
      swSrc: './src/sw.js',
      swDest: 'service-worker.js',
    })
  ]
}

Пример src/sw.js с Workbox:

import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { CacheFirst } from 'workbox-strategies';

// Предварительное кеширование
precacheAndRoute(self.__WB_MANIFEST);

// Динамическое кеширование API
registerRoute(
  new RegExp('/api/'),
  new CacheFirst({
    cacheName: 'api-cache'
  })
);

Стратегии кеширования

  1. Cache First (Сначала кеш):
registerRoute(
  ({request}) => request.destination === 'image',
  new CacheFirst()
);
  1. Network First (Сначала сеть):
registerRoute(
  ({url}) => url.pathname.startsWith('/api'),
  new NetworkFirst()
);
  1. Stale While Revalidate (Устаревшее с повторной проверкой):
registerRoute(
  ({request}) => request.destination === 'style',
  new StaleWhileRevalidate()
);

Отладка Service Worker

  1. Chrome DevTools → Application → Service Workers
  2. Проверка кеша: DevTools → Application → Cache Storage
  3. Принудительное обновление:
    navigator.serviceWorker.getRegistrations().then(regs => {
      regs.forEach(reg => reg.unregister());
      caches.keys().then(keys => keys.forEach(key => caches.delete(key)));
    });
    

Оптимизация Service Worker

  1. Версионирование кеша:
const CACHE_VERSION = 'v2';
const CACHE_NAME = `my-app-${CACHE_VERSION}`;
  1. Очистка старых кешей:
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(cacheNames => {
      return Promise.all(
        cacheNames.map(cache => {
          if (cache !== CACHE_NAME) {
            return caches.delete(cache);
          }
        })
      );
    })
  );
});
  1. Ленивая загрузка ресурсов:
self.addEventListener('fetch', event => {
  if (event.request.url.includes('/lazy/')) {
    event.respondWith(
      caches.match(event.request).then(response => {
        return response || fetch(event.request).then(fetchResponse => {
          return caches.open(CACHE_NAME).then(cache => {
            cache.put(event.request, fetchResponse.clone());
            return fetchResponse;
          });
        });
      })
    );
  }
});

Резюмируем

добавление Service Worker в React приложение можно выполнить через CRA, вручную или с помощью Workbox. Выбор стратегии кеширования зависит от типа ресурсов. Для production-приложений рекомендуется использовать Workbox для более надежной работы и простого обновления кеша. Всегда тестируйте Service Worker в разных сценариях и не забывайте про версионирование кеша.