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

от автора

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

В поисках решения у меня сразу возникла мысль: надо отправлять запрос по адресу ссылки и получать метаданные — те данные, которые заполняют в теге <head> для сайтов-поисков. Погуглив, наткнулась на статью, где описывается кейс, как человек решал вопрос отображения превью ссылок. В материале говорится о том, что в википедии есть собственный 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 случится ошибка, и все упадет ай-яй-яй!

С 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, но картинки там не будет. Не положили!

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

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

const preview = favicon ? (         <img             src={favicon}             alt="link logo"             onError={() => {                 setFavicon('');             }}         />     ) : (         <FontAwesomeIcon icon="link" />     );

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

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

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

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

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

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

Плейграунд

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

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


ссылка на оригинал статьи https://habr.com/ru/articles/840780/


Комментарии

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

Ваш адрес email не будет опубликован. Обязательные поля помечены *