Миграция сайта в Progressive Web App (PWA)

Dragotchi

  1. Обзор
  2. Начинаем
  3. Современные теги в head
  4. Service Worker
  5. Пример push-уведомлений
  6. Кэш service-worker
  7. Императивный кэш

1Обзор

Прогрессивное веб приложение — это хорошо и прекрасно, но как мне использовать его для своего проекта? Давайте оснастим существующий десктопный сайт прекрасными новыми веб функциями, такими как установка, push-уведомления и оффлайн. Эти функции сделают ваш сайт более доступным и неотразимым для пользователей мобильных устройств, а также сделают десктопных пользователей более вовлеченными.

Чему вы научитесь

  • Как быстро превратить существующий сайт в Progressive Web App
  • Как стать mobile-friendly и сделать Web App Manifest
  • Как предложить вовлеченным пользователям установку приложения
  • Как посылать push-уведомления вашим пользователям
  • Как поддерживать статический и динамический контент в оффлайне

Что вам понадобится

  • Chrome 52 или выше
  • (Опционально) Подключенное Android устройство с запущенным Chrome 52 или выше
  • Базовое понимание git и Chrome DevTools
  • Примеры кода и текстовый редактор

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

Точка старта

Вы будете модифицировать сайт под названием Dragotchi, в котором вы можете растить и играть с вашим виртуальным драконом. У сайта три страницы (Home, Dragotchi и FAQ). Две статические, а Dragotchi делает простые Ajax запросы к открытому серверу.

Этот сайт desktop-only, у него нет адаптивного дизайна и он, вобщем, устарел. Тем лучше! Нам понадобится всего несколько шагов, чтобы улучшить его.

Dragotchi

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

 

2Начинаем

Давайте начнем с того, что проверим сайт Dragotchi и настроим ваше рабочее окружение.

Что вам понадобится

Клонируйте репозиторий GitHub из командной строки:

Создастся директория migrate-to-progressive-web-apps содержащая код для каждого шага. Для этого кодлаба используйте папку work и вносите все изменения там.

Для проверки кода, вам понадобится сервер Simple HTTP Server application (или например, локальный Python сервер или какой либо другой HTTP сервер) для работы с папкой work на порту 8887 — если только вы его не изменили.

Теперь вы можете открыть URL и поиграть с 🐲. Не волнуйтесь, кодлаб подождет.

Просмотр сайта на мобильном

Если у вас есть подключенное Android устройство, вы можете (на вашем компьютере) открыть URL: chrome://inspect (вам надо скопировать и вставить это в адресную строку). Затем, пропишите порт, как показано ниже, чтобы перенаправить порт на тот же порт на мобильном. Нажмите enter для сохранения. 

(Примечание перев. Также необходимо, чтобы на Android устройстве был включен режим разработчика и отладка по USB, иначе ничего работать не будет.)

chrome://inspect

Теперь вы должны получить доступ к простой версии сайта Dragotchi по адресу http://localhost:8887/ на вашем мобильном телефоне. Версия на вашем мобильном телефоне не оптимизирована для такого экрана — мы займемся этим в следующем разделе.

 

3Современные теги в head

Готовый код находится в migrate-to-progressive-web-apps/step3-manifest.

Первое, что мы сделаем для этого старомодного сайта — сделаем его mobile-friendly и включим то, что называется Web App Manifest. Файл манифеста описывает мета информацию о сайте, например то, как он будет выглядеть при добавлении на домашний экран пользователя.

У сайта Dragotchi три HTML страницы. Так как он не использует никакой системы для управления шаблонами, вам надо добавить следующие строки в раздел <head> каждой страницы — index.html, faq.html и dragon.html

Если вы торопитесь, то можете добавить эти теги только на странице index.html. Но знайте, что на реальных сайтах вам нужно будет добавить их везде.

Окно просмотра (viewport)

Первой строкой идет тег meta, описывающий вьюпорт. Подробнее о нем вы можете прочитать на favourite search engine, а сейчас, если вы перезагрузите сайт (на вашем андройд телефоне, или используя панель разработчика), вы увидите, что страница сайта корректно умещается на экране.

Манифест веб приложения

Вторая строка добавляет  Web App Manifest, который нужен для управления тем, в каком виде ваш сайт добавляется на домашний экран. Он заменяет старые мета-теги, вроде mobile-web-app-title. В коде страницы мы сослались на этот файл — давайте теперь его сделаем!

Откройте текстовый редактор. Мы напишем в формате JSON. Начнем с чего-то подобного:

Поле short_name определяет то, что появится на домашнем экране пользователя: постарайтесь задать строку настолько минимальной, насколько это возможно, название больше 15 символов может быть обрезано. В нашем случае мы использовали эмодзи 🎆 и 🌋, так как они абсолютно валидны!

Стоит запомнить:

  • Chrome и другие браузеры очень придирчиво относятся к JSON: не добавляйте лишние запятые и всегда используйте двойные кавычки
  • По хорошему вы должны определять несколько иконок под разные размеры экрана — большие иконки, например, могут показываться неправильно на маленьких экранах
  • Есть и другие свойства, которые вы можете использовать, найти их можно тут

Сохраните файл как manifest.json. Перезагрузите страницу на вашем Android устройстве, зайдите в меню в верхнем правом углу и выберите «Add to Home Screen». На вашем домашнем экране должно появиться новое приложение с драконами!

Add to Home Screen

Если у вас нет под рукой андройд устройства, выберите Application в Chrome Developer Tools. Нажмите Manifest, чтобы увидеть детали манифеста. Если вы видите No manifest detected, убедитесь, что вы создали и сохранили файл manifest.json в папке work.

Вау! Это прекрасно!

Я знаю. Давайте двинемся дальше и добавим Service Worker!

 

4Service Worker

Готовый код находится в migrate-to-progressive-web-apps/step4-sw.

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

Даже пустой Service Worker может помочь вашему сайту. Как получить такую прекрасную штуку? Читайте дальше.

Добавляем Service Worker в код

Сначала нам надо создать новый JavaScript файл. Давайте скопируем самый минимум в новый файл

Сохраните это как sw.js! Вот и все, все сделано! Вы создали service worker! 🎆

Регистрация Service Worker

Что, есть еще один шаг? Ну… ладно. На код, приведенный выше, и сам файл (sw.js) еще никто не ссылается. Вам обязательно надо его зарегистрировать, то есть прописать в коде вашего сайта.

Сайт Dragotchi уже содержит скрипт, который запускается на каждой странице. Откройте site.js (еще один пустой файл) и добавьте код регистрации

Вот и все! Этот код будет исполняться на каждой загружаемой странице. Если Service Worker уже зарегистрирован, ваш браузер проигнорирует запрос и проверит изменения чуть позднее.

Перезагрузите страницу и проверьте в chrome://serviceworker-internals/ то, что скрипт для сайта действительно загрузился.

Это выглядит примерно так:serviceworker-internals

Прекрасно, но что мне с этим делать?

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

migrate-to-progressive-web-apps

Во-вторых, вы можете расширить Service Worker так, чтобы ваш сайт поддерживал push-уведомления и работал в офлайне. Читайте дальше!

 

5Пример push-уведомлений

Готовый код находится в migrate-to-progressive-web-apps/step5-push, также вам необходимо добавить publicKey из Push Companion внутри site.js.

Давайте сделаем поддержку push-уведомлений! Мы не станем разбираться с сервером отправки сообщений, а просто зарегистрируем его на вашем сайте, и вы сможете управлять им из командной строки.

Вам нужно сгенерировать ключи — один публичный и один приватный. Откройте Push Companion и не закрывайте, чуть позже мы воспользуемся сгенерированными ключами.

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

Подписка на push

Внутри кода вашего сайта вам необходима подписка на push-уведомления. На самом деле это довольно просто. Давайте добавим код подписки в site.js

Если subscription равен null, то нам нужно зарегистрироваться  — замените комментарий следующим кодом:

Во-первых, обратите внимание, что publicKey нигде не определяется. Создайте его в верхней части файла, используя открытый ключ из Push Companion созданный ранее:

Теперь вам нужно сохранить файл и перезагрузить страницу — на десктопе или мобильном устройстве, не имеет значения. Если вы посмотрите в консоль разработчика, то увидите сообщение в логах о подписке, содержащее поле «endpoint». Мы используем его в дальнейшем, так что не закрывайте окно.

endpoint field

Если вы видите ошибку, убедитесь, что ваш publicKey выглядит как длинная строка с кодировкой base64, а не «<открытый ключ из Push Companion>».

Важно: Демонстрация подписки на push-уведомления сразу после открытия страницы — это прекрасно. Но если пользователи будут получать подобные запросы в неожиданные моменты, то вы будете получать много отказов. Данные Google показывают, что вероятность подписок значительно выше после каких либо действий пользователя.

Показываем уведомление

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

Откройте sw.js и добавьте секцию:

Это одно из самых простых уведомлений, которые мы можем показывать. У него есть заголовок и простое тело письма. Если хотите больше возможностей, посмотрите документацию. А сейчас перезагрузите страницу, чтобы посмотреть, как это сработает.

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

Дальше, давайте откроем командную строку (используйте ⌘-⌥-J или Ctrl-Alt-J, чтобы открыть его, если вы еще этого не сделали) и используем curl для составления правильного HTTP запроса. Он позволит вашему устройству проснуться и запустить код, который мы только что добавили для показа уведомления.

Скопируйте следующий код и вставьте его в консоль внутри Инструментов разработчика, как если бы вы запускали код, набрав его самостоятельно:

Это немедленно предложит вам секретный ключ от Push Companion. Введите его. Как только вы нажмете «ОК», консоль отобразит очень длинную строку. Идите вперед и дважды щелкните по ней, скопируйте и вставьте в ту же самую командную строку, чтобы запустить его.

Важно. Код, который вы только что вставили, использует сохраненный объект подписки, который вы обычно отправляете на свой сервер, чтобы подготовить и выполнить запрос. Он также использует вспомогательный метод под названием prepareAuthorization, находящийся в crypto.js, который примерно соответствует первой части статьи Matt Gaunt Web Push Protocol, для подписания запроса с помощью вашего закрытого ключа.

И, вуаля

Вы должны увидеть нечто подобное на вашем клиенте — на компьютере или в мобильном устройстве. Хорошая работа!

push message received

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

 

6Кэш Service Worker

Готовый код находится в migrate-to-progressive-web-apps/step6-cache (который не включает Push Notifications).

Давайте используем этот новый Service Worker и убедимся в том, что наш сайт Dragotchi может работать в офлайне. Во-первых, давайте снова откроем скрипт sw.js. Для начала нам понадобится объект кэша, который принадлежит типу Cache

Теперь, когда он у нас есть, давайте обновим код и добавим весь сайт в кэш

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

Согласование запросов

Все это хорошо, но сейчас вы в момент установки приложения закэшировали весь контент. Контент в этом кэше на самом деле не соответствует HTTP запросам — это следующий шаг! Давайте проделаем простую работу, также внутри sw.js

Объект Cache будет соответствовать вашему запросу, возвращая правильный ответ или null. Если он null, то мы обращаемся к методу fetch для выполнения настоящего запроса.

Вы можете написать гораздо более сложные функции. Два этих блока представляют простой кэш — вы храните ассеты прямо по URL и получаете их по URL. Но ничто не мешает вам написать более сложный JavaScript — мы коснемся этого в следующем шаге.

Пробуем

Зайдите на свой телефон и удалите существующее приложение Dragotchi при помощи длительного нажатия на него. Потом снова загрузите его в Chrome, обновите страницу, зайдите в меню справа вверху и нажмите «Add to Home Screen».

Если сейчас вы отключите Android устройство от USB кабеля и тапните на иконку на домашнем экране, то Dragotchi должен загрузиться!

Некоторые предостережения

Этот кэш, хоть это и прекрасно, закэширует ваш сайт навсегда!

До конца времен*

*или пока не кончится место на диске

А это уже не здорово. Вы должны изучить Workbox, который представляет собой набор библиотек, выпущенных Google, чтобы помочь вам создать Progressive Web Apps и написать Service Worker код лучше.

Пока же загрузите http://localhost:8887/clear.html и нажмите кнопку «Clear». Эта страница представляет собой тестовую страницу, содержащуюся в исходном коде, которая помогает очистить кэш, созданный событием «install» службы Service Worker.

Делать это после каждого изменения может быть не очень удобно. Это основная причина, из-за которой мы оставили этот шаг на конец. Если у вас нет ясной стратегии кэширования, то это может негативно сказаться на ваших пользователях — они могут никогда не получить новую версию вашего сайта. Часто бывает полезно полностью отключить событие fetch в процессе разработки, так чтобы вы всегда получали самую последнюю версию сайта.

Важно: если у вас нет четкой стратегии кэширования, это не просто повлияет на ваш цикл разработки — это также может повлиять на ваших пользователей. Они никогда не смогут получить новую версию вашего сайта.

Основное правило: если ваш сервис воркер изменится, ваша страница перезагрузит его и переустановит. Во время разработки вы можете добавить простой комментарий, содержащий «версию» вашего сервис воркера. Всякий раз, когда он изменяется, событие install будет происходить снова, кэшируя все другие ресурсы, которые вы, возможно, изменили. Добавьте комментарий сейчас, в верхней части файла sw.js-

Далее

Итак, мы немножко смухлевали — если вы загружаете страницу и растите дракона, кликая на действия, то это работает только пока ваш телефон находится в Сети. Запросы обрабатываются внешним сервером, предоставленным для этого кодлаба — он вне вашего сайта, настоящий URL в интернете.

Вы можете увидеть это переведя ваш телефон в авиарежим, в результате чего вы получите alert или failure.

Давайте исправим это.

alert of failure

7Императивный кэш

Готовый код находится в migrate-to-progressive-web-apps/step6-cache (который не включает Push Notifications).

Как мы уже упоминали, есть гораздо больше возможностей с Cache в Service Worker. Давайте обработаем новый URL. Состояние вашего дракона мы получаем с внешнего сайта, так что мы можем просто перехватить это.

Внутри блока fetch в sw.js давайте посмотрим на запрос определенного URL:

Это показывает нам, что Service Worker на самом деле может перехватывать запросы к URL вне домена вашего сайта. Теперь давайте сделаем что-нибудь с обработкой этого URL

Это вернет валидное, но ограниченное состояние при обращении к URL, которое вызвано с ошибкой (посмотрите блок catch этого Promise). Этот кодлаб всего лишь быстрое введение в тему — который не затрагивает возможности, включающие кэширование, или хранения состояния офлайн в indexDB.

Наша цель — продемонстрировать, что у вас все под контролем.

Пробуем

Как и в предыдущем случае, убедитесь, что вы очистили кэш. Откройте http://localhost:8887/clear.html для этого. Затем удалите приложение с вашего домашнего экрана, перезагрузите страницу в Chrome и снова установите приложение.

Включите авиарежим, затем загрузите сайт через иконку и перейдите на страницу Dragotchi. Вы увидите дефолтное состояние, которое вы прописали в Service Worker и которое он обработал!

2d9ffaf6e7e4124f

 

8Вы все сделали

Поздравляем

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

Теперь попробуйте другие кодлабы, которые раскроют вам больше деталей по всем этим темам. Или прочитайте больше о Service Worker и Push уведомлениях.

Не совсем точный перевод кодлаба на codelabs.developers.google.com