Can’t make the #ChromeDevSummit this year? Catch all the content (and more!) on the livestream, or join your peers for a CDS Extended event at a hosted location nearby. To learn more, check out the Chrome Dev Summit 2019 website.

Ваше первое прогрессивное веб-приложение

Powered by Google Translate

Введение

Что делает веб-приложение прогрессивным веб-приложением?

Прогрессивные веб-приложения предоставляют возможность установки на ПК и мобильных устройствах в виде приложений, которые создаются и доставляются непосредственно через Интернет. Это быстрые и надежные веб-приложения. И самое главное, это веб-приложения, которые работают в любом браузере. Если вы создаете веб-приложение сегодня, вы уже на пути к созданию Progressive Web App.

быстро и надежно

Каждый веб-опыт должен быть быстрым, и это особенно верно для Progressive Web Apps. Под быстрым понимается время, необходимое для получения значимого контента на экране и предоставления интерактивного опыта менее чем за 5 секунд.

И, должно быть, очень быстро. Трудно подчеркнуть, насколько лучше надежная работа. Думайте об этом так: первая загрузка нативного приложения разочаровывает. Он управляется магазином приложений и огромной загрузкой, но как только вы дойдете до точки, где приложение установлено, эта первоначальная стоимость амортизируется во всех запусках приложения, и ни один из этих запусков не имеет переменной задержки. Каждый запуск приложения происходит так же быстро, как и последний, без отклонений. Прогрессивное веб-приложение должно обеспечивать такую надежную производительность, которую пользователи ожидают от любого установленного интерфейса.

Устанавливается

Прогрессивные веб-приложения можно запускать на вкладке браузера, но их также можно установить. Создание закладки для сайта просто добавляет ярлык, но установленное Progressive Web App выглядит и ведет себя как все остальные установленные приложения. Он запускается из того же места, что и другие приложения. Вы можете контролировать процесс запуска, включая настраиваемый экран-заставку, значки и многое другое. Он запускается как приложение в окне приложения без адресной строки или другого пользовательского интерфейса браузера. Как и все другие установленные приложения, это приложение верхнего уровня в переключателе задач.

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

Mobile & Desktop

Используя технологии адаптивного дизайна, Progressive Web Apps работают на обоих мобильных и десктопах, используя единую базу кода между платформами. Если вы планируете написать собственное приложение, посмотрите на преимущества, которые предлагает PWA.

Что вы будете строить

В этой кодовой метке вы создадите веб-приложение для погоды с использованием методов Progressive Web App. Ваше приложение будет:

  • Используйте адаптивный дизайн, чтобы он работал на настольном или мобильном устройстве Быть быстрым, используя работника службы для предварительного кэширования ресурсов приложения (HTML, CSS, JavaScript, изображений), необходимых для запуска, и кэшировать данные о погоде во время выполнения для повышения производительности
  • beforeinstallprompt установки с использованием манифеста веб-приложения и события beforeinstallprompt чтобы уведомить пользователя о возможности его установки

95fe6f7fbeee5bb1.png

Что вы выучите

  • Как создать и добавить манифест веб-приложения
  • Как обеспечить простой опыт работы в автономном режиме
  • Как обеспечить полный опыт работы в автономном режиме
  • Как сделать приложение доступным для установки

Эта кодовая метка ориентирована на прогрессивные веб-приложения. Нерелевантные концепции и блоки кода затенены и предназначены для простого копирования и вставки.

Что вам нужно

  • Недавние версии Chrome (74 или более поздних) - это веб-приложения, которые работают во всех браузерах, но мы будем использовать некоторые функции Chrome DevTools, чтобы лучше понимать, что происходит на уровне браузера, и использовать его для проверить опыт установки.
  • Знание HTML, CSS, JavaScript и Chrome DevTools .

Начало работы

Получите ключ для API Dark Sky

Наши погодные данные Dark Sky API из Dark Sky API . Чтобы использовать его, вам нужно запросить ключ API. Он прост в использовании и бесплатен для некоммерческих проектов.

Register for API Key

Убедитесь, что ваш ключ API работает правильно

Чтобы проверить, работает ли ваш ключ API, сделайте HTTP-запрос к API DarkSky. Обновите приведенный ниже URL-адрес, чтобы заменить DARKSKY_API_KEY вашим ключом API. Если все работает, вы должны увидеть последний прогноз погоды для Нью-Йорка.

https://api.darksky.net/forecast/DARKSKY_API_KEY/40.7720232,-73.9732319

Получить код

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

Настоятельно рекомендуется: используйте Glitch для импорта репо

Использование Glitch - рекомендуемый метод для работы с этим кодовым ярлыком.

  1. Откройте новую вкладку браузера и перейдите к https://glitch.com .
  2. Если у вас нет учетной записи, вам необходимо зарегистрироваться.
  3. Нажмите New Project, затем Clone из Git Repo .
  4. Клонируйте https://github.com/googlecodelabs/your-first-pwapp.git и нажмите OK
  5. После загрузки .env отредактируйте файл .env и обновите его с помощью ключа API DarkSky.
  6. Нажмите кнопку Show Live, чтобы увидеть PWA в действии.

Альтернатива: скачать код и работать локально

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

Download source code

  1. Распакуйте загруженный zip-файл.
  2. Запустите npm install чтобы установить зависимости, необходимые для запуска сервера.
  3. Отредактируйте server.js и установите ваш ключ API DarkSky.
  4. Запустите node server.js чтобы запустить сервер на порту 8000.
  5. Откройте вкладку браузера для http://localhost:8000

Установить базовый уровень

Какая наша отправная точка?

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

Некоторые вещи, чтобы попробовать ...

  1. Добавьте новый город с синей кнопкой «плюс» в правом нижнем углу.
  2. Обновите данные с помощью кнопки обновления в правом верхнем углу.
  3. Удалите город, используя крестик в правом верхнем углу каждой карты города.
  4. Посмотрите, как это работает на настольных и мобильных устройствах.
  5. Посмотрите, что происходит, когда вы выходите из сети.
  6. С помощью панели «Сеть» Chrome узнайте, что происходит, когда сеть переключается в режим медленной 3G.
  7. Добавьте задержку на сервер прогноза, изменив FORECAST_DELAY в server.js

Аудит с Маяком

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

b112675caafccef0.png

Мы будем использовать Lighthouse для аудита нашего приложения Weather и проверки внесенных нами изменений.

Маяк

  1. Откройте ваш проект в новой вкладке. 2. Откройте Chrome DevTools и перейдите на вкладку Audits, DevTools отобразит список категорий аудита, оставив их включенными. 3. Нажмите Run Audits, через 60-90 секунд Lighthouse предоставит вам отчет на странице.

прогрессивного веб-приложения

Мы собираемся сосредоточиться на результатах аудита Progressive Web App.

af1a64a13725428e.png

И есть много красного, чтобы сосредоточиться на:

  • ❗FAILED: Текущая страница не отвечает 200 в автономном режиме.
  • ❗FAILED: start_url не отвечает 200 в автономном режиме.
  • ❗FAILED: Не регистрирует работника службы, который контролирует страницу и start_url.
  • ❗FAILED: Манифест веб-приложения не соответствует требованиям к установке.
  • ❗FAILED: Не настроен для настраиваемой заставки.
  • ❗FAILED: Не устанавливает цвет темы адресной строки.

Давайте перейдем к решению некоторых из этих проблем!

Добавить манифест веб-приложения

К концу этого раздела наше приложение погоды пройдет следующие аудиты:

  • Манифест веб-приложения не соответствует требованиям к установке.
  • Не настроен для собственного заставки.
  • Не устанавливает цвет темы адресной строки.

Создание манифеста веб-приложения

web app manifest - это простой файл JSON, который дает вам, разработчику, возможность контролировать то, как ваше приложение выглядит для пользователя.

Используя манифест веб-приложения, ваше веб-приложение может:

  • Сообщите браузеру, что вы хотите, чтобы ваше приложение открывалось в отдельном окне ( display ).
  • Определите, какая страница открывается при первом запуске приложения ( start_url ).
  • Определите, как приложение должно выглядеть на short_name приложений или в short_name запуска ( short_name , icons )
  • Создать заставку ( name , icons , colors ).
  • Скажите браузеру, чтобы открыть окно в альбомном или портретном режиме ( orientation ).
  • И plenty more .

Создайте файл с именем public/manifest.json в своем проекте и скопируйте / вставьте следующее содержимое:

public/manifest.json

{
  "name": "Weather",
  "short_name": "Weather",
  "icons": [{
    "src": "/images/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-256x256.png",
      "sizes": "256x256",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }],
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#3E4EB8",
  "theme_color": "#2F3BA2"
}

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

Добавить ссылку на манифест веб-приложения

Далее нам нужно сообщить браузеру о нашем манифесте, добавив <link rel="manifest"... на каждую страницу нашего приложения. Добавьте следующую строку в <head> элемент в вашем index.html файле.

public/index.html

<!-- CODELAB: Add link rel manifest -->
<link rel="manifest" href="/manifest.json">

DevTools Detour

DevTools предоставляет быстрый и простой способ проверить ваш файл manifest.json . Откройте панель Manifest на панели Application. Если вы правильно добавили информацию о манифесте, вы сможете увидеть ее проанализированной и отображенной в удобном для человека формате на этой панели.

c462743e1bc26958.png

Добавить метатеги и иконки iOS

Safari на iOS не поддерживает манифест веб-приложения ( yet ), поэтому вам нужно добавить traditional meta tags в <head> вашего файла index.html :

public/index.html

<!-- CODELAB: Add iOS meta tags and icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Weather PWA">
<link rel="apple-touch-icon" href="/images/icons/icon-152x152.png">

Бонус: Easy Lighthouse исправления

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

Установите мета-описание

В ходе SEO-аудита компания Lighthouse отметила, что наши Document does not have a meta description. « Document does not have a meta description. » могут отображаться в результатах поиска Google. Высококачественные уникальные описания могут сделать ваши результаты более релевантными для пользователей поиска и увеличить поисковый трафик.

Чтобы добавить описание, добавьте следующий meta тег в <head> части документа:

public/index.html

<!-- CODELAB: Add description here -->
<meta name="description" content="A sample weather app">

Установить цвет темы адресной строки

В ходе аудита PWA компания Lighthouse отметила наше приложение « Does not set an address-bar theme color ». Тематическое отображение адресной строки браузера в соответствии с цветами вашего бренда обеспечивает более полное погружение пользователя.

Для того, чтобы установить цвет темы на мобильный, добавьте следующий meta тег в <head> части документа:

public/index.html

<!-- CODELAB: Add meta theme-color -->
<meta name="theme-color" content="#2F3BA2" />

Проверьте изменения с Lighthouse

Снова запустите Lighthouse (нажав на значок + в левом верхнем углу панели Audits) и проверьте внесенные изменения.

SEO Аудит

  • ✅ PASSED: В документе есть мета-описание.

Прогрессивный аудит веб-приложений

  • ❗FAILED: Текущая страница не отвечает 200 в автономном режиме.
  • ❗FAILED: start_url не отвечает 200 в автономном режиме.
  • ❗FAILED: Не регистрирует работника службы, который контролирует страницу и start_url.
  • ✅ PASSED: Манифест веб-приложения соответствует требованиям к установке.
  • ✅ PASSED: Настроен для собственного заставки.
  • ✅ PASSED: Устанавливает цвет темы адресной строки.

Обеспечить базовый опыт работы в автономном режиме

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

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

  • Текущая страница не отвечает 200 в автономном режиме.
  • start_url не отвечает 200 в автономном режиме.
  • Не регистрирует сервисного работника, который контролирует страницу и start_url.

В следующем разделе мы заменим нашу пользовательскую страницу в автономном режиме на полноценную работу в автономном режиме. Это улучшит работу в автономном режиме, но, что более важно, значительно улучшит нашу производительность, потому что большинство наших ресурсов (HTML, CSS и JavaScript) будут храниться и обслуживаться локально, устраняя сеть как потенциальное узкое место.

Сервисные работники на помощь

Если вы не знакомы с работниками сферы обслуживания, вы можете получить Introduction To Service Workers представление, прочитав Introduction To Service Workers о том, что они могут сделать, как работает их жизненный цикл и многое другое. После того, как вы закончите эту кодовую лабораторию, обязательно ознакомьтесь с Debugging Service Workers code lab для более глубокого изучения работы с сервисными работниками.

Функции, предоставляемые сервисными работниками, должны рассматриваться как прогрессивное улучшение и добавляться только в том случае, если они поддерживаются браузером. Например, с помощью сервисных работников вы можете кэшировать app shell и данные для вашего приложения, чтобы они были доступны даже тогда, когда сеть недоступна. Когда сервисные работники не поддерживаются, автономный код не вызывается, и пользователь получает базовый опыт. Использование функции обнаружения для обеспечения прогрессивного улучшения не требует больших затрат и не сломается в старых браузерах, которые не поддерживают эту функцию.

Зарегистрируй сервисного работника

Первым шагом является регистрация сервисного работника. Добавьте следующий код в файл index.html :

public/index.html

// CODELAB: Register service worker.
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
        .then((reg) => {
          console.log('Service worker registered.', reg);
        });
  });
}

Этот код проверяет, доступен ли API сервисного работника, и если он есть, сервисный работник на /service-worker.js регистрируется, как только страница становится loaded .

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

Precache офлайн страница

Во-первых, нам нужно сообщить работнику сервиса, что нужно кэшировать. Мы уже создали простой offline page (public/offline.html), который будет отображаться каждый раз, когда нет сетевого подключения

В вашем service-worker.js добавьте '/offline.html', в массив FILES_TO_CACHE , конечный результат должен выглядеть следующим образом:

public/service-worker.js

// CODELAB: Update cache names any time any of the cached files change.
const FILES_TO_CACHE = [
  '/offline.html',
];

Затем нам нужно обновить событие install чтобы указать работнику сервиса предварительно кэшировать автономную страницу:

public/service-worker.js

// CODELAB: Precache static resources here.
evt.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      console.log('[ServiceWorker] Pre-caching offline page');
      return cache.addAll(FILES_TO_CACHE);
    })
);

Наше событие install теперь открывает кеш с caches.open() и предоставляет имя кеша. Предоставление имени кэша позволяет нам создавать версии файлов или отделять данные от кэшированных ресурсов, чтобы мы могли легко обновить одно, но не влиять на другое.

Когда кеш открыт, мы можем вызвать cache.addAll() , который берет список URL-адресов, выбирает их с сервера и добавляет ответ в кеш. Обратите внимание, что cache.addAll() будет отклонен, если какой-либо из отдельных запросов потерпит неудачу. Это означает, что вам гарантировано, что, если этап установки пройдет успешно, ваш кеш будет в согласованном состоянии. Но если по какой-то причине произойдет сбой, он автоматически попытается снова при следующем запуске сервисного работника.

DevTools Detour

Давайте посмотрим, как вы можете использовать DevTools для понимания и отладки сервисных работников. Перед перезагрузкой страницы откройте DevTools, перейдите на панель Service Workers на панели Application Это должно выглядеть так:

b3aa37b67863fd03.png

Когда вы видите пустую страницу, подобную этой, это означает, что на текущей открытой странице нет зарегистрированных сервисных работников.

Теперь перезагрузите страницу. Панель Service Workers теперь должна выглядеть так:

69808e4bf3aee41b.png

Когда вы видите такую информацию, это означает, что на странице запущен сервисный работник.

Рядом с меткой статуса есть номер (в данном случае 34251), следите за этим номером, когда вы работаете с работниками сферы обслуживания. Это простой способ узнать, обновился ли ваш сервисный работник.

Очистить старые офлайн-страницы

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

Добавьте следующий код в событие activate :

public/service-worker.js

// CODELAB: Remove previous cached data from disk.
evt.waitUntil(
    caches.keys().then((keyList) => {
      return Promise.all(keyList.map((key) => {
        if (key !== CACHE_NAME) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        }
      }));
    })
);

DevTools Detour

Открыв панель «Service Workers», обновите страницу, вы увидите, что установлен новый «Service Worker», и увеличится номер статуса.

1db827d76bc0b359.png

Обновленный сервисный работник немедленно получает управление, потому что наше событие install заканчивается с self.skipWaiting() , а событие activate заканчивается с self.clients.claim() . Без них старый сервисный работник продолжал бы контролировать страницу, пока есть открытая вкладка.

Обработка неудачных сетевых запросов

И, наконец, нам нужно обработать события fetch . Мы собираемся использовать network, falling back to cache strategy . Сервисный работник сначала попытается извлечь ресурс из сети, если это не удастся, он вернет автономную страницу из кэша.

6302ad4ba8460944.png

public/service-worker.js

// CODELAB: Add fetch event handler here.
if (evt.request.mode !== 'navigate') {
  // Not a page navigation, bail.
  return;
}
evt.respondWith(
    fetch(evt.request)
        .catch(() => {
          return caches.open(CACHE_NAME)
              .then((cache) => {
                return cache.match('offline.html');
              });
        })
);

Обработчик fetch должен обрабатывать только fetch по страницам, поэтому другие запросы могут быть выгружены из обработчика и обычно обрабатываются браузером. Но, если запрос .mode - это navigate , используйте fetch чтобы попытаться получить элемент из сети. Если это не удается, обработчик catch открывает кеш с caches.open(CACHE_NAME) и использует cache.match('offline.html') для получения предварительно кэшированной автономной страницы. Затем результат передается обратно в браузер с помощью evt.respondWith() .

DevTools Detour

Давайте проверим, чтобы убедиться, что все работает так, как мы ожидаем. Открыв панель «Service Workers», обновите страницу, вы увидите, что установлен новый «Service Worker», и увеличится номер статуса.

Мы также можем проверить, что было кэшировано. Перейдите на панель Cache Storage на панели Application DevTools. Щелкните правой кнопкой мыши Cache Storage, выберите Refresh Caches, разверните раздел, и вы увидите название вашего статического кэша, приведенное в левой части. Нажатие на имя кэша показывает все файлы, которые кэшируются.

c80a2a2e93c1c3ee.png

Теперь давайте проверим автономный режим. Вернитесь к панели Service Workers DevTools и установите флажок Offline. После проверки вы увидите небольшой желтый значок предупреждения рядом с вкладкой панели Network. Это указывает на то, что вы не в сети.

984b34dc2aa667a.png

Перезагрузите страницу и ... это работает! Мы получаем our офлайн панда, а не офлайн dino Chrome!

Советы по тестированию сервисных работников

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

Используйте DevTools

На панели Service Workers панели Application есть несколько флажков, которые значительно облегчат вашу жизнь.

c7ac93904f473a91.png

  • Offline - Если этот флажок установлен, имитирует работу в автономном режиме и предотвращает отправку любых запросов в сеть.
  • Обновить при перезагрузке - Когда установлен флажок, вы получите последнюю версию сервисного работника, установите его и немедленно активируйте
  • Bypass for network - Когда проверенные запросы обходят работника сервиса и отправляются непосредственно в сеть.

Начни с

В некоторых случаях вы можете загружать кэшированные данные или что-то не обновляется, как вы ожидаете. Чтобы очистить все сохраненные данные (localStorage, данные indexedDB, кэшированные файлы) и удалить всех сервисных работников, используйте панель «Очистить хранилище» на вкладке «Приложение». Кроме того, вы также можете работать в окне инкогнито.

398bbcd285e2c5dd.png

Дополнительные советы:

  • Как только сервисный работник был незарегистрирован, он может оставаться в списке, пока не будет закрыто содержащее его окно браузера.
  • Если открыто несколько окон для вашего приложения, новый работник сервиса не вступит в силу, пока все окна не будут перезагружены и обновлены до последней версии работника сервиса.
  • Отмена регистрации сервисного работника не очищает кеш!
  • Если сервисный работник существует и новый сервисный работник зарегистрирован, новый сервисный работник не будет управлять, пока страница не будет перезагружена, если вы не take immediate control .

Проверьте изменения с Lighthouse

Запустите Lighthouse снова и проверьте изменения. Не забудьте снять флажок Оффлайн, прежде чем проверять изменения

SEO Аудит

  • ✅ PASSED: B документе есть мета-описание.

Прогрессивный аудит веб-приложений

  • ✅ PASSED: Текущая страница отвечает 200 в автономном режиме
  • ✅ PASSED: start_url отвечает 200 в автономном режиме
  • ✅ PASSED: Регистрирует сервисного работника, который контролирует страницу и start_url.
  • ✅ PASSED: Манифест веб-приложения соответствует требованиям к установке.
  • ✅ PASSED: Настроен для собственного заставки.
  • ✅ PASSED: Устанавливает цвет темы адресной строки.

Обеспечить полный опыт работы в автономном режиме

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

Сервисный рабочий жизненный цикл

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

install событие

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

72ed77b1720512da.png

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

activate событие

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

fetch событие

Событие fetch позволяет работнику службы перехватывать любые сетевые запросы и обрабатывать запросы. Он может пойти в сеть, чтобы получить ресурс, он может извлечь его из собственного кэша, сгенерировать собственный ответ или любое количество различных опций. Проверьте Offline Cookbook для различных стратегий, которые вы можете использовать.

Обновление сервисного работника

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

Выбор правильной стратегии кэширования

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

Кэширование статических ресурсов

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

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

44860840e2090bd8.png

Извлечение из локального кэша устраняет любую изменчивость сети. Независимо от того, в какой сети находится пользователь (WiFi, 5G, 3G или даже 2G), ключевые ресурсы, необходимые для работы, доступны практически сразу.

Кэширование данных приложения

stale-while-revalidate strategy идеально подходит для определенных типов данных и хорошо работает для нашего приложения. Он выводит данные на экран как можно быстрее, а затем обновляет их, как только сеть вернула последние данные. Stale-while-revalidate означает, что нам нужно запустить два асинхронных запроса, один в кэш и один в сеть.

6ebb2681eb1f58cb.png

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

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

Обновление логики приложения

Как упоминалось ранее, приложению необходимо запустить два асинхронных запроса: один - в кэш, а другой - в сеть. Приложение использует объект caches доступный в window для доступа к кешу и получения самых последних данных. Это отличный пример прогрессивного улучшения, поскольку объект caches может быть доступен не во всех браузерах, и если это не так, сетевой запрос все равно должен работать.

Обновите функцию getForecastFromCache() , чтобы проверить, caches объект caches в глобальном объекте window , и, если это так, запросить данные из кэша.

public/scripts/app.js

// CODELAB: Add code to get weather forecast from the caches object.
if (!('caches' in window)) {
  return null;
}
const url = `${window.location.origin}/forecast/${coords}`;
return caches.match(url)
    .then((response) => {
      if (response) {
        return response.json();
      }
      return null;
    })
    .catch((err) => {
      console.error('Error getting data from cache', err);
      return null;
    });

Затем нам нужно изменить updateData() чтобы он updateData() два вызова, один для getForecastFromNetwork() чтобы получить прогноз из сети, и один для getForecastFromCache() чтобы получить последний кэшированный прогноз:

public/scripts/app.js

// CODELAB: Add code to call getForecastFromCache.
getForecastFromCache(location.geo)
    .then((forecast) => {
      renderForecast(card, forecast);
    });

Наше приложение погоды теперь делает два асинхронных запроса данных, один из кеша и один через fetch . Если в кеше есть данные, они будут возвращены и обработаны очень быстро (десятки миллисекунд). Затем, когда fetch , карта будет обновлена самыми свежими данными непосредственно из API погоды.

Обратите внимание, как запрос кеша и запрос fetch заканчиваются вызовом для обновления карты прогноза. Как приложение узнает, отображает ли оно последние данные? Это обрабатывается в следующем коде из renderForecast() :

public/scripts/app.js

// If the data on the element is newer, skip the update.
if (lastUpdated >= data.currently.time) {
  return;
}

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

Предварительно кешировать ресурсы нашего приложения

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

public/service-worker.js

// CODELAB: Update cache names any time any of the cached files change.
const CACHE_NAME = 'static-cache-v2';
const DATA_CACHE_NAME = 'data-cache-v1';

Не забудьте также обновить CACHE_NAME ; мы также изменим все наши статические ресурсы.

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

Обновите массив FILES_TO_CACHE списком файлов:

public/service-worker.js

// CODELAB: Add list of files to cache here.
const FILES_TO_CACHE = [
  '/',
  '/index.html',
  '/scripts/app.js',
  '/scripts/install.js',
  '/scripts/luxon-1.11.4.js',
  '/styles/inline.css',
  '/images/add.svg',
  '/images/clear-day.svg',
  '/images/clear-night.svg',
  '/images/cloudy.svg',
  '/images/fog.svg',
  '/images/hail.svg',
  '/images/install.svg',
  '/images/partly-cloudy-day.svg',
  '/images/partly-cloudy-night.svg',
  '/images/rain.svg',
  '/images/refresh.svg',
  '/images/sleet.svg',
  '/images/snow.svg',
  '/images/thunderstorm.svg',
  '/images/tornado.svg',
  '/images/wind.svg',
];

Поскольку мы вручную генерируем список файлов для кэширования, каждый раз, когда мы обновляем файл, мы должны обновлять CACHE_NAME. Мы смогли удалить offline.html из нашего списка кэшированных файлов, поскольку наше приложение теперь имеет все необходимые ресурсы, необходимые для работы в автономном режиме, и больше не будет отображать автономную страницу.

Обновление обработчика события активации

Для того, чтобы обеспечить наше activate событие не случайно удалить наши данные, в activate случае service-worker.js , заменить if (key !== CACHE_NAME) { с:

public / service-worker.js

if (key !== CACHE_NAME && key !== DATA_CACHE_NAME) {

Обновление обработчика событий выборки

Нам нужно изменить работника сервиса, чтобы он перехватывал запросы к API погоды и сохранял их ответы в кеше, чтобы мы могли легко получить к ним доступ позже. В стратегии «устаревшего подтверждения» мы ожидаем, что ответ сети будет «источником правды», всегда предоставляя нам самую свежую информацию. Если это невозможно, все в порядке, потому что мы уже получили последние кэшированные данные в нашем приложении.

Обновите fetch событий fetch для обработки запросов к API данных отдельно от других запросов.

public/service-worker.js

// CODELAB: Add fetch event handler here.
if (evt.request.url.includes('/forecast/')) {
  console.log('[Service Worker] Fetch (data)', evt.request.url);
  evt.respondWith(
      caches.open(DATA_CACHE_NAME).then((cache) => {
        return fetch(evt.request)
            .then((response) => {
              // If the response was good, clone it and store it in the cache.
              if (response.status === 200) {
                cache.put(evt.request.url, response.clone());
              }
              return response;
            }).catch((err) => {
              // Network request failed, try to get it from the cache.
              return cache.match(evt.request);
            });
      }));
  return;
}
evt.respondWith(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.match(evt.request)
          .then((response) => {
            return response || fetch(evt.request);
          });
    })
);

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

Нам нужно удалить проверку evt.request.mode !== 'navigate' потому что мы хотим, чтобы наш сервисный работник обрабатывал все запросы (включая изображения, скрипты, CSS-файлы и т. Д.), А не только навигацию. Если мы оставим эту регистрацию, только кеш будет обслуживаться из кэша рабочего сервиса, все остальное будет запрашиваться из сети.

Попробуйте это

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

Затем перейдите на панель Cache Storage на панели Application в DevTools. Разверните раздел, и вы увидите название вашего статического кеша и кеша данных, перечисленных слева. Открытие кеша данных должно показывать данные, хранящиеся для каждого города.

731e91776cb6ef18.png

Затем откройте DevTools и переключитесь на панель Service Workers и установите флажок Offline, затем попробуйте перезагрузить страницу, а затем перейдите в автономный режим и перезагрузите страницу.

Если вы на быструю сеть и хотите увидеть , как прогноз погоды данные обновляются на медленном соединении, установите FORECAST_DELAY свойство в server.js в 5000 . Все запросы к API прогноза будут задерживаться на 5000 мс.

Проверьте изменения с Lighthouse

Это также хорошая идея, чтобы снова запустить Маяк.

SEO Аудит

  • ✅ PASSED: B документе есть мета-описание.

Прогрессивный аудит веб-приложений

  • ✅ PASSED: Текущая страница отвечает 200 в автономном режиме
  • ✅ PASSED: start_url отвечает 200 в автономном режиме
  • ✅ PASSED: Регистрирует сервисного работника, который контролирует страницу и start_url.
  • ✅ PASSED: Манифест веб-приложения соответствует требованиям к установке.
  • ✅ PASSED: Настроен для собственного заставки.
  • ✅ PASSED: Устанавливает цвет темы адресной строки.

Добавить опыт установки

Когда установлено Progressive Web App, оно выглядит и ведет себя как все остальные установленные приложения. Он запускается из того же места, что и другие приложения. Он работает в приложении без адресной строки или другого пользовательского интерфейса браузера. Как и все другие установленные приложения, это приложение верхнего уровня в переключателе задач.

d824e1712e46a1cc.png

В Chrome Progressive Web App можно либо установить через трехточечное контекстное меню, либо вы можете предоставить пользователю кнопку или другой компонент пользовательского интерфейса, который предложит ему установить ваше приложение.

Аудит с Маяком

Чтобы пользователь мог установить ваше Progressive Web App, оно должно соответствовать certain criteria . Самый простой способ проверить это - использовать Lighthouse и убедиться, что он соответствует установленным критериям.

b921f5583fcddf03.png

Если вы работали с этой кодовой меткой, ваш PWA уже должен соответствовать этим критериям.

Добавить install.js в index.html

Сначала добавим install.js в наш файл index.html .

public/index.html

<!-- CODELAB: Add the install script here -->
<script src="/scripts/install.js"></script>

Прослушать событие beforeinstallprompt

Если выполнено добавление на главный экран criteria , Chrome beforeinstallprompt событие beforeinstallprompt , которое можно использовать, чтобы указать, что ваше приложение можно «установить», а затем предложит пользователю установить его. Добавьте код ниже, чтобы прослушать событие beforeinstallprompt :

public/scripts/install.js

// CODELAB: Add event listener for beforeinstallprompt event
window.addEventListener('beforeinstallprompt', saveBeforeInstallPromptEvent);

Сохранить событие и показать кнопку установки

В нашей функции saveBeforeInstallPromptEvent мы сохраним ссылку на событие beforeinstallprompt чтобы мы могли позже вызвать prompt() , и обновим наш пользовательский интерфейс, чтобы отобразить кнопку установки.

public/scripts/install.js

// CODELAB: Add code to save event & show the install button.
deferredInstallPrompt = evt;
installButton.removeAttribute('hidden');

Показать подсказку / скрыть кнопку

Когда пользователь нажимает кнопку установки, нам нужно вызвать .prompt() для сохраненного события beforeinstallprompt . Нам также нужно скрыть кнопку установки, поскольку .prompt() можно .prompt() только один раз для каждого сохраненного события.

public/scripts/install.js

// CODELAB: Add code show install prompt & hide the install button.
deferredInstallPrompt.prompt();
// Hide the install button, it can't be called twice.
evt.srcElement.setAttribute('hidden', true);

Вызов .prompt() покажет пользователю модальное диалоговое окно с просьбой добавить ваше приложение на домашний экран.

Зарегистрировать результаты

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

public/scripts/install.js

// CODELAB: Log user response to prompt.
deferredInstallPrompt.userChoice
    .then((choice) => {
      if (choice.outcome === 'accepted') {
        console.log('User accepted the A2HS prompt', choice);
      } else {
        console.log('User dismissed the A2HS prompt', choice);
      }
      deferredInstallPrompt = null;
    });

Один комментарий о userChoice , spec defines it as a property , а не функция, как вы могли ожидать.

Журнал всех событий установки

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

public/scripts/install.js

// CODELAB: Add event listener for appinstalled event
window.addEventListener('appinstalled', logAppInstalled);

Затем нам нужно обновить функцию logAppInstalled , для этой кодовой метки мы просто будем использовать console.log , но в производственном приложении вы, вероятно, захотите зарегистрировать это как событие в своем аналитическом программном обеспечении.

public/scripts/install.js

// CODELAB: Add code to log the event
console.log('Weather App was installed.', evt);

Обновить сервисный работник

Не забудьте обновить CACHE_NAME в файле service-worker.js так как вы внесли изменения в файлы, которые уже кэшированы. Включение флажка Bypass for network на панели Service Workers панели Application в DevTools будет работать в процессе разработки, но не поможет в реальном мире.

Попробуйте это

Давайте посмотрим, как прошел наш шаг установки. Чтобы быть в безопасности, используйте кнопку Clear site data на панели приложений DevTools, чтобы убрать все и убедиться, что мы начинаем все заново. Если вы ранее установили приложение, обязательно удалите его, иначе значок установки больше не появится.

Убедитесь, что кнопка установки видна

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

  1. Откройте URL-адрес в новой вкладке Chrome.
  2. Откройте трехточечное меню Chrome (рядом с адресной строкой). ▢ Убедитесь, что вы видите «Install Weather ...» в меню.
  3. Обновите данные о погоде, используя кнопку обновления в верхнем правом углу, чтобы убедиться, что мы встречаем user engagement heuristics . Ify Убедитесь, что значок установки отображается в заголовке приложения.

Убедитесь, что кнопка установки работает

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

  1. Откройте Chrome и в новой вкладке браузера перейдите к своему Weather PWA.
  2. Откройте DevTools и переключитесь на панель консоли.
  3. Нажмите кнопку установки в правом верхнем углу. Ify Убедитесь, что кнопка установки исчезла. Ify Убедитесь, что отображается диалоговое окно установки.
  4. Нажмите Отмена. ▢ Убедитесь, что «Пользователь отклонил запрос A2HS» отображается в выводе консоли. Ify Убедитесь, что кнопка установки появляется снова.
  5. Снова нажмите кнопку установки, затем нажмите кнопку установки в модальном диалоговом окне. ▢ Убедитесь, что "Пользователь принял приглашение A2HS" отображается в выводе консоли. ▢ Убедитесь, что в выводе консоли отображается «Приложение погоды было установлено». ▢ Убедитесь, что приложение Погода добавлено в место, где вы обычно находите приложения.
  6. Запустите Weather PWA. ▢ Убедитесь, что приложение открывается как отдельное приложение, либо в окне приложения на рабочем столе, либо в полноэкранном режиме на мобильном телефоне.

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

Убедитесь, что установка iOS работает правильно

Давайте также проверим поведение на iOS. Если у вас есть устройство iOS, вы можете использовать его, или если вы на Mac, попробуйте симулятор iOS, доступный с Xcode.

  1. Откройте Safari и в новой вкладке браузера перейдите к Weather PWA.
  2. Нажмите Поделиться! Кнопка 8ac92dd483c689d3.png .
  3. Прокрутите вправо и нажмите кнопку Добавить на главный экран. ▢ Проверьте правильность заголовка, URL-адреса и значка.
  4. Нажмите Добавить. ▢ Убедитесь, что значок приложения добавлен на главный экран.
  5. апустите Weather PWA на главном экране. ▢ Убедитесь, что приложение запускает полный экран.

Bonus: обнаружение, запущено ли ваше приложение с домашнего экрана

Медиа-запрос display-mode позволяет применять стили в зависимости от того, как было запущено приложение, или определять, как оно запускалось с помощью JavaScript.

@media all and (display-mode: standalone) {
  body {
    background-color: yellow;
  }
}

Вы также можете проверить display-mode медиа - запрос в JavaScript to see if you're running in standalone .

Bonus: удаление вашего PWA

Помните, что beforeinstallevent не beforeinstallevent , если приложение уже установлено, поэтому во время разработки вы, вероятно, захотите установить и удалить приложение несколько раз, чтобы убедиться, что все работает должным образом.

Android

На Android PWA удаляются так же, как и другие установленные приложения.

  • Откройте ящик приложения.
  • Прокрутите вниз, чтобы найти значок погоды.
  • Перетащите значок приложения в верхнюю часть экрана.
  • Выберите Удалить.

ChromeOS

В ChromeOS PWA легко удаляются из окна поиска программы запуска.

  • Откройте лаунчер.
  • Введите "* Погода *" в поле поиска, ваш Weather PWA должен появиться в результатах
  • Щелкните правой кнопкой мыши (alt-click) на Weather PWA.
  • Нажмите Удалить из Chrome ...

macOS и Windows

На Mac и Windows PWA должны быть удалены через Chrome.

  • В новой вкладке браузера откройте chrome: // apps.
  • Щелкните правой кнопкой мыши (alt-click) на Weather PWA.
  • Нажмите Удалить из Chrome ...

Поздравляем

Поздравляем, вы успешно создали свое первое Progressive Web App!

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

Теперь вы знаете ключевые шаги, необходимые для превращения любого веб-приложения в Progressive Web App.

Дальнейшее чтение

Справочные документы

Нашли проблему или есть отзывы?

Помогите нам сделать наши лаборатории кода лучше, отправив issue сегодня. И спасибо!