Статьи

Модернизация вашего сайта как прогрессивного веб-приложения

Эта статья о модернизации вашего веб-сайта в качестве прогрессивного веб-приложения включена в наш сборник « Современный JavaScript» . Если вы хотите, чтобы все в одном месте было в курсе современного JavaScript, зарегистрируйтесь в SitePoint Premium и загрузите себе копию.

В последнее время было много шума вокруг Progressive Web Apps (PWA), и многие люди задавались вопросом, представляют ли они будущее (мобильной) сети.

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

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

Женщина в 1950-х, ретро-сцена, смотрящая на планшет с иконками Progressive Web App

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

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

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

  1. Вам нужно только одно приложение, разработанное с использованием открытых, стандартных веб-технологий W3C. Нет необходимости разрабатывать отдельные нативные базы кода.
  2. Пользователи могут обнаружить и попробовать ваше приложение перед установкой.
  3. Нет необходимости использовать AppStore, соблюдать тайные правила или платить комиссионные. Обновления приложений происходят автоматически без вмешательства пользователя.
  4. Пользователям предлагается «установить», что добавляет значок на их домашний экран.
  5. При запуске PWA отображает привлекательный экран-заставку.
  6. Параметры браузера Chrome могут быть изменены, если необходимо, для обеспечения полноэкранного режима.
  7. Основные файлы кэшируются локально, поэтому PWA отвечают быстрее, чем стандартные веб-приложения. (Они могут даже быть быстрее, чем родные приложения.)
  8. Установка облегчена — возможно, несколько сотен КБ кэшированных данных.
  9. Все обмены данными должны происходить через безопасное соединение HTTPS.
  10. PWA функционируют в автономном режиме и могут синхронизировать данные при восстановлении соединения.

Это первые дни, но тематические исследования положительные . Flipkart, крупнейший в Индии сайт электронной коммерции, продемонстрировал 70-процентное увеличение конверсии продаж и утроил время на месте, когда они отказались от своего собственного приложения для PWA. Alibaba, крупнейшая в мире торговая платформа для бизнеса, показала аналогичный рост конверсии на 76% .

Поддержка технологии Solid PWA доступна в Firefox, Chrome и других браузерах на базе Blink. Microsoft работает над реализацией Edge. Apple хранит молчание, хотя в пятилетнем плане WebKit есть многообещающие комментарии . К счастью, поддержка браузера в основном не имеет значения …

Прогрессивные веб-приложения — прогрессивные улучшения

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

Это не просто приложения

Google руководит движением PWA , поэтому в большинстве учебных пособий рассказывается, как создать мобильное приложение на основе Chrome с нуля. Однако вам не нужно специальное одностраничное приложение или вы должны следовать рекомендациям по дизайну интерфейса материалов. Большинство веб-сайтов могут быть PWA-iized в течение нескольких часов. Это включает в себя ваш WordPress или статический сайт.

Код демонстрации

Демонстрационный код доступен на GitHub .

Он предоставляет простой четырехстраничный веб-сайт с несколькими изображениями, одной таблицей стилей и одним основным файлом JavaScript. Сайт работает во всех современных браузерах (IE10 +). Если браузер поддерживает технологии PWA, пользователь может читать ранее просмотренные страницы в автономном режиме.

Чтобы запустить код, убедитесь, что Node.js установлен, а затем запустите предоставленный веб-сервер в вашем терминале с помощью:

node ./server.js [port] 

В приведенном выше коде [port] является необязательным и по умолчанию используется 8888. Откройте Chrome или другой браузер на основе Blink, например Opera или Vivaldi, затем перейдите по адресу http: // localhost: 8888 / (или какой порт указан вами). Вы также можете открыть Инструменты разработчика (F12 или Cmd / Ctrl + Shift + I ) для просмотра различных сообщений консоли.

Открыть сайт в браузере

Просмотрите домашнюю страницу и, возможно, еще одну, затем перейдите в автономный режим:

  1. остановка веб-сервера с помощью Cmd / Ctrl + C или
  2. установите флажок « Не в сети» на вкладке « Сеть или приложение — работники службы » в инструментах разработчика.

Зайдите на любую из ранее просмотренных страниц, и они все равно будут загружены. Перейдите на страницу, которую вы не видели, чтобы увидеть страницу «Вы в автономном режиме», содержащую список просматриваемых страниц:

автономные страницы

Подключите устройство

Вы также можете просмотреть демонстрационную страницу на смартфоне Android, подключенном к вашему ПК / Mac через USB. Откройте панель « Удаленные устройства» в разделе « Дополнительные инструменты» в верхнем левом трехточечном меню.

удаленные устройства

Выберите « Настройки» слева и нажмите « Добавить правило», чтобы перенаправить порт 8888 на локальный хост: 8888. Теперь вы можете открыть Chrome на смартфоне и перейти по адресу http: // localhost: 8888 / .

Вы можете использовать меню браузера для «Добавить на главный экран». Сделайте пару посещений, и браузер должен предложить вам «установить». Оба варианта создают новый значок на главном экране. Просмотрите несколько страниц, затем закройте Chrome и отключите устройство. Затем вы можете запустить приложение веб-сайта PWA . Вы увидите заставку и сможете просматривать ранее прочитанные страницы, несмотря на отсутствие подключения к серверу.

Есть три основных шага, чтобы превратить ваш сайт в прогрессивное веб-приложение …

Шаг 1: Включить HTTPS

Для PWA требуется HTTPS-соединение по причинам, которые вскоре станут понятны. Цены и процессы будут различаться для разных хостов, но это стоит затрат и усилий, учитывая, что поиск Google ранжирует защищенные сайты выше.

HTTPS не требуется для демонстрации выше, потому что Chrome разрешает использовать localhost или любой адрес 127.xxx для тестирования. Вы также можете протестировать технологию PWA на сайтах HTTP, если запустите Chrome со следующими флагами командной строки:

  • --user-data-dir
  • --unsafety-treat-insecure-origin-as-secure

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

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

Манифест представляет собой текстовый файл JSON в корне вашего приложения. Он должен обслуживаться с HTTP-заголовком Content-Type: application/manifest+json или Content-Type: application/json . Файл может называться как угодно, но в демонстрационном коде он был назван /manifest.json :

 { "name" : "PWA Website", "short_name" : "PWA", "description" : "An example PWA website", "start_url" : "/", "display" : "standalone", "orientation" : "any", "background_color" : "#ACE", "theme_color" : "#ACE", "icons": [ { "src" : "/images/logo/logo072.png", "sizes" : "72x72", "type" : "image/png" }, { "src" : "/images/logo/logo152.png", "sizes" : "152x152", "type" : "image/png" }, { "src" : "/images/logo/logo192.png", "sizes" : "192x192", "type" : "image/png" }, { "src" : "/images/logo/logo256.png", "sizes" : "256x256", "type" : "image/png" }, { "src" : "/images/logo/logo512.png", "sizes" : "512x512", "type" : "image/png" } ] } 

Ссылка на этот файл требуется в <head> всех ваших страниц:

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

Основные свойства манифеста:

  • name : полное имя приложения, которое будет отображаться пользователю
  • short_name : короткое имя для ситуаций, когда для полного имени недостаточно места
  • описание : длинное описание приложения
  • start_url : относительный URL для запуска приложения (обычно / )
  • область действия : область навигации — например, область действия /app/ ограничит приложение этой папкой
  • background_color : цвет фона, используемый для заставок и браузера Chrome (если требуется)
  • theme_color : цвет приложения, обычно такой же, как фон, который может влиять на отображение приложения
  • ориентация : предпочтительная ориентация — any , natural , landscape , landscape-primary , landscape-secondary , portrait , portrait-primary и portrait-secondary
  • дисплей : предпочтительный вид — fullscreen (без Chrome), standalone (выглядит как собственное приложение), minimal-ui (небольшой набор элементов управления пользовательского интерфейса) и browser (обычная вкладка браузера)
  • icons : массив графических объектов, определяющих URL-адрес src , sizes и type (необходимо указать диапазон значков).

MDN предоставляет полный список свойств манифеста веб-приложения .

В разделе « Манифест » вкладки «Инструменты разработки Chrome» проверяется манифест JSON и имеется ссылка «Добавить на домашний экран», которая работает на настольных устройствах:

Манифест PWA

Шаг 3: Создайте сервисного работника

Сервисные работники — это программируемые прокси, которые могут перехватывать и отвечать на сетевые запросы. Это один файл JavaScript, который находится в корне приложения.

JavaScript вашей страницы ( /js/main.js в демонстрационном коде) может проверить поддержку сервисного работника и зарегистрировать файл:

 if ('serviceWorker' in navigator) { // register service worker navigator.serviceWorker.register('/service-worker.js'); } 

Если вам не нужны автономные возможности, просто создайте пустой файл /service-worker.js . Пользователям будет предложено установить ваше приложение!

Работники сферы обслуживания могут сбивать с толку, но вы должны иметь возможность адаптировать демонстрационный код для своих собственных целей. Это стандартный веб-рабочий скрипт, который браузер загружает (когда это возможно) и работает в отдельном потоке. Он не имеет доступа к DOM или другим API страниц, но будет перехватывать сетевые запросы, инициируемые изменениями страниц, загрузками ресурсов и вызовами Ajax.

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

Работники службы реагируют на три основных события: install , activate и fetch .

Установить событие

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

Сначала мы определим некоторые переменные конфигурации для:

  1. Имя кэша ( CACHE ) и версия ( version ). Ваше приложение может иметь несколько хранилищ кэша, но нам требуется только одно. Применяется номер версии, поэтому, если мы сделаем значительные изменения, будет использоваться новый кеш, а все ранее кэшированные файлы игнорируются.
  2. URL автономной страницы ( offlineURL ). Это страница, которая будет отображаться, когда пользователь не в сети и пытается загрузить страницу, которую он ранее не посещал.
  3. Массив необходимых для установки файлов, обеспечивающих работу сайта в автономном режиме ( installFilesEssential ). Это должно включать ресурсы, такие как CSS и JavaScript, но я также включил домашнюю страницу ( / ) и логотип. Вы также должны включить варианты, такие как / и /index.html если URL можно адресовать несколькими способами. Обратите внимание, что offlineURL добавляется в этот массив.
  4. По желанию, массив желаемых файлов ( installFilesDesirable ). Они будут загружены, если это возможно, но не приведут к прерыванию установки при сбое.
 // configuration const version = '1.0.0', CACHE = version + '::PWAsite', offlineURL = '/offline/', installFilesEssential = [ '/', '/manifest.json', '/css/styles.css', '/js/main.js', '/js/offlinepage.js', '/images/logo/logo152.png' ].concat(offlineURL), installFilesDesirable = [ '/favicon.ico', '/images/logo/logo016.png', '/images/hero/power-pv.jpg', '/images/hero/power-lo.jpg', '/images/hero/power-hi.jpg' ]; 

Функция installStaticFiles() добавляет файлы в кэш с помощью API -интерфейса Cache . Возвращаемое значение генерируется только тогда, когда основные файлы кэшируются:

 // install static assets function installStaticFiles() { return caches.open(CACHE) .then(cache => { // cache desirable files cache.addAll(installFilesDesirable); // cache essential files return cache.addAll(installFilesEssential); }); } 

Наконец, мы добавляем прослушиватель событий install . Метод waitUntil гарантирует, что сервисный работник не установится, пока не будет выполнен весь вложенный код. Он запускает installStaticFiles() затем self.skipWaiting() чтобы сделать работника службы активным:

 // application installation self.addEventListener('install', event => { console.log('service worker: install'); // cache core files event.waitUntil( installStaticFiles() .then(() => self.skipWaiting()) ); }); 

Активировать событие

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

 // clear old caches function clearOldCaches() { return caches.keys() .then(keylist => { return Promise.all( keylist .filter(key => key !== CACHE) .map(key => caches.delete(key)) ); }); } // application activated self.addEventListener('activate', event => { console.log('service worker: activate'); // delete old caches event.waitUntil( clearOldCaches() .then(() => self.clients.claim()) ); }); 

Обратите внимание, что последний self.clients.claim() устанавливает этого работника службы в качестве активного работника для сайта.

Получить событие

Это происходит всякий раз, когда делается сетевой запрос. Он вызывает метод respondWith() для перехвата запросов GET и возврата:

  1. Актив из кеша.
  2. В случае сбоя # 1 ресурс загружается из сети с использованием API Fetch (не относится к событию извлечения работника службы). Этот актив затем добавляется в кэш.
  3. Если # 1 и # 2 терпят неудачу, возвращается соответствующий ответ.
 // application fetch network data self.addEventListener('fetch', event => { // abandon non-GET requests if (event.request.method !== 'GET') return; let url = event.request.url; event.respondWith( caches.open(CACHE) .then(cache => { return cache.match(event.request) .then(response => { if (response) { // return cached file console.log('cache fetch: ' + url); return response; } // make network request return fetch(event.request) .then(newreq => { console.log('network fetch: ' + url); if (newreq.ok) cache.put(event.request, newreq.clone()); return newreq; }) // app is offline .catch(() => offlineAsset(url)); }); }) ); }); 

Последний вызов offlineAsset(url) возвращает соответствующий ответ, используя несколько вспомогательных функций:

 // is image URL? let iExt = ['png', 'jpg', 'jpeg', 'gif', 'webp', 'bmp'].map(f => '.' + f); function isImage(url) { return iExt.reduce((ret, ext) => ret || url.endsWith(ext), false); } // return offline asset function offlineAsset(url) { if (isImage(url)) { // return image return new Response( '<svg role="img" viewBox="0 0 400 300" xmlns="http://www.w3.org/2000/svg"><title>offline</title><path d="M0 0h400v300H0z" fill="#eee" /><text x="200" y="150" text-anchor="middle" dominant-baseline="middle" font-family="sans-serif" font-size="50" fill="#ccc">offline</text></svg>', { headers: { 'Content-Type': 'image/svg+xml', 'Cache-Control': 'no-store' }} ); } else { // return page return caches.match(offlineURL); } } 

Функция offlineAsset() проверяет, относится ли запрос к изображению, и возвращает SVG, содержащий текст «offline». Все остальные запросы возвращают страницу offlineURL .

Раздел « Service Worker » на вкладке «Инструменты разработки Chrome» содержит информацию о ваших сотрудниках, с ошибками и средствами для принудительной перезагрузки и отключения браузера:

Работники службы PWA

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

PWA кэшированные файлы

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

PWA очистить кэшированные файлы

Бонус Шаг 4: Создайте полезную автономную страницу

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

Доступ к Cache API можно получить из нашего скрипта main.js Однако API использует обещания, которые не выполняются в неподдерживаемых браузерах и приведут к остановке выполнения всего JavaScript. Чтобы избежать этого, мы добавим код, который проверяет, доступен ли автономный элемент списка и Caches API, перед загрузкой другого /js/offlinepage.js JavaScript /js/offlinepage.js (который должен присутствовать в массиве installFilesEssential выше):

 // load script to populate offline page list if (document.getElementById('cachedpagelist') && 'caches' in window) { var scr = document.createElement('script'); scr.src = '/js/offlinepage.js'; scr.async = 1; document.head.appendChild(scr); } 

/js/offlinepage.js находит самый последний кеш по имени версии, получает список всех ключей URL, удаляет cachedpagelist URL, сортирует список и добавляет его в узел DOM с идентификатором cachedpagelist :

 // cache name const CACHE = '::PWAsite', offlineURL = '/offline/', list = document.getElementById('cachedpagelist'); // fetch all caches window.caches.keys() .then(cacheList => { // find caches by and order by most recent cacheList = cacheList .filter(cName => cName.includes(CACHE)) .sort((a, b) => a - b); // open first cache caches.open(cacheList[0]) .then(cache => { // fetch cached pages cache.keys() .then(reqList => { let frag = document.createDocumentFragment(); reqList .map(req => req.url) .filter(req => (req.endsWith('/') || req.endsWith('.html')) && !req.endsWith(offlineURL)) .sort() .forEach(req => { let li = document.createElement('li'), a = li.appendChild(document.createElement('a')); a.setAttribute('href', req); a.textContent = a.pathname; frag.appendChild(li); }); if (list) list.appendChild(frag); }); }) }); 

Инструменты разработки

Если вы считаете, что отладка JavaScript сложная задача, работникам сферы обслуживания не доставит большого удовольствия! Вкладка « Приложения » Chrome в Инструментах разработчика предоставляет полный набор функций, а операторы журналов также выводятся на консоль.

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

Firefox предлагает JavaScript-отладчик, доступ к которому осуществляется из пункта « Сервисные работники» меню инструментов. Лучшее оборудование обещано в ближайшее время.

Наконец, расширение Lighthouse для Chrome также предоставляет полезную информацию о реализации вашего PWA.

PWA Gotchas

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

Мнения разработчиков различаются, но есть несколько моментов, которые следует учитывать…

Скрытие URL

Демонстрационный сайт скрывает панель URL, которую я бы не рекомендовал, если у вас нет приложения с одним URL, например игры. Опции манифеста display: minimal-ui или display: browser , возможно, лучше всего подходят для большинства сайтов.

Перегрузка кеша

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

Возможно, рассмотрим:

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

Обновление кеша

Демонстрация ищет ресурсы в кеше перед загрузкой из сети. Это замечательно, когда пользователи не в сети, но означает, что они могут просматривать старые страницы, даже когда они в сети.

URL-адреса ресурсов, таких как изображения и видео, никогда не должны изменяться, поэтому долгое кэширование редко является проблемой. Вы можете обеспечить их кэширование в течение как минимум одного года (31 536 000 секунд) с помощью заголовка HTTP Cache-Control :

 Cache-Control: max-age=31536000 

Страницы, CSS и файлы сценариев могут меняться чаще, поэтому вы можете установить более короткий срок действия — 24 часа и убедиться, что он проверен на соответствие версии сервера в режиме онлайн:

 Cache-Control: must-revalidate, max-age=86400 

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

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

Следующие ресурсы полезны, если вы хотите узнать больше о Progressive Web Apps:

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

Эта статья была рецензирована AJ Latour , Panayiotis «pvgr» Velisarakos и Дейв Максвелл . Спасибо всем рецензентам SitePoint за то, что сделали контент SitePoint как можно лучше!