Favicon и где они обитают
Привет! Меня зовут Анна, я JS-разработчик в компании SimbirSoft. Сегодня расскажу об интересном кейсе на одном из наших проектов, а именно, речь пойдет об отображении favicon сторонних сайтов в нашем приложении.
Это не крипта! favicon (от favourite icon) — маленькая картинка, символ страницы в сети, который обычно присутствует на заголовке вкладки браузера.
Зачем ее добывать? Мы будем говорить о ситуации, когда нам надо отображать ссылки, которые приложил пользователь нашего продукта. Например, когда у пользователя есть возможность прикладывать ссылки к сообщению или к профилю, эти ссылки надо как-то прилично отобразить.
Какие у нас варианты?
Отображать ссылку «as is» — много-много букв, зато сразу видно, куда пойдем (подходит для тех, кто любит буквы рассматривать).
Маскируем ссылку коротким описанием — распространенный подход, который используется в текстовых редакторах в том числе.
Маскируем ссылку картинкой — я отделила этот подход от предыдущего пункта, так как для единообразия нужно определиться, как будут выглядеть у нас ссылки — как тексты или как картинки.
Выводим набор: текст + картинка (favicon) — вариант, который улучшает UX. В этом случае пользователю легче воспринимать информацию, если есть графический элемент, и понятнее, если есть текст.
Отображаем превью ссылки — как в крупных социальных сетях. Иногда мы видим буквально скрин страницы, на которую ведет ссылка.
В статье мы подробно поговорим о предпоследнем пункте как наиболее сбалансированном варианте по критерию «цена-качество». В конце будет ссылка на плейграунд, в котором вы можете затестить готовое решение.
Представим ситуацию: вы владелец какого-либо продукта и хотите реализовать в нем подобное отображение ссылок. Ну или вы фронтендер, которому бизнес поставил задачу отображать ссылки как-то так:
В таком контексте добыча favicon нужна, чтобы:
украсить UI (а настоящая красота функциональна — пользователи получают представление о содержании ссылки и возможность воспринять ее через релевантное графическое изображение);
улучшить UX (а хороший пользовательский опыт — это любовь к продукту);
сберечь ресурсы (тут нечего уточнять:)).
В поисках решения у меня сразу возникла мысль: надо отправлять запрос по адресу ссылки и получать метаданные — те данные, которые заполняют в теге
для сайтов-поисков. Погуглив, наткнулась на статью, где описывается кейс, как человек решал вопрос отображения превью ссылок. В материале говорится о том, что в википедии есть собственный 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 ? (
{
setFavicon('');
}}
/>
) : (
);
Подводя итог, хочу сказать, что описанный способ отображения приложенных ссылок серьезно улучшает UX:
ссылки имеют уникальный графический элемент,
информация выделяется,
пользователю «красиво и приятно»,
он получает позитивный эмоциональный отклик.
А для нас — разработчиков — это практически ничего не стоит, потому что наш проект не увеличивает кодовую базу и затрачиваемые ресурсы. Одни плюсы и никаких минусов. Пишите в комментарии свое мнение и делитесь опытом:)
Плейграунд
Спасибо за внимание!
Больше авторских материалов для frontend-разработчиков от моих коллег читайте в соцсетях SimbirSoft — ВКонтакте и Telegram.