Миграция Linear с styled-components на StyleX — разбор
Кейс

С styled-components на StyleX: миграция Linear

Как Linear добился ускорения навигации на ~30%, заменив рантаймовый CSS-in-JS на компилируемый StyleX — и какие уроки может извлечь каждый React-разработчик.

1 июля 2026 8 мин чтения Олег Максимов

«Я потратил больше токенов на эту миграцию, чем хотелось бы признавать.» Так Кеннет Сковхус, инженер Linear, начинает рассказ о переносе React-приложений Linear с styled-components на StyleX. За последние несколько месяцев Linear систематически мигрирует кодовую базу — и результаты впечатляют: примерно на 30% быстрее рендеринг при навигации между страницами.

Это не просто замена одной библиотеки на другую. Это фундаментальный сдвиг в том, как современные React-приложения работают со стилями — от рантаймового CSS-in-JS, где стили генерируются в момент рендеринга, к компилируемому CSS-in-JS, где стили преобразуются на этапе сборки. Для любого, кто строит React-приложения в масштабе, путь Linear даёт конкретные уроки по производительности, архитектуре и направлению развития экосистемы React.

Почему Linear решил перейти

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

Проблема производительности

Рантаймовые CSS-in-JS-библиотеки, такие как styled-components, генерируют CSS-правила и внедряют их в DOM во время рендеринга приложения. Это означает, что пользователи платят за генерацию стилей при каждой навигации. В крупном приложении, таком как Linear — инструмент управления проектами со сложными UI-поверхностями — эти накладные расходы накапливаются на десятках компонентов на страницу.

Особенно заметна стоимость производительности при переходах между страницами. Когда пользователь перемещается между представлениями в Linear, новые компоненты монтируются, styled-components генерирует их CSS, внедряет в документ, и только после этого браузер может отрисовать новый контент. Со StyleX вся эта работа происходит на этапе сборки — сгенерированный CSS — это статический ресурс, который браузер загружает вместе с JavaScript-бандлом.

Переломный момент

Решающим фактором стал перевод styled-components в режим обслуживания. После обновления до React 18 Linear почувствовал это напрямую: React представил useInsertionEffect для оптимизации инъекции стилей, но styled-components так и не внедрил его.

Кеннет Сковхус отследил зависший PR с реализацией useInsertionEffect и связался с его автором, Коди Олсеном из Sanity. Они протестировали оптимизированный форк Sanity — который в статье Sanity назван «последним средством». Форк — это спасательная шлюпка, а не долгосрочное решение.

Что Linear хотел от новой системы стилизации

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

Почему StyleX победил

Linear оценил большинство совместимых с React библиотек стилизации. Ближайшим конкурентом был vanilla-extract — он предлагает хорошую статическую экстракцию и типовую безопасность. Однако его API показался фрагментированным, а необходимость в отдельных файлах стилей не соответствовала предпочтениям Linear.

StyleX — компилируемое решение CSS-in-JS от Meta — соответствовал всем требованиям. Он сохраняет стили локальными для компонентов, предоставляет небольшое API, детерминированное разрешение стилей через атомарные CSS-классы, типобезопасные интерфейсы и строгие ограничения, затрудняющие переопределение стилей компонентов извне. StyleX активно поддерживается Meta, используется на большинстве веб-поверхностей Meta и внедрён такими компаниями, как Figma и Cursor.

Характеристика styled-components StyleX
Генерация стилей Рантайм — во время рендеринга Компиляция — атомарный CSS на этапе сборки
Накладные расходы Инъекция стилей при каждом монтировании Нулевые — статические CSS-классы
Инкапсуляция Открыта — любой компонент можно обернуть в styled() Строгая — намеренные барьеры для внешней стилизации
Разрешение стилей На основе специфичности CSS — возможны конфликты Детерминированное — последний определённый стиль побеждает
Размер рантайма ~12 КБ в бандле Нулевой — только скомпилированный CSS
React Server Components Несовместим — требует доступа к DOM Совместим — только статические CSS-классы
Статус поддержки Режим обслуживания Активно поддерживается Meta
Сложность миграции Н/Д (исходная система) Высокая — требуется кодмод для больших кодовых баз

До и после: сравнение кода

Разница между двумя подходами наиболее наглядна в коде. Вот как изменился типичный компонент Linear:

styled-components (до)

import styled from 'styled-components';
import { Issue } from './types';

const Container = styled.div`
  padding: 12px 16px;
  border-radius: 8px;
  border: 1px solid ${props => props.$active ? '#0f766e' : '#e7e5e4'};
  background: ${props => props.$active ? '#f0fdfa' : '#ffffff'};
  cursor: pointer;
  transition: all 0.2s ease;

  &:hover {
    border-color: #0f766e;
    box-shadow: 0 2px 8px rgba(0,0,0,0.08);
  }
`;

const Title = styled.h3`
  font-size: 0.95rem;
  font-weight: 600;
  margin: 0 0 4px 0;
  color: #1c1917;
`;

const Meta = styled.span`
  font-size: 0.8rem;
  color: #78716c;
`;

function IssueCard({ issue, active }: Props) {
  return (
    <Container $active={active}>
      <Title>{issue.title}</Title>
      <Meta>#{issue.number} · {issue.status}</Meta>
    </Container>
  );
}

StyleX (после)

import stylex from '@stylexjs/stylex';

const styles = stylex.create({
  container: {
    padding: '12px 16px',
    borderRadius: 8,
    border: '1px solid #e7e5e4',
    cursor: 'pointer',
    transition: 'all 0.2s ease',
  },
  containerActive: {
    borderColor: '#0f766e',
    backgroundColor: '#f0fdfa',
  },
  title: {
    fontSize: 14,
    fontWeight: 600,
    marginBottom: 4,
    color: '#1c1917',
  },
  meta: {
    fontSize: 13,
    color: '#78716c',
  },
});

const hoverStyles = stylex.create({
  container: {
    borderColor: '#0f766e',
    boxShadow: '0 2px 8px rgba(0,0,0,0.08)',
  },
});

function IssueCard({ issue, active }: Props) {
  return (
    <div
      {...stylex.props(
        styles.container,
        active && styles.containerActive,
      )}
      onMouseEnter={(e) => {
        stylex.merge(hoverStyles.container);
      }}
    >
      <h3 {...stylex.props(styles.title)}>
        {issue.title}
      </h3>
      <span {...stylex.props(styles.meta)}>
        #{issue.number} · {issue.status}
      </span>
    </div>
  );
}

Версия на StyleX более явная — нет магических шаблонных литералов, нет динамической генерации CSS во время выполнения. Каждый стиль объявлен как обычный объект и детерминированно объединяется через stylex.props(). Активное состояние обрабатывается условной композицией стилей вместо интерполяции строки шаблона.

Миграция в масштабе: создание кодмода

Linear не пытался выполнить миграцию вручную — кодовая база слишком велика и сложна. Вместо этого Кеннет Сковхус создал детерминированный кодмод: styled-components-to-stylex-codemod.

Сложность задачи огромна. styled-components использует тегированные шаблонные литералы — по сути, полный по Тьюрингу язык, встроенный в CSS-строки. Динамические значения, выражения, условные стили и вычисления на основе пропсов создают огромное количество возможных паттернов. Как отмечает Сковхус, «количество способов выразить одно и то же намерение огромно, и слишком легко получить результат, который выглядит правильно, но на деле — нет.»

Что усложняет задачу ещё больше: в Linear нет дизайн-системы. Миграция вынудила их расплачиваться по долгам, накопленным за годы стилизации — убирать гибкость из общих компонентов, ужесточать API и затруднять переопределение стилей извне.

Сейчас кодмод насчитывает 500+ пул-реквестов, примерно 100 000 строк инструментов миграции, онлайн-площадку, кросс-файловую обработку селекторов и обширное регрессионное покрытие. Это свидетельствует как о масштабе современных веб-приложений, так и о сложности паттернов CSS-in-JS на практике.

Что это значит для React-разработчиков

Миграция Linear сигнализирует о более широком сдвиге в экосистеме React. Компилируемый CSS становится подходом по умолчанию для производительных приложений. Вот что стоит учесть для своих проектов:

Для крупных приложений

Если вы используете styled-components на крупной кодовой базе и замечаете задержки при рендеринге, StyleX (или vanilla-extract) может дать измеримые улучшения. Ускорение навигации на 30%, которого добился Linear, трудно игнорировать. Однако затраты на миграцию реальны — готовьтесь инвестировать в инструментарий и погашать долги по стилизации.

Для новых проектов

Начинаете с нуля? Пропустите рантаймовый CSS-in-JS. StyleX, vanilla-extract или даже CSS Modules с современным препроцессором обеспечат лучшую производительность и меньше проблем с поддержкой в долгосрочной перспективе.

Для небольших и средних проектов

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

Общая картина: рантайм vs компилируемый CSS

Миграция styled-components → StyleX — часть более широкого отраслевого тренда. Рантаймовый CSS-in-JS появился около 2016 года как реакция на глобальный CSS — он решал реальные проблемы (изоляция, колокация, динамические стили). Но по мере роста приложений стоимость рантайма стала заметной. Компилируемые решения представляют следующий этап эволюции: сохранить опыт разработки CSS-in-JS (колоцированные стили, привязка к компонентам, динамика), но устранить налог на рантайм.

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

FAQ

Почему Linear перешёл с styled-components на StyleX?
Linear мигрировал по двум причинам: производительность (рантайм CSS-in-JS создаёт накладные расходы на генерацию стилей при рендеринге) и поддержка (styled-components переведён в режим обслуживания). StyleX переносит генерацию стилей на этап сборки и обеспечивает более строгие контракты стилизации.
Какие улучшения производительности заметил Linear?
Linear сообщил об ускорении рендеринга примерно на 30% при навигации между страницами. Улучшение достигнуто за счёт переноса генерации стилей на этап сборки — StyleX компилирует стили в атомарные CSS-классы, поэтому браузеру нужно меньше JavaScript для обработки при переходах.
Что такое StyleX и чем он отличается от styled-components?
StyleX — компилируемое CSS-in-JS решение от Meta. В отличие от styled-components, генерирующего стили во время выполнения, StyleX обрабатывает их на этапе сборки, создавая атомарные CSS-классы. Это даёт нулевые накладные расходы на рантайм, детерминированное разрешение стилей и строгую инкапсуляцию. Используется на поверхностях Meta и в компаниях Figma и Cursor.
Какие альтернативы рассматривал Linear?
Linear оценивал vanilla-extract (хорошая статическая экстракция, но фрагментированное API) и тестировал форк styled-components от Sanity с поддержкой useInsertionEffect. Форк описан как «спасательная шлюпка, а не долгосрочное решение».
Как Linear организовал миграцию в масштабе?
Linear создал детерминированный кодмод styled-components-to-stylex-codemod — 500+ PR, ~100 000 строк инструментов миграции, онлайн-площадка, кросс-файловая обработка селекторов. Поскольку в Linear нет дизайн-системы, значительная часть работы ушла на ужесточение API компонентов.
Какие недостатки у StyleX?
StyleX использует атомарную CSS-систему, что усложняет селекторы, зависящие от родителя, глобальные селекторы и переопределение стилей через обёртки. Строгость намеренная — паттерны, сложные для миграции, обычно являются теми, что усложняют поддержку в масштабе.
Стоит ли мигрировать с styled-components на StyleX?
Для крупных приложений с заметным оверхедом — да, преимущества производительности убедительны. Для небольших проектов затраты на миграцию, вероятно, превысят выгоду. Рассмотрите StyleX, vanilla-extract или CSS Modules. Для новых React-проектов компилируемый CSS — рекомендуемая отправная точка в 2026 году.

Нужна помощь с выбором стратегии стилизации?

Выбор системы стилизации — только часть архитектуры фронтенда. Если вы оцениваете варианты для своего React-приложения или планируете миграцию с рантаймового CSS-in-JS — я могу помочь. Я full-stack веб-разработчик с опытом работы с React, Next.js и различными CSS-методологиями. Живу в Минске, работаю удалённо по всему миру. Свяжитесь для бесплатной консультации — обсудим ваш проект и подберём правильный подход.

Контакты

Обсудим ваш проект

Расскажите о вашем React-приложении — я порекомендую оптимальную архитектуру стилизации и предоставлю предварительную оценку. Бесплатно.