Сжатие css классов. Как сделать веб Ещё быстрее. next.js

4c2ce4e40346ac43b43de02611ff000d.jpg

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

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

Длинные классы увеличивают вес страницы, это в свою очередь означает увеличение времени загрузки самого главного для рендера страницы — документа и файла стилей, от которых напрямую зависят метрики FCP, LCP.

Это стало одной из причин почему я долгое время засматриваюсь на модули (в дополнение к изоляции стилей и их хранении там, где они используется).

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

Сжатие имён классов

Итак, какие есть методы сократить классы:

  1. Называть классы короче (Спасибо, Кэп, да);

  2. Называть классы полноценно, но при сборке оставлять только хеш;

  3. Называть имена по определённому правилу или алгоритму.

Первый способ не подходит для чего-то большего, чем to-do лист — сделав классы слишком короткими мы либо теряем DX, либо рискуем сделать пересечения.

Для второго и третьего же способа, css-loader предлагает свойство localIdentName для модулей.

localIdentName: "[path][name]__[local]--[hash:base64:5]"

localIdentName: "[hash:base64]"

Самое оптимальное сжатие

Подобрав правило можно значительно сократить размер классов, но всё же, значительно не равно максимально. Максимальным уменьшением имён классов будет сохращение до символов — .a, .b, .c, …, etc.

Таким подходом пользуются, например, Google, Facebook, Instagram

Чтобы реализовать такое решение нас интересует свойство getLocalIdent, которое позволяет передавать функцию для генерирования имени. Также можно использовать такие пакеты как posthtml-minify-classnames или mangle-css-class-webpack-plugin.

На этом можно было бы завершать статью, если бы не одна деталь. Я использую next.js.

Решение

Next.js имеет несколько особенностей, которые не позволяют использовать эти решения. Самой очевидной особенностью является то, что он не даёт возможности настроить getLocalIdent снаружи.

Именно поэтому я, 3 года назад сделал пакет — next-classnames-minifier. В нём я реализовал алгоритм подбора имён и настроил встраивание getLocalIdent в нужные правила в вебпаке. За последующие годы пакет незначительно обновлялся, но было в нём то, что не позволяло мне назвать его завершённым и готовым для использования в коммерческих проектах.

Главной проблемой была необходимость каждый раз удалять папку собранного приложения и кеша в ci, что, безусловно, очень сказывалось на удобстве разработки. И в этом вторая особенность Некста — его система кеширования.

Если компонент собрался, то при следующем запуске режима разработки или сборки — он может не пересобираться. То есть при перезапуске, алгоритм начинал работать с чистого листа и генерировал классы с самых простых имён (.a, .b, .c), но в ряде непересобираемых компонент и стилей такие имена были добавлены при прошлом запуске.

По этой причине решение и не включено в next.js

Ответ со-автора next.js на сжатие имён классов.

Ответ со-автора next.js на сжатие имён классов.

Подружиться с Next.js

Очевидно, критично важной задачей было избавить от проблемы очистки кеша. И решение нашлось. Теперь пакет, подобно next.js, кеширует результаты — сгенерированные имена — и при каждом запуске восстанавливает их из кеша, анализируя их и проверяя их актуальность.

При этом, скорость сборки не стала дольше, ведь пакет использует всё тотже оптимизированный алгоритм подбора имени, а за счёт кеширования пакет работает ещё быстрее [чем базовое создание имён с генерированием хеша].

Эффективность

Можно найти статьи с эффективностью сжатия 30%, 50% и даже 70%. В реальности же всё очень индивидуально. Например, если у вас был класс:

.postsListItemTitle {
	font-size: 24px;
}

Из него получится:

.j1 {
	font-size: 24px;
}

21 символ (.j1{font-size: 24px;}) вместо 44 (.postsListItemTitle__h53_j{font-size: 24px;}) — экономия 52%. Этот класс используется в 20 карточках на странице, что уменьшает вес и html.

В среднем же, пожалуй, можно говорить о уменьшении веса css на 10–20%.

next-classnames-minifier — давайте сделаем веб Ещё быстрее.

© Habrahabr.ru