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

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

Мера

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

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

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

  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 и выберите «Очистить кеш и полную перезагрузку», чтобы убедиться, что ваш сервис-воркер обновлен.
  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 и выберите «Очистить кеш и полную перезагрузку», чтобы убедиться, что ваш сервис-воркер обновлен.
  5. Снова установите раскрывающийся список «Регулирование» в положение «Автономно» .
  6. Введите поисковый запрос и снова нажмите кнопку «Поиск» .
  7. Нажмите подписаться на уведомления .
  8. Когда Chrome спросит вас, хотите ли вы предоставить приложению разрешение на отправку уведомлений, нажмите «Разрешить» .
  9. Введите другой поисковый запрос и снова нажмите кнопку «Поиск» .
  10. Снова установите раскрывающийся список «Регулирование» на «В сети» .

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

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

Заключение

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

,

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

Мера

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

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

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

  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 и выберите «Очистить кеш и полную перезагрузку», чтобы убедиться, что ваш сервис-воркер обновлен.
  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 и выберите «Очистить кеш и полную перезагрузку», чтобы убедиться, что ваш сервис-воркер обновлен.
  5. Снова установите в раскрывающемся списке «Регулирование » значение «Автономно» .
  6. Введите поисковый запрос и снова нажмите кнопку «Поиск» .
  7. Нажмите подписаться на уведомления .
  8. Когда Chrome спросит вас, хотите ли вы предоставить приложению разрешение на отправку уведомлений, нажмите «Разрешить» .
  9. Введите другой поисковый запрос и снова нажмите кнопку «Поиск» .
  10. Снова установите раскрывающийся список «Регулирование» на «В сети» .

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

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

Заключение

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