Як перетворити свій сайт на PWA-додаток

Як перетворити свій сайт на PWA-додаток

Progressive Web App (PWA) — це звичайний веб-сайт, який браузер може встановити на пристрій як нативний додаток. Користувач отримує іконку на робочому столі або в меню, додаток відкривається без адресного рядка, працює офлайн і може надсилати push-сповіщення. Для розробника — це той самий HTML/CSS/JS, без App Store і без нативної розробки.

Для перетворення сайту на PWA потрібні три речі: HTTPS, Web App Manifest і Service Worker.


1. HTTPS

PWA працює тільки на захищеному з'єднанні. Якщо сайт вже на HTTPS — цей пункт вже виконано. Для локальної розробки localhost є виключенням і вважається безпечним.


2. Web App Manifest

Manifest — це JSON-файл, який описує додаток: назву, іконки, кольори, режим відображення. Саме він дозволяє браузеру запропонувати користувачу «встановити» сайт.

Створіть файл manifest.json в корені сайту:

{
  "name": "Моя Крамниця",
  "short_name": "Крамниця",
  "description": "Онлайн-магазин товарів для дому",
  "start_url": "/",
  "display": "standalone",
  "background_color": "#ffffff",
  "theme_color": "#1a73e8",
  "orientation": "portrait-primary",
  "icons": [
    {
      "src": "/icons/icon-192.png",
      "sizes": "192x192",
      "type": "image/png",
      "purpose": "any maskable"
    },
    {
      "src": "/icons/icon-512.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "any maskable"
    }
  ]
}

Основні параметри:

  • name — повна назва (відображається при встановленні).
  • short_name — коротка назва під іконкою (до 12 символів).
  • start_url — яка сторінка відкривається при запуску. Можна додати UTM: / або /?source=pwa.
  • display — режим відображення: standalone (без браузерного UI), fullscreen, minimal-ui, browser.
  • theme_color — колір рядка статусу і заголовка браузера.
  • background_color — колір фону сплеш-екрану при завантаженні.
  • icons — обов'язково потрібні розміри 192×192 і 512×512 у PNG.

Підключіть manifest у <head> кожної сторінки:

<link rel="manifest" href="/manifest.json">
<meta name="theme-color" content="#1a73e8">

Для Safari (iOS) додатково:

<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="default">
<meta name="apple-mobile-web-app-title" content="Крамниця">
<link rel="apple-touch-icon" href="/icons/icon-192.png">

iOS досі не підтримує стандартний manifest повністю, тому ці мета-теги обов'язкові для нормальної роботи на iPhone.


3. Service Worker

Service Worker — це JavaScript-файл, який браузер реєструє окремо від сторінки. Він перехоплює мережеві запити і може відповідати з кешу — саме це дає офлайн-режим і швидке завантаження.

Реєстрація

Додайте в основний JS або перед </body>:

if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/sw.js')
      .then(reg => console.log('SW зареєстровано:', reg.scope))
      .catch(err => console.error('SW помилка:', err));
  });
}

Файл sw.js

Мінімальний service worker з кешуванням статики:

const CACHE_NAME = 'my-site-v1';

const STATIC_ASSETS = [
  '/',
  '/index.html',
  '/css/style.css',
  '/js/app.js',
  '/icons/icon-192.png',
  '/icons/icon-512.png',
  '/offline.html'
];

// Встановлення — кешуємо статику
self.addEventListener('install', event => {
  event.waitUntil(
    caches.open(CACHE_NAME)
      .then(cache => cache.addAll(STATIC_ASSETS))
      .then(() => self.skipWaiting())
  );
});

// Активація — видаляємо старі кеші
self.addEventListener('activate', event => {
  event.waitUntil(
    caches.keys().then(keys =>
      Promise.all(
        keys.filter(key => key !== CACHE_NAME)
            .map(key => caches.delete(key))
      )
    ).then(() => self.clients.claim())
  );
});

// Fetch — спочатку кеш, потім мережа
self.addEventListener('fetch', event => {
  // Ігноруємо не-GET запити і запити до інших доменів
  if (event.request.method !== 'GET') return;
  if (!event.request.url.startsWith(self.location.origin)) return;

  event.respondWith(
    caches.match(event.request)
      .then(cached => {
        if (cached) return cached;

        return fetch(event.request)
          .then(response => {
            // Кешуємо успішні відповіді
            if (response.status === 200) {
              const clone = response.clone();
              caches.open(CACHE_NAME)
                .then(cache => cache.put(event.request, clone));
            }
            return response;
          })
          .catch(() => {
            // Якщо мережі немає — показуємо офлайн-сторінку
            if (event.request.headers.get('accept').includes('text/html')) {
              return caches.match('/offline.html');
            }
          });
      })
  );
});

Стратегії кешування

Вище показана стратегія Cache First (спочатку кеш) — підходить для статики. Для динамічного контенту краще Network First (спочатку мережа, кеш як запасний варіант):

// Network First для API-запитів
self.addEventListener('fetch', event => {
  if (event.request.url.includes('/api/')) {
    event.respondWith(
      fetch(event.request)
        .then(response => {
          const clone = response.clone();
          caches.open(CACHE_NAME)
            .then(cache => cache.put(event.request, clone));
          return response;
        })
        .catch(() => caches.match(event.request))
    );
  }
});

4. Офлайн-сторінка

Створіть /offline.html — проста сторінка, яка показується коли немає мережі і потрібний URL не в кеші:

<!DOCTYPE html>
<html lang="uk">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1">
  <title>Немає з'єднання</title>
  <style>
    body { font-family: sans-serif; text-align: center; padding: 60px 20px; color: #333; }
    h1 { font-size: 24px; }
    p { color: #666; }
  </style>
</head>
<body>
  <h1>???? Немає з'єднання з інтернетом</h1>
  <p>Перевірте мережу і спробуйте ще раз.</p>
  <button onclick="location.reload()">Оновити сторінку</button>
</body>
</html>

5. Іконки

Мінімально потрібні два розміри: 192×192 і 512×512 px у PNG. Для purpose: "maskable" важливо, щоб основний контент іконки вміщувався у центральних 80% площі — решта може бути обрізана заокругленою маскою Android.

Згенерувати всі розміри автоматично можна через realfavicongenerator.net або maskable.app для перевірки maskable-варіанту.


6. Перевірка

Відкрийте Chrome DevTools → вкладка Application:

  • Manifest — перевірте, що маніфест завантажився і всі поля розпізнані.
  • Service Workers — має бути статус activated and running.
  • Storage → Cache Storage — тут видно що закешовано.

Також запустіть Lighthouse (DevTools → вкладка Lighthouse → категорія Progressive Web App) — він перевіряє всі критерії PWA і показує що не так.

У Chrome на десктопі кнопка встановлення з'явиться в адресному рядку (іконка монітора зі стрілкою). На Android Chrome покаже банер «Додати на головний екран» після кількох відвідувань.


Оновлення PWA

Коли потрібно оновити кеш — змініть константу CACHE_NAME (наприклад, my-site-v2). При наступному відвідуванні service worker завантажить нову версію, а при активації видалить старий кеш.

Якщо потрібно оновлення відразу при новому деплої — додайте в activate:

self.addEventListener('activate', event => {
  event.waitUntil(self.clients.claim());
});

І при реєстрації в HTML:

navigator.serviceWorker.register('/sw.js')
  .then(reg => {
    reg.addEventListener('updatefound', () => {
      const newWorker = reg.installing;
      newWorker.addEventListener('statechange', () => {
        if (newWorker.state === 'activated') {
          // Можна показати повідомлення "Доступна нова версія"
          location.reload();
        }
      });
    });
  });

Готові рішення для CMS

Якщо немає бажання писати service worker вручну — є готові інструменти:

Workbox (від Google) — бібліотека, яка генерує service worker з потрібними стратегіями кешування через конфіг. Підходить для складних сайтів з різними типами ресурсів.

WordPress — плагіни Super PWA або PWA for WP & AMP додають маніфест і service worker без написання коду.

OpenCart — кастомні модулі або ручне додавання маніфесту і SW через редактор шаблонів.


Мобільний додаток для сайту - це просто

Мінімальний PWA — це три файли: manifest.json, sw.js і offline.html, плюс кілька рядків у <head>. Для більшості сайтів це реалізується за пів дня. Результат: встановлюваний додаток без App Store, кешована статика для швидкого завантаження і базовий офлайн-режим.

Для просунутих сценаріїв (push-сповіщення, фонова синхронізація, складне кешування) є Workbox і розширений Service Worker API — але це вже тема для окремої статті.

Інші статті

Як вивести віджет банки Монобанку на свій сайт
Як вивести віджет банки Монобанку на свій сайт

Правильно налаштований віджет банки Монобанк підвищить довіру відвідувачів до збору. Використовуйте ..

Як збільшити ліміти POST запитів в параметрах PHP
Як збільшити ліміти POST запитів в параметрах PHP

Коли ви працюєте з PHP скриптами, які обробляють великі обсяги даних через POST запити, ви можете зі..

Як створити найповнішу graph розмітку компанії
Як створити найповнішу graph розмітку компанії

Повноцінна graph розмітка трансформує присутність компанії в пошукових системах. Збільшується видимі..

Коментарі

Написати коментар