Обзор на новую CSS-in-JS либу от Facebook* – StyleX

cce63c8498078632b55ebfce2319872b

Недавно компания Facebook* (aka Meta**) выпустила в опенсорс собственную CSS-in-JS библиотеку под названием StyleX. По заявлениям разработчиков, она отлично подходит для больших проектов и ключевым ее преимуществом является перфоманс.

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

Начать стоит с того, что StyleX — framework agnostic. Это означает, что библиотеку можно использовать с любым JS фреймворком, будь то React, Preact, Solid, Angular или Qwik. Однако те, что используют кастомные расширения файлов, типа Svelte и Vue, могут потребовать дополнительной настройки.

Предлагаю взглянуть на компонент Button, написанный на React и TypeScript:

import * as React from "react";
import * as stylex from "@stylexjs/stylex";
import type { StyleXStyles } from "@stylexjs/stylex/lib/StyleXTypes";

const MEDIA_MOBILE = "@media (max-width: 700px)" as const;

const ButtonStyles = stylex.create({
  base: {
    border: "none",
    background: "none",
    cursor: "pointer",
    // Использование медиа-запросов
    fontSize: {
      default: "24px",
      [MEDIA_MOBILE]: "16px",
    },
  },
  primary: {
    color: "white",
    backgroundColor: "black",
  },
  secondary: {
    color: "black",
    backgroundColor: "white",
  },
  block: {
    display: "flex",
    width: "100%",
  },
  dynamic: (opacity) => ({
    opacity,
  }),
});

const Button = ({
  color = "primary",
  block = false,
  styles,
}: {
  color: string;
  block: boolean;
  styles?: StyleXStyles<{
    backgroundColor?: string;
    color?: string;
  }>;
}) => {
  return (
    

Библиотека имеет довольно простое API, мы разберем основные функции и типы. С остальными можно ознакомиться по ссылке.

С помощью stylex.create() создается объект стилей, свойства которого мы можем передать в stylex.props() условно, по ключу или динамически — с использованием функции. Так как props() возвращает объект, его нужно развернуть через spread-оператор.

А используя встроенный тип StyleXStyles мы можем ограничить css-свойства, передаваемые извне.

В StyleX также доступно создание переменных, на которых можно строить дизайн-систему:

import * as stylex from '@stylexjs/stylex';

const colors = stylex.defineVars({
  accent: 'blue',
  background: 'white',
});

Обращение к ним происходит так же, как и к обычным свойствам объекта:

import * as stylex from '@stylexjs/stylex';
import {colors} from './vars.stylex.js';

const styles = stylex.create({
  container: {
    color: colors.accent,
    backgroundColor: colors.background,
  },
});

Ключевые преимущества

Разработчики библиотеки декларируют ряд достоинств:

  • Перфоманс — библиотека на этапе компиляции с помощью Babel-плагина превращает JS в оптимизированный по размеру единый CSS файл, таким образом мы избегаем классических CSS-in-JS проблем с рантаймом.

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

  • Предсказуемость — приоритизация селекторов в StyleX очень проста — всегда побеждает последний заданный стиль. Это значит, что можно забыть про каскадность.

  • Комбинируемость — объекты стилей можно экспортировать и передавать в компоненты. При этом стили всегда будут вести себя предсказуемо.

  • Типизация — каждое css-свойство и переменная полностью типизированы, а мы можем использовать TypeScript или Flow, чтобы определить стили, передаваемые в компонент.

  • Все в одном месте — библиотека поощряет определение стилей в том же файле, что и компонента. При таком подходе StyleX удаляет неиспользуемые свойства из бандла и убирает дубликаты.

История создания

Идея создать новую систему работы с CSS зародилась несколько лет назад, когда разработчики Meta начали переписывать фронтенд фейсбука на React.

Ранее в проекте использовалось нечто похожее на CSS-модули и lazy loading, но у этого подхода были проблемы с масштабированием. При навигации по сайту модули подгружались в разном порядке, что порождало различные казусы с приоритизацией стилей.

В StyleX высший приоритет всегда имеет последнее примененное свойство, а значит можно с легкостью контролировать стили и переопределять их при необходимости.

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

В результате перехода на StyleX размер первоначального CSS бандла facebook.com составил 140 Кбайт. На первый взгляд может показаться, что это много, но нужно учитывать, что эти стили покрывают 100% приложения. Браузер загружает их всего один раз, а потом достает кэша.

Конкуренты

По-моему, сравнивать StyleX, в первую очередь, стоит с Emotion и Tailwind.

Тут у нас, как и в Emotion, co-located подход — стили находятся в одном файле с компонентом. Для многих это большой плюс с точки зрения DX и читабельности кода. Но в то же время, StyleX обгоняет конкурента за счет отсутствия рантайм-нагрузки.

В сравнении с Tailwind, библиотека не так проста и удобна — мы не можем использовать сокращения из коробки, их придется создавать самостоятельно.

Зато нам доступны встроенные типы, которые позволяют четко определить свойства, которые можно будет переопределять. И для этого нам не нужно будет создавать отдельный пропс под каждое свойство.

Заключение

Думаю, данное решениебудет полезно на больших проектах, при построении сложных дизайн-систем, которыми пользуются множество команд.

Компания Facebook* три года тестировала и дорабатывала свой продукт, прежде чем отдать его в опенсорс. Мне кажется, это достаточное основание полагать, что библиотека проверена и может использоваться в реальных проектах.

Лично я рад появлению этой технологии, а что думаете вы?

*Социальная сеть запрещена в России

**Компания Meta Platforms Inc. признана в России экстремистской организацией и запрещена.

© Habrahabr.ru