Шаг первый — сделать… на самом деле, подождать. До этого есть шаг. Шаг нулевой. Запустите свой сайт на HTTPS, если это еще не сделано. Вы не сможете использовать сервис-воркер, если все не будет обслуживаться через HTTPS, что имеет смысл, если учесть потрясающую мощь, которой обладает сервис-воркер.

Если вы разрабатываете локально, сервис-воркеры будут нормально работать для localhost даже без HTTPS. Но для живого сайта HTTPS обязателен.

Сделать офлайн-страницу

Хорошо, предположим, что ваш сайт обслуживается через HTTPS, тогда первый шаг — создать автономную страницу. Сделайте это настолько серьезным или причудливым, насколько это подходит для вашего конкретного бренда. Если веб-сайт предназначен для ресторана, возможно, вы могли бы разместить номер телефона и адрес ресторана на пользовательской офлайн-странице (непрошеный совет: вы также можете разместить это на домашней странице, знаете ли). Вот пример индивидуальной офлайн-страницы для конференции Ampersand в этом году.

Когда вы закончите, опубликуйте автономную страницу с подходящим образным URL-адресом, например, скажем, /offline.html.

Предварительно кэшируйте свою офлайн-страницу

Теперь создайте файл JavaScript с именем serviceworker.js. Это сценарий, на который браузер будет обращать внимание при возникновении определенных событий. Первое событие, которое нужно обработать, — это то, что делать, когда сервис-воркер установлен на устройстве пользователя. Когда это происходит, запускается событие с именем install. Вы можете прослушать это событие, используя addEventListener:

addEventListener('install', installEvent => {
// put your instructions here.
}); // end addEventListener

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

addEventListener('install', installEvent => {
  installEvent.waitUntil(
    caches.open('Johnny')
    .then( JohnnyCache => {
      JohnnyCache.addAll([
       '/offline.html'
      ]); // end addAll
     }) // end open.then
  ); // end waitUntil
}); // end addEventListener

Могу поспорить, что ваша прекрасная офлайн-страница ссылается на файл CSS, может быть, на изображение или два и, возможно, на JavaScript. Вы можете кэшировать все это на этом этапе:

addEventListener('install', installEvent => {
  installEvent.waitUntil(
    caches.open('Johnny')
    .then( JohnnyCache => {
      JohnnyCache.addAll([
       '/offline.html',
       '/path/to/stylesheet.css',
       '/path/to/javascript.js',
         '/path/to/image.jpg'
      ]); // end addAll
     }) // end open.then
  ); // end waitUntil
}); // end addEventListener

Убедитесь, что URL-адреса указаны правильно. Если хотя бы один из URL-адресов в списке не может быть разрешен, ни один из элементов в списке не будет кэширован.

Перехват запросов

Следующее событие, которое вы хотите прослушать, — это событие fetch. Это, пожалуй, самая мощная — и, будем честны, самая жуткая — функция сервис-воркера. После установки сервис-воркер прячется на устройстве пользователя, ожидая любых запросов к вашему сайту. Каждый раз, когда пользователь запрашивает веб-страницу с вашего сайта, срабатывает событие fetch. Каждый раз, когда эта страница запрашивает таблицу стилей или изображение, срабатывает событие fetch. Вы можете предоставить инструкции о том, что должно происходить каждый раз:

addEventListener('fetch', fetchEvent => {
// What happens next is up to you!
}); // end addEventListener

Напишем достаточно консервативный скрипт со следующей логикой:

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

Вот как это переводится в JavaScript:

// Whenever a file is requested
addEventListener('fetch', fetchEvent => {
  const request = fetchEvent.request;
  fetchEvent.respondWith(
    // First, try to fetch it from the network
    fetch(request)
    .then( responseFromFetch => {
      return responseFromFetch;
    }) // end fetch.then
    // But if that doesn't work
    .catch( fetchError => {
      // try to find it in the cache
      caches.match(request)
      .then( responseFromCache => {
        if (responseFromCache) {
         return responseFromCache;
       // But if that doesn't work
       } else {
         // and it's a request for a web page
         if (request.headers.get('Accept').includes('text/html')) {
           // show the custom offline page instead
           return caches.match('/offline.html');
         } // end if
       } // end if/else
     }) // end match.then
   }) // end fetch.catch
  ); // end respondWith
}); // end addEventListener

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

Подключите свой скрипт сервисного работника

Вы можете опубликовать свой скрипт сервис-воркера по адресу /serviceworker.js, но вам все равно нужно указать браузеру, где его искать. Вы можете сделать это с помощью JavaScript. Поместите это в существующий файл JavaScript, который вы вызываете на каждой странице вашего сайта, или добавьте это в элемент script в конце HTML-кода каждой страницы:

if (navigator.serviceWorker) {
  navigator.serviceWorker.register('/serviceworker.js');
}

Это говорит браузеру начать установку сервис-воркера, но не без предварительной проверки того, что браузер понимает, что такое сервис-воркер. Когда дело доходит до JavaScript, обнаружение функций — ваш друг.

Возможно, у вас уже есть несколько файлов JavaScript в такой папке, как /assets/js/, и у вас может возникнуть соблазн поместить туда свой скрипт сервисного работника. Не делай этого. Если вы это сделаете, сервис-воркер сможет обрабатывать запросы к файлам только в пределах /assets/js/. Поместив сценарий сервис-воркера в корневой каталог, вы гарантируете, что каждый запрос может быть перехвачен.

Идти дальше!

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

Это только начало. Вы можете сделать больше с сервисными работниками.

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

Или что, если вместо того, чтобы сначала обращаться к сети, вы сначала проверяете, находится ли файл в кеше? Вы могли бы обслуживать эту кешированную версию — что было бы молниеносно быстро — и при этом получать свежую версию из сети в фоновом режиме, чтобы использовать кеш в следующий раз. Это может быть хорошей стратегией для изображений.

Столько вариантов! Сложность заключается не в написании кода, а в определении шагов, которые вы хотите предпринять. После того, как вы записали эти шаги, нужно перевести их в JavaScript.

Неизбежно на этом пути будут некоторые препятствия — обычно это неуместная фигурная скобка или отсутствующая скобка. Не будьте слишком строги к себе, если ваш код сначала не работает. Это просто закон Мерфи в действии.

Изначально это было опубликовано на моем собственном сайте.