Vytvoření progresivní webové aplikace (PWA)
8.11.2020Slovníček
Nativní aplikace | Aplikace naprogramováná pro konkrétní platformu, například Android nebo iOS. Nativní aplikace je rychlejší oproti webové a poskytuje lepší přístup k funkcím v telefonu. Nevýhodou je potřeba aplikaci registrovat do Google Play nebo App Store a poté aplikaci pravidelně aktualizovat. |
UWP | Universální Windows Platforma je technologie, kdy vývojář naprogramuje aplikaci pouze jednou a poté jí může spustit na libovolné Windows 10 platformě. Například Windows 10, Windows 10 Mobile nebo Xboxu One (Windows 10 Core). |
Obsah
- Minimální požadavky na PWA
- Konfigurace service workera
- Spuštění aplikace
- Lighthouse audit
- Řešení problémů
- Výsledek
- Odkazy
Minimální požadavky na PWA
Aby aplikace mohla být rozpoznána jako progresivní, musí implementovat následující
- HTTPS
- Manifest
- Service worker
HTTPS
Podpora HTTPS je záležitostí především webového serveru, na localhost se pravidlo nevztahuje.
Manifest
Soubor s příponou .json nebo .webmanifest, který přilinkujeme na hlavní stránku html tagem. Jedná se o konfigurační soubor, který se použije v případě, kdy uživatel aplikaci nainstaluje do počítače nebo mobilního telefonu.
<link rel="manifest" href="/manifest.json">
{
"name": "PWA Proof of concept",
"short_name": "PWA PoC",
"icons":[{
"src": "/images/icons/web_hi_res_512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}],
"start_url": "/index.html",
"display": "standalone",
"orientation": "portrait",
"theme_color": "#ffffff",
"background_color":"#ffffff"
}
V konfiguraci je nastaveno několik důležitých věcí
- Jméno aplikace, které se použije při spuštění.
- Ikonku, kterou mobilní telefon použije při uložení aplikace do telefonu. iPhone má definici v apple-touch-icon html atributu.
- 512x512px je největší možná velikost a zařízení si jí přizpůsobí dle potřeby.
- Pro vygenerování ikonky je možné použít Launcher icon generator.
- Start_url definuje adresu, která se použije pro otevření nainstalované aplikace.
Service worker
Alfou a omegou PWA je service worker, javascriptový soubor, který je součástí aplikace a běží na pozadí, nezávisle na webovém prohlížeči. Funguje na principu web workera a hlavním úkolem je synchronizovat offline a online verzi aplikace, jinými slovy spravovat cache úložiště, ale má i jiné funkce. Základní strategií (ale ne jedinou a různé strategie je možné kombinovat) jak nastavit service workera je takzvaná cache-first strategie, kdy se uživateli při první návštěvě nebo instalaci aplikace uloží do cache paměti všechny klíčové soubory, u kterých je předpoklad, že se nebudou často měnit. Jedná se o statické assety jako obrázky, css soubory, js scripty, ale i html stránka, která se má použít při offline režimu (start_url).
Cache-first strategie
- Aplikace si požádá o nějaký soubor
- Service worker se podívá do cache úložiště
- Soubor nalezen
- Soubor nenalezen, přepošle požadavek do sítě
- Service worker předá aplikaci požadovaný soubor
Důležité eventy
Install | Spustí se při první návštěvě stránky nebo její instalaci. Využijeme pro uložení klíčových souborů do cache úložiště. Poté už se nikdy nespustí. |
Active | Spustí se v momentě, kdy je service worker připravený. Využijeme pro aktualizaci cache úložiště, pokud existuje nová verze. |
Fetch | Událost se spustí v momentě, kdy aplikace pošle nějaký http požadavek. Service worker požadavek převezme a podívá se jestli požadovaný soubor není uložený v cache úložišti. Pokud ano, soubor se vezme z cache paměti, pokud ne tak se požadavek pošle dál do sítě. |
Konfigurace service workera
Před tím, než se pustíme do konfigurace, musíme service workera zaregistrovat. Registraci nastavíme v souboru index.html. Starší verze prohlížečů service workera nepodporují, proto registraci obalíme podmínkou. Service worker je javascriptový soubor, v našem případě bude uložený v rootu webu pod jménem serviceworker.js.<html>
<head>
<link rel="manifest" href="/manifest.json">
<!-- https://developer.mozilla.org/en-US/docs/Web/HTML/Element/meta/name/theme-color -->
<meta name="theme-color" content="#FFFFFF">
<!-- https://www.w3schools.com/css/css_rwd_viewport.asp -->
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<!-- https://web.dev/apple-touch-icon/ -->
<link rel="apple-touch-icon" href="/images/icons/apple_touch_icon_192.png">
</head>
<body>
PWA PoC v1
</body>
<script>
if ('serviceWorker' in navigator){
window.addEventListener('load', () => {
navigator.serviceWorker.register('/serviceworker.js')
})
}
</script>
</html>
const cacheName = 'cache-v1';
const resourcesToCache = [
'/',
'index.html',
'styles/main.css',
'images/space1.jpg',
'images/space2.jpg',
'images/space3.jpg'
]
// Install event triggers only once,
// when the user first visit the page.
// We use the install event to pre-cache the core static assets
// for a first-cache strategy.
// In the worker, self is the worker.
// Everywhere else it's the current global object.
self.addEventListener('install', event => {
// Wait for the last promise to complete
// https://stackoverflow.com/a/37906330/2333663
event.waitUntil(
caches.open(cacheName)
// Cache returns a promise. When we call 'then'
// on a promise, the code will be executed after
// the promise is done.
.then(cache => {
// Load resources from the web server
// and puts them into the cache.
return cache.addAll(resourcesToCache);
})
);
});
// When serviceworker is ready, the activate event is called.
// The activate event is used to update pre-cashed resources (core cache), when there is a new version of it.
// https://developer.mozilla.org/en-US/docs/Web/API/Service_Worker_API/Using_Service_Workers#Updating_your_service_worker
self.addEventListener('activate', (event) => {
var cacheKeepList = [cacheName];
event.waitUntil(
caches
.keys()
.then(keys => Promise.all(keys.map((key) => {
if (!cacheKeepList.includes(key)) {
return caches.delete(key);
}
})))
);
});
// For static assets pre-cached in the install event,
// we will use cache-first strategy.
// Strategy looks inside the cache first and network is a fallback.
// This improve performance and enable offline usage of the assets.
// Lighthouse 'Current page responds with a 200 when offline' will be green,
// if the current page is cached.
self.addEventListener('fetch', event => {
// Look into cache for the requesting asset.
event.respondWith(
caches
.match(event.request)
// return cached asset if found,
// otherwise load it from the web server.
.then(cached => cached || fetch(event.request))
);
});
Odinstalace
Pokud bychom chtěli service workera odebrat, nesmíme ho zapomenout odinstalovat. Stávajícímu service workeru dáme vědět, že si má stáhnout novou verzi souboru index.html, tedy souboru, kde probíhá registrace. To provedeme zvýšením verze cache úložiště, respektive přejmenováním cacheName konstanty v serviceworker.js souboru. Nový index.html soubor pak bude obsahovat odinstalaci místo registrace.
if ('serviceWorker' in navigator) {
navigator.serviceWorker.getRegistrations()
.then(function(registrations) {
for(let registration of registrations) {
registration.unregister();
}
});
}
Spuštění aplikace
Pro nasazení aplikace na localhost využijeme rozšíření Web Server For Chrome, které nám umožní aplikaci spustit.Struktura aplikace je následovná (ale libovolně měnitelná)
- Pwa
- images
- space1.png
- space2.png
- space3.png
- icons
- apple_touch_icon_192.png
- web_hi_res_512.png
- images
- styles
- main.css
- favicon.ico
- index.html
- manifest.json
- serviceworker.json
Lighthouse audit
Prohlížeč Chrome má zabudovaný auditní nástroj pro PWA aplikace, který spustíme následovně Otevřeme Chrome > Otevřeme Developer tools (F12) > Záložka Lighthouse > Generate report Výstupem je přehledná obrazovka, která nám zvýrazní případné chyby
Řešení problémů
Pro řešení nejrůznějších problémů nebo jen vyzkoušení funkčnosti můžeme použít záložku Application v prohlížeči Chrome/Edge
Otevřeme Chrome/Edge > Otevřeme Developer tools (F12) > Záložka Application
Můžeme například překontrolovat s jakými hodnotami se nám načetl manifest, jestli běží service worker, jaká verze cache úložiště se používá a jaké obsahuje soubory a mnoho dalšího. Aplikaci také můžeme přepnout do offline režimu.
Výsledek
Výsledkem je webová aplikace, která funguje i v offline režimu (alespoň do té míry, do které má potřebné soubory v cache úložišti). Můžeme jí také nainstalovat (na desktopu do chrome://apps/ nebo edge://apps/, na mobilu jako aplikaci). Na mém Samsung Galaxy A40 v dark módu se Samsung Internet prohlížečem, který používá Chromium engine vypadá postup následovně.
Otevřeme webovou stránku a klikneme na ikonku instalace , která se nám zobrazí, protože prohlížeč rozpoznal PWA aplikaci