Примечание. Поскольку сервис-воркер потенциально может быть использован для атаки «человек посередине», для использования сервис-воркеров необходимо безопасное SSL-соединение.

Жизненный цикл сервисного работника

Service Worker имеет жизненный цикл, отделенный от веб-страниц. Это означает, что он загружается в фоновом режиме и НЕ замедляет вашу первоначальную загрузку или задерживает рендеринг (если вы загружаете его без блокировки рендеринга).

Установка

Как только сервис-воркер регистрируется через javascript вашей страницы, запускается событие установки. Вы можете выбрать предварительную загрузку и кэширование файлов во время установки или вообще игнорировать событие. Обычно вам нужно кэшировать некоторые статические ресурсы, такие как основные файлы css и js. Однако будьте осторожны с файлами, которые вы запрашиваете, потому что, если какой-либо из файлов недоступен, установка завершится ошибкой, и сервисный работник не будет активирован.

Активация

Если установка прошла успешно, сервис-воркер активируется. На этапе активации вы обычно имеете дело с аннулированием старых кешей.

Праздный

Как только активация завершена, сервисный работник сидит без дела, ожидая выполнения запроса. Используя событие выборки, мы можем обрабатывать запросы любым способом, например, возвращая кешированный ответ.

Если вы хотите узнать больше, ознакомьтесь с этой статьей о теории сервис-воркеров.

Настройка сервис-воркера

Хотя вполне возможно написать наш сервис-воркер с нуля, мы будем использовать пакет наших друзей из Google, называемый sw-precache, чтобы сделать всю тяжелую работу.

Сервисному работнику для работы нужны два файла. Фактический файл service-worker.js и файл для регистрации сервис-воркера. Последнее — это много стандартного кода, например, проверка поддержки сервис-воркеров. К счастью, есть готовый файл от разработчиков sw-precache, который мы можем просто добавить: service-worker-registration.js

Скрипт регистрации

В этом сценарии мы проверяем, поддерживает ли браузер сервис-воркеров, если ('serviceWorker' in navigator) (в настоящее время Firefox, Chrome и Opera). Если это так, то после запуска события загрузки сервис-воркер регистрируется сценарием navigator.serviceWorker.register('service-worker.js') и регистрируется сообщение: либо содержимое было обновлено, либо произошла ошибка, что очень удобно для отладки.

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

Обязательно отредактируйте и этот файл, чтобы он был очищен от кеша, если вы что-то измените.

Теперь вам нужно только загрузить этот скрипт на свой сайт, и он зарегистрирует для вас файл service-worker.js.

Создание сервис-воркера

Одна важная вещь, которую нужно знать о сценарии service-worker.js, заключается в том, что он может управлять запросом только в своем корневом каталоге и ниже. Это означает, что вы захотите поместить его в корневой каталог вашего веб-сайта, чтобы сервис-воркер мог контролировать весь трафик ваших страниц.

Мы хотим, чтобы gulp создал нашего сервис-воркера, поэтому нам нужно создать новую задачу service-worker. Конечно, нам нужен пакет sw-precache. Кроме того, мы определяем rootDir и URL-адреса, которые мы хотим предварительно загрузить. Будьте осторожны с предварительной загрузкой, хотя она и не блокирует загрузку, она все равно будет стоить вашим пользователям полосы пропускания, поэтому не загружайте сразу весь веб-сайт.

Возможно, вы помните, что мы используем измененные файлы, что означает, что app.css на самом деле что-то вроде app-123ldsajflkdsaj13.css. Очевидно, вы не хотите обновлять эту ссылку вручную каждый раз, когда вы меняете свои активы. Чтобы обойти это, нам нужно проверить, какие из файлов имеют исправленную версию в нашем rev-manifest.json, и соответствующим образом обновить массив. Для этого мы добавляем следующее ниже массива urlsToPrefetch.

Хорошо, что мы делаем? Сначала мы загружаем rev-manifest.json и анализируем его, так что мы получаем object. После этого мы перебираем пары ключ-значение и проверяем, соответствует ли одно из них нашему имени файла с хэш-суффиксом. Если это так, мы заменяем значение в нашем объекте измененным URL-адресом, в противном случае мы возвращаем неизмененный. Кроме того, нам нужно добавить rootDir к значению, так как оно не указано в нашем rev-manifest.

SW-Precache

Теперь мы можем перейти к sw-precache, добавить следующее ниже вызова urlsToPrefetch.map:

swPrecache.write(`${rootDir}/service-worker.js`, { 
  staticFileGlobs: urlsToPrefetch, 
  stripPrefix: rootDir, 
  runtimeCaching: [{ 
    urlPattern: '/(.*)', 
    handler: 'cacheFirst' 
  },{ 
    urlPattern: /\.googleapis\.com\//, 
    handler: 'cacheFirst' }] 
  }, done)

Метод sw-precache.write имеет сигнатуру write(filePath, options, callback). Он генерирует сервис-воркера и записывает его в filePath с учетом предоставленного options. Как только это сделано, вызывается callback либо с параметром error, либо с null, если не произошло ошибки.

Путь файла

filePath — это просто service-worker.js в корневом каталоге: ${rootDir}/service-worker.js.

опции

Для объекта options мы передаем наш массив urlsToPrefetch в staticFileGlobs. Это предварительно загрузит эти файлы и сделает их доступными в кеше.

stripPrefix: rootDir удаляет корневой каталог (все, что вы сохранили в константе rootDir) из наших URL-адресов при кэшировании во время выполнения, что может быть необходимо в зависимости от вашей настройки. Если у вас есть все ваши файлы, например. public/ и корневой каталог вашего сервера также указывает на public, вы захотите использовать эту опцию, чтобы получить правильный относительный URL-адрес.

Наконец, runtimeCaching — это массив объектов для указания параметров кэширования во время выполнения. Каждый объект должен состоять из urlPattern, который является либо строкой, либо регулярным выражением. И обработчик, который является либо именем одного из обработчиков, поставляемых в базовом пакете sw-toolbox, либо пользовательской функцией обработчика. Мы используем cacheFirst, который сначала попытается получить что-то из кеша, и только если он недоступен, проверит сеть.

Наш первый urlPattern соответствует любому локальному ресурсу, который мы загружаем, поэтому все будет кэшироваться при первом запросе. Второй шаблон соответствует любому запросу, загруженному через googleapis.com, который я использую для веб-шрифтов. Таким образом, они также будут кэшироваться.

Перезвони

Наконец, мы вызываем done в качестве нашего обратного вызова, чтобы gulp task знал, что он закончен, и мы можем двигаться дальше.

Когда вы запускаете gulp service-worker, вы должны получить хорошо созданный сервис-воркер в public/service-worker.js, который включает URL-адреса из вашего массива urlsToPrefetch. Давайте продолжим и добавим эту задачу в наш рабочий процесс.

Устаревшие активы и HTML

Но что, если я изменю свой html, и он уже закэширован кешем среды выполнения, спросите вы. Не бойтесь, sw-precache прикроет вашу спину. По умолчанию он автоматически удаляет из кеша все URL-адреса, если сервис-воркер изменился, поэтому ваши файлы всегда будут актуальными. Однако это также означает, что наши измененные файлы будут повторно загружены. Для решения этой проблемы существует опция dontCacheBustUrlsMatching, но мы сделаем это позже.

Соединяем все вместе

В задаче gulp default добавьте задачу service-worker после задачи html, к этому моменту все ваши активы должны быть скомпилированы, отредактированы и ваши файлы html должны быть созданы. Теперь всякий раз, когда вы запускаете gulp, ваш сервис-воркер будет обновляться. Кроме того, вы должны добавить задачу service-worker к соответствующим задачам наблюдения. Всякий раз, когда актив, который является предварительной выборкой или будет кэшироваться, изменяется, вам также необходимо обновить своего сервисного работника.

Если вы еще этого не сделали, не забудьте загрузить service-worker-registration.js, и все готово.

Первоначально опубликовано на https://vea.re 11 мая 2017 г.