La tua prima app web progressiva

Ultimo aggiornamento: 30-04-2019

Cosa rende un'app web un'app web progressiva?

Le app web progressive offrono un'esperienza simile a quella di un'app su desktop e dispositivi mobili, creata e pubblicata direttamente tramite il Web. Sono app web veloci e affidabili. Ma l'aspetto più importante è che sono app web che funzionano in qualsiasi browser. Se stai creando un'app web oggi, sei già sulla strada giusta per creare un'app web progressiva.

Veloce e affidabile

Tutte le esperienze web devono essere rapide, in particolare per le app web progressive. "Veloce" fa riferimento al tempo necessario per ottenere contenuti significativi sullo schermo e per offrire un'esperienza interattiva.

Inoltre, deve essere molto veloce. È troppo difficile sottolineare quanto sia migliore il rendimento. Pensaci in questo modo: il primo caricamento di un'app nativa è frustrante. Questo servizio è controllato da uno store e da un enorme download, ma quando arrivi al punto in cui è installata l'app, il costo iniziale viene ammortizzato a tutti gli avvii dell'app e nessuno di essi ha un ritardo variabile. Ogni avvio dell'applicazione è veloce come l'ultima, senza varianza. Un'app web progressiva deve offrire queste prestazioni affidabili che gli utenti si aspettano da qualsiasi esperienza installata.

Installabile

Le app web progressive possono essere eseguite in una scheda del browser, ma sono anche installabili. Aggiungere un sito ai preferiti aggiunge solo una scorciatoia, ma un'app web progressiva (PWA) installata si comporta e si comporta come tutte le altre app installate. Viene avviata dalla stessa posizione in cui vengono lanciati le altre app. Puoi controllare l'esperienza di lancio, compresa una schermata iniziale personalizzata, icone e altro ancora. Viene eseguito come app, in una finestra dell'app senza barra degli indirizzi o altre interfacce utente del browser. Come tutte le altre app installate, è un'app di primo livello nel selettore di attività.

Ricorda che una PWA installabile è veloce e affidabile. Gli utenti che installano una PWA si aspettano che le loro app funzionino, indipendentemente dal tipo di connessione di rete su cui sono attivi. È un'aspettativa di base che ogni app installata deve soddisfare.

Dispositivi mobili e dispositivi desktop

Utilizzando tecniche di responsive design, le PWA funzionano sia su dispositivi mobili sia su desktop, utilizzando un unico codebase tra le piattaforme. Se stai pensando di scrivere un'app nativa, dai un'occhiata ai vantaggi offerti da una PWA.

Cosa imparerai a realizzare

In questo codelab, creerai un'app web per il meteo utilizzando tecniche PWA. La tua app sarà in grado di:

  • Il responsive design funziona su desktop o dispositivi mobili.
  • Velocizza l'utilizzo di un service worker per la memorizzazione preliminare nella cache delle risorse dell'app (HTML, CSS, JavaScript, immagini) necessarie per l'esecuzione e per memorizzare nella cache i dati meteo in fase di runtime per migliorare le prestazioni.
  • Installabili, utilizzando un manifest dell'app web e l'evento beforeinstallprompt per informare l'utente che l'app è installabile.

Cosa imparerai a fare:

  • Come creare e aggiungere un manifest per app web
  • Come offrire un'esperienza offline semplice
  • Come offrire un'esperienza offline completa
  • Come rendere l'app installabile

Questo codelab è incentrato sulle app web progressive. Concetti e blocchi di codice non pertinenti sono trattati solo superficialmente e sono forniti solo per operazioni di copia e incolla.

Che cosa ti serve

  • Una versione recente di Chrome (74 o versioni successive). Le PWA funzionano in tutti i browser, ma useremo alcune funzionalità di Chrome DevTools per capire meglio cosa sta succedendo a livello di browser e come usarla per testare l'esperienza di installazione.
  • Conoscenza di HTML, CSS, JavaScript e Chrome DevTools.

Ottieni una chiave per l'API Dark Sky

I nostri dati sul meteo provengono dall'API Dark Sky. Per utilizzarla, dovrai richiedere una chiave API. È facile da usare e senza costi per progetti non commerciali.

Registrati per la chiave API

Verificare che la chiave API funzioni correttamente

Per verificare che la tua chiave API funzioni correttamente, effettua una richiesta HTTP all'API DarkSky. Aggiorna l'URL di seguito per sostituire DARKSKY_API_KEY con la chiave API. Se funziona tutto, dovresti visualizzare le previsioni meteo più recenti di New York.

https://api.darksky.net/forecast/DARKSKY_API_KEY/40.7720232,-73.9732319

Genera il codice

Abbiamo messo tutto ciò che ti serve per questo progetto in un repository Git. Per iniziare, devi prendere il codice e aprirlo nel tuo ambiente di sviluppo preferito. Per questo codelab, ti consigliamo di utilizzare Glitch.

Vivamente consigliato: utilizza Glitch per importare il repository

L'utilizzo di Glitch è il metodo consigliato per lavorare su questo codelab.

  1. Apri una nuova scheda del browser e vai a https://glitch.com.
  2. Se non hai un account, dovrai registrarti.
  3. Fai clic su Nuovo progetto, quindi su Clona dal repository Git.
  4. Clona https://github.com/googlecodelabs/your-first-pwapp.git e fai clic su OK.
  5. Una volta caricato il repository, modifica il file .env e aggiornalo utilizzando la chiave API DarkSky.
  6. Per vedere l'applicazione PWA, fai clic sul pulsante Mostra, quindi scegli In una nuova finestra.

Alternativa: scarica il codice & lavora localmente

Se vuoi scaricare il codice e lavorare localmente, devi disporre di una versione recente di Node.js e di un editor di codice configurato e pronto.

Scaricare il codice sorgente

  1. Apri il file ZIP scaricato.
  2. Esegui npm install per installare le dipendenze necessarie per l'esecuzione del server.
  3. Modifica server.js e imposta la tua chiave API DarkSky.
  4. Esegui node server.js per avviare il server sulla porta 8000.
  5. Apri una scheda del browser all'indirizzo http://localhost:8000.

Qual è il nostro punto di partenza?

Il nostro punto di partenza è un'app meteo di base progettata per questo codelab. Il codice è stato semplificato per mostrare i concetti in questo codelab e ha una gestione ridotta degli errori. Se decidi di riutilizzare questo codice in un'app in produzione, assicurati di gestire gli errori e di testare completamente il codice.

Alcune cose da provare...

  1. Aggiungi una nuova città con il pulsante blu + nell'angolo in basso a destra.
  2. Aggiorna i dati con il pulsante di aggiornamento nell'angolo in alto a destra.
  3. Elimina una città utilizzando la x in alto a destra in ogni scheda.
  4. Utilizzando la barra degli strumenti di attivazione/disattivazione dei dispositivi in Chrome DevTools, scopri come funziona su desktop e dispositivi mobili.
  5. Utilizzando il riquadro Rete in Chrome DevTools, scopri cosa succede quando sei offline.
  6. Utilizzando il riquadro Rete in Chrome DevTools, scopri cosa succede quando la rete viene limitata a 3G lenta.
  7. Aggiungi un ritardo al server di previsione modificando il valore di FORECAST_DELAY in server.js

Controllo con Lighthouse

Lighthouse è uno strumento facile da utilizzare che consente di migliorare la qualità dei siti e delle pagine. Lighthouse esegue controlli per le prestazioni, l'accessibilità, le app web progressive e altro ancora. Ogni controllo contiene un documento di riferimento che spiega perché il controllo è importante e come risolvere i problemi.

Useremo Lighthouse per controllare la nostra app Meteo e verificare le modifiche apportate.

Esegui Lighthouse

  1. Apri il progetto in una nuova scheda.
  2. Apri Chrome DevTools e passa al riquadro Controlli. Lascia attivi tutti i tipi di controllo.
  3. Fai clic su Esegui controlli. Dopo un po' di tempo, Lighthouse ti fornisce un rapporto sulla pagina.

Controlli dell'app web progressiva

Ci concentreremo sui risultati della revisione delle app web progressive.

C'è molto rosso su cui concentrarsi:

  • ❗FAILED: la pagina corrente non risponde con un codice 200 quando è offline.
  • ❗FAILED: start_url non risponde con un codice 200 quando è offline.
  • ❗FAILED: non registra un service worker che controlla la pagina e start_url..
  • ❗FAILED: il file manifest dell'app web non soddisfa i requisiti di installabilità.
  • ❗FAILED: non configurato per una schermata iniziale personalizzata.
  • ❗FAILED: non consente di impostare un colore per il tema della barra degli indirizzi.

Iniziamo a correggere alcuni di questi problemi.

Al termine di questa sezione, la nostra app Meteo supera i seguenti controlli:

  • Il file manifest dell'app web non soddisfa i requisiti di installabilità.
  • Non configurata per una schermata iniziale personalizzata.
  • Non imposta un colore per il tema della barra degli indirizzi.

Creare il manifest dell'app web

Il file manifest dell'app web è un semplice file JSON che offre allo sviluppatore la possibilità di controllare l'aspetto dell'app.

Il file manifest dell'app web consente di:

  • Comunica al browser che vuoi che la tua app si apra in una finestra autonoma (display).
  • Definisci la pagina che viene aperta quando l'app viene avviata per la prima volta (start_url).
  • Definisci l'aspetto dell'app sul dock o su Avvio applicazioni (short_name, icons).
  • Crea una schermata iniziale (name, icons, colors).
  • Indica al browser di aprire la finestra in orizzontale o in verticale (orientation).
  • E molte altre.

Crea un file denominato public/manifest.json nel progetto. Copia e incolla i seguenti contenuti:

public/manifest.json

{
  "name": "Weather",
  "short_name": "Weather",
  "icons": [{
    "src": "/images/icons/icon-128x128.png",
      "sizes": "128x128",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-144x144.png",
      "sizes": "144x144",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-152x152.png",
      "sizes": "152x152",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-192x192.png",
      "sizes": "192x192",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-256x256.png",
      "sizes": "256x256",
      "type": "image/png"
    }, {
      "src": "/images/icons/icon-512x512.png",
      "sizes": "512x512",
      "type": "image/png"
    }],
  "start_url": "/index.html",
  "display": "standalone",
  "background_color": "#3E4EB8",
  "theme_color": "#2F3BA2"
}

Il file manifest supporta un array di icone, destinate a schermi di dimensioni diverse. Per questo codelab, ne abbiamo aggiunti altri per l'integrazione con iOS.

Successivamente, dobbiamo comunicare al browser il nostro file manifest aggiungendo un <link rel="manifest"... a ogni pagina nella nostra app. Aggiungi la seguente riga all'elemento <head> nel file index.html.

pubblico/index.html

<!-- CODELAB: Add link rel manifest -->
<link rel="manifest" href="/manifest.json">

DevTools deviazione

DevTools ti consente di controllare in modo facile e veloce il tuo file manifest.json. Apri il riquadro Manifest (Manifest) nel riquadro Applicazione. Se hai aggiunto correttamente le informazioni del manifest, in questo riquadro potrai vederle analizzate e mostrate in un formato leggibile.

Aggiungere meta tag iOS e icone

Safari su iOS non supporta il manifest dell'app web (ancora), pertanto dovrai aggiungere i tag tradizionali meta al <head> del file index.html:

pubblico/index.html

<!-- CODELAB: Add iOS meta tags and icons -->
<meta name="apple-mobile-web-app-capable" content="yes">
<meta name="apple-mobile-web-app-status-bar-style" content="black">
<meta name="apple-mobile-web-app-title" content="Weather PWA">
<link rel="apple-touch-icon" href="/images/icons/icon-152x152.png">

Bonus: correzioni facili da Lighthouse

Il nostro controllo Lighthouse ha evidenziato alcune cose abbastanza facili da risolvere, perciò le prendiamo in considerazione mentre siamo qui.

Impostare la meta descrizione

Sotto il controllo SEO, Lighthouse ha notato il nostro "Documento non ha una meta descrizione". Le descrizioni possono essere visualizzate nei risultati della Ricerca Google. Descrizioni univoche e di alta qualità possono rendere i risultati più pertinenti per gli utenti che eseguono ricerche e possono aumentare il traffico di ricerca.

Per aggiungere una descrizione, aggiungi il seguente tag meta al tag <head> del documento:

pubblico/index.html

<!-- CODELAB: Add description here -->
<meta name="description" content="A sample weather app">

Impostare il colore del tema della barra degli indirizzi

Durante il controllo PWA, Lighthouse ha rilevato l'app "Non imposta un colore del tema della barra degli indirizzi". Impostando come target la barra degli indirizzi del browser in modo che corrisponda ai colori del brand offre un'esperienza utente più coinvolgente.

Per impostare il colore del tema sui dispositivi mobili, aggiungi il seguente tag meta al tag <head> del documento:

pubblico/index.html

<!-- CODELAB: Add meta theme-color -->
<meta name="theme-color" content="#2F3BA2" />

Verificare le modifiche con Lighthouse

Esegui di nuovo Lighthouse (facendo clic sul segno + nell'angolo in alto a sinistra del riquadro Controlli) e verifica le modifiche.

Controllo SEO

  • ✅ SUPERATO: il documento ha una meta descrizione.

Log di controllo delle app web progressive

  • ❗FAILED: la pagina corrente non risponde con un codice 200 quando è offline.
  • ❗FAILED: start_url non risponde con un codice 200 quando è offline.
  • ❗FAILED: non registra un service worker che controlla la pagina e start_url..
  • ✅ SUPERATO: il file manifest dell'app web soddisfa i requisiti di installabilità.
  • ✅ SUPERATO: Configurato per una schermata iniziale.
  • ✅ SUPERATO: imposta il colore del tema della barra degli indirizzi.

Gli utenti che hanno installato le app avranno sempre un'esperienza di base se sono offline. Ecco perché è fondamentale che le app web installabili non mostrino mai il gioco del dinosauro offline di Chrome. L'esperienza offline va da una semplice pagina offline, a un'esperienza di sola lettura con i dati memorizzati nella cache in precedenza, a un'esperienza offline completamente funzionante che si sincronizza automaticamente quando viene ripristinata la connessione di rete.

In questa sezione aggiungeremo una semplice pagina offline alla nostra app meteo. Se l'utente tenta di caricare l'app mentre è offline, verrà visualizzata la nostra pagina personalizzata, anziché la tipica pagina offline visualizzata dal browser. Al termine di questa sezione, la nostra app Meteo supera i seguenti controlli:

  • La pagina corrente non risponde con un codice 200 quando è offline.
  • start_url non risponde con un codice 200 quando è offline.
  • Non registra un service worker che controlla la pagina e start_url.

Nella sezione successiva, sostituiremo la nostra pagina offline personalizzata con un'esperienza offline completa. Questo migliora l'esperienza offline, ma, soprattutto, consente di migliorare notevolmente le prestazioni, perché la maggior parte degli asset (HTML, CSS e JavaScript) viene archiviata e pubblicata localmente, eliminando la rete come potenziale collo di bottiglia.

I service worker verranno salvati

Se non hai dimestichezza con i service worker, puoi comprendere cosa possono fare, come funzionano e molto altro, leggendo la Introduzione ai service worker.

Le funzionalità fornite tramite i service worker dovrebbero essere considerate un miglioramento progressivo e vengono aggiunte solo se supportate dal browser. Ad esempio, con i service worker puoi memorizzare nella cache la shell dell'app e i dati della tua app in modo che siano disponibili anche quando la rete non è disponibile. Quando i service worker non sono supportati, il codice offline non viene chiamato e l'utente riceve un'esperienza di base. L'utilizzo del rilevamento delle funzionalità per fornire un miglioramento progressivo ha un overhead basso e non avviene nei browser meno recenti che non supportano questa funzionalità.

Registra il service worker

Il primo passaggio consiste nel registrare il service worker. Aggiungi il seguente codice al tuo file index.html:

pubblico/index.html

// CODELAB: Register service worker.
if ('serviceWorker' in navigator) {
  window.addEventListener('load', () => {
    navigator.serviceWorker.register('/service-worker.js')
        .then((reg) => {
          console.log('Service worker registered.', reg);
        });
  });
}

Questo codice controlla se l'API del service worker è disponibile e, se lo è, il service worker all'indirizzo /service-worker.js viene registrato una volta che la pagina è caricata.

Nota: il service worker viene pubblicato dalla directory radice, non dalla directory /scripts/. Questo è il modo più semplice per impostare il scope del tuo service worker. L'scope del service worker determina quali file controlla il service worker, ovvero in base a quale percorso il service worker intercetta le richieste. Il valore predefinito scope è la posizione del file del service worker e si estende a tutte le directory riportate di seguito. Pertanto, se service-worker.js si trova nella directory principale, il service worker controllerà le richieste di tutte le pagine web di questo dominio.

Precache della pagina offline

Innanzitutto, dobbiamo comunicare al service worker cosa memorizzare nella cache. Abbiamo già creato una semplice pagina offline (public/offline.html) che verrà visualizzata in assenza di connessione di rete.

In service-worker.js, aggiungi '/offline.html', all'array di FILES_TO_CACHE, il risultato finale dovrebbe avere il seguente aspetto:

public/service-worker.js

// CODELAB: Add list of files to cache here.
const FILES_TO_CACHE = [
  '/offline.html',
];

Quindi, dobbiamo aggiungere il seguente codice all'evento install per indicare al service worker di memorizzare nella cache la pagina offline:

public/service-worker.js

// CODELAB: Precache static resources here.
evt.waitUntil(
    caches.open(CACHE_NAME).then((cache) => {
      console.log('[ServiceWorker] Pre-caching offline page');
      return cache.addAll(FILES_TO_CACHE);
    })
);

Ora il nostro evento install apre la cache con caches.open() e fornisce un nome cache. Fornisci un nome memorizzato nella cache ci consente di accedere alle versioni dei file o di separare i dati dalle risorse memorizzate nella cache, in modo da poter aggiornare facilmente uno solo dei file ma non l'altro.

Una volta aperta la cache, possiamo chiamare cache.addAll(), che acquisisce un elenco di URL, li recupera dal server e aggiunge la risposta alla cache. Tieni presente che cache.addAll() non riesce se una delle singole richieste non riesce. Ciò significa che, se il passaggio di installazione ha esito positivo, la cache sarà in uno stato coerente. Se, per qualche motivo, l'operazione non riesce, il tentativo verrà eseguito automaticamente al successivo avvio del service worker.

DevTools deviazione

Diamo un'occhiata a come puoi utilizzare DevTools per capire ed eseguire il debug dei service worker. Prima di ricaricare la pagina, apri DevTools e vai al riquadro Service worker nel riquadro Applicazione. Dovrebbe avere questo aspetto:

Quando vedi una pagina vuota come questa, significa che la pagina attualmente aperta non contiene alcun service worker registrato.

Ora, ricarica la tua pagina. Il riquadro Service worker ora dovrebbe essere simile al seguente:

Quando vedi informazioni come queste, significa che nella pagina è presente un service worker.

Accanto all'etichetta Stato, è presente un numero (34251 in questo caso). Tieni d'occhio il numero mentre lavori con i service worker. È un modo semplice per verificare se il service worker è stato aggiornato.

Ripulire le vecchie pagine offline

Utilizzeremo l'evento activate per ripulire tutti i vecchi dati nella cache. Questo codice garantisce che il service worker aggiorni la cache ogni volta che uno dei file della shell dell'app viene modificato. Per questa operazione, devi incrementare la variabile CACHE_NAME nella parte superiore del file del service worker.

Aggiungi il seguente codice al tuo evento activate:

public/service-worker.js

// CODELAB: Remove previous cached data from disk.
evt.waitUntil(
    caches.keys().then((keyList) => {
      return Promise.all(keyList.map((key) => {
        if (key !== CACHE_NAME) {
          console.log('[ServiceWorker] Removing old cache', key);
          return caches.delete(key);
        }
      }));
    })
);

DevTools deviazione

Con il riquadro Service worker aperto, aggiorna la pagina. Vedrai il nuovo service worker installato e il numero di stato è stato incrementato.

Il service worker aggiornato prende il controllo immediatamente perché il nostro evento install termina con self.skipWaiting(), mentre l'evento activate termina con self.clients.claim(). Senza queste impostazioni, il vecchio service worker continuerà a controllare la pagina finché è aperta una scheda.

Gestire le richieste di rete non riuscite

Infine, dobbiamo gestire gli eventi fetch. Useremo una strategia Rete di riserva nella cache. Il service worker tenta innanzitutto di recuperare la risorsa dalla rete. In caso contrario, il service worker restituisce la pagina offline dalla cache.

public/service-worker.js

// CODELAB: Add fetch event handler here.
if (evt.request.mode !== 'navigate') {
  // Not a page navigation, bail.
  return;
}
evt.respondWith(
    fetch(evt.request)
        .catch(() => {
          return caches.open(CACHE_NAME)
              .then((cache) => {
                return cache.match('offline.html');
              });
        })
);

Il gestore fetch deve gestire soltanto le navigazioni delle pagine, pertanto le altre richieste possono essere esportate dal gestore e gestite normalmente dal browser. Se, invece, la richiesta .mode è navigate, utilizza fetch per cercare di scaricare l'elemento dalla rete. Se l'operazione non riesce, il gestore di catch apre la cache con caches.open(CACHE_NAME) e utilizza cache.match('offline.html') per recuperare la pagina offline memorizzata nella cache. Il risultato viene quindi ritrasmesso al browser utilizzando evt.respondWith().

DevTools deviazione

Controlliamo che tutto funzioni come previsto. Con il riquadro Service worker aperto, aggiorna la pagina. Vedrai il nuovo service worker installato e il numero di stato è stato incrementato.

Possiamo anche controllare quali elementi sono stati memorizzati nella cache. Vai al riquadro Archiviazione cache nel riquadro Applicazione di DevTools. Fai clic con il pulsante destro del mouse su Cache Cache, scegli Refresh Caches (Aggiorna cache) ed espandi la sezione. Sul lato sinistro dovresti vedere il nome della cache statica. Fai clic sul nome della cache per visualizzare tutti i file memorizzati nella cache.

Ora testiamo la modalità offline. Torna al riquadro Service worker nel riquadro Applicazione di DevTools e seleziona la casella di controllo Offline. Dopo averlo controllato, dovresti vedere una piccola icona di avviso gialla accanto alla scheda del riquadro Rete. Questa icona indica che sei offline.

Ricarica la pagina... Riceviamo il nostro panda offline anziché un browser offline di Chrome.

Suggerimenti per testare i service worker

Eseguire il debug dei service worker può essere una vera sfida e, quando è necessaria la memorizzazione nella cache, le cose possono diventare ancora più incubi se la cache non viene aggiornata come previsto. Tra il tipico ciclo di vita del service worker e un bug nel codice, potresti rimanere frustrato. Ma non farlo.

Utilizzare DevTools

Nel riquadro Service worker del riquadro Applicazione sono presenti alcune caselle di controllo che ti semplificheranno la vita.

  • Offline: se questa opzione è selezionata, simula un'esperienza offline e impedisce la ricezione di richieste sulla rete.
  • Aggiorna al ricaricamento: se l'opzione è selezionata, viene scaricato l'ultimo service worker, quindi puoi installarlo e attivarlo immediatamente.
  • Ignora per la rete: se l'opzione è selezionata, le richieste ignorano il service worker e vengono inviate direttamente alla rete.

Ricomincia

In alcuni casi, potresti notare che i dati memorizzati nella cache vengono caricati o che gli elementi non vengono aggiornati come previsto. Per cancellare tutti i dati salvati (localStorage, i dati indicizzati, i file memorizzati nella cache) e rimuovere eventuali service worker, utilizza il riquadro Cancella spazio di archiviazione nel riquadro Applicazione. In alternativa, puoi anche lavorare in una finestra di navigazione in incognito.

Ulteriori suggerimenti:

  • Una volta annullata la registrazione di un service worker, può rimanere nell'elenco fino a quando non viene chiusa la finestra del browser che lo contiene.
  • Se sono aperte più finestre alla tua app, un nuovo service worker non avrà effetto finché tutte le finestre non saranno state ricaricate e aggiornate al service worker più recente.
  • L'annullamento della registrazione di un service worker non svuota la cache.
  • Se esiste un service worker e viene registrato un nuovo service worker, quest'ultimo non avrà il controllo fino a quando la pagina non verrà ricaricata, a meno che tu non prenda il controllo immediato.

Verificare le modifiche con Lighthouse

Esegui di nuovo Lighthouse e verifica le modifiche. Prima di verificare le modifiche, non dimenticare di deselezionare la casella di controllo Offline.

Controllo SEO

  • ✅ SUPERATO: il documento ha una meta descrizione.

Log di controllo delle app web progressive

  • ✅ SUPERATO: la pagina corrente risponde con un codice 200 quando è offline.
  • ✅ SUPERATO: start_url risponde con un codice 200 quando è offline.
  • ✅ SUPERATO: registra un service worker che controlla la pagina e start_url.
  • ✅ SUPERATO: il file manifest dell'app web soddisfa i requisiti di installabilità.
  • ✅ SUPERATO: Configurato per una schermata iniziale.
  • ✅ SUPERATO: imposta il colore del tema della barra degli indirizzi.

Attiva la modalità aereo sul telefono e prova a eseguire alcune delle tue app preferite. In quasi tutti i casi, offrono un'esperienza offline abbastanza affidabile. Gli utenti si aspettano un'esperienza solida dalle loro app. E il Web non dovrebbe essere diverso. Le app web progressive devono essere progettate offline come scenario principale.

Ciclo di vita dei service worker

Il ciclo di vita del service worker è la parte più complicata. Se non sai che cosa sta cercando di fare e quali vantaggi ne hai, potrebbe sembrare che tu stia cercando di superarlo. Tuttavia, una volta compreso come funziona, puoi fornire agli utenti aggiornamenti continui e discreti, combinando il meglio del Web con i pattern nativi.

install evento

Il primo evento ricevuto da un service worker è install. Si attiva non appena il worker viene eseguito ed è chiamato una sola volta per ogni service worker. Se modifichi lo script del service worker, il browser lo considera un altro service worker e riceverà un evento install proprio.

In genere, l'evento install viene utilizzato per memorizzare nella cache tutto ciò che ti serve per l'esecuzione della tua app.

activate evento

Il service worker riceverà un evento activate a ogni avvio. Lo scopo principale dell'evento activate è configurare il comportamento del service worker, ripulire tutte le risorse rimaste dalle esecuzioni precedenti (ad es. le vecchie cache) e preparare il service worker a gestire le richieste di rete (ad esempio l'evento fetch descritto di seguito).

fetch evento

L'evento di recupero consente al service worker di intercettare le richieste di rete e gestire le richieste. Può collegarsi alla rete per recuperare la risorsa, recuperarla dalla propria cache, generare una risposta personalizzata o un numero qualsiasi di opzioni diverse. Consulta il libro offline per scoprire le varie strategie da utilizzare.

Aggiornamento di un service worker

Il browser controlla se è presente una nuova versione del service worker a ogni caricamento pagina. Se trova una nuova versione, viene scaricata e installata in background, ma non è attivata. La nuova versione del service worker rimarrà in attesa fino a quando non ci saranno più pagine che lo utilizzano. Dopo aver chiuso tutte le finestre che utilizzano il vecchio service worker, quest'ultimo viene attivato e può assumere il controllo. Per ulteriori dettagli, consulta la sezione Aggiornamento del service worker del documento Ciclo di vita dei service worker.

Scegliere la giusta strategia di memorizzazione nella cache

La scelta della strategia di memorizzazione nella cache corretta dipende dal tipo di risorsa che stai cercando di memorizzare nella cache e da come potresti accedervi in un secondo momento. Per la nostra app relativa al meteo, suddivideremo le risorse necessarie in due categorie: le risorse da memorizzare nella cache e i dati memorizzati nella cache in fase di runtime.

Memorizzazione nella cache delle risorse statiche

La prearchiviazione delle risorse è un concetto simile a quello che si verifica quando un utente installa un'app per dispositivi mobili o desktop. Le risorse principali necessarie per l'esecuzione dell'app vengono installate o memorizzate nella cache sul dispositivo per poter essere caricate in un secondo momento, indipendentemente dal fatto che esista o meno una connessione di rete.

Per la nostra app, eseguiremo una precache di tutte le nostre risorse statiche quando il nostro service worker sarà installato, in modo che tutto ciò di cui abbiamo bisogno per eseguire la nostra app venga archiviato sul dispositivo dell'utente. Per garantire che la nostra app venga caricata velocemente, useremo la strategia cache-first; invece di andare alla rete per scaricare le risorse, verranno estratte dalla cache locale; solo se non sono disponibili, tenteremo di scaricare l'app dalla rete.

Il pull dalla cache locale elimina qualsiasi variabilità di rete. Indipendentemente dal tipo di rete su cui si trova l'utente (Wi-Fi, 5G, 3G o anche 2G), le risorse chiave di cui abbiamo bisogno sono disponibili quasi immediatamente.

Memorizzazione nella cache dei dati dell'applicazione

La strategia stale-while-revalidate è la scelta ideale per alcuni tipi di dati e funziona bene per la nostra app. Visualizza i dati sullo schermo nel più breve tempo possibile, quindi si aggiorna quando la rete ha restituito i dati più recenti. In caso di inattività dello stato di riconvalida significa che dobbiamo avviare due richieste asincrone, una nella cache e una nella rete.

In circostanze normali, i dati memorizzati nella cache vengono restituiti quasi immediatamente fornendo all'app i dati recenti utilizzabili. Quando verrà restituita la richiesta di rete, l'app verrà aggiornata utilizzando i dati più recenti della rete.

Per la nostra app, l'app offre un'esperienza migliore di quella di rete, perché utilizza la strategia di memorizzazione nella cache perché l'utente non deve aspettare che la richiesta di rete scada prima di vedere qualcosa sullo schermo. Inizialmente potrebbero vedere dati precedenti, ma una volta restituita la richiesta di rete, l'app viene aggiornata con i dati più recenti.

Aggiornare la logica dell'app

Come accennato in precedenza, l'app deve avviare due richieste asincrone, una nella cache e una nella rete. L'app utilizza l'oggetto caches disponibile in window per accedere alla cache e recuperare i dati più recenti. Questo è un eccellente esempio di miglioramento progressivo poiché l'oggetto caches potrebbe non essere disponibile in tutti i browser e, in caso contrario, la richiesta di rete dovrebbe comunque funzionare.

Aggiorna la funzione getForecastFromCache(), per verificare se l'oggetto caches è disponibile nell'oggetto window globale e, se lo è, richiedi i dati dalla cache.

public/scripts/app.js

// CODELAB: Add code to get weather forecast from the caches object.
if (!('caches' in window)) {
  return null;
}
const url = `${window.location.origin}/forecast/${coords}`;
return caches.match(url)
    .then((response) => {
      if (response) {
        return response.json();
      }
      return null;
    })
    .catch((err) => {
      console.error('Error getting data from cache', err);
      return null;
    });

Quindi, è necessario modificare updateData() in modo che effettui due chiamate, una a getForecastFromNetwork() per ottenere la previsione dalla rete e una a getForecastFromCache() per ottenere la previsione più recente memorizzata nella cache:

public/scripts/app.js

// CODELAB: Add code to call getForecastFromCache.
getForecastFromCache(location.geo)
    .then((forecast) => {
      renderForecast(card, forecast);
    });

La nostra app relativa al meteo effettua ora due richieste asincrone di dati, una dalla cache e una tramite un fetch. Se nella cache sono presenti dati, verranno restituiti e visualizzati molto rapidamente (decine di millisecondi). Quando fetch risponde, la scheda viene aggiornata con i dati più recenti direttamente dall'API Meteo.

Nota che la richiesta cache e la richiesta fetch terminano entrambe con una chiamata per aggiornare la scheda previsioni. Come fa l'app a sapere se mostra i dati più recenti? Tale numero è gestito nel seguente codice da renderForecast():

public/scripts/app.js

// If the data on the element is newer, skip the update.
if (lastUpdated >= data.currently.time) {
  return;
}

Ogni volta che una scheda viene aggiornata, l'app memorizza il timestamp dei dati su un attributo nascosto. L'app esegue il salvataggio se il timestamp già esistente nella scheda è più recente dei dati trasmessi alla funzione.

Memorizzare in anteprima le risorse dell'app

Nel service worker, proviamo ad aggiungere un elemento DATA_CACHE_NAME per consentirci di separare i dati della nostra applicazione dalla shell dell'app. Quando la shell dell'app viene aggiornata e le cache precedenti vengono eliminate definitivamente, i nostri dati rimangono intatti e sono pronti per un caricamento super veloce. Tieni presente che, se in futuro il tuo formato dei dati cambierà, avrai bisogno di un modo per gestire questa situazione e assicurarti che la shell e i contenuti dell'app rimangano sincronizzati.

public/service-worker.js

// CODELAB: Update cache names any time any of the cached files change.
const CACHE_NAME = 'static-cache-v2';
const DATA_CACHE_NAME = 'data-cache-v1';

Non dimenticare di aggiornare anche CACHE_NAME; modificheremo anche tutte le nostre risorse statiche.

Per consentire il funzionamento offline dell'app, dobbiamo precaricare tutte le risorse necessarie. Ciò ci sarà utile anche per il nostro rendimento. Invece di dover recuperare tutte le risorse dalla rete, l'app sarà in grado di caricarle tutte dalla cache locale, eliminando l'instabilità della rete.

Aggiorna l'array FILES_TO_CACHE con l'elenco dei file:

public/service-worker.js

// CODELAB: Add list of files to cache here.
const FILES_TO_CACHE = [
  '/',
  '/index.html',
  '/scripts/app.js',
  '/scripts/install.js',
  '/scripts/luxon-1.11.4.js',
  '/styles/inline.css',
  '/images/add.svg',
  '/images/clear-day.svg',
  '/images/clear-night.svg',
  '/images/cloudy.svg',
  '/images/fog.svg',
  '/images/hail.svg',
  '/images/install.svg',
  '/images/partly-cloudy-day.svg',
  '/images/partly-cloudy-night.svg',
  '/images/rain.svg',
  '/images/refresh.svg',
  '/images/sleet.svg',
  '/images/snow.svg',
  '/images/thunderstorm.svg',
  '/images/tornado.svg',
  '/images/wind.svg',
];

Poiché generiamo manualmente l'elenco di file da memorizzare nella cache, ogni volta che aggiorniamo un file dobbiamo aggiornare CACHE_NAME. Siamo stati in grado di rimuovere offline.html dal nostro elenco di file memorizzati nella cache perché la nostra app dispone ora di tutte le risorse necessarie per funzionare offline, pertanto non verrà più mostrata.

Aggiornare il gestore di eventi di attivazione

Per garantire che il nostro evento activate non elimini accidentalmente i nostri dati, nell'evento activate di service-worker.js, sostituisci if (key !== CACHE_NAME) { con:

public/service-worker.js

if (key !== CACHE_NAME && key !== DATA_CACHE_NAME) {

Aggiornare il gestore di eventi di recupero

Dobbiamo modificare il service worker per intercettare le richieste all'API Meteo e archiviare le loro risposte nella cache, in modo da potervi accedere facilmente in un secondo momento. Con la strategia obsoleta di riconvalida, ci aspettiamo che la risposta di rete sia la "fonte attendibile", fornendo sempre le informazioni più recenti. Se la rete non riesce, significa che l'errore non è riuscito perché abbiamo già recuperato gli ultimi dati memorizzati nella cache nella nostra app.

Aggiorna il gestore di eventi fetch per gestire le richieste all'API di dati separatamente dalle altre richieste.

public/service-worker.js

// CODELAB: Add fetch event handler here.
if (evt.request.url.includes('/forecast/')) {
  console.log('[Service Worker] Fetch (data)', evt.request.url);
  evt.respondWith(
      caches.open(DATA_CACHE_NAME).then((cache) => {
        return fetch(evt.request)
            .then((response) => {
              // If the response was good, clone it and store it in the cache.
              if (response.status === 200) {
                cache.put(evt.request.url, response.clone());
              }
              return response;
            }).catch((err) => {
              // Network request failed, try to get it from the cache.
              return cache.match(evt.request);
            });
      }));
  return;
}
evt.respondWith(
    caches.open(CACHE_NAME).then((cache) => {
      return cache.match(evt.request)
          .then((response) => {
            return response || fetch(evt.request);
          });
    })
);

Il codice intercetta la richiesta e verifica se si tratta di una previsione meteo. Se lo è, utilizza fetch per effettuare la richiesta. Una volta restituita la risposta, apri la cache, clona la risposta, archiviala nella cache e restituisci la risposta al richiedente originale.

Dobbiamo rimuovere il controllo evt.request.mode !== 'navigate' perché vogliamo che il nostro service worker gestisca tutte le richieste (inclusi immagini, script, file CSS e così via) e non solo le navigazioni. Se abbiamo lasciato il check-in, solo il codice HTML verrebbe pubblicato dalla cache del service worker. Tutto il resto verrebbe richiesto dalla rete.

Prova

Ora l'app dovrebbe essere completamente funzionante. Aggiorna la pagina per assicurarti di avere installato l'ultimo service worker. Salva un paio di città e premi il pulsante di aggiornamento nell'app per ricevere dati aggiornati sul meteo.

Successivamente, vai al riquadro Spazio di archiviazione cache nel riquadro Applicazione di DevTools. Espandi la sezione per visualizzare il nome della cache statica e di quella dati sul lato sinistro. All'apertura della cache dei dati dovrebbero essere visualizzati i dati memorizzati per ogni città.

Passa al riquadro Service worker e seleziona la casella di controllo Offline. Prova a ricaricare la pagina, quindi vai offline e ricarica la pagina.

Se ti trovi su una rete veloce e vuoi vedere come vengono aggiornati i dati delle previsioni meteo in caso di connessione lenta, imposta la proprietà FORECAST_DELAY in server.js su 5000. Tutte le richieste all'API di previsione verranno ritardate di 5000 ms.

Verificare le modifiche con Lighthouse

Inoltre, è una buona idea eseguire di nuovo Lighthouse.

Controllo SEO

  • ✅ SUPERATO: il documento ha una meta descrizione.

Log di controllo delle app web progressive

  • ✅ SUPERATO: la pagina corrente risponde con un codice 200 quando è offline.
  • ✅ SUPERATO: start_url risponde con un codice 200 quando è offline.
  • ✅ SUPERATO: registra un service worker che controlla la pagina e start_url.
  • ✅ SUPERATO: il file manifest dell'app web soddisfa i requisiti di installabilità.
  • ✅ SUPERATO: Configurato per una schermata iniziale.
  • ✅ SUPERATO: imposta il colore del tema della barra degli indirizzi.

Quando è installata, un'app web progressiva ha l'aspetto e il comportamento di tutte le altre app installate. L'avvio viene avviato dalla stessa posizione in cui vengono avviate altre app. Viene eseguito in un'app senza una barra degli indirizzi o un'altra interfaccia utente del browser. E come tutte le altre app installate, è un'app di primo livello nel selettore di attività.

In Chrome, un'app web progressiva può essere installata tramite il menu contestuale con tre puntini oppure puoi fornire all'utente un pulsante o un altro componente dell'interfaccia utente che chiederà di installare la tua app.

Controllo con Lighthouse

Per poter installare la tua app web progressiva, l'utente deve soddisfare determinati criteri. Il modo più semplice per verificarlo è utilizzare Lighthouse e assicurarti che soddisfi i criteri installabili.

Se hai lavorato attraverso questo codelab, la tua PWA dovrebbe già soddisfare questi criteri.

Aggiungere install.js a index.html

Innanzitutto, aggiungiamo install.js al nostro file index.html.

pubblico/index.html

<!-- CODELAB: Add the install script here -->
<script src="/scripts/install.js"></script>

Ascolta l'evento beforeinstallprompt

Se i criteri di aggiunta alla schermata Home vengono soddisfatti, Chrome attiva un evento beforeinstallprompt che puoi utilizzare per indicare che l'app può essere installata 'installata' quindi richiede all'utente di installarla. Aggiungi il codice qui sotto per ascoltare l'evento beforeinstallprompt:

public/scripts/install.js

// CODELAB: Add event listener for beforeinstallprompt event
window.addEventListener('beforeinstallprompt', saveBeforeInstallPromptEvent);

Salvare l'evento e mostrare il pulsante di installazione

Nella nostra funzione saveBeforeInstallPromptEvent, salveremo un riferimento all'evento beforeinstallprompt in modo che possiamo chiamare prompt() in un secondo momento e aggiorneremo la nostra interfaccia utente per mostrare il pulsante di installazione.

public/scripts/install.js

// CODELAB: Add code to save event & show the install button.
deferredInstallPrompt = evt;
installButton.removeAttribute('hidden');

Mostra il messaggio e nascondi il pulsante

Quando l'utente fa clic sul pulsante di installazione, dobbiamo chiamare .prompt() per l'evento beforeinstallprompt salvato. Dobbiamo anche nascondere il pulsante Installa perché .prompt() può essere chiamato una sola volta per ogni evento salvato.

public/scripts/install.js

// CODELAB: Add code show install prompt & hide the install button.
deferredInstallPrompt.prompt();
// Hide the install button, it can't be called twice.
evt.srcElement.setAttribute('hidden', true);

Chiamando .prompt() verrà mostrata una finestra di dialogo modale all'utente, che gli chiede di aggiungere la tua app alla schermata Home.

Registra i risultati

Puoi verificare in che modo l'utente ha risposto alla finestra di dialogo di installazione ascoltando la promessa restituita dalla proprietà userChoice dell'evento beforeinstallprompt salvato. La promessa restituisce un oggetto con una proprietà outcome dopo che il prompt è stato mostrato e l'utente ha risposto.

public/scripts/install.js

// CODELAB: Log user response to prompt.
deferredInstallPrompt.userChoice
    .then((choice) => {
      if (choice.outcome === 'accepted') {
        console.log('User accepted the A2HS prompt', choice);
      } else {
        console.log('User dismissed the A2HS prompt', choice);
      }
      deferredInstallPrompt = null;
    });

Un commento su userChoice: la specifica lo definisce come una proprietà, non una funzione come puoi aspettarti.

Registra tutti gli eventi di installazione

Oltre a qualsiasi interfaccia utente aggiunta per installare l'app, gli utenti possono installare la tua PWA utilizzando altri metodi, ad esempio il menu con tre puntini di Chrome. Per monitorare questi eventi, ascolta l'evento installato dall'app.

public/scripts/install.js

// CODELAB: Add event listener for appinstalled event
window.addEventListener('appinstalled', logAppInstalled);

Dobbiamo quindi aggiornare la funzione logAppInstalled. Per questo codelab, utilizzeremo console.log, ma in un'app per la produzione probabilmente vorrai registrarlo come un evento con il tuo software di analisi.

public/scripts/install.js

// CODELAB: Add code to log the event
console.log('Weather App was installed.', evt);

Aggiorna il service worker

Non dimenticare di aggiornare CACHE_NAME nel file service-worker.js perché hai apportato modifiche ai file già memorizzati nella cache. L'attivazione della casella di controllo Ignora per la rete nel riquadro Lavoratori di servizi del riquadro Applicazione in DevTools funzionerà in fase di sviluppo, ma non sarà realistica.

Prova

Vediamo come è andato il nostro passaggio di installazione. Per sicurezza, utilizza il pulsante Cancella i dati dei siti nel riquadro Applicazione di DevTools per cancellare tutto e assicurarti che si riavvii da zero. Se hai installato l'app in precedenza, assicurati di disinstallarla, altrimenti l'icona di installazione non verrà visualizzata di nuovo.

Verificare che il pulsante di installazione sia visibile

Per prima cosa, verifichiamo che la nostra icona di installazione venga visualizzata correttamente. Assicurati di provare sia su desktop sia su dispositivi mobili.

  1. Apri l'URL in una nuova scheda di Chrome.
  2. Apri il menu con tre puntini di Chrome (accanto alla barra degli indirizzi).
    ▢ visualizzati: "Installa Meteo..." nel menu.
  3. Aggiorna i dati meteorologici utilizzando il pulsante di aggiornamento nell'angolo in alto a destra per garantire il rispetto dell'euristica del coinvolgimento degli utenti.
    ▢ Verifica che l'icona di installazione sia visibile nell'intestazione dell'app.

Verificare il funzionamento del pulsante di installazione

Ora facciamo in modo che tutto venga installato correttamente e che i nostri eventi siano attivati correttamente. Puoi farlo su desktop o dispositivi mobili. Se vuoi verificarlo su dispositivi mobili, assicurati di utilizzare il debug remoto in modo da poter vedere cosa è stato registrato nella console.

  1. Apri Chrome e, in una nuova scheda del browser, vai alla PWA Meteo.
  2. Apri DevTools e passa al riquadro Console.
  3. Fai clic sul pulsante di installazione nell'angolo in alto a destra.
    ▢ Verifica che il pulsante di installazione non sia più visibile
    ▢ visualizzati la finestra di dialogo dell'installazione.
  4. Fai clic su Annulla.
    ▢ Verification &L'utente ha ignorato la richiesta A2HS. Nell'output della console viene visualizzato.
    ▢ Verifica che il pulsante di installazione venga visualizzato di nuovo.
  5. Fai di nuovo clic sul pulsante Installa, quindi fai clic sul pulsante Installa nella finestra di dialogo modale.
    ▢ Verifica &L'utente ha accettato la richiesta A2HS. Viene visualizzato nell'output della console.
    ▢ Verifica "L'app Meteo è stata installata nell'output della console.
    ▢ App Meteo in cui vengono solitamente trovate le app.
  6. Avvia la meteo PWA.
    ▢ Verifica che l'app si apra come app autonoma, in una finestra dell'app su desktop o a schermo intero sui dispositivi mobili.

.

Verificare il corretto funzionamento dell'installazione con iOS

Controlliamo anche il comportamento su iOS. Se disponi di un dispositivo iOS, puoi utilizzarlo o, se utilizzi un Mac, prova il Simulatore di iOS disponibile con Xcode.

  1. Apri Safari e, in una nuova scheda del browser, vai alla tua PWA Meteo.
  2. Fai clic sul pulsante Condividi.
  3. Scorri verso destra e fai clic sul pulsante Aggiungi a schermata Home.
    ▢ Verifica che il titolo, l'URL e l'icona siano corretti.
  4. Fai clic su Aggiungi
    .
    Verifica che l'icona dell'app sia stata aggiunta alla schermata Home.
  5. Avvia la PWA Meteo dalla schermata Home.
    ▢ Verifica che l'app avvii la modalità a schermo intero.

Bonus: viene rilevato se l'app viene avviata dalla schermata Home

La query supporti display-mode consente di applicare gli stili in base al modo in cui l'app è stata avviata o a determinare la modalità di lancio con JavaScript.

@media all and (display-mode: standalone) {
  body {
    background-color: yellow;
  }
}

Puoi anche controllare la query supporti display-mode in JavaScript per verificare se è in esecuzione in modalità autonoma.

Bonus: disinstalla la tua PWA

Tieni presente che il beforeinstallevent non viene attivato se l'app è già installata, quindi durante lo sviluppo dovrai installare e disinstallare più volte l'app per assicurarti che tutto funzioni come previsto.

Android

Su Android, le PWA vengono disinstallate come le altre app installate.

  1. Apri il riquadro a scomparsa dell'app.
  2. Scorri verso il basso fino all'icona Meteo.
  3. Trascina l'icona dell'app nella parte superiore dello schermo.
  4. Scegli Disinstalla.

Chrome OS

Su Chrome OS, le PWA possono essere disinstallate facilmente dalla casella di ricerca di Avvio app.

  1. Aprire Avvio app.
  2. Digita "Meteo" nella casella di ricerca, la PWA Meteo dovrebbe comparire nei risultati.
  3. Fare clic con il pulsante destro del mouse (alt-click) sulla PWA Meteo.
  4. Fai clic su Rimuovi da Chrome...

macOS e Windows

Su Mac e Windows, le PWA possono essere disinstallate tramite Chrome:

  1. Apri la pagina chrome://apps in una nuova scheda del browser.
  2. Fare clic con il pulsante destro del mouse (alt-click) sulla PWA Meteo.
  3. Fai clic su Rimuovi da Chrome...

Puoi anche aprire la PWA installata, fare clic sul menu contestuale con tre puntini nell'angolo in alto a destra e scegliere "Disinstalla Meteo PWA...".

Congratulazioni, hai creato la tua prima app web progressiva.

Hai aggiunto un manifest dell'app web per installarlo e hai aggiunto un service worker per assicurarti che la tua PWA sia sempre veloce e affidabile. Hai scoperto come usare DevTools per controllare un'app e come può aiutarti a migliorare l'esperienza utente.

Ora sai quali sono i passaggi principali necessari per trasformare qualsiasi app web in un'app web progressiva.

Qual è il passaggio successivo?

Dai un'occhiata ad alcuni di questi codelab...

Ulteriori letture

Documenti di riferimento