Какие характеристики должны быть у 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 может быть приемлемым вариантом.
vmkazakoff
Отдельное спасибо за то, что сделали все в "блокноте".
Обычно такие статьи начинаются с "для начала нам надо сделать одну простую вещь… — npm install 1, 2, ..., 189, 190,… 100500" и сидишь такой и думаешь что это не статья была "как сделать" а подборка типа "используйте эти топ 10 npm пакетов если хотите..."