Разработка прогрессивных веб-приложений 02.0: быстрый старт в автономном режиме

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

Полную информацию о курсе смотрите в обзоре «Разработка прогрессивных веб-приложений» .

Введение

В этой лабораторной работе вы будете использовать Lighthouse для аудита веб-сайта на соответствие стандартам Progressive Web App (PWA). Вы также добавите офлайн-функциональность с помощью API сервис-воркера.

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

  • Как проводить аудит сайтов с помощью Lighthouse
  • Как добавить в приложение автономные возможности

Что вам следует знать

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

  • Компьютер с доступом к терминалу/оболочке
  • Подключение к Интернету
  • Браузер Chrome (для использования Lighthouse)
  • Текстовый редактор
  • Дополнительно: Chrome на устройстве Android

Загрузите или клонируйте репозиторий pwa-training-labs с github и установите LTS-версию Node.js , если необходимо.

Перейдите в каталог offline-quickstart-lab/app/ и запустите локальный сервер разработки:

cd offline-quickstart-lab/app
npm install
node server.js

Вы можете завершить работу сервера в любое время с помощью сочетания Ctrl-c .

Откройте браузер и перейдите по адресу localhost:8081/ . Вы увидите простую статическую веб-страницу.

Примечание: Отмените регистрацию всех сервис-воркеров и очистите все кэши сервис-воркеров для локального хоста, чтобы они не мешали работе лаборатории. В Chrome DevTools это можно сделать, нажав «Очистить данные сайта» в разделе «Очистить хранилище» на вкладке «Приложение» .

Откройте папку offline-quickstart-lab/app/ в предпочитаемом вами текстовом редакторе. В этой app/ вы будете создавать лабораторную работу.

Эта папка содержит:

  • папка images/ содержит примеры изображений
  • styles/main.css — основная таблица стилей
  • index.html — главная HTML-страница нашего образца сайта.
  • package-lock.json и package.json отслеживают зависимости приложения (в данном случае единственные зависимости — для локального сервера разработки)
  • server.js — это локальный сервер разработки для тестирования
  • service-worker.js — файл сервисного работника (в настоящее время пустой)

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

Вернитесь в приложение (в Chrome) и откройте вкладку «Аудит» в инструментах разработчика . Вы увидите значок маяка и параметры конфигурации. Выберите «Мобильное устройство» для устройства , выберите все аудиты , выберите один из вариантов регулирования и нажмите «Очистить хранилище ».

Нажмите «Запустить аудит» . Аудит может занять несколько минут.

Объяснение

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

Примечание: оценки Lighthouse являются приблизительными и могут зависеть от вашей среды (например, если открыто много окон браузера). Ваши оценки могут отличаться от представленных здесь.

А раздел Progressive Web App должен выглядеть примерно так:

Отчет содержит оценки и показатели по пяти категориям:

  • Прогрессивное веб-приложение
  • Производительность
  • Доступность
  • Лучшие практики
  • SEO

Как видите, наше приложение получило низкие оценки в категории «Прогрессивные веб-приложения» (PWA). Давайте улучшим наш результат!

Уделите немного времени просмотру раздела PWA в отчете и посмотрите, чего не хватает.

Регистрация работника сферы услуг

Одна из ошибок, перечисленных в отчёте, заключается в том, что не зарегистрирован ни один сервис-воркер. В настоящее время файл сервис-воркера в app/service-worker.js пуст.

Добавьте следующий скрипт в конец index.html , непосредственно перед закрывающимся тегом </body> :

<script>
if ('serviceWorker' in navigator) {
  window.addEventListener('load', function() {
    navigator.serviceWorker.register('service-worker.js')
      .then(reg => {
        console.log('Service worker registered! 😎', reg);
      })
      .catch(err => {
        console.log('😥 Service worker registration failed: ', err);
      });
  });
}
</script>

Объяснение

Этот код регистрирует пустой файл service-worker.js после загрузки страницы. Однако текущий файл сервис-воркера пуст и не выполняет никаких действий. Добавим код сервиса на следующем шаге.

Предварительное кэширование ресурсов

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

Добавьте следующий код в файл service service-worker.js :

const cacheName = 'cache-v1';
const precacheResources = [
  '/',
  'index.html',
  'styles/main.css',
  'images/space1.jpg',
  'images/space2.jpg',
  'images/space3.jpg'
];

self.addEventListener('install', event => {
  console.log('Service worker install event!');
  event.waitUntil(
    caches.open(cacheName)
      .then(cache => {
        return cache.addAll(precacheResources);
      })
  );
});

self.addEventListener('activate', event => {
  console.log('Service worker activate event!');
});

self.addEventListener('fetch', event => {
  console.log('Fetch intercepted for:', event.request.url);
  event.respondWith(caches.match(event.request)
    .then(cachedResponse => {
        if (cachedResponse) {
          return cachedResponse;
        }
        return fetch(event.request);
      })
    );
});

Теперь вернитесь в браузер и обновите сайт. Проверьте консоль, чтобы убедиться, что сервис-воркер:

  • зарегистрированный
  • установлен
  • активированный

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

Затем завершите работу локального сервера разработки в командной строке, нажав Ctrl + c . Снова обновите сайт и убедитесь, что он загружается, даже если сервер отключен!

Примечание: Вы можете увидеть сообщение об ошибке консоли, указывающее на то, что не удалось загрузить Service Worker: An unknown error occurred when fetching the script. service-worker.js Failed to load resource: net::ERR_CONNECTION_REFUSED . Эта ошибка возникает, поскольку браузеру не удалось загрузить скрипт Service Worker (сайт отключен), но это ожидаемо, поскольку мы не можем использовать Service Worker для кэширования самого себя. В противном случае браузер пользователя будет постоянно использовать один и тот же Service Worker!

Объяснение

После регистрации сервис-воркера скриптом регистрации в index.html происходит событие install сервис-воркера. Во время этого события прослушиватель событий install открывает именованный кэш и кэширует файлы, указанные с помощью метода cache.addAll . Это называется «предварительным кэшированием», поскольку происходит во время события install , которое обычно происходит при первом посещении сайта пользователем.

После установки Service Worker, если другой Service Worker в данный момент не управляет страницей, новый Service Worker «активируется» (в Service Worker срабатывает прослушиватель событий activate ), и он начинает управлять страницей.

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

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

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

Дополнительно : вы также можете просмотреть кэшированные ресурсы на вкладке «Приложение» в инструментах разработчика, развернув раздел «Хранилище кэша» :

Перезапустите сервер разработки с помощью node server.js и обновите сайт. Затем снова откройте вкладку «Аудиты» в инструментах разработчика и повторно запустите аудит Lighthouse, выбрав «Новый аудит» (значок «плюс» в левом верхнем углу). После завершения аудита вы увидите, что наш результат PWA значительно улучшился, но его ещё можно улучшить. Мы продолжим улучшать наш результат в следующем разделе.

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

Наш рейтинг PWA всё ещё невелик. Среди оставшихся проблем, перечисленных в отчёте, — отсутствие запроса на установку веб-приложения, а также отсутствие настройки заставки и фирменных цветов в адресной строке. Мы можем исправить эти проблемы и постепенно реализовать функцию «Добавить на главный экран» , выполнив ряд дополнительных условий . Самое главное — создать файл манифеста .

Создать файл манифеста

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

{
  "name": "Space Missions",
  "short_name": "Space Missions",
  "lang": "en-US",
  "start_url": "/index.html",
  "display": "standalone",
  "theme_color": "#FF9800",
  "background_color": "#FF9800",
  "icons": [
    {
      "src": "images/touch/icon-128x128.png",
      "sizes": "128x128"
    },
    {
      "src": "images/touch/icon-192x192.png",
      "sizes": "192x192"
    },
    {
      "src": "images/touch/icon-256x256.png",
      "sizes": "256x256"
    },
    {
      "src": "images/touch/icon-384x384.png",
      "sizes": "384x384"
    },
    {
      "src": "images/touch/icon-512x512.png",
      "sizes": "512x512"
    }
  ]
}

Изображения, указанные в манифесте, уже присутствуют в приложении.

Затем добавьте следующий HTML-код в конец тега <head> в index.html :

<link rel="manifest" href="manifest.json">

<meta name="mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="application-name" content="Space Missions">
<meta name="apple-mobile-web-app-title" content="Space Missions">
<meta name="theme-color" content="#FF9800">
<meta name="msapplication-navbutton-color" content="#FF9800">
<meta name="apple-mobile-web-app-status-bar-style" content="black-translucent">
<meta name="msapplication-starturl" content="/index.html">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">

<link rel="icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="apple-touch-icon" sizes="128x128" href="/images/touch/icon-128x128.png">
<link rel="icon" sizes="192x192" href="icon-192x192.png">
<link rel="apple-touch-icon" sizes="192x192" href="/images/touch/icon-192x192.png">
<link rel="icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="apple-touch-icon" sizes="256x256" href="/images/touch/icon-256x256.png">
<link rel="icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="apple-touch-icon" sizes="384x384" href="/images/touch/icon-384x384.png">
<link rel="icon" sizes="512x512" href="/images/touch/icon-512x512.png">
<link rel="apple-touch-icon" sizes="512x512" href="/images/touch/icon-512x512.png">

Вернитесь на сайт. На вкладке «Приложение» в разделе «Инструменты разработчика» выберите раздел «Очистить хранилище» и нажмите «Очистить данные сайта» . Затем обновите страницу. Теперь выберите раздел «Манифест» . Вы должны увидеть значки и параметры конфигурации, заданные в файле manifest.json . Если вы не видите изменений, откройте сайт в режиме инкогнито и проверьте ещё раз.

Объяснение

Файл manifest.json сообщает браузеру, как стилизовать и форматировать некоторые элементы прогрессивного приложения, такие как браузерный Chrome, значок главного экрана и заставку. Его также можно использовать для настройки веб-приложения для работы в standalone режиме, как это делают нативные приложения (то есть вне браузера).

На момент написания этой статьи поддержка для некоторых браузеров все еще находилась в стадии разработки, а теги <meta> настраивают подмножество этих функций для определенных браузеров, которые пока не имеют полной поддержки.

Нам пришлось очистить данные сайта , чтобы удалить старую кэшированную версию index.html (поскольку в ней не было ссылки на манифест). Попробуйте ещё раз запустить аудит Lighthouse и посмотрите, насколько улучшился рейтинг PWA!

Активация приглашения к установке

Следующий шаг установки нашего приложения — показать пользователям запрос на установку. В Chrome 67 запрос появлялся автоматически, но, начиная с Chrome 68 , запрос на установку должен активироваться программно в ответ на жест пользователя.

Добавьте кнопку «Установить приложение» и баннер в верхнюю часть index.html (сразу после тега <main> ) с помощью следующего кода:

<section id="installBanner" class="banner">
    <button id="installBtn">Install app</button>
</section>

Затем стилизуйте баннер, добавив следующие стили в styles/main.css :

.banner {
  align-content: center;
  display: none;
  justify-content: center;
  width: 100%;
}

Сохраните файл. Наконец, добавьте следующий тег script в index.html :

  <script>
    let deferredPrompt;
    window.addEventListener('beforeinstallprompt', event => {

      // Prevent Chrome 67 and earlier from automatically showing the prompt
      event.preventDefault();

      // Stash the event so it can be triggered later.
      deferredPrompt = event;

      // Attach the install prompt to a user gesture
      document.querySelector('#installBtn').addEventListener('click', event => {

        // Show the prompt
        deferredPrompt.prompt();

        // Wait for the user to respond to the prompt
        deferredPrompt.userChoice
          .then((choiceResult) => {
            if (choiceResult.outcome === 'accepted') {
              console.log('User accepted the A2HS prompt');
            } else {
              console.log('User dismissed the A2HS prompt');
            }
            deferredPrompt = null;
          });
      });

      // Update UI notify the user they can add to home screen
      document.querySelector('#installBanner').style.display = 'flex';
    });
  </script>

Сохраните файл. Откройте приложение в Chrome на устройстве Android, используя удалённую отладку . После загрузки страницы вы увидите кнопку «Установить приложение» (она не будет видна на настольном компьютере, поэтому убедитесь, что вы тестируете приложение на мобильном устройстве). Нажмите кнопку, и появится запрос на добавление на главный экран. Следуйте инструкциям по установке приложения на устройство. После установки вы сможете открыть веб-приложение в автономном режиме (вне браузера), нажав на созданный значок главного экрана.

Объяснение

Код HTML и CSS добавляет скрытый баннер и кнопку, которые мы можем использовать, чтобы позволить пользователям активировать запрос на установку.

После срабатывания события beforeinstallprompt мы отключаем стандартный режим (при котором Chrome 67 и более ранние версии автоматически предлагают пользователям установить приложение) и фиксируем событие beforeinstallevent в глобальной переменной deferredPrompt . Кнопка «Установить приложение» затем настраивается на отображение запроса с помощью метода prompt() объекта beforeinstallevent . Как только пользователь делает выбор (устанавливать или нет), обещание userChoice разрешается с выбором пользователя ( outcome ). Наконец, когда всё готово, мы отображаем кнопку установки.

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

Больше ресурсов

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

Чтобы увидеть все практические работы в учебном курсе PWA, ознакомьтесь с приветственными практическими работами для курса.