Workbox (далее — WB) — это библиотека (точнее, набор библиотек), основной целью которой является "предоставление лучших практик и избавление от шаблонного кода при работе с сервис-воркерами" (далее — СВ). Если вы впервые слышите о СВ, то перед изучением данного руководства настоятельно рекомендуется ознакомиться со следующими материалами: WB предоставляет следующие возможности: Ниже приведены примеры основных подходов к разработке прогрессивных веб-приложений (приложений, в которых используются возможности, предоставляемые СВ). Хотели бы вы, чтобы ваши гугл-шрифты были доступны в режиме офлайн после того, как пользователь в первый раз посетил ваш сайт? Тогда запишите их в кэш: Сделайте ваш JS и CSS-код быстрым за счет его доставки из кэша, будучи уверенными в его актуальности за счет периодического обновления (в фоновом режиме): Как правило, основной "вес" страницы — это изображения. Используйте следующее правило для сохранения изображений в кэше, будучи уверенными, что они не переполнят хранилище пользователя: Используйте WB для предварительного кэширования ресурсов, используемых вашим приложением, с помощью CLI, Node-модуля или Webpack-плагина. Хотите, чтобы гугл-аналитика продолжала работать при отсутствии подключения к сети? Никаких проблем. WB — это набор библиотек для помощи в создании и управлении СВ и кэшированием через CacheStorage API. СВ и CacheStorage API при совместном использовании позволяют управлять тем, откуда загружаются ресурсы, используемые приложением (JavaScript, CSS, HTML, изображения и т.д.), из сети или из кэша. Начиная с 5 версии, WB может быть использован внутри СВ с помощью JS-модулей и npm посредством установки необходимых модулей WB и их импорта. К сожалению, JS-модули не работают в СВ, поэтому для компиляции СВ требуется сборщик модулей, такой как Webpack, Rollup или Parcel (см. ниже). Перед использованием WB, необходимо создать СВ и зарегистрировать его на странице. Начнем с создания файла service-worker.js в корневой директории проекта: Далее регистрируем СВ на странице: Это сообщает браузеру, что данный СВ должен использоваться для текущей страницы. Если вы перезагрузите страницу, откроете инструменты разработчика Chrome и перейдете во вкладку Console, то увидите там сообщение от СВ. Если переключиться на вкладку Application, то можно увидеть, что СВ был успешно зарегистрирован. После этого можно подключать WB. WB — это набор npm-модулей. Сначала требуется установить нужный модуль, затем импортировать его. Одними из основных возможностей WB является маршрутизация и стратегии кэширования, с них и начнем. WB позволяет управлять кэшированием HTTP-запросов с помощью различных стратегий кэширования. Первым делом необходимо определить, соответствует ли поступивший запрос определенному критерию и, если это так, применить к нему соответствующую стратегию. Можно использовать предварительно определенную стратегию (предоставляемую WB) или определить собственную. Базовая реализация маршрутизации и кэширования может выглядеть так: В дополнение к кэшированию после выполнения запроса (кэшированию во время выполнения), WB поддерживает предварительное кэширование — кэширование ресурсов во время установки СВ. Хорошими кандидатами для предварительного кэширования являются начальный URL приложения, резервная (офлайн) страница, а также ключевые JS и CSS-файлы. Предварительное кэширование позволяет гарантировать, что основные ресурсы приложения являются доступными в момент, когда СВ получает контроль над страницей. Предварительное кэширование можно использовать внутри СВ с помощью плагина, предоставляемого сборщиком модулей, поддерживающим встраивание (внедрение) “манифеста предварительного кэширования” (см. ниже): Данный СВ предварительно кэширует файлы во время установки, заменяя self.__WB_MANIFEST списком вхождений, добавляемых в СВ во время сборки. Как правило, для подготовки приложения к работе в режиме офлайн вместо "дефолтной" страницы с ошибкой предоставляется резервная страница. С помощью WB этот паттерн можно реализовать при помощи нескольких строк кода: Данный СВ предварительно сохраняет резервную страницу и возвращает ее при отсутствии подключения к сети вместо ошибки. Как было отмечено ранее, начиная с 5 версии, WB может использоваться в СВ с помощью JS-модулей. Выбор сборщика модулей Подойдет любой сборщик, поддерживающий модули, например, Webpack, Rollup или Parcel. Написание кода СВ Ниже приведен пример гипотетического СВ, импортирующего несколько WB-библиотек. Данный СВ должен быть обработан сборщиком перед запуском в браузере. Следует отметить, что WB поддерживает расширенное логгирование в режиме для разработки и минимальное логгирование в производственном режиме. Опционально: встраивание манифеста предварительного кэширования Для того, чтобы кэшировать ресурсы во время установки СВ, необходимо предоставить WB оформленный определенным образом список URL. Данный список называется “манифестом предварительного кэширования” (precaching manifest). Место для вставки такого манифеста во время сборки обозначается с помощью self.__WB_MANIFEST. Настройка вебпака Плагин Inject Manifest отвечает как за сборку СВ, так и за встраивание манифеста. При его использование не требуется отдельно настраивать СВ. Настройка CLI Вместо плагина для сборщика можно использовать workbox-cli в режиме injectManifest. При использовании данного подхода после каждой успешной сборки необходимо запускать injectManifest, передавая ему свежего СВ в качестве настройки swSrc. GenerateSW В режиме generateSW при использовании workbox-build, workbox-cli или GenerateSW в workbox-webpack-plugin не нужно настраивать процесс сборки — готовый к использованию СВ будет сгенерирован автоматически. Маршрутизация в WB — это процесс определения совпадения маршрута с запросом и обработка совпавшего запроса (отправка ответа на него). Существует три способа реализации определения совпадений с помощью workbox-routing: С помощью строк Запрашиваемый URL сравнивается со строкой и, если они равны, запрос передается обработчику (handler). Маршрутизатор для /logo.png может быть реализован так: Проблема такого подхода состоит в том, что запросы из другого источника (origin) не будут совпадать со строкой. Поэтому лучше определять абсолютный путь: С помощью регулярных выражений Лучшим способом обработки группы запросов является использование регулярного выражения. Данный подход является гораздо более гибким, чем предыдущий. Например, вот как можно реализовать маршрутизацию на основе расширений файлов: Регулярные выражения также могут использоваться для поиска совпадения с определенным форматом URL, например: И снова наш маршрут не будет совпадать с запросом из другого источника. Эту проблему можно решить с помощью wildcard (.+): Такой же фокус можно проделать с первым примером: С помощью колбэков Для дальнейшей кастомизации определения совпадений можно воспользоваться функцией matchCallback. Данная функция принимает ExtendableEvent, Request и объект URL. Простой пример: Существует два способа обработки запросов: С помощью стратегий WB предоставляет следующие стратегии кэширования: Поведение маршрутизатора при использовании любой стратегии может быть кастомизировано посредством определения используемого кэша или добавления плагинов: С помощью колбэков Для дальнейшей кастомизации обработки запросов можно воспользоваться асинхронным колбэком, возвращающим объект Response. Данный колбэк принимает объект со свойствами url и event: Следует отметить, что значение, возвращаемое колбэком match, передается в функцию обратного вызова handler в виде аргумента params: Это может быть полезным, например, в случае, когда у нас имеется какая-то информации, “зашитая” в URL, которая извлекается в match (путем разбора URL) и используется в handler. WB предоставляет названия для кэша и уровни логгирования из коробки. Эти значения можно изменять. При использовании различных WB API можно заметить, что некоторый кэш создается автоматически. При отсутствии названий кэша WB использует дефолтные названия, определенные в workbox-core. Предопределенные названия кэша выглядят так: Каждое название состоит из трех частей: Эти названия можно менять как целиком, так и по частям: Или так: Некоторые части WB API принимают настройку cacheName с названием кэша. К таким API, в частности, относятся стратегии. В случае установки настройки cacheName, префикс и суффикс не используются. Например, вот как можно определить название для кэша изображений: Теперь изображения будут записываться в кэш my-image-cache. При использовании кастомной стратегии для кэширования во время выполнения может потребоваться настройка некоторых аспектов исходящих запросов. Например, в запросе могут отсутствовать необходимые данные для авторизации. Для реализации такого сценария мы можем передать в конструктор стратегии настройку fetchOptions, соответствующую настройкам init Fetch API. Эти настройки будут применяться в отношении всех исходящих запросов, которые обрабатываются данной стратегией. Запросы к другим источникам обрабатываются WB особым образом. Одним из основных защитных механизмов, используемых браузером, является запрет доступа к телу и другим частям ответа, поступившего из другого источника без CORS-заголовков. Такие ответы являются "непрозрачными" (opaque). СВ в этом отношении не является исключением. Если вы запрашиваете ресурсы с источника, поддерживающего CORS, но получаете непрозрачные ответы, возможно, вы неправильно их запрашиваете. Например, следующий HTML запускает запросы, приводящие к непрозрачным ответам, даже если example.com поддерживает CORS: В данном случае, для отправки запросов, в ответ на которые возвращаются прозрачные ответы, следует включить режим CORS с помощью атрибута crossorigin: Обычно, WB не кэширует непрозрачные ответы. Причина этого заключается в том, что такие ответы могут привести к плохому "состоянию" приложения. Предположим, что мы определили такой маршрутизатор: В данном случае, любой ответ будет записываться в кэш и возвращаться в ответ на запрос. Сохранение и возврат непрозрачного ответа могут привести к поломке приложения. Тем не менее, данный подход можно использовать с такими стратегиями как StaleWhileRevalidate и NetworkFirst, поскольку в этом случае время жизни плохого ответа будет непродолжительным за счет регулярного обновления кэша. При использовании другой стратегии и получении непрозрачного ответа WB выведет в консоль предупреждение о том, что ответ не кэширован. Непрозрачные ответы могут принудительно записываться в кэш с помощью плагинов, таких как workbox-cacheable-response: Плагины позволяют определять дополнительное поведение, связанное с обработкой запросов или ответов, в течение жизненного цикла запроса. WB предоставляет следующие плагины: Пользовательский плагин — это объект, содержащий один из следующих методов: Все эти функции вызываются с ключевым словом await при достижении кэшем (или событием fetch) контрольной точки. Вот как выглядит использование этих колбэков: Как правило, объект event, передаваемый в колбэк — это исходное событие, вызвавшее операцию fetch или cache. Тем не менее, всегда следует проверять наличие данного объекта перед его использованием. При вызове метода handle() в стратегии event, передаваемый в него, будет передан в колбэки плагинов. Все колбэки также принимают объект state, который является уникальным по отношению к объекту конкретного плагина и вызову стратегии. Это делает возможным реализацию плагинов, где один колбэк выполняет операции на основе данных, полученных от другого колбэка в том же плагине (например, вычисление дельты времени между запуском requestWillFetch() и fetchDidSucceed() или fetchDidFail()). Каждый браузер устанавливает определенный лимит объема памяти, который может использоваться приложением. Данный лимит зависит от браузера. Объем используемой и доступной памяти можно проверить с помощью navigator.storage.estimate(). WB позволяет настроить автоматическую очистку хранилища при достижении квоты (storage quota). Ниже приведено несколько примеров использования стратегий кэширования для разных случаев. Сервис гугл-шрифтов состоит из двух частей: Таблица стилей может часто изменяться, поэтому для нее лучше использовать стратегию stale-while-revalidate, которая выполняет обновление кэша после каждого запроса. Для файлов шрифтов, которые меняются редко, можно использовать стратегию cache-first. В следующем примере мы пытаемся вернуть ответ из сети. Если запрос выполняется дольше 3 секунд, возвращается ответ из кэша: Cache Storage API доступен как в СВ, так и в контексте window. Если вы хотите изменить кэш — добавить или удалить из него записи или получить список кэшированных URL, вы можете сделать это напрямую, без обращения к СВ через postMessage(). В следующем примере мы добавляем в кэш новые записи при выполнении пользователем определенного действия в приложении: Название кэша my-cache затем может быть использовано в СВ: Хорошей практикой является отображение “баннера” (оповещения) во время обновления и установки СВ. Для реализации этого паттерна требуется некоторый код на странице и в СВ. Код на странице При обнаружении ожидающего СВ, мы сообщаем пользователю о том, что доступна обновленная версия приложения и запрашиваем у него разрешение на перезагрузку страницы. Если пользователь предоставил разрешение, мы используем messageSkipWaiting() для указания ожидающему СВ запустить self.skipWaiting(), что означает начало его активации. После того, как новый СВ был активирован и получил контроль над страницей, мы перезагружаем ее, что приводит к отображению последней версии предварительно кэшированных ресурсов. Код в СВ Если вы используете один из встроенных инструментов WB в режиме GenerateSW и skipWaiting имеет значение false (значение по умолчанию), то приведенный ниже код будет автоматически включен в генерируемого СВ. Если вы создаете собственного СВ или работаете в режиме InjectManifest, тогда в код СВ необходимо добавить следующее: Этот код "слушает" сообщения с type: 'SKIP_WAITING' и запускает метод self.skipWaiting() для активации СВ. После настройки маршрутов для кэширования ресурсов, может возникнуть желание добавить некоторые файлы в кэш во время установки СВ. Для этого нужные ресурсы следует записать в кэш во время выполнения: При использовании стратегий с кастомным названием для кэша просто присвойте это название свойству cacheName. Возврат резервного ответа — это лучше, чем отсутствие ответа. Например, можно возвращать заменитель (placeholder) изображения, когда не удалось получить само изображение, или резервную HTML-страницу вместо стандартной офлайн-страницы, предоставляемой браузером. Резервная страница Более сложный пример Все встроенные стратегии отклоняются (reject) одинаково при провале запроса и/или отсутствии кэша. Это позволяет добавить глобальный "перехватчик" для обработки всех ошибок. Большинство разработчиков использует одну из стратегий как часть настройки маршрутизатора. Данная настройка позволяет автоматически реагировать на определенное событие fetch ответом, полученным от стратегии. Существуют ситуации, когда мы хотим использовать стратегию в собственной настройке маршрутизатора или вместо обычного запроса fetch(). В таких случаях можно использовать стратегию в "автономном" режиме: Параметр request является обязательным и должен иметь тип Request. Параметр event является опциональным ExtendableEvent. Если данный параметр указан, он будет использоваться для сохранения СВ (через event.waitUntil()) в течение времени, достаточного для завершения "фонового" обновления кэша и его очистки. handle() возвращает промис для объекта Response. Более сложный пример Устанавливаем CLI: Запускам wizard. Он настраивает CLI для проекта, задавая несколько вопросов о его структуре для определения файлов для кэширования. Создаем СВ: Регистрируем СВ на странице: Добавляем в workbox-config.js настройку runtimeCaching для кэширования изображений во время выполнения: Под капотом workbox-cli использует модуль workbox-build, облегчая интеграцию WB в процесс сборки проекта с помощью командной строки. Режимы CLI CLI имеет 4 режима: wizard wizard задает несколько вопросов, связанных с настройкой проекта, а также с тем, какие файлы нуждаются в предварительном кэшировании. Ответы используются для генерации файла с настройками, который используется при запуске в режиме generateSW. Начальный файл с настройками можно кастомизировать с помощью любых поддерживаемых настроек. generateSW Используется для генерации готового СВ на основе файла с настройками. Когда использовать: Когда лучше не использовать: injectManifest Режим injectManifest предоставляет более полный контроль над тем, как будет выглядеть финальный СВ. Использование этого режима предполагает наличие файла с СВ (в локации, определенной в config.js). При запуске injectManifest он ищет специальную строку (precacheAndRoute(self.__WB_MANIFEST) по умолчанию) в коде СВ. Он заменяет пустой массив списком URL для предварительного кэширования и записывает СВ в локацию, определенную в config.js. Остальной код СВ остается неизменным. Когда использовать: Когда лучше не использовать: copyLibraries Данный режим может быть полезен, когда вы хотите использовать режим injectManifest и локальную копию WB вместо CDN. Установка: Вызываем generateSW(). Для генерации СВ необходимо добавить workboxBuild.generateSW() в Node.js-скрипт: Этот код создаст СВ в build/sw.js, который предварительно кэширует все файлы в директории build, совпадающие с globPatterns. Регистрируем СВ на странице: Настройка СВ для кэширования изображений во время выполнения идентична настройке, используемой для создания СВ с помощью workbox-cli. Модуль workbox-build интегрируется в процесс сборки проекта с помощью Node.js и может генерировать готовый СВ или формировать список ресурсов для предварительного кэширования, который используется существующим СВ. generateSW injectManifest WB предоставляет два плагина для вебпака: один для создания готового СВ, другой для формирования списка ресурсов для предварительного кэширования. Эти плагины реализованы в виде двух классов в модуле workbox-webpack-plugin: GenerateSW и InjectManifest. GenerateSW InjectManifest На этом первая часть руководства завершена. В следующей части мы подробно рассмотрим большинство модулей, предоставляемых WB, разработаем несколько сниппетов, которые можно будет использовать в приложениях “как есть”, а также кратко рассмотрим готовые решения для создания PWA, предоставляемые такими фреймворками для фронтенда как React и Vue. Ссылка на вторую часть. VPS серверы от Маклауд быстрые и безопасные. Зарегистрируйтесь по ссылке выше или кликнув на баннер и получите 10% скидку на первый месяц аренды сервера любой конфигурации!