Офлайн версия сайта или как не "сливать" клиента, когда у него пропал интернет

Привет, друзья. С Новым годом и Рождеством всех вас. Недавно моя девушка, работая с сайтом на CMS Битрикс, столкнулась с задачей вывести лендинг на странице поиска и попросила помочь. Я сначала подумал, что это какой-то бред, а потом оказалось, что речь идёт о локальном поиске на сайте и в шаблоне действительно есть возможность настроить продающую страничку и оформить ее под запрос клиента если товар действительно есть на сайте. А уже под мини-лендингом идут остальные результаты поиска.

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

Да, есть всякие виджеты, есть всплывающее окно, которое появляется, когда посетитель пытается покинуть сайт (кстати, скоро сделаю такой виджет), но это все достаточно банально. Хотелось найти еще что-то и в голову пришла идея, что можно попробовать вернуть часть клиентов и даже предложить им что-то даже если у посетителя вдруг пропал интернет.

Я много слышал об офлайн версии сайта или о том, что можно показать особенную страницу или туже (закешированную), если у пользователя вдруг пропадает интернет-соединение, но понятия не имел как это реализовать. Обдумывая способ как еще можно влиять на конверсию на лендинге я решил зацепиться за эту идею и попробовать реализовать ее, а результатом поделиться в блоге. Об этом и пойдет речь в статье. Будем делать offline мини-лендинг для пользователей, у которых неожиданно пропадает интернет, и они больше не могут перемещаться по сайту. Согласитесь, что неплохо было бы вернуть часть таких пользователей. Вы, в свою очередь, можете сделать полноценную продающую страницу или еще как-то обыграть эту ситуацию.

Прежде чем начать

Так как для реализации задуманной идеи мы будем использовать service worker, то хотелось бы пояснить в двух словах что это такое.

Простым языком service worker это некий скрипт, который выполняется браузером в фоновом режиме. Он никак не взаимодействует со страницей, поэтому не влияет на скорость ее загрузки, выполняется в отдельном потоке и нужен для обработки сетевых запросов, работой с закешированными ресурсами, отправки push-уведомлений и другого.

Подробнее можно почитать тут: developer.mozilla.org. Для вас это все будет в виде готового скрипта, в котором нужно просто прописать пути к файлам, которые будут использоваться при потере интернет-соединения.

Несколько условий и условностей для работы

  • Вся задумка заработает только при подключении https, так что если вы еще каким-то чудом не перешли на этот протокол, то давно пора.
  • Скрипт service-worker размещаем в корне сайта, это связанно с особенностью его работы. Если разместить сервис-воркер, например, в папке «/js/», то он сможет обработать запросы только внутри этой директории.

Приступаем

Я подготовил для вас папку “offline” с исходником простейшего лендинга и файл “service-worker.js” которые нужно поместить в корень сайта.

Файлы для создания offline страницы сайта

Размер: 69 кб

Офлайн версия сайта

Давайте разбираться подробнее. Как и говорил, на скриншоте пример обычного статического сайта, в корне которого есть файл service-worker.js и папка "offline" с лендингом, который будет показываться при потере интернета у пользователя. Я набросал скромный пример простой страницы больше похожей на модальное окно, но вы можете сделать полноценный лендинг.

Offline landing page

Итак, скачайте архив, распакуйте его и поместите файл service-worker.js и папку "offline" в корень сайта.

Затем разместите следующий js-код в футере вашей посадочной страницы перед закрывающим тегом "body".

  <script>
    if ('serviceWorker' in navigator) {
      console.log('CLIENT: service worker registration in progress.');
      navigator.serviceWorker.register('/service-worker.js').then(function () {
        console.log('CLIENT: service worker registration complete.');
      }, function () {
        console.log('CLIENT: service worker registration failure.');
      });
    } else {
      console.log('CLIENT: service worker is not supported.');
    }
  </script>

Тут ничего менять не нужно, если не хотите изменить само название воркера.

Теперь можете перейти в папку "offline" и изменить мой пример лендинга под свои нужды. Я назвал файл "offline-landing.html". Вам не обязательно оставлять такое имя.

Когда закончите с версткой, откройте файл "service-worker.js" и пропишите пути к элементам, которые использовали на странице. Это те элементы, которые будут закешированы браузером и смогут подгрузиться, когда пропадет соединение с сетью. Я подготовил специальный массив для этого.

Пути для кэширования в service worker

Единственное условие - первым должен быть путь к html-файлу с вашей версткой, а дальше уже в любом порядке.

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

Если обнаружите, что что-то не работает, откройте консоль браузера и изучите ошибку. Скорее всего дело будет в путях, так как скрипт прерывает работу если не находит хотя бы один из предложенных к кешу ресурсов.

Успешная регистрация сервис воркера

Чтобы посмотреть какие ресурсы были успешно закешированы перейдите во вкладку "Application" и выберите "Cache Storage".

Закешированные ресурсы сервис воркером

Для отладки вам придется регулярно очищать кеш и другие данные. Проще всего это делать тут:

Очистка кеша

Чтобы тестировать все без отключения интернета, можно перейти в пункт "Service Workers", выбрать режим "offline" и обновить страницу. Так интернет-соединение пропадет только на этой вкладке.

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

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

Полезные ссылки для погружения в тему:

Похожие публикации

6 комментариев

  1. Владимир

    Задумка интересная, но есть проблемы. В основном они выражаются в том, что на Android периодически отваливаются стили, а на iOS так вообще не удалось их подтянуть. Даже у вас на демо с девайсов на iOS выводится только содержимое html.

    1. Дмитрий Давыдов

      Владимир, здравствуйте. Да, пока, не все идеально. Сам тоже заметил.

  2. Владимир

    Есть мысли как исправить? Такое ощущение, что проблемы кроются в кэшировании.
    И еще такой момент. Для тестирования я взял ваш демо-исходник, заменил только текст в html и цвета в CSS, то есть правки были минимальны. Тем не менее даже на Android у меня проблема проявляется чаще чем у вас. Есть возможность скинуть исходник, используемый у вас на сайте? Наверняка он отличается от того, который опубликован в статье.

    1. Дмитрий Давыдов

      У меня на сайте такой же:
      [javascript]
      const CACHEVERSION = 1;
      const CACHENAME = 'offline landing';
      const OFFLINELANDINGURL = '/offline/offline-landing.html';
      const OFFLINESTYLEURL = '/offline/css/offline.css';
      const OFFLINESCRIPTSURL = '/offline/js/offline.js';
      const OFFLINEIMGURL = '/offline/img/logo.png';
      const OFFLINEFAVICONURL = '/favicon-16x16.png';
      const OFFLINEFONTSURL = 'https://fonts.googleapis.com/css2?family=Roboto:wght@400;700;900&display=swap';

      self.addEventListener('install', (event) => {
      event.waitUntil((async () => {
      const cache = await caches.open(CACHENAME);
      await cache.addAll([OFFLINELANDINGURL, OFFLINESTYLEURL, OFFLINESCRIPTSURL, OFFLINEFAVICONURL, OFFLINEFONTSURL, OFFLINEIMGURL]);
      })());
      });

      self.addEventListener('activate', (event) => {
      event.waitUntil((async () => {
      if ('navigationPreload' in self.registration) {
      await self.registration.navigationPreload.enable();
      }
      })());
      self.clients.claim();
      });

      self.addEventListener('fetch', (event) => {
      if (event.request.mode === 'navigate') {
      event.respondWith((async () => {
      try {
      const preloadResponse = await event.preloadResponse;
      if (preloadResponse) {
      return preloadResponse;
      }

      const networkResponse = await fetch(event.request);
      return networkResponse;
      } catch (error) {
      console.log('Fetch failed; returning offline page instead.', error);
      const cache = await caches.open(CACHENAME);
      const cachedResponse = await cache.match(OFFLINELANDINGURL);
      return cachedResponse;
      }
      })());
      }
      });
      [javascript]

  3. Владимир

    В примере код у вас другой. Заменил его на этот, стало работать более стабильно, но по какой-то неведомой мне причине не выводится logo.png

  4. Милена

    Попробовала сделать на сайте вордпресс, не получилось(

Добавить комментарий