Favicon и где они обитают

Привет! Меня зовут Анна, я JS-разработчик в компании SimbirSoft. Сегодня расскажу об интересном кейсе на одном из наших проектов, а именно, речь пойдет об отображении favicon сторонних сайтов в нашем приложении. 

Это не крипта! favicon (от favourite icon) — маленькая картинка, символ страницы в сети, который обычно присутствует на заголовке вкладки браузера.

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

Какие у нас варианты?  

  • Отображать ссылку «as is» — много-много букв, зато сразу видно, куда пойдем (подходит для тех, кто любит буквы рассматривать).

  • Маскируем ссылку коротким описанием — распространенный подход, который используется в текстовых редакторах в том числе.

  • Маскируем ссылку картинкой — я отделила этот подход от предыдущего пункта, так как для единообразия нужно определиться, как будут выглядеть у нас ссылки — как тексты или как картинки.

  • Выводим набор: текст + картинка (favicon) — вариант, который улучшает UX. В этом случае пользователю легче воспринимать информацию, если есть графический элемент, и понятнее, если есть текст.

  • Отображаем превью ссылки — как в крупных социальных сетях. Иногда мы видим буквально скрин страницы, на которую ведет ссылка.

d90a465c0143c83a679fe87959db2e1a.jpg

В статье мы подробно поговорим о предпоследнем пункте как наиболее сбалансированном варианте по критерию «цена-качество». В конце будет ссылка на плейграунд, в котором вы можете затестить готовое решение.

Представим ситуацию: вы владелец какого-либо продукта и хотите реализовать в нем подобное отображение ссылок. Ну или вы фронтендер, которому бизнес поставил задачу отображать ссылки как-то так:

c8f80080d11583c204f5d07116db7dc3.png

В таком контексте добыча favicon нужна, чтобы:

  1. украсить UI (а настоящая красота функциональна — пользователи получают представление о содержании ссылки и возможность воспринять ее через релевантное графическое изображение);

  2. улучшить UX (а хороший пользовательский опыт — это любовь к продукту);

  3. сберечь ресурсы (тут нечего уточнять:)).

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

Изучив вопрос с npm-пакетами, я подумала, что решать эту задачу на фронте дороговато. Предложила команде другой вариант: отправляем ссылку на сервер → бэк ее обрабатывает, после чего присылает нам name и thumbnail → мы фронте их красиво отображаем. Но из-за высокой загрузки бэка мы решили, что вместо метаданных нам будет достаточно получить только favicon. Название при этом пользователь пишет сам. На этом решении и остановились.

Почему получение favicon дешевле получения метаданных? Потому что favicon принято размещать по тому же URL, где лежит index.html. Поэтому ссылкой на эту картинку будет url ссылки (его доменная часть) с добавлением »/favicon.ico». То есть задача сводится к получению строки адреса картинки, а не к отправке запроса и получению данных.

Итак, надо извлечь из строки часть, которая содержит протокол и доменное имя.

Если загуглить этот вопрос, перед нами откроются необозримые горизонты обсуждения темы «распарсить URL». Я думала только о regexp и new URL, но можно, оказывается, использовать createElement (не буду здесь освещать этот способ, но он похож на использование new URL, в этом видео все об этих трех способах).

В сети можно найти такие примеры регулярного выражения:  

const re = new RegExp('(https|http)://.*(com|ru|org|en)/');
if (re.test(value)) {
      setFavicon(`${re.exec(value)[0] ?? ''}favicon.ico`);
      }

Именно с этого варианта я начала писать функцию получения favicon. Он вполне рабочий, но понятно, например, что вот эта часть регулярки: (com|ru|org|en) исключает прохождение URL с другими доменами (dev, uk и т.п.).

Тогда я обратилась к конструктору new URL и написала свою функцию таким образом:

const url = new URL(value);
if (url.origin) {
      const favicon = `${url.origin}/favicon.ico`;
      setFavicon(favicon);
      }

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

7590bb4841c776c9af94efa6e25dccc0.png

С regexp такой неприятности не произойдет, но решить проблему нетрудно, оборачиваем блок добычи favicon в try-catch:

try {
    const url = new URL(value);
    if (url.origin) {
          const favicon = `${url.origin}/favicon.ico`;
          setFavicon(favicon);
          }
} catch {
     console.log(`Ошибка при получении иконки адреса ${value}`);
}

Я думала на этом всё, а оказалось — нет. Строка может распарситься в URL, мы получим ссылку на favicon, но картинки там не будет. Не положили!

2cc1edb94d213eb3a1fa34485db417a9.png

Что тогда будет отображено на фронте? Вот такая кракозябра:

69f7daafb069c1b0abc2b3b742131197.png

В связи с этим вспоминаем HTML, атрибуты тегов: у тега img есть возможность обрабатывать ошибки полученных изображений, функция onerror. Я в ней скидываю favicon до пустой строки и, таким образом, выводится заглушка.

const preview = favicon ? (
        link logo {
                setFavicon('');
            }}
        />
    ) : (
        
    );

16585112c5de64fd7a784fea4cf5ce9e.png

Подводя итог, хочу сказать, что описанный способ отображения приложенных ссылок серьезно улучшает UX:  

  • ссылки имеют уникальный графический элемент,  

  • информация выделяется,  

  • пользователю «красиво и приятно»,  

  • он получает позитивный эмоциональный отклик. 

А для нас — разработчиков — это практически ничего не стоит, потому что наш проект не увеличивает кодовую базу и затрачиваемые ресурсы. Одни плюсы и никаких минусов. Пишите в комментарии свое мнение и делитесь опытом:)

Плейграунд

Спасибо за внимание!

Больше авторских материалов для frontend-разработчиков от моих коллег читайте в соцсетях SimbirSoft — ВКонтакте и Telegram.

© Habrahabr.ru