Creazione di esperienze di ricerca resilienti con Workbox

Questo codelab mostra come implementare un'esperienza di ricerca resiliente con Workbox. L'app demo che utilizza contiene una casella di ricerca che chiama un endpoint del server e reindirizza l'utente a una pagina HTML di base.

Misura

Prima di aggiungere le ottimizzazioni, è sempre opportuno analizzare lo stato attuale dell'applicazione.

  • Fai clic su Remix per modificare per rendere il progetto modificabile.
  • Per visualizzare l'anteprima del sito, premi Visualizza app, quindi Schermo intero schermo intero.

Nella nuova scheda appena aperta, controlla il comportamento del sito web quando è offline:

  1. Premi "Control+Maiusc+J" (o "Comando+Opzione+J" su Mac) per aprire DevTools.
  2. Fai clic sulla scheda Rete.
  3. Apri Chrome DevTools e seleziona il riquadro Rete.
  4. Nell'elenco a discesa Limitazione, seleziona Offline.
  5. Nell'app demo inserisci una query di ricerca, quindi fai clic sul pulsante Cerca.

Viene visualizzata la pagina di errore standard del browser:

Uno screenshot dell'UX offline predefinita nel browser.

Fornisci una risposta di riserva

Il service worker contiene il codice per aggiungere la pagina offline all'elenco di preregistrazione, in modo che possa essere sempre memorizzata nella cache durante l'evento install del service worker.

Di solito devi chiedere a Workbox di aggiungere questo file all'elenco di pre-cache al momento della creazione, integrando la libreria con lo strumento di creazione che preferisci (ad esempio webpack o gulp).

Per semplicità, l'abbiamo già fatto per te. Il seguente codice in public/sw.js lo fa:

const FALLBACK_HTML_URL = '/index_offline.html';
…
workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

Poi, aggiungi il codice per utilizzare la pagina offline come risposta di riserva:

  1. Per visualizzare la fonte, premi Visualizza sorgente.
  2. Aggiungi il seguente codice in fondo a public/sw.js:
workbox.routing.setDefaultHandler(new workbox.strategies.NetworkOnly());

workbox.routing.setCatchHandler(({event}) => {
  switch (event.request.destination) {
    case 'document':
      return caches.match(FALLBACK_HTML_URL);
      break;
    default:
      return Response.error();
  }
});

Il codice fa quanto segue:

  • Definisce una strategia Solo rete predefinita che verrà applicata a tutte le richieste.
  • Dichiara un gestore degli errori globale, chiamando workbox.routing.setCatchHandler() per gestire le richieste non riuscite. Quando le richieste riguardano documenti, verrà restituita una pagina HTML offline di riserva.

Per testare questa funzionalità:

  1. Torna all'altra scheda su cui è in esecuzione l'app.
  2. Imposta di nuovo l'elenco a discesa Minore su Online.
  3. Premi il pulsante Indietro di Chrome per tornare alla pagina di ricerca.
  4. Assicurati che la casella di controllo Disattiva cache in DevTools sia disattivata.
  5. Tieni premuto a lungo il pulsante Ricarica di Chrome e seleziona Svuota la cache e ricarica a freddo per assicurarti che il service worker sia aggiornato.
  6. Imposta di nuovo l'elenco a discesa Minore su Offline.
  7. Inserisci una query di ricerca e fai di nuovo clic sul pulsante Cerca.

Viene visualizzata la pagina HTML di riserva:

Uno screenshot dell'UX offline personalizzata nel browser.

Richiedi autorizzazione alle notifiche

Per semplicità, la pagina offline all'indirizzo views/index_offline.html contiene già il codice per richiedere le autorizzazioni alle notifiche in un blocco di script in basso:

function requestNotificationPermission(event) {
  event.preventDefault();

  Notification.requestPermission().then(function (result) {
    showOfflineText(result);
  });
}

Il codice fa quanto segue:

  • Quando l'utente fa clic su Iscriviti alle notifiche viene richiamata la funzione requestNotificationPermission(), che chiama Notification.requestPermission(), per mostrare la richiesta di autorizzazione del browser predefinita. La promessa si risolve con l'autorizzazione scelta dall'utente, che può essere granted, denied o default.
  • Passa l'autorizzazione risolta a showOfflineText() per mostrare all'utente il testo appropriato.

Mantieni le query offline e riprova quando sarai di nuovo online

In seguito, implementa la sincronizzazione in background della casella di lavoro per mantenere le query offline in modo che possano essere ritentate quando il browser rileva che la connettività è tornata.

  1. Apri public/sw.js per la modifica.
  2. Aggiungi il seguente codice alla fine del file:
const bgSyncPlugin = new workbox.backgroundSync.Plugin('offlineQueryQueue', {
  maxRetentionTime: 60,
  onSync: async ({queue}) => {
    let entry;
    while ((entry = await queue.shiftRequest())) {
      try {
        const response = await fetch(entry.request);
        const cache = await caches.open('offline-search-responses');
        const offlineUrl = `${entry.request.url}&notification=true`;
        cache.put(offlineUrl, response);
        showNotification(offlineUrl);
      } catch (error) {
        await this.unshiftRequest(entry);
        throw error;
      }
    }
  },
});

Il codice fa quanto segue:

  • workbox.backgroundSync.Plugin contiene la logica per aggiungere le richieste non riuscite a una coda in modo che possano essere ritentate in un secondo momento. Queste richieste verranno rese persistenti in IndexedDB.
  • maxRetentionTime indica per quanto tempo è possibile riprovare una richiesta. In questo caso abbiamo scelto 60 minuti (dopo i quali verranno eliminati).
  • onSync è la parte più importante di questo codice. Questo callback verrà chiamato quando la connessione sarà di nuovo disponibile, in modo che le richieste in coda vengano recuperate e poi recuperate dalla rete.
  • La risposta di rete viene aggiunta alla cache di offline-search-responses, aggiungendo il parametro di query &notification=true, in modo che la voce della cache possa essere acquisita quando un utente fa clic sulla notifica.

Per integrare la sincronizzazione in background con il tuo servizio, definisci una strategia NetworkOnly per le richieste all'URL di ricerca (/search_action) e trasmetti il valore bgSyncPlugin definito in precedenza. Aggiungi il seguente codice in fondo a public/sw.js:

const matchSearchUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return url.pathname === '/search_action' && !(notificationParam === 'true');
};

workbox.routing.registerRoute(
  matchSearchUrl,
  new workbox.strategies.NetworkOnly({
    plugins: [bgSyncPlugin],
  }),
);

Questo indica a Workbox di collegarsi sempre alla rete e, se le richieste non vanno a buon fine, di utilizzare la logica di sincronizzazione in background.

Successivamente, aggiungi il seguente codice in fondo a public/sw.js per definire una strategia di memorizzazione nella cache per le richieste provenienti dalle notifiche. Utilizza una strategia CacheFirst in modo che possano essere pubblicati dalla cache.

const matchNotificationUrl = ({url}) => {
  const notificationParam = url.searchParams.get('notification');
  return (url.pathname === '/search_action' && (notificationParam === 'true'));
};

workbox.routing.registerRoute(matchNotificationUrl,
  new workbox.strategies.CacheFirst({
     cacheName: 'offline-search-responses',
  })
);

Infine, aggiungi il codice per mostrare le notifiche:

function showNotification(notificationUrl) {
  if (Notification.permission) {
     self.registration.showNotification('Your search is ready!', {
        body: 'Click to see you search result',
        icon: '/img/workbox.jpg',
        data: {
           url: notificationUrl
        }
     });
  }
}

self.addEventListener('notificationclick', function(event) {
  event.notification.close();
  event.waitUntil(
     clients.openWindow(event.notification.data.url)
  );
});

Testa la funzionalità

  1. Torna all'altra scheda su cui è in esecuzione l'app.
  2. Imposta di nuovo l'elenco a discesa Minore su Online.
  3. Premi il pulsante Indietro di Chrome per tornare alla pagina di ricerca.
  4. Tieni premuto a lungo il pulsante Ricarica di Chrome e seleziona Svuota la cache e ricarica a freddo per assicurarti che il service worker sia aggiornato.
  5. Imposta di nuovo l'elenco a discesa Minore su Offline.
  6. Inserisci una query di ricerca e fai di nuovo clic sul pulsante Cerca.
  7. Fai clic su Iscriviti alle notifiche.
  8. Quando Chrome ti chiede se vuoi concedere all'app l'autorizzazione a inviare notifiche, fai clic su Consenti.
  9. Inserisci un'altra query di ricerca e fai di nuovo clic sul pulsante Cerca.
  10. Imposta di nuovo l'elenco a discesa Minore su Online.

Una volta ripristinata la connessione, verrà visualizzata una notifica:

Uno screenshot dell'intero flusso offline.

Conclusione

Workbox fornisce molte funzionalità integrate per rendere le tue PWA più resilienti e coinvolgenti. In questo codelab hai scoperto come implementare l'API Background Sync tramite l'astrazione Workbox, per assicurarti che le query degli utenti offline non vadano perse e che possano essere ritentate una volta ristabilita la connessione. La demo è una semplice app di ricerca, ma puoi utilizzare un'implementazione simile per scenari e casi d'uso più complessi, tra cui app di chat, pubblicazione di messaggi su un social network e così via.