Какие характеристики должны быть у 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 может быть приемлемым вариантом.