Библиотеки прогрессивных веб-приложений в рабочей среде
Два года назад наша команда в Google начала работу над библиотеками JavaScript, чтобы уменьшить трение при создании прогрессивных веб-приложений.
Мы начали с инструментов Service Worker, таких как sw-precache и sw-toolbox, которые сейчас используются тысячами брендов для автономного кэширования и мгновенной загрузки (при повторном посещении) в своих производственных мобильных устройствах. места:
В 2017 году, если вы не пользуетесь услугами Service Workers, вы оставляете выигрыш в производительности для вернувшихся пользователей.
Давайте сравним временные полосы до / после для PWA CNet’s Tech Today и Housing.com. Мы можем видеть, что первый просмотр занимает несколько секунд по сравнению со средним показателем 3G. Посмотрите на улучшение на 3–4 секунды Service Worker, кэширующее оболочку своего приложения, и данные о времени загрузки:
Ууу. Они почти мгновенные :) Такой подход помог сайтам загружаться и быстрее взаимодействовать с Service Worker. Это воспроизводит желаемую характеристику производительности нативных приложений - после установки (веб-приложения) первоначальные затраты на перезагрузку амортизируются и не имеют переменной задержки.
Сервис-воркеры о надежной работе. Не только офлайн-поддержка - Алекс Рассел, Chrome
Крупные сайты, такие как Twitter.com, которые недавно отправили 100% своего мобильного веб-трафика в свои PWA с помощью Service Worker, архитектуры оболочки приложения и шаблона PRPL, также добились аналогичных результатов:
Это оптимизация не только для мобильных устройств и PWA. Сервисные работники также могут повысить производительность загрузки ваших настольных сайтов.
Например, Flipkart кэширует свои статические ресурсы , поэтому при повторных посещениях первая значимая отрисовка происходит на 1,5 секунды быстрее, чем первая загрузка:
Как описано в разделе Производительность при запуске JavaScript, Service Worker также разрешает вам использовать кеширование кода V8 при первом выполнении вашего JavaScript, поэтому вы также получите более быстрое время запуска для JS.
Сервис-воркеры могут помочь не только в кэшировании.
Мы также отправили библиотеку для Offline Google Analytics, основанную на Service Worker и IndexedDB. Когда пользователь не в сети или у него нестабильное сетевое соединение, мы ставим в очередь его аналитические данные и публикуем их, как только они вернутся в Интернет. Это используется такими сайтами, как eBay Ads в Мексике, чтобы свести к минимуму потерю полезной статистики, когда пользователи находятся в пути:
После успешной реализации этой идеи на сайте Google I / O 2015 мы сочли ее достаточно полезной и захотели обобщить ее, чтобы любой мог ее использовать.
Хорошим дополнением к библиотеке офлайн-аналитики является Autotrack - помощник, упрощающий отслеживание событий аналитики, которые волнуют большинство людей. Он имеет плагины для изменения URL-адресов PWA / SPA, видимости элементов, пользовательской прокрутки, медиа-запросов, видимости страниц и многого другого. Эти плагины помогают производственным сайтам, таким как 1Password, легко отслеживать важные события без шаблонных накладных расходов:
Затем мы начали работу над библиотекой Web Push Notifications, но появилась возможность сотрудничать с Firebase над гораздо более приятным решением, поэтому мы также помогли выпустить Firebase Cloud Messaging. Это кроссплатформенное решение для обмена сообщениями, которое может отправлять уведомления на основе сообщений или данных и отлично работает с PWA.
Alibaba - это всего лишь одна из производственных PWA, использующих FCM сегодня:
Мы также внесли свой вклад в библиотеку web-push от Mozilla, альтернативу, которую ребята могут посмотреть в этом разделе.
Поскольку Service Worker является основной частью многих наших библиотек, нам
также потребовались некоторые утилиты для их модульного тестирования. Мы создали селен-помощник для сквозного тестирования в нескольких браузерах с использованием Selenium. Мы также написали sw-testing-helpers для управления Service Workers в тестах.
Начало работы с нашими библиотеками JavaScript
Лаборатории разработчиков Google для sw-preache, sw-toolbox и offline-analytics находятся в свободном доступе.
Генерация сервис-воркеров
Sw-precache (который также отлично работает с Webpack) создает для вас Service Worker. В самом простом случае вы можете предоставить ему каталог dist, и он предоставит разумные настройки по умолчанию для кэширования любых статических ресурсов в автономном режиме, чтобы они мгновенно загружались из Cache Storage API при повторных посещениях:
$ sw-precache --root=dist
Вы можете проверить правильность кэширования файлов с помощью Панели приложений Chrome DevTools. После загрузки страницы найдите Cache Storage, и вы должны увидеть записи, соответствующие предоставленному каталогу:
Также поддерживается передача сложных конфигураций с использованием --config <file>
. Любые параметры из файла можно переопределить с помощью флага командной строки. Мы рекомендуем использовать внешний файл JavaScript для определения конфигураций с помощью module.exports. Например, предположим, что существует файл path / to / sw-precache-config.js, который содержит:
module.exports = {
staticFileGlobs: [
'app/css/**.css',
'app/**.html',
'app/images/**.*',
'app/js/**.js'
],
stripPrefix: 'app/',
runtimeCaching: [{
urlPattern: /this\\.is\\.a\\.regex/,
handler: 'networkFirst'
}]
};
Мы можем передать файл в интерфейс командной строки, также установив опцию подробного вывода:
sw-precache --config=path/to/sw-precache-config.js --verbose
Это обеспечивает максимальную гибкость, например, предоставление регулярного выражения для параметра runtimeCaching.urlPattern
. При успешном запуске sw-precache, он также суммирует предполагаемый размер предварительно кэшируемых ресурсов, чтобы помочь вам быть в курсе использования тарифного плана пользователя:
С плагином Webpack типичная настройка для предварительного кеширования статических ресурсов может выглядеть следующим образом:
const SWPrecacheWebpackPlugin = require('sw-precache-webpack-plugin'); module.exports = { // ... plugins: [ // ... new SWPrecacheWebpackPlugin({ cacheId: 'my-cache', filename: 'service-worker.js', staticFileGlobs: [ './public/images/**/*.{png,jpg,gif}', './public/scripts/**/*.js', './public/styles/**/*.css', './public/partials/**/*.html' ], stripPrefix: './public/' }) ] };
Интеграция sw-preache в систему сборки gulp
Чтобы использовать sw-precache
в gulp, мы сначала импортируем плагин в начало нашего gulpfile:
const swPrecache = require('sw-precache');
Затем мы создаем задачу gulp и вызываем write
на swPrecache
следующим образом:
swPrecache.write(filePath, options, callback)
filePath
- это расположение файла, в который будет записывать сервис-воркер. options
- это объект, который определяет поведение сгенерированного сервис-воркера (полный список опций см. В документации на Github). Обратный вызов выполняется всегда. Это нужно для того, чтобы gulp узнал, когда асинхронная операция завершена. Если есть ошибка, она передается в обратный вызов. Если ошибок не обнаружено, обратному вызову передается null.
Давайте посмотрим на пример:
gulp.task('generate-service-worker', function(callback) {
swPrecache.write('app/service-worker.js'), {
//1
staticFileGlobs: [
'app/index.html',
'app/js/bundle.js',
'app/css/bundle.css',
'app/img/**/*.{svg,png,jpg,gif}'
],
// 2
importScripts: [
'app/node_modules/sw-toolbox/sw-toolbox.js',
'app/js/toolbox-script.js'
],
// 3
stripPrefix: 'app/'
}, callback);
});
Мы вызываем задачу gulp 'generate-service-worker'
и передаем обратный вызов функции, чтобы сделать ее асинхронной.
swPrecache.write
создает сервис-воркера со следующими параметрами:
- Ресурсы в
staticFileGlobs
предварительно кэшированы, что означает, что созданный сервисный работник будет содержатьinstall
обработчик событий, который кэширует ресурсы. - Сценарии в
importScripts
включаются в сгенерированный сервис-воркер внутриimportScripts
метода. В этот пример мы включаем модульsw-toolbox
и скрипт, содержащий наши маршруты. - Префикс
app/
удаляется из всех путей к файлам вstaticFileGlobs
, так что пути в сгенерированном сервис-воркере являются относительными.
Кэширование во время выполнения
Sw-toolbox - это бесплатная библиотека, которая позволяет вам перехватывать сетевые запросы в Service Worker и выполнять стратегию кэширования с ответом. Он работает без маршрутов, которые ведут себя как прослушиватели событий fetch ().
Маршрут перехватывает сетевые запросы, соответствующие шаблону URL и методу HTTP-запроса. Затем он отвечает на основе правил в обработчике запросов. sw-toolbox имеет около 5 встроенных обработчиков для покрытия наиболее распространенных стратегий кеширования:
Если вы знакомы с Express, sw-toolbox поддерживает шаблоны URL, используя синтаксис, аналогичный синтаксису маршрутизации.
toolbox.router.get('img/**/*.{png,jpg}', global.toolbox.cacheFirst);
Это перехватит запросы GET для любого файла PNG / JPG в папке img. Он обрабатывает запросы в соответствии со стратегией cacheFirst, сначала проверяя кеш на предмет ответа. Если это не удается, запрос отправляется в сеть. Если это удается, ответ добавляется в кеш.
Здесь также можно использовать полные домены, например, это кеширует ваши шрифты Google:
toolbox.router.get('https://fonts.googleapis.com/', toolbox.cacheFirst);
Мы также можем перехватывать GET-запросы к другому домену, используя маршрутизацию в стиле Express. Мы просто определяем свойство «origin» в наших параметрах (строка или RegExp), которое сопоставляется с полным источником URL-адреса.
toolbox.router.get('/(.*)', global.toolbox.cacheFirst, {
origin: /\.googleapis\.com$/
});
Также можно использовать объект RegExp. Здесь мы определяем маршрут для запросов POST, которые начинаются с https://www.googleapis.com:
toolbox.router.post(/^https://www.googleapis.com\//, global.toolbox.networkFirst);
Совет. При проверке хранилища кэша вы можете различить, какой sw-toolbox кэширует, поскольку он управляет пространством имен $$$ toolbox-cache $$.
Более детальный контроль
sw-toolbox также дает нам возможность детально контролировать характеристики кеширования. Помимо указания источника, мы также можем настроить кеш следующим образом:
- Мы даем ему имя («продукты»)
- Мы даем ему максимальный размер 12 элементов (используя параметр maxEntries)
- Мы устанавливаем срок действия контента через день (24 часа = 86400 секунд)
toolbox.router.get('/(.*)', global.toolbox.cacheFirst, {
cache: {
name: 'products',
maxEntries: 12,
maxAgeSeconds: 86400
},
origin: /\.products\.com$/
});
Вы можете найти учебные пособия по sw-precache и sw-toolbox в нашем учебном материале под руководством инструктора по прогрессивным веб-приложениям.
Офлайн-сервис Google Analytics
Как упоминалось ранее, автономная Google Analytics может ретранслировать запросы аналитики, выполняемые пользователем в автономном режиме, когда сетевое соединение снова становится доступным. Чтобы добавить это к вашему Service Worker, нужно всего две строчки кода:
// Import offline analytics into the SW global scope: importScripts('path/to/offline-google-analytics-import.js'); // initialize it goog.offlineGoogleAnalytics.initialize();
Бум. Вот и все!
Также можно предоставить объект с настраиваемыми параметрами, которые будут включены в каждый запрос, который воспроизводится:
goog.offlineGoogleAnalytics.initialize({ parameterOverrides: { cd1: 'Guacamole', cd2: 'So much cheese' } });
Примечание: основной вариант использования для передачи объекта переопределения параметров - это определение того, когда обращения отправляются нормально (а не воспроизводятся Service Worker).
Autotrack.js
Настройка Autotrack относительно проста. Помимо включения analytics.js на вашу страницу, также можно выполнить асинхронную загрузку в библиотеке Autotrack. Затем обновите код отслеживания по умолчанию, чтобы потребовались все необходимые плагины Autotrack:
<script> window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; ga('create', '<!-- your google_analytics_tracking_id -->', 'auto'); // Autotrack plugins available ga('require', 'urlChangeTracker'); ga('require', 'cleanUrlTracker'); ga('require', 'eventTracker'); ga('require', 'maxScrollTracker'); ga('require', 'outboundLinkTracker'); ga('require', 'pageVisibilityTracker'); ga('send', 'pageview'); </script> <script async src='https://www.google-analytics.com/analytics.js'></script> <script async src='/public/js/autotrack.js'></script>
Примечание. Некоторые плагины Autotrack.js работают без указания параметров конфигурации (например, outboundLinkTracker), а другие - нет (например, clearUrlTracker). Обязательно загляните в документацию, чтобы узнать, какие варианты поддерживают различные плагины :)
Селен Ассистент
Как уже упоминалось, Selenium Assistant помогает нам получить список браузеров, доступных на наших машинах, получить для них экземпляр веб-драйвера, а затем запустить несколько тестов.
Вы устанавливаете модули Web Driver для браузеров, которые хотите протестировать (npm install chromedriver и т. Д.), А затем можете перебирать список этих браузеров и управлять ими по мере необходимости. Помощник также отлично работает с Sauce Labs, если вам нужно протестировать браузеры, которые не установлены в вашей локальной системе.
Обмен сообщениями Firebase Cloud
После добавления Firebase в существующий проект необходимо выполнить несколько дополнительных шагов для добавления поддержки Web Push-уведомлений:
1. Добавьте FCM gcm_sender_id в файл манифеста веб-приложения (manifest.json):
"gcm_sender_id": "103953800507"
2. Создайте новый файл firebase-messaging-service-worker.js. Мы собираемся предоставить
ему доступ к FCM, импортировав библиотеки Firebase Messaging в этот файл:
importScripts('https://www.gstatic.com/firebasejs/3.6.10/firebase-app.js') importScripts('https://www.gstatic.com/firebasejs/3.6.10/firebase-messaging.js')
Затем инициализируйте приложение Firebase в Service Worker. Для этого передайте свой
messagingSenderId (из настроек проекта Firebase):
firebase.initializeApp({ 'messagingSenderId': '<-- your sender ID goes here -->' });
Затем получите экземпляр Firebase Messaging для обработки фоновых
сообщений:
const messaging = firebase.messaging();
и запросить разрешение на показ уведомлений. Вы можете подождать
подходящего времени, а не делать это при загрузке страницы:
messaging.requestPermission() .then(function() { console.log('Notification permissions granted.'); // ... }) .catch(function(err) { console.log('Permission denied', err); });
Теперь, когда пользователь получает сообщение от FCM, отображается уведомление
, если он предоставил разрешение, чтобы включить это.
Что дальше?
В настоящее время мы работаем над следующей большой версией наших библиотек Service Worker, расширяя наши исследования, чтобы также охватить Фоновую синхронизацию, переключение изображений HiDPI на основе Service Worker и более интеллектуальную аналитику для PWA. Мы с нетерпением ждем возможности поделиться новыми версиями по мере появления бета-версий этих библиотек.
Мы также планируем разместить новый пост на нашем канале Устойчивая загрузка о сервисных работниках в производстве на Google.com.
А пока мы надеемся, что наши библиотеки окажутся полезными независимо от того, создаете ли вы PWA или просто пытаетесь повысить производительность своего сайта :)
Выражаем благодарность замечательным членам нашей команды - Джеффу Поснику, Мэтту Гонту, Тейлору Сэвиджу, Джо Медли, Пратеку Бхатнагару, Лукасу Малленсу, Филу Уолтону, Алексу Расселу и бывшему участнику Мэт Скейлз за их вклад в нашу небольшую семью открытых -исходные библиотеки.
Ресурсы
- Мгновенная загрузка с обслуживающими работниками
- Начало работы с Firebase Cloud Messaging для Интернета
- Отличные библиотеки и инструменты для отличных прогрессивных веб-приложений
- Книга Web Push-уведомлений
- Мгновенная загрузка: создание PWA, работающего в автономном режиме
- Оффлайн Google Analytics
- Офлайн-кеширование для вашего статического сайта
- Booking.com: PWA с обслуживающим персоналом (sw-toolbox)
- WashingtonPost: AMP с помощью PWA (sw-toolbox)
- Добавление поддержки PWA в приложение create-react-app с sw-preache
- Офлайн-приложения Angular с сервис-воркерами (sw-preache)