До этой главы PWA выглядела как набор инструментов, которые «просто работают». На практике у технологии есть набор тонких мест, на которые наступают почти все. Разберём четыре главных: ограничения iOS Safari, проблема «обновление не подхватывается», что показывает Lighthouse-аудит и как отлаживать service worker в DevTools.
Что не работает в iOS Safari
iOS — самая капризная платформа для PWA. Apple исторически не заинтересована в том, чтобы веб конкурировал с App Store, поэтому многие возможности либо работают с задержкой, либо урезаны.
На что наступают чаще всего:
- Push-уведомления — только с iOS 16.4. На более ранних версиях pushManager.subscribe() просто бросает ошибку. И даже на новых iOS push работает только если PWA установлено на главный экран — в обычной вкладке Safari push не работает.
- Нет badging. navigator.setAppBadge() на iOS Safari отсутствует. Значок «3 непрочитанных» на иконке показать нельзя.
- Background sync не поддерживается. Если задача в офлайн-режиме должна автоматически отправиться, когда сеть вернётся, — на iOS придётся отправлять её при следующем открытии приложения, не «в фоне».
- Web Share Target недоступен. Установленное PWA не появляется в системном меню «Поделиться».
- Квота хранилища меньше и сбрасывается. Safari ограничивает Cache API и IndexedDB примерно 1 ГБ, и может очистить хранилище, если приложением не пользовались неделю-две. Никаких гарантий на сохранность кэша между визитами нет.
- Service worker засыпает быстрее. Safari агрессивно убивает SW спустя 30 секунд бездействия, в то время как Chrome держит дольше. Длительные задачи в SW — ненадёжный паттерн на iOS.
Практический вывод: не стройте критические для бизнеса флоу на одних только PWA-возможностях, если ваша аудитория — iPhone. Push-канал дублируйте email/SMS, важные данные синхронизируйте при следующем заходе вручную, не полагайтесь на background sync.
Проблема «обновление не подхватывается»
Типичная ситуация: разработчик задеплоил новую версию сайта, открывает свой PWA — видит старую. Перезагрузил страницу — всё равно старая. Закрыл вкладку, открыл заново — старая. Почистил кэш в DevTools — наконец-то новая.
Причина в том, как именно service worker управляет обновлениями. По умолчанию:
- Браузер скачивает новый sw.js, обнаруживает, что он отличается от установленного.
- Новая версия SW переходит в состояние waiting.
- Старая версия SW продолжает контролировать все открытые вкладки до тех пор, пока пользователь их все не закроет.
- Только после полного закрытия новая версия активируется и берёт управление.
Это поведение хорошо для стабильности (пользователь не получит разную JS-логику в открытых вкладках одновременно), но неудобно для развёртывания. Лекарство — явное обновление имени кэша при каждом деплое:
const BUILD_VERSION = "a3b9f4c"; // короткий git-хэш коммита, подставляется на сборке
const CACHE_NAME = `pwa-cache-${BUILD_VERSION}`;
Если CACHE_NAME поменялся — на новой версии SW в install положится в кэш свежая копия всех файлов, а в activate удалятся старые. Главное — что само имя файла sw.js остаётся прежним, поэтому браузер замечает изменение содержимого и инициирует обновление.
В CI это автоматизируют скриптом, который вписывает в sw.js хэш текущего коммита перед сборкой:
// build.js
const fs = require("fs");
const { execSync } = require("child_process");
const hash = execSync("git rev-parse --short HEAD").toString().trim();
let sw = fs.readFileSync("src/sw.js", "utf8");
sw = sw.replace("__BUILD_HASH__", hash);
fs.writeFileSync("dist/sw.js", sw);
В коде SW при этом стоит плейсхолдер const BUILD_VERSION = "__BUILD_HASH__";, который заменяется на реальный хэш на этапе сборки.
Если хочется ускорить обновление ещё сильнее — добавить self.skipWaiting() в install и self.clients.claim() в activate, как разбирали в главе 4. Но это с оговорками: открытые вкладки получат новую версию SW резко, и если в них уже была загружена JS-логика старой версии, может появиться рассинхронизация.
Lighthouse PWA audit
Lighthouse — встроенный в Chrome DevTools аудит производительности. Кроме performance, accessibility и SEO у него есть категория PWA, которая проверяет десяток условий: HTTPS, валидный манифест с обязательными полями, иконки правильных размеров, зарегистрированный service worker, оффлайн-фолбэк и так далее.
Запуск: открыть DevTools (Ctrl+Shift+I или Cmd+Opt+I) → вкладка Lighthouse → выбрать категорию «Progressive Web App» → кнопка «Analyze page load». Через 20–40 секунд появится отчёт со списком пройденных и не пройденных проверок.
Самые частые провалы:
- Нет иконки 512×512 — Chrome не покажет кнопку установки без неё.
- Нет background_color или theme_color в манифесте.
- Service worker не контролирует start_url — обычно потому, что scope SW уже, чем директория start_url.
- Сайт не отвечает кодом 200, если выключить сеть — то есть нет offline.html в кэше.
Пройдите Lighthouse-аудит до того, как считать PWA готовым к выкатке.
Отладка в DevTools
Главный инструмент — вкладка Application в Chrome или Firefox DevTools.
Полезные секции:
- Manifest. Распарсенный манифест, превью иконок, ошибки и предупреждения. Первое место, куда смотреть, если «кнопка установки не появляется».
- Service Workers. Список зарегистрированных SW, кнопки Update (форсировать проверку обновления), Skip waiting (активировать ждущую версию), Unregister (полностью снять SW). Чекбокс Update on reload — на этапе разработки бесценен: каждое обновление страницы будет переустанавливать SW, не нужно вручную закрывать вкладки.
- Cache Storage. Все именованные кэши с их содержимым. Можно вручную удалить запись и проверить, что произойдёт.
- Storage. Кнопка Clear site data — полностью обнулить состояние: снять SW, очистить кэши, очистить IndexedDB. Удобно для проверки «как сайт выглядит для нового пользователя».
В консоли service worker запускается в собственном контексте — в DevTools его консоль доступна через выпадающий список «top frame» в правом верхнем углу, нужно переключиться на sw.js. console.log внутри SW попадает именно туда, а не в основную консоль страницы.
[СКРИНШОТ: Chrome DevTools → вкладка Application → раздел Manifest с распарсенным манифестом и превью иконок справа, ниже — раздел Service Workers с активным SW и чекбоксом «Update on reload».]
Чек-лист перед выкаткой PWA в прод
- HTTPS на проде; на staging тоже — иначе SW там не зарегистрируется.
- Манифест проходит Lighthouse PWA audit без ошибок.
- В sw.js имя кэша содержит версию/хэш сборки.
- В install предзагружается offline.html; в fetch есть fallback на него.
- В коде есть проверка isStandalone для подсказки iOS-пользователям, как установить.
- На push-уведомлениях не построены критические флоу для iOS-аудитории — есть запасной канал.
- В аналитику отправляется событие appinstalled, чтобы видеть процент установок.
Если все семь пунктов выполнены — ваше PWA готово.