WorkBox: ваш toolkit в мире сервис-воркеров

    Привет, Хабр!

    Меня зовут Святослав. Я работаю в компании ДомКлик и отвечаю за развитие сервисов оформления ипотеки. В начале года мы взяли курс на внедрение философии Progressive Web Application (PWA) в наших клиентских приложениях.

    Одним из важных аспектов PWA является использование технологии Service Worker API, выполняющей роль прокси между браузером и сервером. Это позволяет поддерживать работу приложения в оффлайн-режиме, управлять кэшированием сетевых данных с их фоновой синхронизацией, а также работать с push-уведомлениями.

    Однако эта технология не так проста, как кажется на первый взгляд. Для её эффективного использования придётся пройти тернистый путь из квестов, связанных с особенностями жизненного цикла воркеров, неполной поддержкой браузерами, проблемами с политикой кэширования и попутными побочными эффектами (устаревшее содержимое кэша браузера или, к примеру, сломанные ссылки).

    Workbox — это разработанный в Google набор инструментов, предоставляющих высокоуровневый API для работы с такими браузерными технологиями, как Service Worker API и Cache Storage API. Инструментарий состоит из набора изолированных модулей, которые помогут вам сделать полноценное PWA-приложение. 

    Входящие в состав Workbox модули.
    Входящие в состав Workbox модули.

    Вы можете работать с сервис-воркерами нативно, однако использование Workbox даст вам значительные преимущества. Давайте рассмотрим их.

    Управление кэшированием

    Зачастую сложно сформировать единую политику кэширования для всех запрашиваемых ресурсов. К примеру, можно себе позволить кэшировать шрифты на долгий срок и не нагружать сеть запросами, но мы не можем кэшировать запросы, отвечающие за предоставление актуальных данных, влияющих на бизнес-процесс (например, ипотечную ставку или срок кредитования). Здесь нам на помощь приходит Workbox, который предлагает тонкую настройку стратегий кэширования, вплоть до каждого запроса. Разберём особенности работы каждой из них.

    Network Only

    При получении запроса сервис-воркер перенаправляет его в сеть. Кэш не используется.

    Cache Only

    Сервис-воркер формирует ответ на запрос только из кэша. Сеть не используется. Эта стратегия будет полезна, если у вас используется предварительное кэширование.

    Network First

    В самом начале происходит попытка получить данные из сети. Если получен корректный ответ, то сервис-воркер возвращает его браузеру, перед этим сохраняя полученные данные в кэш. Если же запрос, направленный в сеть, завершился ошибкой, то для ответа будут использоваться данные из кэша.

    Cache First

    Согласно этой стратегии, система сперва пытается получить данные из кэша. Если в хранилище ничего не найдено, то запрос уходит в сеть. При получении успешного ответа кэш обновляется, после чего ответ возвращается браузеру.

    Stale While Revalidate

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

    С помощью плагинов можно настроить каждую стратегию посредством дополнительных параметров. Например, добавить имя сегмента для Cache Storage, выставить сроки «протухания» данных, настроить статусы ответов, которые нужно кэшировать.

    В приведенном ниже примере определяются правила для кэширования изображений. При успешном статусе ответа файлы будут сохраняться в сегмент хранилища с названием "assets". Максимальное число хранимых записей — 60, срок актуальности данных — 30 дней.

    import {registerRoute} from 'workbox-routing';
    import {CacheFirst} from 'workbox-strategies';
    import {CacheableResponsePlugin} from 'workbox-cacheable-response';
    import {ExpirationPlugin} from 'workbox-expiration';
    
    registerRoute(
      ({request}) => request.destination === 'image',
      new CacheFirst({
        cacheName: 'assets',
        plugins: [
          new CacheableResponsePlugin({
            statuses: [0, 200]
          }),
          new ExpirationPlugin({
            maxEntries: 60,
            maxAgeSeconds: 30 * 24 * 60 * 60, // 30 Days
          })
        ]
      })
    );
    

    Кэширование потоковых аудио- и видеоданных

    Некоторые HTTP-запросы включают в себя заголовок Range:, который говорит серверу о том, чтобы тот вернул часть запрашиваемого ресурса. Такие запросы используются в случае потоковых аудио- и видеоданных для реализации чанковой загрузки информации, что является более выигрышной альтернативой по сравнению с одинарным запросом на весь объём данных.

    Workbox содержит модуль workbox-range-requests, который реализует всю необходимую логику для поддержки чанковой загрузки с участием кэша.

    Простой пример работы с этим модулем:

    import {registerRoute} from 'workbox-routing';
    import {CacheFirst} from 'workbox-strategies';
    import {RangeRequestsPlugin} from 'workbox-range-requests';
    
    registerRoute(
      ({url}) => url.pathname.endsWith('.mp4'),
      new CacheFirst({
        plugins: [
          new RangeRequestsPlugin(),
        ]
      });
    );

    Журналирование

    Отладка работы сервис-воркера является неотъемлемой частью процесса разработки PWA-приложений. У Workbox есть отладочный режим, который позволяет выводить в консоль браузера подробную информацию о работе вашего сервис-воркера. Опираясь на журналы, разработчик сможет намного быстрее добраться до корня возникшей проблемы.

    Кроссбраузерная работа

    Workbox разрабатывается с учётом кроссбраузерной работы. Если браузер не поддерживает определённую технологию, будет использоваться альтернативная реализация.

    К примеру:

    • Модуль оповещения об обновлении кэшированных данных (workbox-broadcast-cache-update) использует под капотом Broadcast Channel API. А если браузер его не поддерживает, то переключается на механизм postMessage.

    • Модуль фоновой синхронизации данных (workbox-background-sync) использует Background Sync API. При отсутствии браузерной поддержки модуль попытается повторить запрос из очереди событий во время следующего запуска сервис-воркера.

    Интеграция с Google Analytics

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

    Модуль Workbox Google Analytics создан для решения этой проблемы. При оффлайн-работе он отлавливает неудачные запросы и сохраняет их в локальную базу данных браузера — IndexedDB. А при возобновлении интернет-соединения запросы повторно отправляются на серверы Google Analytics.

    Простой пример подключения этого модуля:

    import * as googleAnalytics from 'workbox-google-analytics';
    
    googleAnalytics.initialize();

    Способы использования

    Workbox предлагает следующие варианты использования:

    Работа с Webpack

    Давайте рассмотрим один из способов использования Workbox вместе со сборщиком статических модулей Webpack. Для начала нам нужно установить плагин, который поставляется в виде npm-пакета:

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

    Далее нужно подключить плагин в конфигурационном файле webpack.config.js, чтобы webpack автоматически сгенерировал воркер-файл на этапе сборки приложения.

    Возьмем за основу пример из официальной документации. По умолчанию Workbox добавляет в предварительный кэш все файлы, которые участвуют в webpack-сборке. Но было бы ошибкой кэшировать все изображения вашего приложения, когда их число измеряется сотнями, а общий размер — мегабайтами (нужно помнить, что браузер имеет квоту на хранение данных в Cache Storage). Вместо этого выставим такие параметры, чтобы сервис-воркер кэшировал изображения только тогда, когда приложение обращается за их загрузкой. А также установим лимит в 10 записей.

    // Inside of webpack.config.js:
    const WorkboxPlugin = require('workbox-webpack-plugin');
    
    module.exports = {
      // Other webpack config...
    
      plugins: [
        // Other plugins...
    
        new WorkboxPlugin.GenerateSW({
          // Do not precache images
          exclude: [/\.(?:png|jpg|jpeg|svg)$/],
    
          // Define runtime caching rules.
          runtimeCaching: [{
            // Match any request that ends with .png, .jpg, .jpeg or .svg.
            urlPattern: /\.(?:png|jpg|jpeg|svg)$/,
    
            // Apply a cache-first strategy.
            handler: 'CacheFirst',
    
            options: {
              // Use a custom cache name.
              cacheName: 'images',
    
              // Only cache 10 images.
              expiration: {
                maxEntries: 10,
              }
            }
          }]
        })
      ]
    };

    На выходе мы получим сгенерированный файл sw.js с определенными правилами кэширования сетевых данных.

    Резюме

    Workbox делает работу с сервис-воркерами более комфортной. Этот инструмент позволяет декларативно определить правила кэширования ресурсов приложения, взяв низкоуровневую работу на себя. К тому же Workbox уже интегрирован с такими инструментами разработки, как react-create-app, vue-cli, preact-cli, next.js, что говорит о его признании со стороны сообщества разработчиков.

    ДомКлик
    Место силы

    Похожие публикации

    Комментарии 5

      +1
      ОФФ: я один на логотипе вижу не ящик с инструментами, а ШОО?!
      +1

      Давеча разгребал диск. Пытался понять куда уходят заветные гигабайты. Обнаружил что Chrome и Vivaldi на пару съели 5+ GiB места на… Service Worker-ы.


      Не то, чтобы 5 GiB в наше время были чем-то сильно дорогим, но, сдаётся мне, что из этих 5 GiB процента 3% являются полезными, а остальные 97% это дань моде. Или эгоизму создателей очередного https://roga-i-kopyta.com, которые решили, что я, как постоянный посетитель этого ресурса (разумеется нет), мечтаю о том, чтобы он целиком был закеширован на диске :)

        0

        О, тоже лидил ипотеку в той компании)


        В целом к SW отношусь осторожно — недостатки очевидны ("Для её эффективного использования придётся пройти тернистый путь из квестов, связанных с особенностями жизненного цикла воркеров, неполной поддержкой браузерами, проблемами с политикой кэширования и попутными побочными эффектами (устаревшее содержимое кэша браузера или, к примеру, сломанные ссылки)"). А единственный плюс по сравнению со стандартным браузерным кешированием — возможность работы приложения в оффлайне, что конкретно для сервиса ипотеки — лишнее, т.к. пользователь ожидает интерактив (чаты, актуальные данные, услуги) и может нарушиться безопасность (авторизация в оффлайне не работает). Также процесс обновления клиентских файлов, если апдейт приложения произошел когда юзер был в оффлайне, потребует дополнительного кода.


        Есть ли реальная польза в этом проекте от PWA, или только значительное усложнение поддержки?

          0
          Дмитрий, приветствую!

          Я бы отметил такие моменты:
          — улучшение пользовательского опыта за счет скорости открытия приложения (AppShell from Cache)
          — возможность кэшировать и повторять запросы при кратковременных перебоях с сетью (например, когда пользователь загружает файлы и при отправке происходит разрыв соединения)
          — возможность выносить сложные вычисления в отдельный поток сервис-воркера для того, чтобы не нагружать клиент
          — Google продвигает технологию PWA и повышает в поисковой выдаче те сервисы, которые разработаны в соответствии с данной философией
          — Дистрибуция приложения прямо из браузера без использования магазинов приложений
          — Небольшой размер приложения по сравнению с мобильным приложением
          — Мгновенные обновления без необходимости скачивать и переустанавливать приложение
          — Единая стек и кодовая база для веба и мобилы
          — Меньше ресурсов на разработку и сопровождение
          — …

        Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

        Самое читаемое