Přejít k navigační liště

Zdroják » JavaScript » Offline stránka v PWA přes ServiceWorker

Offline stránka v PWA přes ServiceWorker

Články JavaScript

Jak udělat web fungující offline. A splnit tak požadavky na PWA.

Nálepky:

Text vyšel původně na autorově webu.

PWA (Progressive Web Apps) je postup, jak vytvářet webové stránky, které se chováním podobají nativním aplikací.

Tedy v tomto případě například fungují bez připojení k internetu.

Proč mít PWA

V praxi je to dobré například k tomu, aby stránku šlo v Chrome nainstalovat.

Výsledkem je potom v macOS upravené okno prohlížeče Chrome a přidání ikony mezi ostatní aplikace:

Na Androidu jde takový web připnout na plochu mezi ostatní aplikace.

Chrome jeden čas upozorňoval, že v budoucnu bude možná vyžadovat i offline fungování.

Site cannot be installed: Page does not work offline. Starting in Chrome 93, the installability criteria is changing, and this site will not be installable. See https://goo.gle/improved-pwa-offline-detection for more information.

Nakonec byl tento požadavek pro splnění PWA odložen. Ale kdo ví, kdy zase přijde.

Ověřit, co má stránka splňovat, aby byla validní PWA, jde zjistit v DevTools na záložce Lighthouse:

Vytvoření ServiceWorkeru

Aby vůbec mohl ServiceWorker fungovat, musí web běžet na HTTPS (výjimkou je vývoj na localhostu).

ServiceWorker je skript psaný v JavaScriptu. Většinou se tento soubor jmenuje sw.js nebo serviceWorker.js.

Záleží na tom, kde je umístěn. Je to dost důležité, protože pokud bude registrován z umístění např. assets/js/sw.js, nebude fungovat na adresách, které nezačínají assets/js.

Proto se většinou dává rovnou do rootu webu. Případně jde nastavit rozsah působení parametrem scope:

if('serviceWorker' in navigator) {
  navigator.serviceWorker.register('/serviceWorker.js', { scope: '/'})
}

Výše uvedený kód zaregistruje SW, pokud ho prohlížeč podporuje.

Offline stránka offline.html

Offline stránka může být pro jednoduchost obyčejný HTML soubor s inline styly i obrázky:

<!doctype html>
<meta charset="utf-8">
<title>Offline</title>
<meta name="viewport" content="width=device-width,initial-scale=1">
Jste offline.

V offline stránce je možné používat JS, takže není problém například přidat chování, aby se stránka sama obnovila, když je uživatel opět online:

<script>
    window.addEventListener('online',  function () {
        window.location.reload()
    })
</script>

Jde používat i externí styly, skripty nebo obrázky, ale musely by se rovněž přidat do cache.

Obsah serviceWorker.js

Úplně základní offline stránku stačí při instalaci workeru uložit do cache.

Třeba následovně:

const CACHE_VERSION = 1
const CACHE = {
    OFFLINE: 'offline-cache-' + CACHE_VERSION,
}
const OFFLINE_URL = 'offline.html'

self.addEventListener('install', function (event) {
    event.waitUntil(
        caches.open(CACHE.OFFLINE).then(function (cache) {
            return cache.add(OFFLINE_URL)
        })
    )
})

Tento kód při instalaci SW (událost install) otevře cache s názvem offline-cache-1 (případně ji vytvoří, pokud neexistuje – těchto keší může být i víc) a přidá do ní obsah z URL offline.html.

Druhý úkol je odchytávat fetch události. Tam si je možné upravit chování standardních požadavků na soubory.

A v případě chyby vrátit offline.html z cache:

self.addEventListener('fetch', function (event) {
    if (event.request.mode === 'navigate' || (event.request.method === 'GET' && event.request.headers.get('accept').includes('text/html'))) {
        event.respondWith(
            (async function () {
                try {
                    return await fetch(event.request, { redirect: 'manual' })
                } catch {
                    const cache = await caches.open(CACHE.OFFLINE)
                    return await cache.match(OFFLINE_URL)
                }
            })()
        )
    }
})

To je celé.

Celý kód je obalen do podmínky omezující vykonávání na případy, kdy je cílem získat dokument. Konstrukce event.request.mode nefunguje všude, proto je uvedena ještě alternativní podmínka. Jsou tam kvůli tomu, aby se v případě požadavků třeba na obrázky nic nedělalo.

Za povšimnutí stojí { redirect: 'manual' } – bez toho nemusí offline stránka fungovat, pokud se na doméně používá nějaké přesměrování.

Volání standardního požadavku metodou fetch je v try – catch bloku, takže v případě chyby (tj. uživatel je offline) se otevře cache a pokusí se v ní najít soubor offline.html.

Na kartě Network je potom u requestů vidět, že je zpracoval ServiceWorker (znázorňuje to ozubené kolečko před názvem):

Zpracování požadavku SW

Debugování a vývoj

Základem je karta Application ve vývojářských nástrojích Chrome.

Je zde vidět samotný Service Worker – v jakém je stavu:

Pro vývoj se hodí možnost Update on reload a pro otestování si zapnout Offline. Jen pozor na to, že obě zaškrtnuté položky způsobí, že se offline stránka nezobrazí.

Užitečné může být i podívat se do cache:

Je dobré tohle fakt dobře otestovat, protože nakešovaný nefunkční serviceWorker.js může klidně návštěvníkům web úplně vyřadit.

Když ServiceWorker zpracovává všechny požadavky na HTML stránky jako na příkladu výše, může kompletně rozbít toto servírování obsahu návštěvníkovi.

Soubor manifest.json

Další podmínkou PWA je manifest.json – jedná se o soubor ve formátu JSON, kde jsou základní informace o aplikaci a odkazy na ikony.

Asi nejsnazší je si takový soubor vytvořit použitím nějakého generátoru: Web App Manifest Generator.

Výstupem je něco takového:

{
  "name": "Je čas",
  "short_name": "Je čas",
  "theme_color": "#1079CF",
  "background_color": "#fff",
  "display": "standalone",
  "orientation": "portrait",
  "scope": "/",
  "start_url": "/",
  "icons": [
    {
      "src": "images/icons/icon-72x72.png",
      "sizes": "72x72",
      "type": "image/png"
    },
  ]
}

Tento soubor se připojuje značkou <link> v hlavičce webu.

Maskable ikona

Posledním trendem v ikonách aplikací je tzv. maskable formát. Řeší to problém, kdy různé verse a nadstavby Androidu mají jinak přizpůsobené ikony – zejména jejich zaoblení.

Aby se nemusely vytvářet různé varianty, maskable formát definuje ochrannou zónu kolem ikony.

To znamená, že cokoliv mimo zelený kruh může systém libovolně zprůhlednit.

Pro připravení vlastní maskable ikony se hodí Maskable.app Editor – nástroj pro vygenerování maskable ikony.

Odkaz na tuto ikonu je následně potřeba přidat do manifest.json mezi ostatní ikony (do pole icons):

    {
      "src": "images/icons/maskable_icon.png",
      "sizes": "512x512",
      "type": "image/png",
      "purpose": "maskable",
      "density": 4
    }

Má smysl mít PWA?

Při splnění kroků výše bude web splňovat formální požadavky na PWA, které je možné automaticky testovat Lighthouse nástrojem ve vývojářských nástrojích.

Podobně jako kdysi řešená validita HTML/CSS kódu nezajišťovala automaticky dobrý web, ani stránka splňující PWA nemusí být nikterak lepší.

Příklad popsaný v tomto článku je tak trochu PWA pro PWA – praktický přínos pro uživatele je dost malý.

Výhoda PWA je v podstatě jen možnost instalace na plochu na Androidu, kde je otázka, jestli to významné množství lidí potřebuje.

Význam takto hloupé offline.html stránky je trochu sporný.

Standardní hláška prohlížeče má výhody v tom, že je na ni návštěvník zvyklý, je přeložená do jeho jazyka a případně respektuje i nastavení světlého/tmavého režimu:

Vlastní offline stránka tak může pro návštěvníky znamenat zhoršení situace.

Nevýhoda PWA spočívá v tom, že se musí navíc:

  1. Spustit JS kód registrující ServiceWorker.
  2. Stáhnout a vykonat/instalovat kód v souboru serviceWorker.js.
  3. Stáhnout a uložit do cache obsah stránky offline.html.
  4. Stáhnout a zpracovat obsah souboru manifest.json.
  5. Každý požadavek na soubory musí projít logikou ServiceWorkeru.

První příchod na stránku tak znamená stahovat další 3 soubory navíc. K tomu sice malou, ale pořád nějakou zátěž v podobě JavaScriptu pro registraci, instalaci a samotného běhu SW.

Vytvářet PWA tak dává smysl spíš v situacích, kdy to nabídne návštěvníkům více funkcionality – například push notifikace.

Případně když stránka nabídne opravdové offline použití, ne jen vlastní chybovou offline stránku.

To je dobře proveditelné u SPA (single page aplikací), kde se může díky ServiceWorkeru uložit do cache celá logika aplikace včetně skriptů, stylů nebo obrázků a opakovaný příchod na takovou stránku je téměř okamžitý, protože spuštění celé aplikace obslouží SW z cache.

Riziko rozbití webu

ServiceWorker s offline fungováním přináší dost velkou šanci poměrně zásadně rozbít celý web.

Je to tím, že pro offline fungování stránky veškeré požadavky prochází přes ServiceWorker. Takže když tam bude chyba, nemusí vůbec nic fungovat.

Velmi vhodné je mít před spuštěním na webu monitoring typu Sentry.

U větších webů ideálně pustit úpravu nejprve na menší část návštěvníků.

Odkazy jinam

Komentáře

Subscribe
Upozornit na
guest
2 Komentářů
Nejstarší
Nejnovější Most Voted
Inline Feedbacks
View all comments
Ondra Novák

Myslel jsem si, že příklad s offline.html je jen příklad a že hlavní výhodou PWA aplikace v offline režimu je, že funguje jako aplikace, tedy, že pokud má k dispozici již nějaký stažený obsah, že mohu tento obsah v aplikaci procházet aniž bych internet potřeboval. Napsal jsem několik PWAček, které běží vyloženě offline.

Závěr je tedy dost sporný, včetně výčtů nevýhod. Jistě je zřejmý, že každý request chodí přes service worker, ale ne každý request musí být jím zpracován. I v tom eventu řešíte jen ten html a servírujete mu to pres fetch… a jak to vypadá u obrázků a jiných resourců? ty se nenaservírují? Hmm. ale naservírují, když ten event nic neudělá, projde request normálně. Ten fetch tam máte jen proto, abyste poznal, že „nejde internet“ a vyhodilo to výjimku ještě v SW.

Rozbíjení webu a podobně… je třeba si uvědomit, že PWA je „aplikace“, ne webovka. Je třeba se k tomu tak stavět. Pokud tedy děláte update PWAčka, musíte si vyvinout nějaký mechanismus jak ten update zařídit v samotné „aplikaci“. Začíná to samozřejmě updatem samotného service workeru, ale jak aktualizovat cache, to už je čistě váš problém, jak se s tím kód popere. A to je ještě pořád dobrý, že nemusíte update dělat přes play store. Pokud při vývojí počítáte s tím, že deploynete něco, co nemáte pořádně odladěný, tak … radši žádný deploy ani PWA nedělejte. Přeci jen, věci se lépe spravují online, těch pár lidí, co uvidí chvíli bílou obrazovku to přežije.

Enum a statická analýza kódu

Mám jednu univerzální radu pro začínající programátorty. V učení sice neexistují rychlé zkratky, ovšem tuhle radu můžete snadno začít používat a zrychlit tak tempo učení. Tou tajemnou ingrediencí je statická analýza kódu. Ukážeme si to na příkladu enum.