Венец эволюции CSS-in-JS уже здесь: полностью типизированные стили без рантайма в vanilla-extract
После взлёта тайпскрипта (извини, flow) нетипизированные области фронтенда стали мозолить глаза гораздо сильнее. Логика уже давно на TS, вёрстка, при необходимости, на TSX, а вот у CSS ситуация посложнее.
Можешь использовать CSS файлы (с диалектами и модулями по вкусу) и указывать классы в вёрстке руками - но типизация здесь на уровне "препроцессор может сгенерировать тайпинги со списком классов прямо в рабочем дереве", да и в общем интеграция с рантаймом никакая. При этом гибкость диалекта достигается с помощью плагинов - которые, в общем случае, друг с другом (и, тем более, с IDE) могут и не дружить.
Либо бери любое из CSS-in-JS решений, предоставляющих полную типизацию и интеграцию с остальным кодом, но готовься платить ощутимое пенальти в рантайме - всё же парсинг объектов/строк со стилями занимает ощутимое время. Гибкость при этом, разумеется, максимальная.
Где-то в промежутке между ними находятся проекты вроде linaria или astroturf, которые предполагают парсинг CSS-in-JS на этапе компиляции (примерно как с graphql-tag). Типизация на уровне, производительность в рантайме - тоже, однако это всё ещё препроцессоры строк, пусть и более умные, так что расширяемость оставляет желать лучшего.
Вот тут-то в дело и вступает vanilla-extract. Пару месяцев назад Mark Dalgleish (один из создателей CSS модулей, кстати) решил узнать что получится, если использовать для препроцессинга стилей... сам тайпскрипт!
Спойлер: получилось очень хорошо. Впрочем, обо всём по порядку.
Предшественник
treat - главное отличие в том, что оно никак не привязано к реакту, благодаря css переменным для тем
Пример использования
сразу с vanilla-classnames
Предупреждение
альфа версия - говорят (но не обещают) что будут готовы к стабильной версии в течении нескольких недель, пробовать можно уже сейчас
быстрый взлет
webpack (с babel plugin для дебага), esbuild, vite
Особенности
темы как набор css переменных
css переменные и способы обходиться без них - например можно статически генерировать все возможные варианты правил, как если бы они писались вручную, как в треат или просто использовать одну тему как дефолтную и вырубать возможность сменить её. Возможно что это попадёт и в ядро, но это неточно
scoped всё по умолчанию, есть глобальные варианты
слегка opinionated - обычный стиль должен быть рассчитан на один элемент, иначе используйте глобальный стиль
На самом деле не полностью типизированные (псевдо селекторы), но должно быть исправимо
Да и рантайм есть на самом деле при необходимости
Батарейки в комплекте
sprinkles - атомы, встроенные брекпоинты
Рантайм
Утилиты
Как работает?
механизм работы - esbuild, потом eval ит код, преобразует экспорты в строку с дополнительной обработкой для функций
экспорт функций как пока экспериментальная фича, мост между билдтаймом и рантаймом
Немного философии
typescript как препроцессор открывает множество возможностей для расширения - противопоставление обычным препроцессорам с системой плагинов или генерации тайпингов на основании css
classnames, возможность сделать styled divы и вообще всё что душе угодно
В целом это достаточно новая техника, связанная со спецификой стилей в целом и css-модулей в частности. Это не назвать традиционным компилятором и даже препроцессором - оно никак не завязано на AST (исключение в виде бабель плагина для более красивых дебаг названий).
Учитывая гибкость этого подхода и огромную интероперабельность между css и js в нём, осталось лишь подождать когда на его основе наделают множество утилит (или даже целых DSL), которые закроют болевые точки, о которых мы и не подозреваем, пока не увидим их решение.
Как вам, например, строго типизированный z-index (и вообще контекст наложения) во всём приложении? Или возможность рантайм проверок правильной вложенности классов без единой дополнительной строчки кода? Или же вообще полностью новая система стилизации, предназначенная именно для приложений, а не документов, но при этом компилируемая в нативный css и работающая с его скоростью, да ещё и учитывающая современные компонентные подходы? И это всё без нового синтаксиса, заметим, да ещё и не влияющая на производительность в рантайме!
Впрочем, билд-тайм тоже должен будет сократиться, ведь тут вместо парсинга текста с дальнейшей дженерик-обработкой AST предполагается прямой запуск кода.