Генерация Service Worker с помощью sw-precache
должна строго учитывать порядок выполнения остальных задач сборки.
Неправильное размещение приводит к устаревшему кэшу, отсутствию ресурсов
в precache или некорректной работе офлайн-режима.
Ключевой принцип: Service Worker генерируется только после
того, как все статические ресурсы окончательно
сформированы.
Общая схема сборочного
процесса
Типичный pipeline сборки фронтенд-приложения включает следующие
этапы:
- Трансформация исходного кода (Babel, TypeScript)
- Бандлинг (Webpack, Rollup, Parcel)
- Минификация (JS, CSS, HTML)
- Генерация ассетов (изображения, шрифты)
- Хеширование файлов (cache busting)
- Копирование файлов в директорию сборки (
dist,
build)
- Генерация Service Worker (sw-precache)
sw-precache всегда выполняется последним шагом, так
как он анализирует уже готовую директорию и формирует список файлов для
кэширования.
Почему порядок критичен
1. Корректность списка
precache
sw-precache сканирует файловую систему по заданным шаблонам
(staticFileGlobs). Если генерация происходит раньше:
- часть файлов может отсутствовать
- имена файлов могут измениться позже (например, при хешировании)
- Service Worker закэширует устаревшие версии
2. Поддержка хешированных
файлов
При использовании подхода cache busting (например,
app.8f3a2.js) важно:
- сначала сгенерировать файлы с хешами
- затем передать их в sw-precache
Иначе:
- Service Worker будет ссылаться на старые имена файлов
- обновления не будут подхватываться клиентом
3. Минификация и оптимизация
Если Service Worker создаётся до минификации:
- в кэш попадут не оптимизированные файлы
- увеличится размер precache
- ухудшится производительность офлайн-режима
Интеграция с системами
сборки
Webpack
При использовании Webpack sw-precache обычно подключается через:
- отдельный скрипт после сборки
- или через плагины (например,
sw-precache-webpack-plugin)
Правильный порядок:
- Webpack завершает сборку
- Генерируются все ассеты
- Запускается sw-precache
Пример через npm-скрипты:
{
"scripts": {
"build": "webpack",
"postbuild": "node generate-sw.js"
}
}
postbuild гарантирует запуск после завершения
сборки.
Gulp
В Gulp порядок контролируется через последовательность задач:
const gulp = require('gulp');
const swPrecache = require('sw-precache');
gulp.task('build', function() {
// сборка проекта
});
gulp.task('service-worker', function(callback) {
swPrecache.write('dist/service-worker.js', {
staticFileGlobs: ['dist/**/*.{js,html,css,png,jpg}']
}, callback);
});
gulp.task('default', gulp.series('build', 'service-worker'));
Использование gulp.series гарантирует:
- сначала
build
- затем
service-worker
npm / standalone
В простых проектах порядок реализуется через цепочку скриптов:
{
"scripts": {
"clean": "rimraf dist",
"build": "webpack",
"generate-sw": "node sw.js",
"start": "npm run clean && npm run build && npm run generate-sw"
}
}
Типичные ошибки порядка
выполнения
Генерация до сборки
sw-precache → webpack
Проблемы:
- пустой или неполный precache
- отсутствие файлов в кэше
Генерация до хеширования
webpack → sw-precache → hash
Проблемы:
- Service Worker указывает на файлы без хеша
- клиент загружает устаревшие версии
Параллельное выполнение
webpack & sw-precache
Проблемы:
- гонка состояний (race condition)
- непредсказуемый набор файлов
Контроль завершения
асинхронных задач
sw-precache работает асинхронно, поэтому важно:
- дожидаться завершения записи Service Worker
- не завершать процесс сборки преждевременно
Пример:
swPrecache.write('dist/service-worker.js', config)
.then(() => {
console.log('Service Worker сгенерирован');
});
Или с callback:
swPrecache.write('dist/service-worker.js', config, function() {
console.log('Готово');
});
Взаимодействие с другими
оптимизациями
Tree Shaking
Tree shaking должен завершиться до генерации Service Worker,
иначе:
- в кэш попадут неиспользуемые модули
Code Splitting
При динамической загрузке чанков:
- sw-precache должен учитывать все чанки
- особенно важно включать шаблоны вида:
staticFileGlobs: ['dist/**/*.js']
Генерация HTML
(например, HtmlWebpackPlugin)
HTML-файлы должны быть:
- уже ссылающимися на финальные ресурсы
- включёнными в precache
Практическая стратегия
Оптимальная последовательность:
- Очистка директории сборки
- Компиляция и бандлинг
- Минификация
- Генерация ассетов
- Хеширование файлов
- Генерация HTML
- Копирование статических файлов
- Генерация Service Worker (sw-precache)
Проверка корректности
порядка
Признаки правильной интеграции:
- Service Worker содержит актуальные хеши файлов
- список precache совпадает с содержимым
dist
- при изменении файлов обновляется Service Worker
- отсутствуют 404 при работе офлайн
Инкрементальная сборка и
CI/CD
В CI/CD pipeline важно:
- запускать sw-precache после всех шагов сборки
- исключать кэшированные артефакты предыдущих сборок
- пересоздавать Service Worker при каждом деплое
Влияние порядка на
обновление кэша
sw-precache генерирует версию кэша на основе содержимого файлов. Если
порядок нарушен:
- клиент может не получать обновления
- старые версии файлов будут храниться в кеше
- Service Worker не будет пересоздаваться
Разделение окружений
В development режиме:
- генерация Service Worker часто отключается
- либо выполняется отдельно
В production:
- строго после полной сборки
- с финальными путями и ресурсами
Автоматизация порядка
Для гарантии правильного порядка используются:
postbuild хуки
gulp.series
- Webpack hooks (
afterEmit)
- CI pipelines (GitHub Actions, GitLab CI)
Встраивание в Webpack
lifecycle
При использовании плагинов важно подключаться к правильному хуку:
emit — может быть слишком рано
afterEmit — предпочтительно, так как
все файлы уже записаны
Критерии правильной точки
запуска
Service Worker должен генерироваться в момент, когда:
- файловая структура окончательная
- имена файлов неизменны
- все ресурсы доступны на диске
- сборка полностью завершена
Последствия неправильного
порядка
- неработающий офлайн-режим
- устаревшие ресурсы в кэше
- некорректное обновление приложения
- увеличение размера кэша
- проблемы с CDN и кэшированием браузера
Вывод ключевых правил
- Генерация Service Worker — самый последний шаг
сборки
- Никаких параллельных запусков с основными задачами
- Учитываются уже оптимизированные и хешированные файлы
- Вся логика должна быть встроена в финальный этап pipeline