Обрезать нельзя сжать. Как ускорить метрики проекта без больших вложений

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

d33f9c9eb77f570cad4aaa042da07740.png

Мы же оказались где-то посередине. У нас были плохие показатели, но времени на какие-то значительные изменения не было. И несмотря на наличие ресурсов мы решили пойти самым простым путём и, как и гласит закон Парето, получить 80% результата за 20% усилий. Меня зовут Савичев Игорь, я работаю в 10D Самолета и мы занимаемся цифровизацией строительства на российском рынке. Мы развиваем IT-технологии в разных направлениях от девелопмента до финтеха. И сегодня я расскажу, можно ли сделать себе хорошо, быстро и не очень дорого.

Стройка — очень сложный и комплексный процесс, в котором участвуют тысячи людей, как на площадке, так и в офисе. А помимо человеческого фактора, на результат влияют погода, сроки поставок, качество планирования и координация данных. Мы в Самолет 10D поставили цель сделать работу каждого человека на стройке проще. Ведь каждый день мы строим не просто квартиры, а помогаем людям исполнять мечты о собственном доме. Если говорить о моей команде, то мы занимаемся системой контроля сроков всего девелоперского цикла.

Выявление проблем

Как и многие на рынке, для измерений производительности фронтенда мы используем Lighthouse — это автоматизированный инструмент Google с открытым исходным кодом для измерения качества веб-страниц. И после запуска проекта у нас всё было не очень гладко. По сравнению со «средней температуре по больнице», то есть, по похожим сайтам в сети, наши значения были сильно ниже. Попадание сайта в красную зону означает, что опыт клиентов, которые заходят на сайт, будет негативным. Всё тормозит, плохо загружается, а следовательно, люди постараются заходить реже или вообще пользоваться чем-то другим. Например, метрика LCP (Largest Contentful Paint) одна из самых важных и она измеряет насколько быстро человек увидит основное содержимое сайта. И все сайты сейчас стремятся к уменьшению этого параметра.

Анализ LightHouse

Анализ LightHouse

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

И тут же поделимся с вами списком, который наша команда сформулировала для анализа этого и будущих проектов в контексте сборщика Webpack:

  • Есть ли минификация JS/CSS:

  • Оптимизированы ли шрифты:

  • Есть ли оптимизация изображений:

  • Есть ли неиспользуемый код:

    • работает ли tree-shaking, т.е. используется правильный импорт библиотек;

  • Есть ли возможность подключить CDN

  • Есть ли алгоритмы сжатия в nginx

  • Возможно ли использовать «ленивую» загрузку блоков

  • Оптимизированы ли тэги link и script

  • Можно ли поднять целевую сборку ECMA стандарта

  • Есть ли возможность отказаться от избыточных библиотек в бандле:

Минифицируем код и оптимизируем шрифты

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

В итоге, минификация JS и CSS помогает ускорить загрузку веб-страниц, уменьшить сетевой трафик, сделать код менее уязвимым к атакам и повысить общую производительность вашего веб-сайта.

В дополнение к этому мы заменили все шрифты на формат woff2. Во-первых, в woff2 по сравнению с woff и sfnt изменились алгоритмы сжатия и возможность добавления мета-информации. Во-вторых, этот формат совместим с большинством современных веб-браузеров (с момента как похоронили IE 11). И наконец, WOFF2 позволяет уменьшить размер файлов шрифтов, ускоряя загрузку страницы и снижая нагрузку на сервер, что положительно сказывается на производительности и пользовательском опыте. 

И разумеется, включили свойство font-display: swap; — его основная суть —  обеспечить быстрое отображение текста на странице, даже если запрошенные шрифты еще не загрузились полностью. Когда вы используете это свойство, браузер начинает рендерить текст с системными шрифтами, а затем, когда запрошенные вами шрифты загрузятся, они заменяют системные. Это предотвращает мигание или пустые места в тексте, которые могли бы появиться, если браузер ждал загрузки всех шрифтов перед началом рендеринга. Да, swap убирает Flash Of Invisible Text (FOIT), но добавляет Flash Of Unstyled Text (FOUT). Поэтому, когда кастомный шрифт подгружается, сайт всё равно «мигает» (происходит reflow + repaint). Но если оптимизируется метрика LCP, то FOUT предпочтительнее.

Оптимизация изображений

Если говорить об оптимизации изображений, то для сжатия интерфейсных SVG и PNG элементов мы использовали ImageMinimizerWebpackPlugin на этапе сборки. А вот для картинок в контенте существуют прекрасные сервисы, такие как https://tinypng.com/ и https://svgoptimizer.com/. TinyPNG, например, работает работает с png, webp и jpeg форматом. Само сжатие происходит путем изменения количества бит. То есть идет преобразование 24 битного изображения в 8 битное (уменьшается количество цветов). Вследствие этого существенно изменяется и сам размер файла.

Сжать можно более 70% размера файла. Изменение качества изображения почти не видимы для нас. Однако это не для всех фотографий. Если само изображение небольшое или содержит небольшое количество цветовых элементов, то при сжатии, ухудшения качества картинки мы не заметим. А вот если взять изображение с большим разрешением, да еще и с многообразным цветовым оформлением (например, какой-то красивый пейзаж), то качество здесь все же немного ухудшится и различия станут видимыми. Но нам это было не особо принципиально.

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

Чуть углубляемся: TreeShaking, CDN и Lazy Load

Tree Shaking — это важная оптимизация в современной разработке JavaScript. С этим методом, внедренным благодаря нововведениям import/export в стандарте ES6, можно избегать включения в итоговый бандл кода, который фактически не используется в приложении. Для активации Tree Shaking, необходимо установить режим "production" при сборке проекта, что позволит системе определить и удалить неиспользуемые части кода, сократив размер итогового файла. Однако, для успешной работы Tree Shaking, необходимо использовать синтаксис import/export, чтобы система могла точно определить зависимости и удалить неиспользуемый код. 

Использование Content Delivery Network (CDN) для обработки статических ресурсов в вашем проекте может значительно повысить производительность и снизить нагрузку на сервер. Для этого следует следовать нижеперечисленной краткой инструкции:

  • Заказываем бакет у команды DevOps: Первым шагом является запрос на создание S3-бакета, в котором будут храниться статические ресурсы, и привязанный к нему СВТ-сервис. Обратитесь к вашей команде DevOps с запросом на создание бакета, указав требуемые параметры и настройки.

  • Изменяем publicPath для статики: В вашем проекте необходимо настроить publicPath так, чтобы он указывал на URL CDN бакета. Это обеспечит доставку статических ресурсов через CDN вместо вашего сервера.

  • Настройка CI job для загрузки статики перед деплоем: Создайте и настройте задачу (job), которая будет отвечать за автоматическую загрузку статических ресурсов в бакет CDN перед каждым деплоем окружения. Это позволит обновлять статику на CDN с минимальными усилиями.

  • Включаем сжатие на источнике: Убедитесь, что на источнике статики включено сжатие, как gzip, brotli или другие методы сжатия. Это поможет уменьшить размер передаваемых файлов и улучшить скорость загрузки для пользователей.

Для эффективной оптимизации загрузки веб-приложений важно разбить исходный код на чанки или куски, которые можно загружать по мере необходимости. Это позволяет уменьшить начальную нагрузку страницы и улучшить производительность. Одним из способов сделать это является использование плагина splitChunks, доступного во многих современных сборщиках JavaScript, таких как Webpack.

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

Кроме того, для улучшения загрузки страниц вы можете рассмотреть возможность оборачивания отдельных компонентов или страниц в React.LazyLoad. Это позволяет отложить загрузку определенных частей вашего приложения до тех пор, пока они действительно не понадобятся пользователю. Такой ленивый подход к загрузке компонентов также способствует более быстрой загрузке и уменьшению начального объема передаваемых данных.

Оптимизируем тэги link и script

Теги , , и, а также атрибуты