Вы столкнулись с проектом/веб-сайтом, который вы не особо удосужились оптимизировать и вам нужно ускорить его в короткие сроки?
Тогда эта статья может вам помочь!

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

TL;DR

1. Оптимизируйте медиаданные
2. Сжимайте текстовые файлы
3. Кэшируйте статические файлы
4. Используйте разделение кода
5. Удалите ресурсы, блокирующие рендеринг

1. Оптимизируйте медиа

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

  • Уменьшайте свои PNG, JPEG с помощью таких сервисов, как TinyPNG или подобных.
  • Измените размер изображений в зависимости от размера, в котором они будут отображаться.

Как мы видим, котенок сверху и снизу выглядит одинаково (мило). Таким образом, нет необходимости загружать изображение размером 3700x3700 пикселей, если размер нашего контейнера значительно меньше. Таким образом, мы можем уменьшить изображение до размера div 400x400px и ускорить время загрузки в 5 раз, а размер файла уменьшить более чем на 1 МБ.

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

Благодаря медиазапросу браузер будет знать, что большой фон нужно загружать только при разрешении 1900 пикселей и выше.

  • Конвертируйте медиа в Webp, Webm и используйте их.

Когда вы используете формат WebP, изображения меньше по размеру, но они почти никогда не ухудшают качество, что позволяет вашей странице загружаться быстрее.
Большинство новых версий браузеров поддерживают формат webp/webm.
А для старых браузеров всегда можно использовать другие форматы в качестве запасных:

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

  • Удалите метаданные изображения (если хотите сойти с ума)

В среднем метаданные изображения составляют 16% типичного файла JPEG в Интернете. Он используется для хранения данных, описывающих информацию о правах на изображение и администрировании. Метаданные изображения также могут отправляться и использоваться искусственным интеллектом.
Так что, если вас не волнуют вопросы авторского права, искусственного интеллекта и вы хотите сойти с ума — просто урежьте метаданные с помощью таких инструментов, как verexif.

2. Сжать (GZIP)

Когда мы используем веб-сайты, мы получаем файлы HTML, CSS и JS с сервера. Это все текстовые файлы, и они могут быть сжаты.

Если мы отправим в браузер сжатый файл вместо старого простого index.html, мы сэкономим на пропускной способности и времени загрузки. Браузер может загрузить сжатый файл, распаковать его, а затем показать пользователю намного быстрее.

Хорошо, а как сделать так, чтобы наши файлы были сжаты?

Ответ: мы добавляем на наш сервер (бэкенд) HTTP-заголовок Content-Encoding: gzip.

Работает просто, если браузер поддерживает какие-либо схемы сжатия, при выполнении запроса добавляет заголовок Accept-Encoding: gzip, deflate, где gzip и deflate — две возможные схемы сжатия.

Если сервер не отправляет заголовок ответа content-encoding, это означает, что файл не сжат, что является поведением по умолчанию на многих серверах.

Итак, все, что нам нужно сделать, это добавить заголовок кодирования содержимого нашего сервера.

Например, в Go нам нужно обернуть наш обработчик так:

В Nodejs мы могли бы использовать библиотеку compress (имейте в виду, что вы можете указать, какие файлы/маршруты сжимать):

Включение сжатия — один из самых быстрых и эффективных способов повысить производительность веб-сайта. Так что дерзайте и наслаждайтесь ускорением.

3. Кэшировать статические файлы

Я бы разделил кеширование на две части:

  • Кэш браузера
  • Кэш на стороне сервера

Кэш браузера

Как мы знаем, кеширование браузера улучшает и ускоряет просмотр. После того, как вы загрузили ресурс, он живет (какое-то время) на вашем компьютере. Извлечение файлов с жесткого диска всегда будет быстрее, чем извлечение их с удаленного сервера, независимо от скорости вашего соединения.

Поэтому мы определенно должны использовать его для статических ресурсов, таких как JavaScript, CSS и Изображения.

Итак, что нам нужно для настройки кеша браузера?

По сути, для практического использования нам нужно всего два HTTP-заголовка! Просто, верно?

Наш HTTP-заголовок будет Cache-Control и Etag.

  • Управление кэшем. Сервер может вернуть заголовок Cache-Control, чтобы указать, как и как долго браузер должен кэшировать отдельный ответ.
  • ETag. Когда браузер находит кешированный ответ с истекшим сроком действия, он может отправить небольшой токен (обычно это хэш содержимого файла) на сервер, чтобы проверить, изменился ли файл. Если сервер возвращает тот же токен, значит, файл тот же, и повторно скачивать его не нужно.

Обратите внимание, что вы можете использовать Expires вместо Cache-Control. Но Cache-Control был представлен в HTTP/1.1 и предлагает больше возможностей, чем Expires.

Если вы используете Express.js, то все готово, потому что Express.js настраивает заголовки за вас. Если вы используете чистый Nodejs, ваш код может выглядеть так:

В Go это может выглядеть так:

Механизм одинаков для обоих языков, если есть совпадение между полем If-None-Match и ключом, сгенерированным на сервере, нет необходимости повторно перестраивать ответ, так как браузер уже есть. В этом случае установите статус HTTP на StatusNotModified, т.е. 304 и вернитесь.

Кэш на стороне сервера

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

Вот где кеш на стороне сервера пригодится.

Трудная часть состоит в том, чтобы решить, где вы хотите кэшировать страницу.

Никогда не кэшируйте запросы POST, PUT или DELETE. Они используются для изменения ресурсов, а не для извлечения данных, поэтому кэшировать их не имеет смысла.

  • In-Memory: используйте часть ОЗУ на сервере в качестве кеша, таким образом, это самый быстрый кеш, который у вас когда-либо будет, и самый простой в реализации. В этом случае дополнительное место в ОЗУ необходимо для целей кэширования. Недостатком является то, что если у вас есть несколько серверов (что, вероятно, должно быть), вы закончите с N копиями этого кэшированного контента. Если процесс перезапустится по какой-либо причине, он потеряет весь кешированный контент и, таким образом, снова замедлит первый запрос.
  • Централизованный кеш: например, Redis. Это высокая производительность, обеспечивающая согласованность данных и широко используемая база данных в оперативной памяти, проверенная в боевых условиях. Это не так быстро, как процесс в памяти, поскольку требует сетевых вызовов, но контент используется всеми серверами, поэтому они не дублируются и не требуют ресурсов сервера приложений.

По сути, с точки зрения кода не имеет значения, где хранить наши кешированные данные в Redis или в памяти, потому что мы будем просто set и get данных из хранилища (если это Redis или в кеше памяти).

Итак, кеш Nodejs и Redis будет выглядеть так:

4. Используйте разделение кода

Когда вы загружаете свой веб-сайт в первый раз, он будет загружать такие файлы, как HTML, CSS и JS. Может случиться так, что загружается ненужный контент, в результате чего пакетный файл становится большим, а загрузка занимает много времени; это увеличивает время загрузки сайта.

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

Вот где в игру вступает разделение кода.

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

Отлично, правда?

Разделение кода может быть достигнуто с помощью любых сборщиков, таких как Webpack, Browserify, Rollup и т. д. Например, документация Webpack сообщает нам, что существует три основных подхода к разделению кода:

  • Точки входа: разделите код вручную, используя конфигурацию входа.
  • Предотвращение дублирования: используйте зависимости Entry или SplitChunksPlugin для дедупликации и разделения фрагментов.
  • Динамический импорт: разделите код с помощью встроенных вызовов функций внутри модулей.

Так как наша задача максимально быстро ускорить работу сайта, предлагаю присмотреться к динамическому импорту.
Пользоваться динамическим импортом довольно просто.
Большинству библиотек нравится В React, Vue, Angular есть отличная документация о том, как это сделать.

Например, в реакции мы могли бы использовать динамический импорт js (выглядит точно так же, как чистый динамический импорт js):

или используйте встроенные методы в реагирующей библиотеке для компонентов:

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

И поскольку решить, с чего начать разбиение, может быть сложно, я бы лично предложил начать с маршрутов (используя динамический импорт). Это безопасный выбор, поскольку пользователи вряд ли будут одновременно взаимодействовать с другими элементами на странице и привыкли ждать загрузки нового маршрута.

После этого вы можете разделить все больше и больше, используя остальные методы.

5. Удалите ресурсы, блокирующие рендеринг

Что такое ресурсы, блокирующие отрисовку?

Ресурсы, блокирующие отрисовку, – это скрипты, таблицы стилей и импорт HTML, которые блокируют или задерживают отображение веб-страницы в браузере.

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

Для изображений:

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

Для CSS

Вы не можете использовать весь свой CSS для отображения важной части вашей страницы (контент верхней части страницы, CSS других страниц).
Таким образом, вы можете разделить CSS на критические и некритические части.
На самом деле, это метод оптимизации производительности, который приобрел большую популярность с момента появления Core Web Vitals, поскольку он также улучшает показатели LCP. .

Вы можете отложить загрузку CSS следующим образом:

Для javascript-скриптов

Как только вы определили критический код, вы можете применить один из двух атрибутов к некритическому сценарию: отложенный или асинхронный. Defer говорит браузеру не ждать скрипт, пока async загружается в фоновом режиме и запускается, когда готов.

Все вышеперечисленные методы направлены на устранение ресурсов, блокирующих рендеринг, и предотвращение создания цепочки критических запросов.

Заключение

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

В своем процессе я настоятельно рекомендую использовать:
— вкладки performance insight и lighthouse в devtools
— «Еще более быстрые веб-сайты» Стива Содерса
— эта статья ;)