Концепция CSS-in-JS годами оставалась отраслевым золотым стандартом для фронтенда на React. Разработчики восторгались удобством: стили инкапсулированы внутри компонентов, динамические переменные прокидываются прямо через JavaScript-пропсы, а универсальный пропс sx позволяет быстро подправить отступ или цвет без создания отдельных классов. Однако по мере роста масштаба веб-приложения за эту иллюзорную простоту приходится расплачиваться миллисекундами времени отклика каждого пользователя.
Инженеры GitHub Джош Блэк (Josh Black) и Мари Лукка (Mari Luuka) подвели итоги масштабной многолетней миграции флагманской дизайн-системы Primer: компания полностью отказалась от библиотеки styled-components и пропса sx, переведя всю кодовую базу GitHub.com на классические статические CSS-модули (CSS Modules).
Архитектурная ловушка рантайм-стилизации
Главным пороком рантайм-подхода CSS-in-JS оказалась его линейная деградация по мере увеличения сложности страницы. При каждом рендеринге компонента библиотека styled-components:
- Вычисляет криптографический хэш от объекта переданных стилей.
- Парсит правила и преобразует их в строковый CSS.
- Динамически инжектирует новые теги
<style>в DOM-дерево документа.
В сценарии серверного рендеринга (SSR) на стороне Node.js это создавало колоссальную нагрузку на центральный процессор. Сервер тратил десятки миллисекунд только на то, чтобы собрать и сериализовать стили сотен компонентов интерфейса перед отправкой первого байта (TTFB). А на клиенте браузер тратил ценное процессорное время основного потока на повторный разбор стилей во время гидратации, блокируя отзывчивость кнопок и ссылок.
Сравним устаревший компонент с пропсом sx и его оптимизированную версию.
Раньше верстка компонента выглядела так:
// Устаревший подход Primer: пропс sx парсится в рантайме на каждый рендер
import { Box, Text } from '@primer/react';
export const UserCard = ({ name, role, isHighlighted }: Props) => (
<Box
sx={{
p: 3,
borderRadius: 2,
border: '1px solid',
borderColor: isHighlighted ? 'accent.emphasis' : 'border.default',
backgroundColor: 'canvas.subtle',
display: 'flex',
alignItems: 'center',
gap: 2,
}}
>
<Text sx={{ fontWeight: 'bold', color: 'fg.default' }}>{name}</Text>
<Text sx={{ color: 'fg.muted', fontSize: 1 }}>{role}</Text>
</Box>
);
В новой архитектуре компонент перешел на статичные CSS-модули и стандартные пользовательские переменные (CSS Custom Properties):
// Современный подход Primer: статические CSS-модули без рантайм-оверхеда
import clsx from 'clsx';
import styles from './UserCard.module.css';
export const UserCard = ({ name, role, isHighlighted }: Props) => (
<div
className={clsx(styles.card, {
[styles.highlighted]: isHighlighted,
})}
>
<span className={styles.name}>{name}</span>
<span className={styles.role}>{role}</span>
</div>
);
Стили теперь компилируются сборщиком в обычный статический файл UserCard.module.css один раз при билде:
.card {
padding: var(--base-size-16);
border-radius: var(--borderRadius-medium);
border: 1px solid var(--borderColor-default);
background-color: var(--bgColor-muted);
display: flex;
align-items: center;
gap: var(--base-size-8);
}
.highlighted {
border-color: var(--borderColor-accent-emphasis);
}
.name {
font-weight: var(--base-text-weight-semibold);
color: var(--fgColor-default);
}
.role {
font-size: var(--primer-font-size-small);
color: var(--fgColor-muted);
}
Замеры производительности и уроки миграции
Результаты отказа от рантайм-вычислений превзошли ожидания:
- Сокращение времени SSR на 55%: на тяжелых страницах репозиториев (Pull Requests, код-ревью, списки коммитов) задержка генерации разметки упала более чем вдвое.
- Ускорение гидратации на 25%: первое монтирование компонентов на клиенте стало происходить на четверть быстрее, мгновенно делая страницу интерактивной.
- Кэширование на CDN: статические CSS-файлы теперь эффективно кэшируются на периферии сети независимо от обновлений JavaScript-логики.
Для проведения столь масштабного рефакторинга команда GitHub активно привлекала автономных агентов GitHub Copilot, автоматизировавших рутинную замену десятков тысяч вызовов sx по всей кодовой базе.
Опыт GitHub ставит окончательную точку в спорах о CSS-in-JS: для высоконагруженных веб-сервисов с серверным рендерингом будущее лежит в плоскости статических CSS-модулей и нативных возможностей браузерной платформы.
