Интеграция с Gulp: продвинутые сценарии

Для интеграции sw-precache с Gulp необходимо сначала установить пакет через npm:

npm install --save-dev sw-precache gulp

После установки создаётся файл Gulp задачи, который будет генерировать сервис-воркеры для кэширования статических ресурсов. Базовая конфигурация выглядит следующим образом:

const gulp = require('gulp');
const swPrecache = require('sw-precache');

gulp.task('generate-service-worker', function(callback) {
  swPrecache.write('dist/service-worker.js', {
    staticFileGlobs: [
      'dist/**/*.html',
      'dist/**/*.js',
      'dist/**/*.css',
      'dist/images/**/*.{png,jpg,gif,svg}'
    ],
    stripPrefix: 'dist/',
    runtimeCaching: [{
      urlPattern: /\/api\/.*$/,
      handler: 'networkFirst'
    }]
  }, callback);
});

Ключевые моменты конфигурации:

  • staticFileGlobs — массив шаблонов для файлов, которые должны быть кэшированы при установке сервис-воркера.
  • stripPrefix — убирает часть пути при сохранении файлов в кэше, что упрощает их адресацию.
  • runtimeCaching — массив правил для динамического кэширования, позволяющий управлять стратегиями (networkFirst, cacheFirst и др.).

Продвинутые сценарии кэширования

1. Смешанное кэширование с версияцией

Чтобы управлять версиями кэша и гарантировать корректное обновление ресурсов:

const cacheId = 'my-app-cache';
const cacheVersion = 'v1';

swPrecache.write('dist/service-worker.js', {
  cacheId: `${cacheId}-${cacheVersion}`,
  staticFileGlobs: [
    'dist/**/*.html',
    'dist/**/*.css',
    'dist/**/*.js'
  ],
  stripPrefix: 'dist/',
  dynamicUrlToDependencies: {
    '/index.html': ['dist/index.html']
  },
  runtimeCaching: [
    {
      urlPattern: /\/api\/.*$/,
      handler: 'networkFirst'
    }
  ]
});
  • cacheId позволяет разграничивать кэши между разными проектами.
  • dynamicUrlToDependencies используется для обновления конкретных URL при изменении файлов зависимостей.

2. Кэширование с обработкой версии хеша

Для ресурсов с хешированными именами можно исключить их из переиндексации, используя регулярные выражения:

staticFileGlobs: [
  'dist/**/*.{css,js,png,jpg,gif,svg}',
  '!dist/**/*.map'
],
  • Исключение .map файлов предотвращает лишнее кэширование, ускоряя установку сервис-воркера.
  • Можно настроить автоматическую генерацию хешей с помощью Gulp-плагинов, таких как gulp-rev, и передавать итоговые файлы в staticFileGlobs.

Интеграция с другими Gulp-задачами

1. Автоматическая генерация при сборке проекта

gulp.task('build', gulp.series('clean', 'styles', 'scripts', 'images', 'generate-service-worker'));
  • Сервис-воркер генерируется после всех остальных задач, чтобы включить только актуальные ресурсы.
  • Обеспечивает синхронизацию кэширования с версией сборки.

2. Инкрементальное обновление кэша

Можно использовать опцию stripPrefixMulti для разных директорий:

swPrecache.write('dist/service-worker.js', {
  stripPrefixMulti: {
    'dist/': '',
    'bower_components/': 'vendor/'
  },
  staticFileGlobs: [
    'dist/**/*.html',
    'dist/**/*.js',
    'bower_components/**/*.js'
  ]
});
  • Позволяет интегрировать сторонние библиотеки в кэш без изменения их оригинальных путей.
  • Обеспечивает совместимость с различными структурами проекта.

Настройка стратегий runtimeCaching

sw-precache поддерживает несколько стратегий кэширования для динамических запросов:

  • cacheFirst — сначала проверяется кэш, затем сеть.
  • networkFirst — сначала сеть, затем кэш.
  • fastest — выбирается первый отклик между сетью и кэшем.
  • networkOnly / cacheOnly — полностью исключает одну из опций.

Пример продвинутой конфигурации:

runtimeCaching: [
  {
    urlPattern: /\/api\/v1\/users/,
    handler: 'networkFirst',
    options: {
      cache: {
        maxEntries: 50,
        name: 'users-api-cache'
      }
    }
  },
  {
    urlPattern: /\/images\/.*\.(png|jpg|gif|svg)/,
    handler: 'cacheFirst',
    options: {
      cache: {
        maxEntries: 100,
        maxAgeSeconds: 60 * 60 * 24 * 30 // 30 дней
      }
    }
  }
]
  • Настройка maxEntries и maxAgeSeconds позволяет контролировать размер кэша и срок хранения.
  • Разделение кэшей для разных типов ресурсов предотвращает переполнение и конфликт версий.

Интеграция с PWA-процессом

Для полноценной PWA-оптимизации сервис-воркер, сгенерированный через sw-precache, можно:

  1. Автоматически регистрировать в index.html:
if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/service-worker.js');
}
  1. Обновлять кэш при выпуске новой версии, используя skipWaiting и clientsClaim через ручное редактирование сгенерированного файла или через шаблон:
self.addEventListener('install', event => {
  self.skipWaiting();
});

self.addEventListener('activate', event => {
  event.waitUntil(clients.claim());
});
  • Это гарантирует мгновенное применение нового сервис-воркера без ожидания закрытия вкладок.

Обработка ошибок и отладка

  • Использовать gulp-plumber для безопасного выполнения задачи:
const plumber = require('gulp-plumber');

gulp.task('generate-service-worker', function(callback) {
  return gulp.src('dist')
    .pipe(plumber())
    .pipe(swPrecache.write('service-worker.js', {/* конфиг */}, callback));
});
  • Логи ошибок выводятся в консоль, что позволяет быстро локализовать проблемы при неверной конфигурации шаблонов или стратегии кэширования.

  • Для отладки можно включить verbose режим:

swPrecache.write('dist/service-worker.js', {
  verbose: true,
  staticFileGlobs: ['dist/**/*.{js,css,html}']
});