Créer des expériences de recherche résilientes avec Workbox

Cet atelier de programmation vous explique comment implémenter une expérience de recherche résiliente avec Workbox. L'application de démonstration qu'elle utilise contient un champ de recherche qui appelle un point de terminaison de serveur et redirige l'utilisateur vers une page HTML de base.

Mesurer

Avant d'ajouter des optimisations, il est toujours judicieux d'analyser d'abord l'état actuel de l'application.

  • Cliquez sur Remix to Edit (Remixer pour modifier) pour rendre le projet modifiable.
  • Pour prévisualiser le site, appuyez sur Afficher l'application, puis sur Plein écran plein écran.

Dans l'onglet qui vient de s'ouvrir, vérifiez le comportement du site Web hors connexion:

  1. Appuyez sur Ctrl+Maj+J (ou Cmd+Option+J sur Mac) pour ouvrir les outils de développement.
  2. Cliquez sur l'onglet Réseau.
  3. Ouvrez les Outils pour les développeurs Chrome, puis sélectionnez le panneau "Network" (Réseau).
  4. Dans la liste déroulante de limitation, sélectionnez Hors connexion.
  5. Dans l'application de démonstration, saisissez une requête de recherche, puis cliquez sur le bouton Rechercher.

La page d'erreur standard du navigateur s'affiche:

Capture d'écran de l'expérience utilisateur hors connexion par défaut dans le navigateur

Fournir une réponse de remplacement

Le service worker contient le code permettant d'ajouter la page hors connexion à la liste de pré-cache, afin qu'elle puisse toujours être mise en cache lors de l'événement install du service worker.

En règle générale, vous devez demander à Workbox d'ajouter ce fichier à la liste de pré-cache au moment de la compilation, en intégrant la bibliothèque à l'outil de compilation de votre choix (par exemple, webpack ou gulp).

Pour plus de simplicité, nous l'avons déjà fait pour vous. Le code suivant sur public/sw.js permet d'effectuer cette opération:

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

Ensuite, ajoutez du code pour utiliser la page hors connexion comme réponse de remplacement:

  1. Pour afficher la source, appuyez sur Afficher la source.
  2. Ajoutez le code suivant en bas de 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();
  }
});

Le code :

  • Définit une stratégie "Réseau uniquement" par défaut qui s'appliquera à toutes les requêtes.
  • Déclare un gestionnaire d'erreurs global en appelant workbox.routing.setCatchHandler() pour gérer les requêtes ayant échoué. Lorsque les demandes concernent des documents, une page HTML hors connexion de remplacement s'affiche.

Pour tester cette fonctionnalité:

  1. Revenez à l'autre onglet qui exécute votre application.
  2. Définissez la liste déroulante Throttling (Limitation) sur Online (En ligne).
  3. Appuyez sur le bouton Retour de Chrome pour revenir à la page de recherche.
  4. Assurez-vous que la case Désactiver le cache est désactivée dans les outils de développement.
  5. Appuyez de manière prolongée sur le bouton Actualiser de Chrome, puis sélectionnez Vider le cache et effectuer une actualisation forcée pour vous assurer que votre service worker est mis à jour.
  6. Redéfinissez la liste déroulante Throttling (Limitation) sur Hors connexion.
  7. Saisissez une requête de recherche, puis cliquez à nouveau sur le bouton Rechercher.

La page HTML de remplacement s'affiche:

Capture d'écran de l'expérience utilisateur hors connexion personnalisée dans le navigateur

Demander une autorisation pour les notifications

Pour plus de simplicité, la page hors connexion sur views/index_offline.html contient déjà le code permettant de demander des autorisations de notification dans un bloc de script situé en bas:

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

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

Le code :

  • Lorsque l'utilisateur clique sur S'abonner aux notifications, la fonction requestNotificationPermission() est appelée, qui appelle Notification.requestPermission(), pour afficher l'invite d'autorisation par défaut du navigateur. La promesse se résout avec l'autorisation choisie par l'utilisateur, qui peut être granted, denied ou default.
  • Transmet l'autorisation résolue à showOfflineText() pour afficher le texte approprié à l'utilisateur.

Conserver les requêtes hors connexion et réessayer une fois de nouveau en ligne

Ensuite, implémentez la synchronisation en arrière-plan de Workbox pour conserver les requêtes hors connexion, afin qu'elles puissent être relancées lorsque le navigateur détecte que la connectivité est de retour.

  1. Ouvrez public/sw.js pour le modifier.
  2. Ajoutez le code suivant à la fin du fichier:
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;
      }
    }
  },
});

Le code :

  • workbox.backgroundSync.Plugin contient la logique permettant d'ajouter à une file d'attente les requêtes ayant échoué afin qu'elles puissent être relancées ultérieurement. Ces requêtes seront conservées dans IndexedDB.
  • maxRetentionTime indique la durée pendant laquelle une requête peut être relancée. Dans le cas présent, nous avons choisi 60 minutes (au bout de 60 minutes). Passé ce délai, elles seront supprimées.
  • onSync est la partie la plus importante de ce code. Ce rappel sera appelé lors du retour de la connexion afin que les requêtes en file d'attente soient récupérées, puis extraites du réseau.
  • La réponse du réseau est ajoutée au cache offline-search-responses, avec le paramètre de requête &notification=true ajouté, de sorte que cette entrée de cache puisse être récupérée lorsqu'un utilisateur clique sur la notification.

Pour intégrer la synchronisation en arrière-plan à votre service, définissez une stratégie NetworkOnly pour les requêtes adressées à l'URL de recherche (/search_action) et transmettez le bgSyncPlugin précédemment défini. Ajoutez le code suivant en bas de 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],
  }),
);

Cela indique à Workbox de toujours se connecter au réseau et, en cas d'échec des requêtes, d'utiliser la logique de synchronisation en arrière-plan.

Ajoutez ensuite le code suivant en bas de public/sw.js pour définir une stratégie de mise en cache pour les requêtes provenant de notifications. Utiliser une stratégie CacheFirst afin qu'elles puissent être diffusées à partir du 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',
  })
);

Enfin, ajoutez le code permettant d'afficher les notifications:

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)
  );
});

Tester la fonctionnalité

  1. Revenez à l'autre onglet qui exécute votre application.
  2. Définissez la liste déroulante Throttling (Limitation) sur Online (En ligne).
  3. Appuyez sur le bouton Retour de Chrome pour revenir à la page de recherche.
  4. Appuyez de manière prolongée sur le bouton Actualiser de Chrome, puis sélectionnez Vider le cache et effectuer une actualisation forcée pour vous assurer que votre service worker est mis à jour.
  5. Redéfinissez la liste déroulante Throttling (Limitation) sur Hors connexion.
  6. Saisissez une requête de recherche, puis cliquez à nouveau sur le bouton Rechercher.
  7. Cliquez sur S'abonner aux notifications.
  8. Lorsque Chrome vous demande si vous souhaitez autoriser l'application à envoyer des notifications, cliquez sur Autoriser.
  9. Saisissez une autre requête de recherche, puis cliquez à nouveau sur le bouton Rechercher.
  10. Redéfinissez la liste déroulante Throttling sur Online (En ligne).

Une fois la connexion rétablie, une notification s'affiche:

Capture d'écran du flux hors connexion complet

Conclusion

Workbox fournit de nombreuses fonctionnalités intégrées pour rendre vos PWA plus résilientes et plus engageantes. Dans cet atelier de programmation, vous avez découvert comment implémenter l'API Background Sync à l'aide de l'abstraction Workbox afin de vous assurer que les requêtes des utilisateurs hors connexion ne sont pas perdues et que vous pouvez effectuer de nouvelles tentatives une fois la connexion rétablie. La version de démonstration est une application de recherche simple, mais vous pouvez utiliser une implémentation similaire pour des scénarios et des cas d'utilisation plus complexes, comme les applications de chat, la publication de messages sur un réseau social, etc.