Как увеличить производительность CSS-in-JS в 175 раз



Книга Как увеличить производительность CSS-in-JS в 175 раз

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


  1. В том, что обязательно нужно использовать хешированные классы вместо классов пространств имён. А представьте, как может раздражать их присутствие в сторонних компонентах!
  2. В том, что применение логики в CSS всегда лучше или более удобно для восприятия человеком. А также это даёт мощный рост производительности (подробнее об этом ниже).
  3. И наконец, в том, что добавлять 25–40 Кбайт минифицированного кода JavaScript к npm-компоненту размером в 10 Кбайт  —  это хорошая идея.

Поначалу всё хорошо и беззаботно и никаких проблем с производительностью этих CSS-решений с «невероятно быстрым» временем выполнения не замечается. Но это до тех пор, пока вы не поместите всех их на одной странице в Storybook.


Обратимся к вездесущему компоненту Button, имеющему различные стили и параметры:



У нас там было множество простых и быстрых функций для создания стилей. Мы даже оптимизировали статический css, выделив его в самостоятельный фрагмент (sharedStaticButtonStyles):



В компоненте Button были самые динамические вызовы функций и наибольшее число элементов в Storybook. Посмотрим, как он выполняет загрузку:



Около 36 секунд ушло у Emotion на выполнение парсинга (см. подчёркнутое красным). Инструмент производительности Performance делает это примерно в 2–3 раза быстрее, но всё равно это слишком долго.


Дальше всё только медленнее


Сначала я думал, что проблема в компоненте Tooltip (всплывающая подсказка): может быть, это он так медленно отображается? А затем понял, что это происходит, только когда он прикреплён к Button. Стало быть, Emotion при наведении курсора снова выполняет парсинг CSS (потому что Tooltip вызывает повторное отображение) и приостанавливает основной поток примерно на 900 миллисекунд, прежде чем появится всплывающая подсказка!



Вы можете подумать: «Ну мои компоненты не такие сложные и медленные». Даже если они в два раза быстрее в крупном приложении с большим количеством компонентов на странице, тратить 1–2 лишних секунды на загрузку, пока выполняется парсинг CSS, недопустимо. Особенно в высокодинамичных приложениях, получающих большое количество обновлений в секунду. В них Emotion выполняет повторный парсинг при каждом отображении (как это происходит при наведении курсора), что обусловлено динамической природой стилевого оформления с использованием пропсов.


Как же сделать всё быстрым?


Во-первых, если вы начинаете новый проект, стоит подумать о CSS-in-JS решениях времени компиляции: таком или таком.


Если речи о новом проекте не идёт, можно увеличить производительность уже имеющегося стилевого оформления до 175 раз, сделав CSS более статичным.


Уже написано несколько статей о том, как использование пропсов при тематическом оформлении засоряет приложение специальными обёртками.


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


Но узкое место производительности не в этом


А в тех вызовах вложенных функций в css, которые принимают вдобавок к теме ещё и пропсы:



Я не рассматривал подробно CSS-код во время выполнения, но мне кажется, что при вызове функция фактически заявляет: «Я не знаю, что она вернёт, так что буду пересчитывать её при каждом отображении».


На помощь приходят атрибуты данных и CSS-переменные


Давайте поменяем то, как мы делаем этот компонент Button:



Нас здесь интересует использование CSS-переменных, позволяющее резко сократить объём статического CSS, который необходимо написать.


В ходе выполнения рефакторинга старые функции для получения цветов и размеров были сохранены и перемещены из Emotion CSS в CSS-переменные почти 1 к 1:



Эта функция выполняется в первый раз примерно за 0,002 миллисекунды. Посмотрим, как теперь выглядит CSS компонента Button:



Помните, на парсинг уходило 36 секунд? Посмотрим, что сейчас:



А теперь парсинг CSS выполняется чуть больше чем за 200 миллисекунд. В то время как Performance делал это всего в 2–3 раза быстрее (т. е. за 12–18 секунд).


Подведём итоги:


  • В новых проектах используйте CSS времени компиляции.
  • Для тематического оформления задействуйте в новых проектах CSS-переменные.
  • Делайте CSS как можно более статичным для вариаций (это самая важная оптимизация).

453   0  

Comments

    Ничего не найдено.