Gratulujeme! Úspěšně jste se přihlásili k odběru novinek Frontend Garden.
Ajaj. Při pokusu o přihlášení k odběru novinek došlo k chybě. Zkuste to prosím znovu.
Frontend Garden
  • Články
  • Slovník nové
  • Instagram
  • GitHub
14. říjen 2020 —
  • PWA,
  • JavaScript,
  • Rychlost
— čtení na 12 min.

Progresivní webové aplikace, díl II. — Jak zlepšit performance metriky a fungovat i offline?

I s elementárními znalostmi JavaScriptu můžete během chvíle vylepšit svůj web a poskytnout uživatelům prožitek, který znají z nativních aplikací. V pokračování minisérie o PWA se dozvíte, jak umožnit instalaci aplikace na domovskou obrazovku nebo jak začít web vykreslovat výrazně rychleji.

Kateřina Klouček Dlouhá

Kateřina Klouček Dlouhá

Katka je kodérkou od roku 2017. V současné chvíli pracuje jako Design System Architect. Oplývá entuziasmem pro vše, co souvisí s UX nebo typografií. Více o autorovi

Progresivní webové aplikace, díl II. — Jak zlepšit performance metriky a fungovat i offline?

V minulém dílu jste se mohli dozvědět, co jsou progresivní webové aplikace vůbec zač a kdy je vhodné o nich začít uvažovat. Pokud je teď třípísmenná zkratka PWA ve vašem hledáčku a chcete se dozvědět něco k samotné implementaci, tento a následující díl minisérie o PWA vám poskytnou detailnější vhled do problematiky.

✍🏻
Článek je druhým dílem minisérie o PWA. První díl →

V následujících odstavcích si ukážeme, jak docílit:

  1. stažení webové stránky na zařízení uživatele,
  2. rychlejšího zobrazení webu po prvním načtení,
  3. nezávislosti webové stránky na internetovém připojení.

Co musím udělat pro to, abych sestavil PWA?

Na stránkách od Google Developers můžete najít velmi podrobný checklist se všemi požadavky na plnohodnotnou PWA. U každého bodu dostanete odpověď na klíčové otázky — co, proč a jak. Neboli: Co to je? Proč by mě to mělo zajímat? Jak na implementaci?

PWA checklist ze stránky web.dev/pwa-checklist

Protože není cílem a především ani možné detailně sepsat splnění všech kritérií na PWA v tomto článku, budeme předpokládat, že váš web splňuje následující:

  1. Web servírujete ze zabezpečené domény přes HTTPS.
    V případě, že tomu tak není, doporučuji si přečíst článek o nasazování webu na HTTPS.
  2. Stránky jsou plně responzivní a fungují i napříč prohlížeči.
    Pokud vyvíjíte s přístupem mobile first, nemusíte se bát, že byste kritérium responzivity nesplňovali. Pokud si nejste jistí, použijte Lighthouse audit nebo Mobile Friendly Test, abyste zjistili, zda se vaše stránka adekvátně vykresluje i na mobilních zařízeních nebo tabletech. Nebo můžete váš web proklikat prostřednictvím Chrome pluginu Responsive viewer.
  3. Každá stránka je odkazovatelná přes URL a obsahuje metadata pro sociální sítě.
    Ujistěte se, že každá stránka má svůj unikátní odkaz a v hlavičce jsou dostupné informace pro sociální sítě jako Twitter, Facebook nebo Instagram. Facebook i Twitter poskytují zdarma debugovací rozhraní na otestování vzhledu odkazu stránky na své sociální síti. Díky tomu bude aplikace snáze dohledatelná v prohlížečích.

Pojďme se nyní podívat, jak umožnit uživatelům stažení webové aplikace na zařízení (zatím nehledě na specifika některých OS).

Instalace webové stránky na zařízení

Pokud chceme učinit naši aplikaci instalovatelnou z webového prohlížeče či nativní platformy Google Play, musí mít definovaný web app manifest. Chrome navíc vyžaduje zaregistrovaný service worker, ale o něm se budeme bavit až v další kapitole.

Web App Manifest je JSON soubor, který poskytuje všechny potřebné informace o webové aplikaci, aby bylo možné ji stáhnout a chovala se tak jako všechny ostatní nativní aplikace v telefonu. Měl by vždy obsahovat minimálně název aplikace, ikony, které se mohou používat, a počáteční URL. Pokud chceme, aby správně fungovalo přidání na domovskou stránku (někdy označované jako A2HS – Add to Home Screen), musíme navíc definovat barvu pozadí a režim zobrazení aplikace.

Pro lepší představu, zde je ukázka jednoho takového manifestu a napojení na web.

// manifest.webmanifest nebo manifest.json

{
  "background_color": "#fff",
  "description": "První český online magazín o webovém frontendu",
  "display": "standalone",
  "icons": [
    {
      "src": "/images/icons-192.png",
      "type": "image/png",
      "sizes": "192x192"
    },
    {
      "src": "/images/icons-512.png",
      "type": "image/png",
      "sizes": "512x512"
    }
  ],
  "name": "Frontend Garden",
  "short_name": "Frontend Garden",
  "start_url": "/",
  "theme_color": "#40bf4f"
}
<!-- index.html -->

<link rel="manifest" href="/manifest.webmanifest" />

👇🏻 Je zapotřebí mít na paměti následující.

Chrome doporučuje, aby byly vždy definovány minimálně 2 velikosti ikon, a to o rozměrech 192 𐄂 192 px a 512 𐄂 512 px. Ostatní náležitosti doporučuju ověřit na webu konsorcia pro standardy WWW.

Pokud chcete podporovat i iOS 🍎:

  • Aby se aplikace otevírala v samostatném okně, musíme nastavit vlastnost display na standalone nebo vložit do hlavičky v index.html meta tag <meta name="apple-mobile-web-app-capable" content="yes">.
  • Pokud se název aplikace nevejde do 12 znaků a chcete se vyhnout jeho zkrácení, nebo tomu, že se nezobrazí vůbec, musíme opět vložit do hlavičky tag s názvem aplikace, který chceme, aby se zobrazoval na domovské stránce pod ikonou: <meta name="apple-mobile-web-app-title" content="Frontend Mag">.
  • iOS nepoužívá ikony definované v manifestu. Proto nesmíte zapomenout na vygenerování favicon pro iOS, na které se taktéž musíte odkázat v hlavičce kořenového HTML souboru.
  • Další užitečné triky pro iOS zařízení se můžete dočíst v článku Designing Native-Like Progressive Web Apps For iOS.

Chcete-li předejít špatnému ořezu ikon vlivem různých tvarů ikon mezi platformami, určitě stojí za zvážení maskovatelné ikony. Stačí pouze umístit do tzv. safe zone důležité oblasti ikony, které musí být zachovány. Velmi pěkný návod je například na stránkách web.dev.

0:00
/
Ukázka možných ořezů ikony webové aplikace napříč platformami. Převzato z web.dev

🎉 Voilà! Aplikaci by nyní mělo být možné nainstalovat na domovskou obrazovku a pracovat s ní (téměř) jako s nativní aplikací. Stačí jen při načtení webu potvrdit v banneru přidání stránky na domovskou obrazovku a pro příště už netřeba zadávat URL stránky do prohlížeče, nebo hledat v záložkách.

Ukázka instalovatelné aplikace Web.dev na Android zařízení v prohlížeči Chrome
Ukázka instalovatelné aplikace Web.dev v desktopové verzi prohlížeče Chrome

Podpora Web App Manifestu

Pokud nahlédneme do Can I Use, tak bohužel zjistíme, že s podporou na desktopu to vyjma prohlížečů Edge a Chrome není žádná sláva (ale to v mnohých případech není klíčové). Až na Operu, tak mobilní prohlížeče A2HS podporují.

Současná podpora Web App Manifestu napříč prohlížeči. Aktuální k 7. říjnu 2020

⚠️ S iOS Safari je to poněkud komplikovanější, jelikož nepodporuje událost beforeinstallprompt, která nám zobrazí banner na instalaci/přidání aplikace, proto je třeba se proklikat přes Share Sheet. Apple v současnou chvíli neumožňuje A2HS ve webviews, kterými je například Chrome nebo Firefox.

Ukázka instalovatelné aplikace Web.dev v iPadOS verzi prohlížeče Safari
📱
Pokud má být aplikace k dispozici ke stažení na Google Play, musíme učinit řadu dalších kroků. Psaní o tom by vystačilo na další článek, proto dychtivým zájemcům o toto téma zde alespoň poskytnu odkaz na velmi pěkný text: Google Play Store now open for Progressive Web Apps 😱.

Rychlejší zobrazení webu po prvním načtení

Aplikace nyní splňuje čtyři z výše zmíněných kritérií: je responzivní a zabezpečená (plynoucí z předpokladu), instalovatelná a částečně dohledatelná díky manifest souboru. Nyní bychom chtěli dosáhnout toho, aby byla plně dohledatelná, rychleji se načetl (téměř všechen) její obsah a aby fungovala i offline. K tomu nám dopomůže service worker.

👉🏻
Jestliže zvažujete provést následující úpravy i na svém webu, zkuste si pro zajímavost nejprve spustit audit webu, ať už v Chrome Dev Tools na záložce Lighthouse nebo na WebPageTest.org. Jakmile budete mít naimplementovaný service worker včetně cachování, zkuste audit spustit znovu a porovnat naměřené hodnoty.

Pro ty z vás, kteří se s tímto pojmem setkávají poprvé a nebo jim svět JavaScriptu není blízký, přiblížím význam a způsob fungování této technologie.

Service worker je speciálním typem web workeru, což je označení pro skript, který je spuštěn odděleně od hlavního vlákna pro vykreslování webové stránky. Stránku jako takovou neomezuje. Samotný service worker proto může odesílat push notifikace a synchronizovat data na pozadí, jelikož se jedná o programovatelnou proxy mezi stránkou a sítí, která umožňuje zachytit a ukládat síťové požadavky.

Je založený na promisách, což jsou programovací konstrukce, které představují hodnotu proměnné, která ještě není známá v době vykonání kódu. Vzhledem k tomu, že běží v odděleném vlákně, není možné z jeho instance přistupovat na prvky DOMu a pracovat tak s některými API jako XHR či cookies.

Jak tedy funguje instance service workeru? Jeho zapojení do chodu aplikace sestává ze tří fází:

  1. Registrace – do globálního objektu navigator se zaregistruje skript se service workerem (⚠️ tento skript musí být vždy samostatný soubor).
  2. Instalace – inicializuje se chování offline režimu.
  3. Aktivace – service worker plně přebírá kontrolu nad webovou aplikací podle definovaného chování. Pokud dochází k aktualizaci service workeru, zbavujeme se předchozích verzí mezipaměti.
Životní cyklus service workeru. Převzato z Google Developers

Při prvotním spuštění webové stránky se service worker zaregistruje do webového prohlížeče (za předpokladu, že prohlížeč podporuje tuto technologii, více v kapitole Podpora service workeru). Pokud registrace byla úspěšná, přichází proces instalace.

Instalace proběhne v případě, že service worker nebyl doposud pro web registrován, nebo byl registrován, ale došlo ke změně skriptu.

Poslední fází je aktivace. Ta nastane, pokud není žádný service worker aktivní, uživatel obnoví stránku, nebo se zavolá self.skipWaiting() v instalační fázi.

Jakmile máme service worker aktivní a neprovádí žádné operace, může nabývat dvou stavů: terminated, nebo fetching/messaging. Doporučuji bedlivě pracovat s DevTools, kde se pod záložkou Application skrývá sekce Service Workers, ve které můžete sledovat stav service workeru, a nejen to.

Ukázka DevTools okna při práci s moderními funkcemi prohlížečů.

Stručná rekapitulace k service workeru:

  1. Jedná se o programovatelnou proxy, pomocí níž můžeme řídit zpracování síťových požadavků na stránce.
  2. Umožňuje cachování dat a pomocí Cache API data zprostředkuje aplikaci v momentě, kdy prohlížeč pracuje bez připojení k internetové síti.
  3. Přijímá a zobrazuje push notifikace díky Push API a Nofications API.

Podpora Service Workeru

Opět platí, že – až na Operu – je podpora napříč prohlížeči poměrně slušná.

Současná podpora Service Workeru napříč prohlížeči. Aktuální k 7. říjnu 2020

A nyní k samotné implementaci...

Krok č. 1 – Registrace service workeru

Nejprve ze všeho musíme zaregistrovat service worker do globálního objektu navigator. Service worker registrujeme pouze v případě, že jej daný prohlížeč podporuje.

// register-sw.js

if ('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/sw.js')
  .then((registration) => {
    console.log('Service worker registered.');
  });
  .catch((error) => {
    console.error('Oh, no. Service worker registration failed: ', error);
  });
}

Pokud máme i vytvořený soubor sw.js v kořenovém adresáři, měli bychom po načtení stránky vidět v konzoli zprávu, že se service worker podařilo zaregistrovat.

Pakliže se nám podařilo úspěšně zaregistrovat service worker, můžeme přejít k jeho instalaci a aktivaci.

Krok č. 2 – Instalace a aktivace service workeru

Ze všeho nejdřív chceme nadefinovat název cache a statické soubory, které tvoří tzv. application shell, a vše následně uložit do mezipaměti.

// sw.js

// 0. Údaje o mezipaměti a relativních cestách k app shell souborům.
const CACHE_VERSION = 'v1';
const CACHE_NAME = 'frontend-garden-' + CACHE_VERSION;
const assetsToCache = [
  '/',
  '/built/css/main.css',
  '/built/js/main.js',
];

// 1. Inicializace mezipaměti.
self.addEventListener('install', (event) => {
  event.waitUntil(
    caches.open(CACHE_NAME) 
    .then(function (cache) {
      console.log('Opened cache.');
      return cache.addAll(assetsToCache);
    })
  );
});

// 2. Úklid po předchozích verzí service workeru.
self.addEventListener('activate', (event) => {
  event.waitUntil(
    caches.keys().then((cacheNames) => {
      cacheNames.map(function (cacheName) {
        if (cacheName.indexOf(CACHE_VERSION) < 0) {
         console.log(`Deleted cache ${cacheName}.`);
         return caches.delete(cacheName);
	    }
      });
    })
  );
});

Mnozí z vás si všimli, že události navěšujeme na objekt self. Jedná se o klíčové slovo, které se používá k přístupu k web workeru.

Krok č. 3 – Zpracování požadavků a jejich ukládání do mezipaměti

Jak už bylo zmíněno, service worker umí zachytávat a ukládat jednotlivé požadavky mezi stránkou a sítí. Událost fetch se spustí pokaždé, pokud se dotazujeme na nějaký zdroj, který spravuje service worker. Během této události řešíme, zdali chceme data ukládat a jak je zprostředkujeme stránce.

Jak zpracovávat požadavky na stránce

Existuje několik přístupů, jak můžeme zpracovat requesty na stránce:

Cache only/Network only

  • Cache only používáme v momentě, kdy vracíme (téměř) neměnná data.
  • Network only potřebujeme, pokud pracuje s non-GET requesty a potřebujeme pracovat s "živými daty".
  • Většinou tento přístup nepotřebujeme používat. Lepší je používat variantu Network falling back to cache (viz dále).

Cache, falling back to network

  • Vhodné, pokud usilujeme o přístup offline-first.
  • Uložená data vracíme z cache, ostatní požadavky vracíme ze sítě.
Vizualizace přístupu Cache, falling back to network. Převzato z Google Developers

Network falling back to cache

  • Pro často se měnící data, jako jsou články, avatary, nebo verzované assety (CSS a JS).
  • Nespornou výhodou je, že uživatel pracuje s nejaktuálnějšími daty. Pokud však není k dispozici stabilní připojení k síti, může to vést k frustrujícímu uživatelskému zážitku.
  • Vhodnějším řešením může být přístup Cache then network.
Vizualizace přístupu Network falling back to cache. Převzato z Google Developers

Cache then network

  • Vhodné pro často se měnící obsah stránky (seznam článků, časové osy na sociálních sítích, žebříčky), kde jsme schopni oželet poněkud rušivý moment při nahrazování části stránky aktuálními daty.
  • Stránka pošle 2 dotazy – jeden do cache, druhý do sítě. Cílem je co nejrychleji zobrazit data z cache a jakmile se vrátí aktuální data ze sítě, stránka nahradí obsah právě získanými daty.
Vizualizace přístupu Cache then network. Převzato z Google Developers

Existují i další přístupy, jako Cache & network race, Generic fallback, ServiceWorker-side templating. Perfektně zpracovaný článek včetně ukázek kódu je k dispozici na stránkách Google Developers od Jake Archibalda.

Nyní se vraťme k našemu kódu. Následující ukázka kódu za nás řeší následující:

  1. Víme, že naše stránka pracuje s daty třetích stran. Tato data chceme nejprve vracet z cache.
  2. Pokud nenajdeme shodu s dotazem v mezipaměti a jsme připojeni k síti, vracíme odpověď ze sítě a data si následně naklonujeme do cache (odpovídá přístupu Cache then network).
  3. Pokud nejsme připojeni k síti a chceme, aby naši uživatelé viděli něco lepšího než je skákající 🦖, vrátíme z cache vlastní offline stránku (viz níže).
// sw.js

...
// 0. URL a styly offline stránky
const OFFLINE_URL = '/offline/';
const assetsToCache = [
 ...
 '/offline/,
 '/built/css/offline.css'
];

...
// 1. Zpracování fetch požadavků na stránce
self.addEventListener('fetch', (event) => {
 event.respondWith(
  caches.open(CACHE_NAME)
  .then((cache) => {
   return cache.match(event.request)
   .then((response) => {
    return response || fetch(event.request)
    .then((response) => {
     cache.put(event.request, response.clone());
    });
   })
   .catch((error) => {
    console.error(`${error}. Returning offline page.`);
    return caches.match(OFFLINE_URL);
   });
  })
 );
});

Pokud není uživatel připojen k internetu, s největší pravděpodobností bude zbytečné mít na offline stránce interní odkazy (pokud nepředpokládáte, že obsah bude načten v mezipaměti). Externí odkazy lze pro jistotu úplně vynechat.

Ukázka offline stránky webu Web.dev

Méně práce díky Workboxu

Naše stránka však nezpracovává jen pár požadavků na vlastní styly a skripty. Často potřebujeme získávat data ze třetích stran, jakou jsou písma z Google Fonts nebo Adobe Typekit, obrázky z CDN a další. Z jednotek dotazů na stránce se rázem může stát několik desítek. Velikost cache je omezená, i když přesné číslo se ve specifikaci horko těžko dozvíme (často se však kalkuluje s horní hranicí 50 MB). Kapacita totiž záleží na daném prohlížeči a zařízení.

Workbox je sada javascriptových knihoven pro vývoj PWA

Svědomitý a zodpovědný přístup při práci s mezipamětí je gró celé funkcionality. Neměli bychom zapomínat ani na maximální životnost dat a aplikovat různé cachovací přístupy podle jejich typu.

Tato a jiná další trápení při jejich implementaci za nás může vyřešit Workbox. Workbox je kolekce javascriptových knihoven pro vývoj PWA. Vývojářům ulehčuje práce se service workerem a Cache Storage APIs, čímž následně uživatelům aplikace zpříjemňuje prožitek při používání aplikace offline.

Pinterest, Tinder a i další organizace, které učinily ze svých webových aplikací PWA a zrealizovaly i řadu dalších vylepšení, se dočkaly ještě závratnějších změn. Pinterestu se podařilo markantně snížit časy pro první vykreslení stránky a interakci s ní. First Paint se jim podařilo zredukovat z 4,2 s na 1,8 s, tj. zlepšení o zhruba 60 %. Time to Interactive dokonce stáhli z neuvěřitelných 23 s na 5,6 s – tady se bavíme dokonce o 75% zlepšení.

Další případové studie na téma PWA a performance se můžete dočíst například na stránkách Google Developers nebo na Mediu, kde se tomuto tématu hojně věnuje Addy Osmani.

Související odkazy

  • Progresivní webové aplikace — co to je a kdy má smysl se o to zajímat? (Frontend Garden)
  • Web App Manifest (Google Developers)
  • Service Workers (Google Developers)
  • Designing Native-Like Progressive Web Apps For iOS (Medium)
  • Caching Files with Service Worker (Google Developers)
  • iPhone 11, iPadOS and iOS 13 for PWAs and web development (Medium)


Kateřina Klouček Dlouhá

Kateřina Klouček Dlouhá

Katka je kodérkou od roku 2017. V současné chvíli pracuje jako Design System Architect. Oplývá entuziasmem pro vše, co souvisí s UX nebo typografií. Více o autorovi

Další články od autora:

  • FrontKon 2024 obrazem
  • WebExpo 2024 je za rohem! + SLEVA NA VSTUPENKU
  • Proč (ne)dělat code review?
Více k tématu:
  • PWA
  • JavaScript
  • Rychlost

Sdílejte

Líbí se vám článek? Podpořte jej sdílením!

X (Twitter) Facebook LinkedIn

Komentujte

Chcete k článku něco doplnit? Našli jste chybu? Napište e-mail.

Adam Kudrna

Nejnovější články

WebExpo — čtení na 3 min.

Pozvánka na WebExpo 2025

Rok se s rokem sešel, přichází měsíc květen a s ním WebExpo 2025, které se po nejistých letech usadilo v tomto jarním termínu. Jaké bude?

  • Adam Kudrna
    Adam Kudrna
Pozvánka na WebExpo 2025
JavaScript — čtení na 10 min.

Jak předcházet chaotické organizaci npm skriptů

Řešíte, jak organizovat skripty napříč projekty přehledně a konzistentně? Inspirujte se systémem, který zjednoduší práci vám i kolegům.

  • Tomáš Litera
    Tomáš Litera
Jak předcházet chaotické organizaci npm skriptů
Reportáž — čtení na 2 min.

FrontKon 2024 obrazem

Frontendisti letos připravili třetí ročník konference FrontKon. Ta se letos historicky poprvé odehrála naživo v Praze, a to v prostorách O2 Universum.

  • Kateřina Klouček Dlouhá
    Kateřina Klouček Dlouhá
FrontKon 2024 obrazem

Odběr novinek

Zadejte svůj e-mail a nenechte si ujít další nové články!

Odesláním formuláře souhlasíte se .
Zpracování osobních údajů probíhá za účelem zasílání newsletteru. Můžete se spolehnout, že vaše osobní údaje nebudeme s nikým sdílet. Z newsletteru se můžete kdykoli odhlásit. Stejně tak můžete kdykoli požádat o úplné smazání svých osobních údajů z naší databáze.
Zkontrolujte svoji e-mailovou schránku a potvrďte své přihlášení kliknutím na odkaz.

Všechna témata

  • Bootstrap
  • CSS
  • Design
  • Dokumentace
  • HTML
  • ITCSS
  • JavaScript
  • Kariéra
  • Kvalita kódu
  • Nástroje
  • No-code
  • Přístupnost
  • PWA
  • Reportáž
  • Rozhovor
  • Rychlost
  • Sass
  • Spolupráce
  • Typografie
  • Variable fonts
  • WebExpo
  • ✏️ Napište článek
  • Autoři
  • Cookies
  • Instagram
  • GitHub

Obsah na tomto webu je publikován pod licencí Creative Commons CC BY-NC 4.0.
Frontend Garden vysázel, zastřihuje a okopává (s ♥️) Adam Kudrna.
Založeno v květnu 2019.