PWA (Progressive Web App) — este o aplicație web care utilizează capabilitățile moderne ale browserului pentru a funcționa ca o aplicație nativă: se încarcă rapid, funcționează offline, trimite notificări push și se instalează pe ecranul principal. La baza PWA stau trei tehnologii: Service Worker, manifest și HTTPS. Service Worker — este un script pe care browserul îl rulează în fundal, separat de pagina web, deschizând posibilități inaccesibile site-urilor obișnuite: interceptarea cererilor de rețea, stocarea în cache a resurselor, sincronizarea în fundal și notificările push. Manifestul — este un fișier JSON care informează browserul cum trebuie să arate aplicația la instalarea pe dispozitiv: nume, pictograme, culoarea temei, orientarea ecranului. Fără HTTPS, Service Worker nu funcționează — este o cerință obligatorie de securitate. PWA este compatibil cu orice browser modern și nu necesită publicare în magazinul de aplicații. Utilizatorul deschide site-ul, vede propunerea de instalare a aplicației, apasă «Adaugă pe ecranul principal» — și aplicația este gata. Pentru afaceri, PWA înseamnă acoperirea oricărei audiențe fără costuri de dezvoltare separată pentru iOS și Android, viteză mare de încărcare chiar și în rețele lente și implicare prin notificări push. În articol vom analiza cum funcționează Service Worker, cum se creează manifestul, ce strategii de cache să folosim și cum să asigurăm accesul offline.
Principalele
Principalele
Progressive Web App (PWA) — este o abordare de dezvoltare a aplicațiilor web care combină cele mai bune calități ale webului și aplicațiilor native. Termenul a fost introdus de Francesco Berriman în 2015, iar Google promovează activ PWA ca înlocuitor pentru aplicațiile mobile simple. Ideea principală: site-ul web se îmbunătățește treptat în funcție de capacitățile browserului și dispozitivului. Dacă browserul suportă Service Worker — se activează modul offline. Dacă suportă manifest — apare butonul «Instalează». Dacă există API de notificări — aplicația poate trimite push. Utilizatorul pe un dispozitiv slab cu internet lent va primi versiunea de bază a site-ului, iar pe un smartphone modern — o aplicație completă cu pictogramă pe desktop.
PWA nu trebuie instalat prin magazinul de aplicații. Este suficient un link. Aceasta rezolvă principala problemă a aplicațiilor mobile — pragul ridicat de intrare. Utilizatorul nu merge în Google Play sau App Store, nu așteaptă descărcarea a 100 MB, nu acordă zeci de permisiuni. El deschide pur și simplu site-ul, iar browserul propune instalarea aplicației. Dacă utilizatorul refuză — el folosește totuși site-ul. Iar dacă acceptă — pictograma apare pe ecranul principal, iar aplicația se deschide ca nativă: fără bara de adrese a browserului, în mod ecran complet și cu pornire rapidă.
Tehnic, PWA trebuie să îndeplinească trei criterii: să funcționeze prin HTTPS (conexiune securizată), să aibă Service Worker (script de procesare în fundal) și să conțină manifest (Web App Manifest). Aceste trei componente transformă un site obișnuit într-o aplicație instalabilă.
Service Worker — este un script JavaScript pe care browserul îl rulează într-un fir separat, independent de pagina web. Nu are acces la DOM, nu poate interacționa direct cu interfața, dar poate intercepta și modifica cererile de rețea, gestiona cache-ul, procesa notificările push și efectua sincronizarea în fundal. Service Worker funcționează ca un server proxy între browser și rețea: fiecare cerere de la pagină trece prin Service Worker, care decide — să returneze datele din cache, să solicite de la server sau să facă ambele.
Service Worker trăiește după propriul său ciclu de viață, nelegat de pagina deschisă. El este instalat, activat și funcționează în fundal chiar și după închiderea tuturor filelor site-ului. Aceasta permite PWA să primească notificări push și să actualizeze cache-ul în fundal, fără participarea utilizatorului.
Service Worker parcurge patru etape: înregistrare, instalare, activare și inactivitate/finalizare.
Înregistrare. Browserul primește un link către fișierul JS al Service Worker și începe descărcarea. Înregistrarea se realizează din JavaScript obișnuit pe pagină:
if ('serviceWorker' in navigator) {
navigator.serviceWorker.register('/sw.js')
.then(registration => {
console.log('SW înregistrat:', registration.scope);
})
.catch(error => {
console.log('Înregistrarea SW a eșuat:', error);
});
}Instalare. După descărcarea reușită, browserul declanșează evenimentul install. În această etapă se obișnuiește să se stocheze în cache resursele cheie (scheletul HTML, CSS, imaginile principale) pentru ca aplicația să poată funcționa offline. Dacă instalarea reușește, Service Worker trece la etapa următoare. Dacă scriptul generează o eroare — instalarea este anulată, iar Service Worker vechi continuă să funcționeze.
self.addEventListener('install', event => {
event.waitUntil(
caches.open('pwa-cache-v1').then(cache => {
return cache.addAll([
'/',
'/index.html',
'/styles/main.css',
'/scripts/app.js',
'/images/logo.png'
]);
})
);
});Activare. Când toate filele site-ului sunt închise, Service Worker vechi se termină, iar cel nou se activează. Evenimentul activate este utilizat pentru curățarea cache-urilor vechi și migrarea datelor:
self.addEventListener('activate', event => {
const cacheWhitelist = ['pwa-cache-v2'];
event.waitUntil(
caches.keys().then(cacheNames => {
return Promise.all(
cacheNames.map(cacheName => {
if (!cacheWhitelist.includes(cacheName)) {
return caches.delete(cacheName);
}
})
);
})
);
});Inactivitate. Service Worker activat interceptează cererile și procesează evenimentele. Poate fi oprit de browser pentru economisirea resurselor și repornit la următoarea cerere. Service Worker este orientat pe evenimente: trăiește doar cât procesează evenimente.
Service Worker suportă mai multe strategii de cache. Alegerea depinde de tipul resursei și cerințele de actualitate a datelor.
Cache First (cache mai întâi). Se verifică mai întâi cache-ul. Dacă resursa este găsită — se returnează din cache. Dacă nu — cererea merge la server, răspunsul este salvat în cache. Strategia este potrivită pentru resurse statice: imagini, fonturi, CSS, JS. Asigură viteză maximă și funcționare completă offline.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request).then(fetchResponse => {
return caches.open('pwa-cache-v1').then(cache => {
cache.put(event.request, fetchResponse.clone());
return fetchResponse;
});
});
})
);
});Network First (rețeaua mai întâi). Cererea merge mai întâi la server. Dacă serverul răspunde — datele sunt returnate utilizatorului și salvate în cache. Dacă serverul este indisponibil — se returnează copia din cache. Strategia este potrivită pentru cereri API, știri, conținut care trebuie să fie actual, dar poate funcționa și offline.
self.addEventListener('fetch', event => {
event.respondWith(
fetch(event.request).then(response => {
return caches.open('pwa-dynamic-v1').then(cache => {
cache.put(event.request, response.clone());
return response;
});
}).catch(() => {
return caches.match(event.request);
})
);
});Stale While Revalidate (învechit cu reîmprospătare). Răspunsul este returnat imediat din cache, iar în fundal se trimite o cerere la server pentru actualizarea cache-ului. Utilizatorul vede conținutul instantaneu, iar următoarea cerere va primi deja date proaspete. Ideal pentru conținut care se schimbă, dar nu este critic dacă utilizatorul vede o versiune cu câteva minute mai veche.
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(cached => {
const fetchPromise = fetch(event.request).then(response => {
return caches.open('pwa-dynamic-v1').then(cache => {
cache.put(event.request, response.clone());
return response;
});
});
return cached || fetchPromise;
})
);
});Manifestul — este un fișier JSON, de obicei manifest.json, care se conectează prin tagul <link> în head-ul paginii HTML. El informează browserul cum trebuie să se afișeze aplicația la instalarea pe dispozitiv: nume, pictograme de diferite dimensiuni, culoarea de fundal, culoarea temei, orientarea și modul de afișare (browser, UI minim, ecran complet).
{
"name": "PWA Demo App",
"short_name": "PWA Demo",
"description": "Aplicație demonstrativă PWA",
"start_url": "/",
"display": "standalone",
"background_color": "#ffffff",
"theme_color": "#3f51b5",
"orientation": "portrait",
"icons": [
{
"src": "/icons/icon-192x192.png",
"sizes": "192x192",
"type": "image/png"
},
{
"src": "/icons/icon-512x512.png",
"sizes": "512x512",
"type": "image/png",
"purpose": "any maskable"
}
]
}Parametrul display determină cum va arăta aplicația după instalare. standalone ascunde bara de adrese a browserului și panoul de navigare — aplicația arată ca nativă. fullscreen utilizează tot ecranul fără niciun element al browserului. minimal-ui lasă elementele minime ale browserului (butoanele înapoi și reîmprospătare).
Pictogramele trebuie pregătite în cel puțin două dimensiuni: 192x192 și 512x512 pixeli. Formatul PNG cu suport pentru parametrul purpose (de exemplu, maskable) permite browserului să adapteze pictograma la forma carcasei dispozitivului — pe Android pictograma poate fi tăiată la un pătrat rotunjit. După conectarea manifestului, browserul Chrome pe Android începe să afișeze bannerul «Adaugă pe ecranul principal» la îndeplinirea condițiilor: HTTPS, Service Worker înregistrat, manifest corect și cel puțin două vizite cu interval de 5 minute.
PWA poate trimite notificări push ca o aplicație nativă. Pentru aceasta se utilizează două API: Push API (trimitere de pe server) și Notification API (afișare pe dispozitiv). Service Worker primește evenimentul push chiar dacă aplicația nu este deschisă și poate afișa o notificare cu titlu, text și pictogramă.
Pentru a primi notificări push, utilizatorul trebuie să acorde permisiunea:
Notification.requestPermission().then(permission => {
if (permission === 'granted') {
console.log('Push permis');
}
});Service Worker se abonează la evenimentul push și afișează notificarea:
self.addEventListener('push', event => {
const data = event.data.json();
self.registration.showNotification(data.title, {
body: data.body,
icon: '/icons/icon-192x192.png',
badge: '/icons/badge-72x72.png',
actions: [
{ action: 'open', title: 'Deschide' },
{ action: 'close', title: 'Închide' }
]
});
});
self.addEventListener('notificationclick', event => {
event.notification.close();
if (event.action === 'open') {
clients.openWindow('/');
}
});Pentru trimiterea push de pe server se utilizează protocolul Web Push (VAPID). Serverul criptează mesajul și îl trimite prin serviciul push al browserului (Firebase Cloud Messaging pentru Chrome, Mozilla Autopush pentru Firefox). Abonamentul utilizatorului (obiectul PushSubscription) trebuie salvat pe server la înregistrare.
PWA trebuie să fie rapid. Google Lighthouse — instrument de audit care verifică PWA după o listă de control: înregistrarea Service Worker, răspunsul 200 la acces offline, manifest corect, HTTPS, dimensiunea corectă a pictogramelor, încărcare rapidă în rețele lente. Scorul minim de trecere pentru PWA — 80 din 100 pe scara Lighthouse. Aplicațiile cu scor sub 80 nu primesc bannerul de instalare în Chrome.
Metricile cheie de performanță pentru PWA — First Contentful Paint (FCP) până la 1.8 secunde, Largest Contentful Paint (LCP) până la 2.5 secunde, Time to Interactive (TTI) până la 3.5 secunde. Service Worker poate îmbunătăți semnificativ FCP și LCP dacă stochează în cache HTML și CSS critic la instalare. Strategia Cache First pentru statică și Stale While Revalidate pentru API oferă cea mai bună experiență utilizator.
Una dintre principalele capacități ale PWA — funcționarea fără internet. Service Worker interceptează cererile și returnează versiunile stocate în cache ale paginilor. Dacă utilizatorul încearcă să deschidă o pagină care nu este în cache, se poate afișa o pagină de rezervă personalizată:
self.addEventListener('fetch', event => {
event.respondWith(
caches.match(event.request).then(response => {
return response || fetch(event.request);
}).catch(() => {
return caches.match('/offline.html');
})
);
});Sincronizarea în fundal (Background Sync) permite amânarea trimiterii datelor pe server dacă dispozitivul este offline. Service Worker salvează cererea și o trimite automat când conexiunea este restabilită:
self.addEventListener('sync', event => {
if (event.tag === 'sync-messages') {
event.waitUntil(sendMessages());
}
});
function sendMessages() {
return caches.open('pwa-pending-v1').then(cache => {
return cache.keys().then(requests => {
return Promise.all(requests.map(request => {
return fetch(request).then(() => cache.delete(request));
}));
});
});
}Chrome DevTools oferă panoul Application, unde se poate depana Service Worker (înregistrare, stare, cache, push), verifica manifestul, curăța cache-ul și crea propriile notificări push pentru testare. Fila Network cu emularea modului offline ajută la verificarea funcționării cache-ului. Lighthouse în panoul Audits oferă un audit PWA complet cu recomandări.
Workbox — biblioteca de la Google care simplifică crearea Service Worker. În locul scrierii manuale a strategiilor de cache, Workbox oferă module gata făcute:
import { precacheAndRoute } from 'workbox-precaching';
import { registerRoute } from 'workbox-routing';
import { StaleWhileRevalidate } from 'workbox-strategies';
precacheAndRoute(self.__WB_MANIFEST);
registerRoute(
/\.(?:png|jpg|jpeg|svg|gif)$/,
new StaleWhileRevalidate()
);Workbox se integrează cu bundleri (Webpack, Vite) și generează automat manifestul de pre-cache. PWA Builder (pwabuilder.com) de la Microsoft generează toate fișierele PWA online: Service Worker, manifest, pictograme, șablon HTML.
FAQ
PWA — este un site care după instalarea pe telefon funcționează ca o aplicație obișnuită: are pictogramă pe desktop, acces offline, notificări push, mod ecran complet fără bara de adrese a browserului. În același timp, nu trebuie să mergi în App Store sau Google Play — instalarea are loc cu un singur clic din browser.
Aplicația nativă este scrisă pentru o platformă specifică (Swift pentru iOS, Kotlin pentru Android), necesită publicare în magazin și instalare manuală. PWA — este un site web scris în HTML, CSS și JavaScript, care poate fi instalat pe dispozitiv prin browser. PWA nu ocupă mult spațiu (doar cache-ul), se actualizează automat și este suportat de toate browserele moderne.
Chrome, Firefox, Safari (începând cu iOS 11.3), Edge, Samsung Internet, Opera. Service Worker este suportat de toate browserele moderne, cu excepția Internet Explorer. Safari are suport limitat pentru notificări push, dar capabilitățile de bază ale PWA (instalare pe ecranul principal, acces offline) funcționează.
Da. Pentru aceasta trebuie adăugat manifestul (manifest.json), creat și înregistrat Service Worker (sw.js), trecut site-ul pe HTTPS, adăugate meta taguri și pictograme. Site-ul în sine nu necesită rescriere dacă funcționează pe JavaScript și returnează HTML. Dacă site-ul este complet server-side (MPA), se poate adăuga Service Worker ca strat de cache fără a modifica arhitectura.
Când utilizatorul deschide PWA, browserul verifică dacă fișierul Service Worker de pe server s-a modificat. Dacă fișierul diferă măcar cu un octet, browserul descarcă noul Service Worker și începe instalarea acestuia. Service Worker vechi continuă să funcționeze până când toate filele aplicației sunt închise. După închiderea filelor, noul Service Worker se activează și îl înlocuiește pe cel vechi. Utilizatorul poate forța actualizarea aplicației reîncărcând pagina.
PWA este justificat dacă scopul este acoperirea audienței maxime fără costuri de dezvoltare pentru două platforme, dacă aplicația nu necesită acces profund la hardware (Bluetooth, NFC, cameră în fundal), dacă conținutul se schimbă frecvent. Pentru aplicații complexe (jocuri, editoare video) aplicația nativă rămâne preferabilă. PWA este adesea folosit ca canal suplimentar sau ca MVP înaintea unei aplicații complete.
Rezumat
Vom dezvolta o aplicație mobilă la cheie
IT Sectr creează aplicații iOS și Android pentru startup-uri și afaceri din 2017. Vă vom consilia și vă vom propune cea mai bună soluție.
Citiți și