Стиснення css класів. Як зробити веб ще швидше. Next.js
Довгі роки точилися суперечки, як краще називати класи – по бему, за цілями, за компонентами або як завгодно, але з додаванням хеша. І це дійсно важливе питання, який спосіб буде комфортний у розробці великого проекту, що розвивається. Але що ці способи означають для користувача, чи потрібні йому ці класи і як вони пов’язані з його досвідом?
Часом, заходячи в стилі проектів, я мимоволі лякаюся довжині імен, що склалася – модуль, блок, елемент, поделемент, модифікатор 1, модифікатор 2. БЕМ дійсно чудовий і я не збираюся його заперечувати, але його розміри залишають бажати кращого.
Довгі класи збільшують вагу сторінки, це означає збільшення часу завантаження найголовнішого для рендеру сторінки – документа і файлу стилів, від яких безпосередньо залежать метрики FCP, LCP.
Це стало однією з причин, чому я довгий час задивляюся на модулі (на додаток до ізоляції стилів та їх зберігання там, де вони використовуються).
Модулі дають можливість називати класи коротшими, тільки під поточний компонент, зберігаючи при цьому зручність розробки. Але тепер до класів додаються хеші, роблячи їх довшими, а отже перевага не така, як хотілося б. Тому нарешті до теми статті.
Стиснення імен класів
Отже, які є методи скоротити класи:
- Називати класи коротше (Спасибі, Кеп, так);
- Називати класи повноцінно, але при складанні залишати лише хеш;
- Називати імена за певним правилом чи алгоритмом.
Перший спосіб не підходить для чогось більшого, ніж 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, кешує результати – згенеровані імена – і при кожному запуску відновлює їх з кешу, аналізуючи їх та перевіряючи їхню актуальність.
При цьому швидкість збірки не стала довшою, адже пакет використовує все той же оптимізований алгоритм підбору імені, а за рахунок кешування пакет працює ще швидше [ ніж базове створення імен з генеруванням хешу ].
Ефективність
Можна знайти статті з ефективністю стиснення 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 – давайте зробимо веб Ще швидше.