Progressiva webbapplikationer
Allt du har byggt sedan kursvecka 8 körs i en flik i webbläsaren. Den här veckan tar du steget mot applikationer som går att installera och som fungerar utan uppkoppling, progressiva webbapplikationer. Det är också vad som krävs för högre betyg på examinationsuppgift B3, där skrivbordet du bygger ska gå att installera och fungera offline.
Den här artikeln går igenom begreppen och hur ett manifest gör applikationen installerbar. De två följande artiklarna, Service workers och Offline med Cache API, visar hur den fungerar offline.
Tidsåtgång: Ungefär 12 minuter.
En sida, inte flera
Section titled “En sida, inte flera”En traditionell webbplats består av många HTML-dokument. Varje klick på en länk hämtar ett nytt dokument från servern, och webbläsaren ritar upp sidan från början. En sådan webbplats kallas ibland för en MPA, en multi-page application.
En SPA, en single-page application, laddar ett enda HTML-dokument. Därefter är det JavaScript som
ändrar DOM:en när användaren gör något, och hämtar data med fetch() eller över en WebSocket när det
behövs. Sidan laddas aldrig om. Det är så alla dina applikationer i delkurs B har fungerat: quizet i
B2 byter mellan fråga och topplista utan att ladda ett nytt dokument, och B3 ska vara en SPA enligt
kraven.
Att sidan aldrig laddas om har två följder som är värda att känna till:
- Tillståndet finns i JavaScript. Vilka fönster som är öppna, var de står och vad som har skrivits i dem finns i variabler och i DOM:en, och försvinner när sidan laddas om.
- Adressen ändras inte av sig själv. Användaren hamnar alltid på samma adress, och bakåtknappen lämnar applikationen. Hur en SPA kan uppdatera adressen tar du upp i Routing i en SPA i kursvecka 16.
Fråga: vad finns kvar?
Section titled “Fråga: vad finns kvar?”Användaren har tre fönster öppna i ditt PWD: ett Memory mitt i en omgång, ett Messages-fönster och din egen underapplikation. Sedan trycker användaren på F5. Vad finns kvar?
Ett tomt skrivbord. Sidan laddas om, all JavaScript körs från början och alla variabler och element skapas på nytt. Omgången i Memory är borta, liksom fönstrens placering.
Det som har sparats överlever: användarnamnet i Messages, om du har sparat det i localStorage som
kraven säger, och de meddelanden servern skickar när du ansluter på nytt. Att spara fönstrens läge
mellan sessioner är ett av förslagen på utökningar i B3, och du har redan verktyget för det från
Web Storage.
Fyra sätt att bygga en app
Section titled “Fyra sätt att bygga en app”Ska en applikation finnas på telefonen och på datorn finns i stort sett fyra vägar att gå:
- Native app. Skrivs för en plattform i dess eget språk och med dess egna verktyg, Swift för iOS och Kotlin för Android. Ger full tillgång till enheten och bäst prestanda, men en kodbas per plattform och installation via appbutiken.
- Plattformsoberoende app. En kodbas som byggs till appar för flera plattformar. Tekniken skiljer sig åt: Capacitor och Cordova kör en webbapplikation i en webview, en inbyggd webbläsare utan adressfält, inuti en native app. React Native kör JavaScript men ritar plattformens egna gränssnittselement. Flutter skrivs i Dart, kompileras till maskinkod och ritar hela gränssnittet själv.
- Responsiv webbplats. Anpassar sig efter skärmen, men lever i en flik i webbläsaren och fungerar inte utan uppkoppling.
- Progressiv webbapplikation. En webbapplikation som går att installera och som fungerar offline. En kodbas, ingen appbutik, och en uppdatering når alla användare nästa gång de öppnar den.
På datorn finns en motsvarighet till webview-appen. Electron paketerar en webbapplikation tillsammans med en egen Chromium och Node.js till ett skrivbordsprogram. VS Code, Slack och Discord är byggda så. Tauri gör samma sak men använder operativsystemets inbyggda webview i stället för att skicka med en egen webbläsare. Det är webbteknik, men inte en PWA: programmet installeras som vilket program som helst, inte från webbläsaren.
| Native | Plattformsoberoende | Responsiv webbplats | PWA | |
|---|---|---|---|---|
| Kodbaser | En per plattform | En | En | En |
| Installeras från | Appbutik | Appbutik | Installeras inte | Webbläsaren |
| Fungerar offline | Ja | Ja | Nej | Ja |
| Tillgång till enheten | All | Det mesta | Webbläsarens API:er | Webbläsarens API:er |
| Nås via en länk | Nej | Nej | Ja | Ja |
| Uppdatering | Via appbutiken | Via appbutiken | Direkt | Direkt |
Inget av alternativen är bäst i allmänhet. En PWA är ett bra val när webbläsarens API:er räcker, och de räcker långt: kamera, mikrofon, position, notiser, filer, Bluetooth och WebGL finns alla i webbläsaren, även om stödet skiljer sig mellan webbläsare.
Vad gör en webbapplikation progressiv?
Section titled “Vad gör en webbapplikation progressiv?”Begreppet progressive web app myntades 2015 av Frances Berriman och Alex Russell, då på Google. Det är inte en enskild teknik utan en samling egenskaper. Tre brukar lyftas fram:
- Installerbar. Användaren kan installera applikationen från webbläsaren. Den startar sedan i ett eget fönster, med egen ikon, som andra program. Det kräver ett manifest, som du ser nedan.
- Pålitlig. Applikationen startar och fungerar även när nätverket är långsamt eller saknas helt. Det kräver en service worker, som är ämnet för de två följande artiklarna.
- Kapabel. Applikationen använder det webbläsaren kan, och gör saker användaren annars hade installerat en native app för.
Ordet progressiv kommer från progressive enhancement, progressiv förbättring. Applikationen ska fungera som en vanlig webbsida i varje webbläsare, och bli bättre där webbläsaren kan mer. Därför kontrollerar du att ett API finns innan du använder det, i stället för att anta det:
if ('serviceWorker' in navigator) { // Register the service worker}
if (navigator.share) { // Show a share button}Saknas stödet fungerar applikationen ändå, bara utan just den förbättringen.
Offline first
Section titled “Offline first”Den som bygger pålitliga applikationer behöver tänka om kring nätverket. I en vanlig webbplats är uppkoppling något som tas för givet, och ett avbrott är ett fel. Offline first vänder på det: uppkopplingen är något som kan finnas, och applikationen ska fungera så långt det går utan den. Memory behöver inget nätverk alls efter att filerna har hämtats en gång. Messages behöver nätverket för att skicka och ta emot meddelanden, men kan fortfarande starta och tala om för användaren att den är offline, i stället för att visa webbläsarens felsida.
Hur applikationen märker att den är offline, och varför navigator.onLine inte räcker, tar du upp i
Online, offline och Lie-Fi i kursvecka 16.
Ett manifest gör applikationen installerbar
Section titled “Ett manifest gör applikationen installerbar”Manifestet är en JSON-fil som beskriver applikationen för operativsystemet: vad den heter, vilka ikoner den har och hur den ska visas när den är installerad. Ett manifest för memoryspelet:
{ "name": "Memory Game", "short_name": "Memory", "description": "A memory game with flipping tiles.", "start_url": "./", "display": "standalone", "background_color": "#ffffff", "theme_color": "#ffe000", "icons": [ { "src": "icons/icon-192.png", "sizes": "192x192", "type": "image/png" }, { "src": "icons/icon-512.png", "sizes": "512x512", "type": "image/png" } ]}nameochshort_nameär namnet i fönstrets namnlist och under ikonen, där det korta används när utrymmet är litet.start_urlär adressen som öppnas när applikationen startas.displaybestämmer hur mycket av webbläsaren som syns.standaloneger ett eget fönster utan adressfält och flikar, som ett vanligt program.minimal-uibehåller några navigeringsknappar,fullscreentar hela skärmen ochbrowseröppnar en vanlig flik.background_colorochtheme_coloranvänds för startskärmen och fönstrets ram, innan din CSS har laddats.iconsär ikonerna i olika storlekar.
Relativa adresser i manifestet, som ./ och icons/icon-192.png, räknas från manifestets egen
adress, inte från sidans.
Var filerna ligger
Section titled “Var filerna ligger”I ett Vite-projekt lägger du manifestet och ikonerna i public/. Vite kopierar allt där som det är,
med samma namn, medan filer som importeras från din kod får en hash i namnet vid bygget, som
index-DpQX1ODm.js. Manifestet pekar ut ikonerna med namn, och då måste namnen vara desamma efter
bygget.
public/├── favicon.ico├── manifest.webmanifest└── icons/ ├── icon-192.png └── icon-512.pngSedan länkar du in manifestet i src/index.html, bredvid ikonen som redan finns där:
<link rel="icon" href="./favicon.ico" /><link rel="manifest" href="./manifest.webmanifest" />Vad krävs för att kunna installera?
Section titled “Vad krävs för att kunna installera?”Kraven skiljer sig mellan webbläsare. Chrome och Edge, som båda bygger på Chromium, kräver:
- att sidan visas i en säker kontext, alltså över HTTPS eller från
localhost, - ett manifest med
nameellershort_name,start_url,displaysatt tillstandalone,fullscreenellerminimal-ui, och ikoner i storlekarna 192 × 192 och 512 × 512 pixlar.
En service worker krävs inte längre för att installera via webbläsarens meny, sedan Chrome 108 på mobilen och 112 på datorn. Utan den startar applikationen, men visar webbläsarens felsida när nätverket saknas. Det är först med en service worker som den blir pålitlig.
Stödet i övrigt:
- Chrome och Edge installerar på Windows, macOS, Linux och Android.
- Safari på macOS (sedan version 17) lägger till vilken webbplats som helst i Dock via Arkiv → Lägg till i Dock. På iOS och iPadOS (sedan 16.4) installeras den via delningsmenyn.
- Firefox installerar inte utifrån manifestet. Sedan version 143 kan en webbplats fästas som app i aktivitetsfältet i Windows.
Testa därför installationen i Chrome eller Edge. Under fliken Application → Manifest i utvecklarverktygen ser du hur webbläsaren har tolkat manifestet och om något saknas.
Fråga: varför går den inte att installera?
Section titled “Fråga: varför går den inte att installera?”Du har lagt till ett manifest med name, start_url, display: "standalone" och en ikon på 192 ×
192 pixlar. Du kör npm run build och npm run serve, öppnar http://localhost:4173 i Chrome, men
webbläsaren erbjuder ingen installation. Vad är fel?
Ikonen på 512 × 512 pixlar saknas. Chromium kräver båda storlekarna, och utan den är applikationen inte installerbar. Fliken Application → Manifest i utvecklarverktygen visar vilket krav som inte är uppfyllt.
localhost är inte problemet. Det räknas som en säker kontext, precis som HTTPS, så att du kan
utveckla utan certifikat.
Att ta med sig
Section titled “Att ta med sig”- En SPA laddar ett dokument och låter JavaScript sköta resten. Tillståndet finns i minnet och försvinner när sidan laddas om, om du inte sparar det.
- Native, plattformsoberoende, responsiv webbplats och PWA är fyra sätt att bygga en app, med olika avvägningar mellan räckvidd, tillgång till enheten och hur uppdateringar når användaren.
- En PWA är installerbar, pålitlig och kapabel. Progressiv betyder att den fungerar överallt och blir bättre där webbläsaren kan mer.
- Ett manifest i
public/, länkat frånindex.html, gör applikationen installerbar. Chromium kräver ikoner i 192 och 512 pixlar. - Installerbar är inte samma sak som pålitlig. Det kräver en service worker.
Vidare läsning
Section titled “Vidare läsning”- Läsanvisningarna för veckan.
- Progressive web apps och Making PWAs installable på MDN.
- Web app manifest på MDN, med alla fält.