Создание гибкого поиска с помощью Workbox

Демиан Рензулли
Demián Renzulli

В этой лабораторной работе показано, как реализовать отказоустойчивый поиск с помощью Workbox. Используемое демо-приложение содержит поле поиска, которое вызывает конечную точку сервера и перенаправляет пользователя на простую HTML-страницу.

Мера

Перед добавлением оптимизаций всегда полезно проанализировать текущее состояние приложения.

  • Нажмите «Ремикс для редактирования», чтобы сделать проект редактируемым.
  • Для предварительного просмотра сайта нажмите «Просмотреть приложение» . Затем нажмите «Полный экран». полноэкранный .

В новой вкладке, которая только что открылась, проверьте, как ведет себя сайт при переходе в автономный режим:

  1. Нажмите `Control+Shift+J` (или `Command+Option+J` на Mac), чтобы открыть DevTools.
  2. Откройте вкладку Сеть .
  3. Откройте Chrome DevTools и выберите панель «Сеть».
  4. В раскрывающемся списке Регулирование выберите Автономно .
  5. В демо-приложении введите поисковый запрос, затем нажмите кнопку «Поиск» .

Отображается стандартная страница ошибки браузера:

Скриншот офлайн-интерфейса по умолчанию в браузере.

Предоставьте запасной вариант ответа

Service Worker содержит код для добавления автономной страницы в список предварительного кэширования , поэтому ее всегда можно кэшировать при событии install Service Worker.

Обычно вам нужно указать Workbox добавить этот файл в список предварительного кэширования во время сборки, интегрировав библиотеку с выбранным вами инструментом сборки (например, webpack или gulp ).

Для простоты мы уже сделали это за вас. Следующий код в public/sw.js реализует это:

const FALLBACK_HTML_URL = '/index_offline.html';

workbox.precaching.precacheAndRoute([FALLBACK_HTML_URL]);

Затем добавьте код для использования автономной страницы в качестве резервного ответа:

  1. Чтобы просмотреть исходный текст, нажмите « Просмотреть исходный текст» .
  2. Добавьте следующий код в конец 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();
  }
});

Код делает следующее:

  • Определяет стратегию «Только сеть» по умолчанию, которая будет применяться ко всем запросам.
  • Объявляет глобальный обработчик ошибок, вызывая workbox.routing.setCatchHandler() для обработки невыполненных запросов. При запросах документов возвращается резервная офлайн-страница HTML.

Чтобы проверить эту функциональность:

  1. Вернитесь на другую вкладку, на которой запущено ваше приложение.
  2. Установите в раскрывающемся списке Регулирование значение Онлайн .
  3. Нажмите кнопку «Назад» в Chrome, чтобы вернуться на страницу поиска.
  4. Убедитесь, что флажок Отключить кэш в DevTools отключен.
  5. Нажмите и удерживайте кнопку «Перезагрузить» в Chrome и выберите «Очистить кэш и принудительно перезагрузить», чтобы убедиться, что ваш Service Worker обновлен.
  6. Снова установите в раскрывающемся списке «Регулирование » значение «Оффлайн» .
  7. Введите поисковый запрос и снова нажмите кнопку «Поиск» .

Показана резервная HTML-страница:

Скриншот пользовательского интерфейса в автономном режиме в браузере.

Запрос разрешения на уведомление

Для простоты автономная страница views/index_offline.html уже содержит код для запроса разрешений на уведомления в блоке скрипта внизу:

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

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

Код делает следующее:

  • Когда пользователь нажимает кнопку «Подписаться на уведомления», вызывается функция requestNotificationPermission() , которая, в свою очередь, вызывает Notification.requestPermission() для отображения запроса на разрешение браузера по умолчанию. Промис выполняется с разрешением, выбранным пользователем: granted , denied ) или default .
  • Передает разрешенное разрешение showOfflineText() для показа соответствующего текста пользователю.

Сохраняйте запросы в автономном режиме и повторяйте попытки, когда снова будете в сети

Затем реализуйте фоновую синхронизацию Workbox для сохранения автономных запросов, чтобы их можно было повторить, когда браузер обнаружит, что соединение восстановлено.

  1. Откройте public/sw.js для редактирования.
  2. Добавьте следующий код в конец файла:
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;
      }
    }
  },
});

Код делает следующее:

  • workbox.backgroundSync.Plugin содержит логику добавления невыполненных запросов в очередь для повторной попытки. Эти запросы будут сохранены в IndexedDB .
  • maxRetentionTime указывает время, в течение которого запрос может быть повторен. В данном случае мы выбрали 60 минут (по истечении которых запрос будет отклонён).
  • onSync — самая важная часть этого кода. Этот обратный вызов будет вызван при восстановлении соединения, чтобы запросы из очереди были извлечены и извлечены из сети.
  • Сетевой ответ добавляется в кэш offline-search-responses с добавлением параметра запроса &notification=true , чтобы эта запись кэша могла быть извлечена, когда пользователь нажимает на уведомление.

Чтобы интегрировать фоновую синхронизацию с вашим сервисом, определите стратегию NetworkOnly для запросов к URL поиска ( /search_action ) и передайте ранее определенный bgSyncPlugin . Добавьте следующий код в конец файла 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],
  }),
);

Это сообщает Workbox, что нужно всегда подключаться к сети и в случае сбоя запросов использовать логику фоновой синхронизации.

Затем добавьте следующий код в конец файла public/sw.js чтобы определить стратегию кэширования запросов, поступающих от уведомлений. Используйте стратегию CacheFirst , чтобы их можно было обслуживать из кэша.

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

Наконец, добавьте код для показа уведомлений:

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

Протестируйте функцию

  1. Вернитесь на другую вкладку, на которой запущено ваше приложение.
  2. Установите в раскрывающемся списке Регулирование значение Онлайн .
  3. Нажмите кнопку «Назад» в Chrome, чтобы вернуться на страницу поиска.
  4. Нажмите и удерживайте кнопку «Перезагрузить» в Chrome и выберите «Очистить кэш и принудительно перезагрузить», чтобы убедиться, что ваш Service Worker обновлен.
  5. Снова установите в раскрывающемся списке «Регулирование » значение «Оффлайн» .
  6. Введите поисковый запрос и снова нажмите кнопку «Поиск» .
  7. Нажмите «Подписаться на уведомления» .
  8. Когда Chrome спросит вас, хотите ли вы предоставить приложению разрешение на отправку уведомлений, нажмите Разрешить .
  9. Введите другой поисковый запрос и снова нажмите кнопку «Поиск» .
  10. Снова установите в раскрывающемся списке «Регулирование » значение «Онлайн» .

Как только соединение восстановится, появится уведомление:

Скриншот полного офлайн-процесса.

Заключение

Workbox предоставляет множество встроенных функций, которые сделают ваши PWA более надёжными и интересными. В этой лабораторной работе вы изучили, как реализовать API фоновой синхронизации с помощью абстракции Workbox, чтобы гарантировать, что запросы пользователей, отправленные офлайн, не будут потеряны и их можно будет повторить после восстановления соединения. Демоверсия представляет собой простое поисковое приложение, но вы можете использовать похожую реализацию для более сложных сценариев и вариантов использования, включая чаты, публикацию сообщений в социальных сетях и т. д.