8 критичних помилок при інтеграції PWA: сценарії, причини та рішення з кодом

Оновлено:
8 критичних помилок при інтеграції PWA: сценарії, причини та рішення з кодом

Ви додали manifest.json, зареєстрували Service Worker, протестували — все працює.

А через тиждень користувачі бачать стару версію сайту, Google індексує неправильні сторінки,

а аналітика показує вдвічі менше переглядів, ніж насправді.

Спойлер: 90% цих проблем — наслідок типових помилок при інтеграції PWA, які легко уникнути, якщо знати про них заздалегідь.

⚡ Коротко

  • Кешування HTML — найнебезпечніша помилка: користувачі бачать застарілий контент, а ви навіть не знаєте про це
  • Service Worker може заблокувати оновлення: без правильної стратегії активації старий код живе вічно
  • PWA на iOS має унікальні обмеження: Safari очищує кеш через 7 днів неактивності
  • 🎯 Ви отримаєте: 8 детальних розборів з форматом "Сценарій → Проблема → Рішення" та готовим кодом для кожної ситуації
  • 👇 Нижче — реальні приклади, фрагменти коду та чек-лист перевірки

📚 Зміст статті

🎯 Помилка 1. Кешування HTML-сторінок (найнебезпечніша помилка)

Кешування динамічного HTML

Якщо Service Worker кешує HTML-сторінки за стратегією Cache First, користувачі назавжди залишаються

на старій версії сайту. Нові товари, акції, виправлення багів — нічого з цього вони не побачать,

поки вручну не очистять кеш браузера.

Кешувати CSS та JS — правильно. Кешувати HTML із Cache First — шлях до невидимих оновлень.

📋 Сценарій

Ви розгорнули PWA для інтернет-магазину. Service Worker кешує всі відповіді, включаючи HTML-сторінки,

за стратегією Cache First — спочатку дивиться в кеш, і тільки якщо там немає — йде в мережу.

Через тиждень ви оновили каталог товарів, змінили ціни та додали банер з акцією. Але користувачі,

які вже відвідували сайт раніше, продовжують бачити стару версію.

❌ Проблема

Стратегія Cache First для HTML означає: браузер навіть не намагається перевірити, чи є новіша

версія на сервері. Він завжди віддає те, що вже є в кеші. Для статичних ресурсів (шрифти,

іконки, бібліотеки) це ідеально. Для HTML, який змінюється — це катастрофа.

Користувач не бачить оновлень, не бачить нових товарів, може навіть оформити замовлення

на товар, якого вже немає в наявності.

✅ Правильна стратегія

Використовуйте Network First для HTML-сторінок: спочатку запит йде на сервер,

і тільки якщо мережа недоступна — показується кешована версія. Так користувач завжди отримує

свіжий контент, а кеш слугує лише як резервний варіант для офлайн-режиму.

self.addEventListener('fetch', event => {

const url = new URL(event.request.url);

// Статичні ресурси — Cache First (змінюються рідко)

if (url.pathname.match(/\.(css|js|png|jpg|woff2)$/)) {

event.respondWith(

caches.match(event.request)

.then(cached => cached || fetch(event.request))

);

return;

}

// HTML-сторінки — Network First (завжди свіжий контент)

event.respondWith(

fetch(event.request)

.then(response => {

if (response.ok) {

const clone = response.clone();

caches.open('html-cache').then(cache =>

cache.put(event.request, clone)

);

}

return response;

})

.catch(() => caches.match(event.request))

);

});

Ключовий принцип: розділяйте кеш на два типи. Статика (CSS, JS, зображення) —

Cache First з версіонуванням через ім'я кешу. HTML та API — Network First, щоб дані завжди

були актуальними.

🎯 Service Worker блокує оновлення сторінок

Застарілий Service Worker

Без skipWaiting() та правильної стратегії активації новий Service Worker чекає,

поки користувач закриє всі вкладки сайту. Це може тривати дні або тижні — весь цей час

працює стара версія з потенційними багами.

Ви задеплоїли фікс критичного бага, але користувачі його не отримують — бо старий Service Worker досі "на варті".

📋 Сценарій

Ви знайшли та виправили серйозний баг у кешуванні — деяким користувачам показувалась чужа

сторінка профілю. Задеплоїли новий sw.js з виправленням. Але нова версія

Service Worker не активується — вона чекає в статусі "waiting", поки всі вкладки з вашим

сайтом не будуть закриті. Користувачі, які тримають вкладку відкритою постійно, можуть

не отримати оновлення тижнями.

❌ Проблема

За замовчуванням браузер не активує новий Service Worker, поки старий обслуговує хоча б одну

відкриту вкладку. Це зроблено для стабільності — щоб під час сесії користувача логіка кешування

не змінилася раптово. Але на практиці це означає, що критичні оновлення застрягають у черзі.

На мобільних пристроях ситуація ще гірша — Safari на iOS може тримати PWA "живою" у фоні

протягом тривалого часу.

✅ Правильна стратегія

Додайте skipWaiting() у подію install — це змушує новий Service Worker

негайно стати активним, не чекаючи закриття вкладок. А clients.claim() у подію

activate гарантує, що вже відкриті сторінки одразу перейдуть під контроль нового SW.

Додатково — версіонуйте кеш, щоб старі дані видалялися автоматично.

const CACHE_NAME = 'my-app-v3'; // Змінюйте версію при кожному деплої

self.addEventListener('install', event => {

// Не чекаємо закриття вкладок — активуємось негайно

self.skipWaiting();

event.waitUntil(

caches.open(CACHE_NAME)

.then(cache => cache.addAll(STATIC_ASSETS))

);

});

self.addEventListener('activate', event => {

event.waitUntil(

caches.keys().then(keys =>

Promise.all(

// Видаляємо всі старі версії кешу

keys.filter(key => key !== CACHE_NAME)

.map(key => caches.delete(key))

)

).then(() => {

// Беремо під контроль усі відкриті вкладки

return self.clients.claim();

})

);

});

Порада: автоматизуйте зміну версії кешу. Найпростіший варіант — використовуйте

timestamp або хеш git-коміту як частину імені кешу. Так ви ніколи не забудете оновити версію

після деплою.

🎯 PWA перехоплює навігацію (помилка роутингу)

Service Worker перехоплює чужі маршрути

Якщо Service Worker зареєстрований у кореневій директорії без фільтрації маршрутів,

він перехоплює запити до адмін-панелі, API-ендпоінтів, webhook-ів та сторонніх сервісів.

Це призводить до помилок авторизації, некоректних відповідей та "зависання" інтерфейсу.

Адміністратор не може увійти в адмін-панель, бо Service Worker віддає йому кешовану головну сторінку замість /admin/login.

📋 Сценарій

У вас є сайт з клієнтською частиною на / та адмін-панеллю на /admin.

Service Worker зареєстрований з scope: "/" і кешує всі GET-запити. Адміністратор

переходить на /admin/dashboard, але замість адмін-панелі бачить кешовану версію

головної сторінки. Або ще гірше — API-запити до /api/webhook від платіжної системи

перехоплюються SW і повертають HTML замість JSON.

❌ Проблема

Service Worker за замовчуванням перехоплює всі запити в межах свого scope. Якщо scope — це корінь

сайту /, він обробляє абсолютно все: клієнтські сторінки, адмін-панель, REST API,

webhook-и, файли завантаження. Без явної фільтрації маршрутів це призводить до непередбачуваної

поведінки — особливо для авторизованих сторінок, де кешування може показати дані іншого користувача.

✅ Правильна стратегія

Чітко визначте у fetch-обробнику, які маршрути має обробляти Service Worker,

а які — пропускати без втручання. Правило просте: все, що не є публічним клієнтським контентом,

повинно проходити повз SW напряму до сервера.

self.addEventListener('fetch', event => {

const url = new URL(event.request.url);

// Пропускаємо все, що не потребує кешування

if (event.request.method !== 'GET') return;

if (url.pathname.startsWith('/api/')) return;

if (url.pathname.startsWith('/admin')) return;

if (url.pathname.startsWith('/webhook')) return;

if (url.pathname.startsWith('/login')) return;

if (url.pathname.startsWith('/register')) return;

if (url.pathname.startsWith('/logout')) return;

// Авторизовані сторінки — не кешуємо

if (url.pathname.startsWith('/dashboard')) return;

if (url.pathname.startsWith('/profile')) return;

if (url.pathname.startsWith('/payment')) return;

// Аудіо та великі файли — не кешуємо

if (url.pathname.startsWith('/audio')) return;

if (url.pathname.startsWith('/upload')) return;

// Тільки публічний контент — Network First

event.respondWith(

fetch(event.request)

.then(response => {

if (response.ok) {

const clone = response.clone();

caches.open('public-cache').then(c => c.put(event.request, clone));

}

return response;

})

.catch(() => caches.match(event.request))

);

});

Принцип "білого списку": замість того, щоб думати "що виключити", краще визначити

"що саме кешувати". Публічні сторінки (головна, блог, каталог, FAQ) — кешуємо. Все інше — пропускаємо.

Це безпечніше, ніж намагатися передбачити всі маршрути, які не можна кешувати.

🎯 SPA-навігація без pageview подій

Аналітика втрачає дані

У Single Page Application (SPA) переходи між сторінками відбуваються без перезавантаження.

Google Analytics та інші системи аналітики фіксують тільки перше завантаження, а всі наступні

переходи — невидимі. Ви втрачаєте 60-80% реальних даних про поведінку користувачів.

За аналітикою у вас 1000 переглядів на день. Насправді — 5000. Але ви цього не знаєте, бо SPA "з'їдає" pageview.

📋 Сценарій

Ви запустили PWA як SPA на React або Vue. Користувач заходить на головну сторінку — Google Analytics

фіксує pageview. Далі він переходить на каталог, відкриває товар, читає відгуки — але все це

відбувається без перезавантаження сторінки (client-side routing). GA не фіксує жодного з цих

переходів. У вашому звіті — 1 перегляд замість 4.

❌ Проблема

Класичний Google Analytics (і більшість аналітичних систем) фіксує pageview при завантаженні

сторінки — коли браузер виконує повний запит до сервера. У SPA цього не відбувається: JavaScript

змінює URL через History API та підставляє новий контент без перезавантаження.

Наслідки: некоректна воронка конверсії, заниження популярних сторінок, неможливість оцінити

ефективність контенту та рекламних кампаній.

✅ Правильна стратегія

Відстежуйте зміни URL через History API та вручну відправляйте pageview при кожному переході.

Для Google Analytics 4 (GA4) використовуйте подію page_view. Для серверних додатків

на Thymeleaf / Spring Boot, де кожна сторінка — це повний запит, ця проблема менш актуальна,

але якщо ви використовуєте AJAX-навігацію або htmx — перевірте.

// Для SPA: відстежуємо кожну зміну маршруту

// React Router, Vue Router або ручна навігація

function trackPageView(path) {

gtag('event', 'page_view', {

page_path: path,

page_title: document.title

});

}

// Варіант 1: слухаємо popstate (кнопки "назад/вперед")

window.addEventListener('popstate', () => {

trackPageView(window.location.pathname);

});

// Варіант 2: перехоплюємо pushState

const originalPushState = history.pushState;

history.pushState = function() {

originalPushState.apply(this, arguments);

trackPageView(arguments[2]); // третій аргумент — URL

};

// Варіант 3: для React Router

// у кореневому компоненті

useEffect(() => {

trackPageView(location.pathname);

}, [location.pathname]);

Важливо: якщо ваш PWA побудований на серверному рендерингу (Thymeleaf, Django,

Laravel) і кожна сторінка — це окремий HTTP-запит, ця помилка вас не стосується. GA працюватиме

коректно "з коробки". Проблема актуальна саме для SPA-фреймворків (React, Vue, Angular).

🎯 Проблеми з canonical URL

Дублювання сторінок в індексі Google

PWA може створити кілька версій однієї сторінки: ?source=pwa,

?utm_source=homescreen, з trailing slash та без. Google індексує їх як різні

сторінки, розмиваючи SEO-вагу та створюючи дублі в пошуковій видачі.

Одна сторінка — три URL в індексі Google. Ваш SEO-трафік ділиться на три замість того, щоб концентруватися на одному.

📋 Сценарій

У manifest.json ви вказали "start_url": "/?source=pwa", щоб

відстежувати в аналітиці, скільки людей заходять через встановлений PWA. Також маркетолог

додав UTM-мітки для рекламних кампаній. В результаті одна й та сама головна сторінка доступна

за трьома адресами: /, /?source=pwa і

/?utm_source=homescreen. Google бачить три різні сторінки з однаковим контентом.

❌ Проблема

Пошукові роботи індексують URL повністю — з усіма параметрами. Без правильного canonical-тегу

Google не знає, яку версію вважати основною. Він може обрати будь-яку з них — або навіть

вважати їх дублями та знизити рейтинг усіх трьох. Це класична проблема "розмивання" SEO-ваги.

Особливо болюче для сайтів, де кожна сторінка — це потенційна точка входу з пошуку.

✅ Правильна стратегія

Завжди вказуйте canonical URL без параметрів відстеження. У manifest.json можна

залишити start_url з параметром для аналітики, але на самій сторінці canonical

повинен вказувати на чисту URL. Також переконайтеся, що canonical однаковий для версій з

trailing slash та без нього.

<!-- На КОЖНІЙ сторінці сайту -->

<link rel="canonical" href="https://example.com/catalog">

<!-- Навіть якщо реальна URL: -->

<!-- https://example.com/catalog?source=pwa -->

<!-- https://example.com/catalog?utm_source=homescreen -->

<!-- https://example.com/catalog/ (з trailing slash) -->

<!-- manifest.json — тут параметр допустимий для аналітики -->

{

"start_url": "/?source=pwa"

}

<!-- Thymeleaf приклад -->

<link rel="canonical" th:href="${pageSEO.canonicalUrl}">

<!-- Контролер Spring Boot -->

// Canonical завжди без параметрів

String canonical = "https://kazkiua.com" + request.getRequestURI();

seo.setCanonicalUrl(canonical); // без ?source=pwa

Перевірка: відкрийте Google Search Console → Сторінки → Виключені →

"Дублікат без канонічного тегу". Якщо бачите там свої сторінки з параметрами — canonical

налаштований неправильно.

🎯 HTTPS забули на піддомені

Service Worker не реєструється без HTTPS

Service Worker — ключовий компонент PWA — працює виключно через HTTPS (єдиний виняток —

localhost для розробки). Якщо ваш піддомен (api.example.com,

cdn.example.com) працює через HTTP, SW не зможе кешувати ресурси з цього джерела.

Основний домен на HTTPS, а CDN для зображень — на HTTP. Service Worker мовчки ігнорує всі картинки.

📋 Сценарій

Ваш сайт https://example.com працює через HTTPS. Service Worker зареєстрований

та кешує сторінки. Але зображення завантажуються з CDN на http://cdn.example.com

(без SSL). При спробі кешувати ці зображення SW отримує помилку mixed content — браузер блокує

HTTP-запити зі сторінки, завантаженої через HTTPS. В результаті при офлайн-режимі всі

зображення зникають.

❌ Проблема

Вимога HTTPS поширюється не тільки на основний домен, а й на всі ресурси, які завантажуються

на сторінці. Mixed content (змішування HTTPS та HTTP) блокується сучасними браузерами.

Service Worker навіть не зможе виконати fetch() до HTTP-ресурсу зі сторінки на HTTPS.

Ця помилка особливо підступна, бо все працює при активному інтернеті (браузер завантажує

зображення напряму), але ламається в офлайн-режимі (SW не може віддати некешоване).

✅ Правильна стратегія

Переконайтеся, що абсолютно всі ресурси — основний домен, піддомени, CDN, зовнішні API —

працюють через HTTPS. Використовуйте безкоштовні сертифікати Let's Encrypt. Для CDN-сервісів

(Cloudinary, AWS CloudFront, Cloudflare) HTTPS зазвичай увімкнений за замовчуванням — перевірте це.

<!-- ❌ НЕПРАВИЛЬНО: mixed content -->

<img src="http://cdn.example.com/photo.jpg">

<script src="http://analytics.example.com/tracker.js"></script>

<!-- ✅ ПРАВИЛЬНО: все через HTTPS -->

<img src="https://cdn.example.com/photo.jpg">

<script src="https://analytics.example.com/tracker.js"></script>

<!-- ✅ АБО: protocol-relative URL (використовує протокол сторінки) -->

<img src="//cdn.example.com/photo.jpg">

<!-- Перевірка в DevTools: Console → фільтр "Mixed Content" -->

<!-- Або: Security tab → перевірте статус кожного ресурсу -->

Швидка перевірка: відкрийте DevTools → Console та шукайте попередження

"Mixed Content". Або перейдіть на вкладку Security — вона покаже, які ресурси завантажуються

через небезпечне з'єднання.

🎯 manifest.json без правильного scope

PWA "захоплює" чужі URL

Параметр scope у manifest.json визначає, які URL належать вашому PWA. Без нього

або з занадто широким scope PWA може перехоплювати навігацію на сторонні сервіси,

платіжні шлюзи та OAuth-сторінки, ламаючи критичні потоки.

Користувач натискає "Оплатити" — і замість переходу на платіжну сторінку бачить помилку, бо PWA намагається відкрити її у своєму вікні.

📋 Сценарій

Ваш PWA встановлений на домашній екран. Користувач оформляє замовлення та натискає "Оплатити".

Сайт перенаправляє на https://pay.example.com/checkout — зовнішній платіжний шлюз.

Але PWA відкриває цю URL у своєму standalone-вікні замість зовнішнього браузера. Платіжна сторінка

не працює коректно без повного браузерного середовища, і оплата зривається.

❌ Проблема

Якщо scope не вказаний у manifest.json, браузер визначає його автоматично на основі

розташування маніфесту. Це може призвести до того, що PWA вважає своїми URL, які до нього

не належать. Зовнішні посилання, які повинні відкриватися у браузері (платежі, OAuth, соціальні

мережі), відкриваються у вікні PWA — і часто ламаються.

✅ Правильна стратегія

Явно вкажіть scope у manifest.json. Для більшості сайтів це "/" — корінь

вашого домену. URL за межами scope автоматично відкриватимуться у зовнішньому браузері.

Для зовнішніх посилань у вашому HTML додавайте target="_blank".

// manifest.json

{

"name": "My PWA",

"short_name": "MyPWA",

"start_url": "/",

"scope": "/",

"display": "standalone",

"background_color": "#ffffff",

"theme_color": "#4f46e5"

}

// Якщо PWA живе у підкаталозі:

{

"start_url": "/app/",

"scope": "/app/"

}

// У HTML — зовнішні посилання відкриваємо у браузері

<a href="https://pay.example.com/checkout"

target="_blank"

rel="noopener noreferrer">

Оплатити

</a>

<a href="https://accounts.google.com/oauth"

target="_blank"

rel="noopener noreferrer">

Увійти через Google

</a>

Правило: все, що виходить за межі вашого домену — платежі, OAuth, соціальні

мережі — повинно мати target="_blank". Це гарантує відкриття у повному браузері

незалежно від налаштувань scope.

🎯 iOS Safari очищує кеш через 7 днів

Apple видаляє дані PWA при неактивності

Safari на iOS автоматично очищує весь кеш PWA (Cache API, IndexedDB, LocalStorage), якщо

користувач не відкривав додаток протягом 7 днів. Це означає, що офлайн-функціональність,

збережені дані та навіть авторизація — все зникає без попередження.

Користувач відкриває PWA через тиждень відпустки — і починає все з нуля: авторизація скинута, збережені дані зникли, кеш порожній.

📋 Сценарій

Ви створили PWA для читання статей офлайн. Користувач зберіг 20 статей у кеш, щоб читати

в літаку. Але рейс перенесли на 10 днів. Коли він нарешті відкриває PWA — кеш порожній.

Safari видалив усі збережені дані, бо PWA не використовувався більше 7 днів.

Жодного попередження — просто порожній екран.

❌ Проблема

Apple впровадила політику Intelligent Tracking Prevention (ITP), яка обмежує зберігання

даних для веб-сайтів. Для PWA на iOS це означає: якщо користувач не відвідує додаток протягом

7 днів, Safari має право видалити всі дані, записані через JavaScript — Cache API, IndexedDB,

LocalStorage, SessionStorage. Це обмеження не стосується нативних додатків з App Store,

тільки PWA. На Android такого обмеження немає.

✅ Правильна стратегія

Повністю обійти це обмеження неможливо — це рішення Apple на рівні операційної системи.

Але можна мінімізувати наслідки: не покладайтеся на клієнтський кеш як єдине сховище даних,

зберігайте критичні дані на сервері, і при відкритті PWA завжди перевіряйте наявність кешу

та відновлюйте його за потреби.

// При кожному запуску PWA — перевіряємо стан кешу

async function checkAndRestoreCache() {

const cache = await caches.open('my-app-v3');

const keys = await cache.keys();

if (keys.length === 0) {

console.log('Кеш порожній — відновлюємо базові ресурси');

await cache.addAll(STATIC_ASSETS);

// Якщо є авторизація — перевіряємо токен

const token = localStorage.getItem('auth_token');

if (!token) {

// Токен теж видалений — перенаправляємо на логін

window.location.href = '/login';

}

}

}

// Викликаємо при завантаженні

if ('serviceWorker' in navigator) {

checkAndRestoreCache();

}

// Порада: зберігайте критичні дані на сервері

// Клієнтський кеш — це прискорення, а не сховище

// ❌ Не зберігайте тут: чернетки, налаштування, прогрес

// ✅ Зберігайте на сервері, а кеш — лише для швидкості

Головне правило для iOS: клієнтський кеш — це оптимізація швидкості, а не

надійне сховище. Все важливе повинно зберігатися на сервері. Кеш може зникнути будь-якого

моменту — і ваш додаток повинен бути готовий до цього.

❓ Часті питання (FAQ)

Чи потрібен Service Worker, якщо мій сайт — серверний (Thymeleaf, Django, Laravel)?

Так, якщо ви хочете PWA-функціональність: встановлення на домашній екран, офлайн-режим,

швидке завантаження. Але стратегія кешування буде простішою — Network First для HTML,

Cache First для статики. SPA-специфічні проблеми (помилка 4) вас не стосуються.

Як перевірити, чи правильно працює мій Service Worker?

Chrome DevTools → Application → Service Workers. Тут ви побачите статус SW (active, waiting,

redundant), зможете примусово оновити або зупинити його. Вкладка Cache Storage покаже,

що саме закешовано. Також запустіть Lighthouse → PWA — він покаже список проблем.

Чи можна відкликати (видалити) Service Worker, якщо він зламав сайт?

Так. Задеплойте новий sw.js з порожнім fetch-обробником, або використайте

self.registration.unregister(). У крайньому випадку — користувач може вручну

видалити SW через DevTools → Application → Service Workers → Unregister.

Чи впливає PWA на SEO?

Позитивно — якщо правильно налаштований. PWA покращує Core Web Vitals (швидкість завантаження),

що є фактором ранжування Google. Але неправильне кешування HTML (помилка 1) або дублі

canonical (помилка 5) можуть нашкодити SEO.

Обмеження iOS — це назавжди?

Ситуація повільно покращується. Apple додала push-повідомлення в iOS 16.4, background sync

в Safari 18+. Але 7-денне обмеження кешу поки залишається. Європейський DMA тисне на Apple,

але реальних змін у 2026 році поки немає.

✅ Висновки та чек-лист перевірки

Коли я інтегрував PWA у свій проєкт Kazki AI — сервіс

персоналізованих аудіоказок для дітей на Spring Boot — я зіткнувся з більшістю

помилок із цього списку. Не в теорії, а на продакшені, з реальними користувачами. Саме тому

я вирішив зібрати цей матеріал: кожен сценарій тут — це або мій власний досвід, або

проблема, яку я спостерігав у колег-розробників.

Головний висновок, до якого я прийшов: PWA — це не "додав manifest.json і готово".

Це архітектурне рішення, яке впливає на кешування, аналітику, SEO, авторизацію та поведінку

на різних платформах. На Android все працює майже ідеально — користувачі Kazki AI отримали

автоматичний банер встановлення, миттєве завантаження сторінок і повноекранний режим без

адресного рядка. На iOS ситуація складніша — автоматичного банеру немає, кеш може зникнути

через тиждень неактивності, і користувачам потрібно пояснювати, як додати додаток на екран

через меню "Поділитися" в Safari.

Найнебезпечніша помилка, на мою думку — це кешування HTML зі стратегією Cache First.

Вона невидима: сайт працює, сторінки відкриваються, але користувач бачить застарілу версію

і навіть не підозрює про це. У випадку Kazki AI, де контент генерується динамічно —

нові казки, лімити підписок, персоналізація — це було б критично. Тому я з самого початку

обрав Network First для HTML і повністю виключив з кешування авторизовані сторінки,

API-запити та аудіофайли. Результат: сайт завантажується швидше, офлайн показує хоча б

базову оболонку, а дані завжди актуальні.

Ще один важливий урок — версіонування кешу. Після кожного деплою я змінюю

CACHE_NAME (наприклад, з kazki-v2 на kazki-v3),

і старий кеш автоматично видаляється. Це просте правило, але без нього користувачі

залишаються на старій версії сайту на невизначений час.

Мій чек-лист перед кожним деплоєм PWA:

1. Кешування: HTML — Network First, статика — Cache First з версіонуванням.

2. Оновлення SW: skipWaiting() + clients.claim() + нова версія кешу.

3. Роутинг: API, адмін, авторизація, платежі — виключені з обробки SW.

4. Аналітика: pageview відправляється при кожному переході (актуально для SPA).

5. Canonical: кожна сторінка має canonical URL без UTM-параметрів.

6. HTTPS: всі ресурси, включаючи CDN та піддомени — через HTTPS.

7. Scope: manifest.json має явний scope, зовнішні посилання — target="_blank".

8. iOS: критичні дані — на сервері, клієнтський кеш — лише для швидкості.

Цей чек-лист я проходжу перед кожним релізом Kazki AI. Він займає 5 хвилин, але рятує

від годин дебагу та незадоволених користувачів. Сподіваюсь, мій досвід допоможе вам

уникнути тих самих граблів і запустити PWA, який дійсно покращить досвід ваших користувачів.

Якщо ви тільки починаєте знайомство з PWA — рекомендую спочатку прочитати мою попередню статтю

Progressive Web Apps (PWA) — повний гід для бізнесу та розробників,

де я детально розглянув що таке PWA, як вони працюють, порівняння з нативними додатками

та покрокову інструкцію створення.

📖 Джерела та корисні посилання

Останні статті

Читайте більше цікавих матеріалів

Proof of Personhood: навіщо світу потрібно доводити що ти людина

Proof of Personhood: навіщо світу потрібно доводити що ти людина

У 2026 році питання «ти людина чи бот?» перестало бути технічною формальністю і стало інфраструктурною проблемою інтернету. Генеративний ШІ знищив більшість методів верифікації, розроблених за останні 25 років. Ця стаття — аналіз того, чому це сталось, що пропонує ринок і де проходить межа між...

World Orb і приватність: ризики біометрії райдужки

World Orb і приватність: ризики біометрії райдужки

Сканування райдужки — технічно один із найзахищеніших методів біометричної верифікації. Але технічна захищеність і відсутність ризиків — не одне і те саме. У цій статті ми розбираємо, що насправді відбувається з вашими даними, де архітектура World Orb дійсно захищає — і де залишаються відкриті...

World ID, Face ID і державна біометрія: у чому різниця

World ID, Face ID і державна біометрія: у чому різниця

Три системи збирають біометричні дані. Всі три стверджують, що захищають приватність. Але вони принципово різні за архітектурою, метою і моделлю загроз — і «безпечніша» система залежить від того, від чого саме ви захищаєтесь. Коротко: ця стаття — аналітичне порівняння трьох моделей...

Як World Orb перетворює райдужку на цифровий доказ

Як World Orb перетворює райдужку на цифровий доказ

За 30 секунд сканування Orb виконує чотири складні операції: знімає райдужку в інфрачервоному діапазоні, перетворює її на числовий код, перевіряє унікальність серед мільйонів записів — і робить все це так, щоб ніхто, включно з самою компанією, не міг встановити вашу особу.Коротко: ця стаття —...

Що таке World Orb і World ID: повний розбір

Що таке World Orb і World ID: повний розбір

Уявіть: ви підходите до металевої кулі розміром з боулінговий м'яч, дивитесь у неї кілька секунд — і отримуєте цифровий паспорт, який підтверджує, що ви реальна людина, а не бот. Коротко: World Orb — це біометричний пристрій, який сканує райдужку ока і генерує унікальний цифровий...

PWA чи нативний додаток у 2026: порівняння, сценарії вибору та реальний кейс

PWA чи нативний додаток у 2026: порівняння, сценарії вибору та реальний кейс

Ви хочете мобільний додаток, але не знаєте, чи варто витрачати місяці на розробку під iOS та Android,чи можна обійтися Progressive Web App. Це питання, з яким стикається кожен бізнес та розробник-одинак.Спойлер: для 70% проєктів PWA — це швидше, дешевше та достатньо, але є сценарії,де без нативного...