Какие характеристики должны быть у web-приложения, чтобы
соответствовать критерию "прогрессивное"? Понятно, что, как и
обычные web-приложения, прогрессивные строятся на базе "большой
тройки" web-технологий - HTML/CSS/JS. Но что именно делает
web-приложения прогрессивными?
В данной публикации я попробую найти минимальный набор
характеристик, которым на данный момент должно соответствовать
web-приложение, чтобы называться "прогрессивным", а также отвечу на
вопрос, почему в августе этого года некоторые "прогрессивные"
приложения перестанут быть таковыми.
Принципы отбора характеристик
Я возьму пустой HTML-файл и буду постепенно добавлять к нему
артефакты, превращающие его в PWA, пока
мой смартфон не решит установить это приложение, а Chrome не
перестанет выкидывать предупреждения. Chrome выбран по причине
того, что основным "движителем" технологии PWA на данный момент
является Google.
HTTPS
Первое, что нужно настроить на сервере - это шифрование трафика.
Тут всё делается так же, как и для обычных web-приложений. Лично я
использую Apache httpd, а сертификаты
для шифрования генерирую через Let's Encrypt.
App Shell
Оболочка приложения - это
минимальный набор файлов, позволяющий приложению запускаться в
offline-режиме. Я попробую весь необходимый код (HTML/CSS/JS) по
максимуму уместить в одном файле - index.html
.
<!DOCTYPE html><html lang="en"><head> <title>PWA</title> <style> BODY { background-color: #FB9902; color: #342309; font-size: xx-large; margin: 0; } DIV { align-content: center; display: grid; height: 100vh; justify-content: center; } </style></head><body><div>App Shell</div></body></html>
Manifest
Манифест является
непосредственным маркером того, что данная страница является частью
прогрессивного web-приложения. Подключается манифест в заголовке
HTML-страницы:
<link rel="manifest" href="demo.pwa.json">
Специальных правил для наименования файла с манифестом я не
видел, тип содержимого маркируется через значение
manifest
атрибута rel
.
Пустой манифест генерирует такие сообщения об ошибках в
Chrome:
Вот минимальное содержимое, которое не вызывает появления в
Chrome предупреждений:
{ "start_url": "./", "name": "PWA", "display": "standalone", "icons": [ { "src": "./icon.png", "sizes": "144x144", "type": "image/png" } ]}
Icon
Как видно из предупреждений Chrome'а, иконка должна быть размера
144x144 минимум и в формате PNG, SVG или WebP. Примерно такую я и
сделал:
В общем случае может быть
множество иконок различных размеров.
Service Worker
После добавления минимального манифеста и иконки в Chrome
остаётся только одно предупреждение - относительно service
worker'а.
Service worker подключается через скрипты в оболочке приложения
(index.html
):
<script> if ("serviceWorker" in navigator) { self.addEventListener("load", async () => { const container = navigator.serviceWorker; if (container.controller === null) { const reg = await container.register("sw.js"); } }); }</script>
Минимальное содержимое файла sw.js
:
'use strict';
вызывает вот такое предупреждение в Chrome: Page does not
work offline
Stackoverflow сообщает, что предупреждение
связано с отсутствием обработчика на событие fetch
.
Добавляем пустой обработчик:
'use strict';function hndlEventFetch(evt) {}self.addEventListener('fetch', hndlEventFetch);
Теперь предупреждение изменилось на:
Site cannot be installed: Page does not work offline. Starting
in Chrome 93, the installability criteria is changing, and this
site will not be installable. See https://goo.gle/improved-pwa-offline-detection
for more information.
Моя текущая версия Chrome: Version 89.0.4389.72 (Official
Build) (64-bit)
Тем не менее, смартфон предлагает установить приложение при
заходе на страницу:
То есть, на данный момент service worker может быть номинальным,
но в ближайшем будущем (в августе 2021-го) этого
будет недостаточно.
Кэширование
Чтобы наше приложение оставалось PWA и после августа 2021-го,
нам нужно добавить кэширование файлов, входящих в оболочку
приложения. Вот полный код service worker'а:
'use strict';const CACHE_STATIC = 'static-cache-v1';function hndlEventInstall(evt) { /** * @returns {Promise<void>} */ async function cacheStaticFiles() { const files = [ './', './demo.pwa.json', './icon.png', './index.html', './sw.js', ]; const cacheStat = await caches.open(CACHE_STATIC); await Promise.all( files.map(function (url) { return cacheStat.add(url).catch(function (reason) { console.log(`'${url}' failed: ${String(reason)}`); }); }) ); } // wait until all static files will be cached evt.waitUntil(cacheStaticFiles());}function hndlEventFetch(evt) { async function getFromCache() { const cache = await self.caches.open(CACHE_STATIC); const cachedResponse = await cache.match(evt.request); if (cachedResponse) { return cachedResponse; } // wait until resource will be fetched from server and stored in cache const resp = await fetch(evt.request); await cache.put(evt.request, resp.clone()); return resp; } evt.respondWith(getFromCache());}self.addEventListener('install', hndlEventInstall);self.addEventListener('fetch', hndlEventFetch);
С таким service worker'ом наше приложение будет считаться
прогрессивным и в Chrome 93+. Вот какие файлы легли в кэш:
Ошибка, которая высветилась в консоли - отсутствие файла
favicon.ico
:
GET https://bwl.local.teqfw.com/favicon.ico 404
Но это уже особенности работы браузера, а не PWA.
Резюме
Чтобы web-приложение считалось прогрессивным (в том числе и
после августа 2021-го) оно должно удовлетворять следующим
условиям:
-
Использовать шифрование (HTTPS).
-
Оболочка приложения (загружает манифест приложения).
-
Манифест (загружает иконку и service worker).
-
Иконка.
-
Service worker.
-
Кэширование файлов оболочки приложения.
При соблюдении этих условий PWA устанавливается на
смартфоне:
Послесловие
На написание этой статьи меня натолкнуло сообщение в Chrome о
том, что с версии 93 web-приложения без кэширования оболочки
приложения более не будут считаться прогрессивными и им будет
отказано в установке. Я вышел на PWA через такое замечательное
приложение, как Vue Storefront. Разработчики
провели гигантскую работу и привязали к Magento 2 фронт, созданный
с использованием современных технологий (положа руку на сердце,
оригинальный фронт Magento 2 очень сильно отстал от современных
тенденций web-разработки).
Когда я разбирался с тем, как устроен Vue Storefront, я обратил
внимание, что приложение написано из расчёта, что соединение с
интернетом будет всегда. Что и понятно, e-коммерция без интернета
перестаёт быть таковой. И хотя браузеры предоставляют определённые
возможности для того, чтобы PWA были максимально похожи на нативные
мобильные приложения, современные PWA не спешат их использовать.
Всё-таки, они во-первых - web, а прогрессивные - лишь во-вторых.
Можно написать web-приложение, можно написать serverless приложение
(за исключением App Shell, манифеста и service worker'а, разумеется
- их всё равно придётся тянуть с сервера). Но написать приложение,
которое бы работало как web-приложение при наличии
интернет-соединения, и работало в автономном режиме в его
отсутствие - в разы сложнее каждого из этих вариантов.
Именно поэтому разработчики Vue Storefront не стали
заморачиваться с автономной функциональностью, ограничившись
кэшированием статики и некоторых данных. Именно поэтому для Vue
Storefront вылетает сообщение о том, что в Chrome 93+ их приложение
более не будет считаться прогрессивным (демо, откройте консоль). Кстати,
для собственной PWA-разработки самой
Magento ситуация аналогичная.
Другими словами Google ужесточает критерии PWA, сдвигая фокус от
web'а в сторону мобильных платформ. Конечно, можно и дальше
называть обычные web-приложения прогрессивными, даже если они на
100% предполагают использование на десктопах и в условиях
стабильного интернет-соединения. Но общая тенденция говорит о том, что место для
PWA - мобильные устройства:
In December 2020, Firefox for desktop abandoned implementation
of PWAs (specifically, removed the prototype "site-specific
browser" configuration that had been available as an experimental
feature). A Firefox architect noted: "The signal I hope we are
sending is that PWA support is not coming to desktop Firefox
anytime soon." Mozilla still plans to support PWAs on Android.
Разработчики Firefox не собираются поддерживать
PWA в десктопной версии своего браузера.
Нельзя сказать, что PWA являются
чисто Google'овской технологией:
всё-таки поддержка PWA-технологии различными браузерами на
различных платформах достаточно объемлющая. Но дрейф в сторону
"мобилизации" технологии я игнорировать не могу.
На мой взгляд PWA - это "нишевое" решение, для мобильных
устройств. Да, оно сделано с использованием web-технологий
(HTML/CSS/JS) и крутится внутри браузера, но к разработке PWA нужно
подходить скорее с точки зрения нативных мобильных приложений, чем
с точки зрения web-приложений (сайтов или SPA).
Другими словами, если вам нужно именно web-приложение, то вам не
нужно PWA. А вот если вам нужно разработать именно мобильное
приложение, то PWA может быть приемлемым вариантом.