feat(pwa): надёжное обновление + пер-кооп имя/иконка установочника #93
Reference in New Issue
Block a user
Delete Branch "feat/pwa-reliable-update"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Что и зачем
Три связанных улучшения PWA-установочника кооператива. Зонтичный PR, по коммиту на блок.
1. Надёжное пользовательское обновление (убирает «подвисание между релизами»)
Было: Workbox GenerateSW с
skipWaiting+clientsClaim→ новый SW активировался в фоне сам → гонкаcontrollerchange↔updated(). При сбое тайминга страница оставалась старой, а SW — новым: рассинхрон версий, «подвисли между релизами». Внезапный авто-reload.Стало:
skipWaiting/clientsClaim=false→ новый SW ждёт вwaiting.updated()шлётwindow-событиеsw:update-available; bootpwa-updateпоказывает канон-тост в левом нижнем углу (UpdateAlert,timeout:0, кнопки «Обновить»/«Позже»). По «Обновить» →window.applyUpdate()→SKIP_WAITING→controllerchange→reload. Один детерминированный путь, без фонового свопа. Бонус: приskipWaiting:falseWorkbox сам инжектит listenerSKIP_WAITING.2. Имя установочника = имя кооператива
Было: образ generic, кооп задаётся env контейнера (
COOP_SHORT_NAME), а manifest пёкся на сборке → на домашнем экране всегда дефолтное «Цифровой Кооператив».Стало: manifest отдаётся динамически SSR-middleware из env. Ловушка:
serveStatic('/')регистрируется до user-middleware (ssr-prod-webserver), поэтому статический/manifest.jsonперехватил бы запрос. Отдаём по/manifest.webmanifest(статики там нет → fall-through) и переписываем<link rel=manifest>в HTML. Плюс рантайм-apple-mobile-web-app-titleдля iOS.3. Стандартная иконка приложения
Было: PNG-иконки manifest'а физически отсутствовали (
/icons/*.pngотдавали HTML-фоллбэк) → дефолтная иконка на домашнем экране.Стало: полный набор PNG из
logo.svg(квадрат, белый фон, центр, maskable-safe) + в динамическом manifest основная иконка — масштабируемый/logo.svg(purpose: any maskable).Режимы
SW-логика и тост — client-only (guard
typeof window), в SSR серверно не исполняются. Динамический manifest — SSR-only; в чистом SPA/статике остаётся build-time fallback. SPA и SSR не затронуты.Проверки перед мержем (среда CI)
service-worker.jsсодержит инжектнутый listenerSKIP_WAITING(приskipWaiting:falseWorkbox должен добавить — подтвердить после сборки).<link rel=manifest>в SSR-HTML реально переписывается на/manifest.webmanifest(порядок атрибутов rel/href — regex учитывает оба).🤖 Generated with Claude Code
6fe06c3ec8toc3bedef6b2c3bedef6b2to30e8e0a1b630e8e0a1b6to949b007961949b007961to4471ea2fb94471ea2fb9tode974d336d