Технология CSS-in-JS заняла прочное место среди инструментов фронтенд-разработки. И возникает ощущение, что CSS-in-JS-тренд в ближайшем будущем лишь усилится. Особенно — в мире React. Например, в исследовании State of CSS, проведённом в 2020 году, приняли участие 11492 человека. Лишь 14,3% из них не слышали о Styled Components (о ведущей CSS-in-JS-библиотеке). А вот пользовались этой библиотекой более 40% участников исследования.
Мне уже давно хотелось найти серьёзный материал, посвящённый сравнению производительности CSS-in-JS-библиотек, вроде Styled Components, и доброго старого CSS. Но я, к сожалению, ничего такого, вроде сравнения их производительности на реальном проекте, а не на каком-то простом наборе тестов, найти не смог. Поэтому я решил сам сделать такое сравнение. Я перевёл реальное приложение со Styled Components на Linaria, на библиотеку, которая выполняет извлечение CSS в файлы во время сборки проекта. В результате в приложении, использующем Linaria, не выполняется генерирование стилей во время работы этого приложения на компьютере пользователя.
Прежде чем мы приступим к делу — хочу прояснить некоторые вещи. Я не отношу себя к людям, которые ненавидят CSS-in-JS. Я признаю то, что эта технология отличается отличным «опытом разработчика» (Developer Experience, DX), и то, что она обладает замечательной моделью композиции, унаследованной от React. CSS-in-JS способна дать разработчикам много хорошего (почитать об этом можно здесь). Да и я сам пользуюсь библиотекой Styled Components в нескольких собственных проектах и в проектах, над которыми мне доводилось работать. Но мне всегда было интересно знать о том, сколько пользователям веб-проектов приходится платить за те удобства, которые даёт разработчикам CSS-in-JS.
Да, если вас интересуют лишь мои выводы — то вот они: не используйте CSS-in-JS с вычислением стилей во время работы программы в том случае, если вы заботитесь о скорости загрузки вашего сайта. Тут всё просто: чем меньше JavaScript-кода — тем быстрее сайт. И с этим ничего особо поделать нельзя. Если же вам интересно узнать о том, как я пришёл к таким выводам — продолжайте читать.
Приложение, которое я использовал в тестах — это вполне обычный React-проект. Его основа создана с помощью Create React App (CRA), в нём используется Redux и Styled Components (v5). Это — достаточно большое приложение с множеством экранов, с настраиваемой панелью управления, с поддержкой тем и со многими другими возможностями. Так как оно было создано с помощью CRA — оно не поддерживает серверный рендеринг, в результате всё рендерится на стороне клиента (речь идёт о B2B-приложении, в перечне требований к нему серверного рендеринга не было).
Я взял это приложение и заменил Styled Components на библиотеку Linaria, которая, как мне казалось, имеет похожий API. Я полагал, что перейти со Styled Components на Linaria будет просто. Но, на самом деле, перевод приложения на новую библиотеку стилизации потребовал определённых усилий. А именно, на то, чтобы перевести приложение на Linaria, у меня ушло два месяца. Но даже после того, как у меня получилось что-то такое, с чем уже можно было работать, переведены были лишь несколько страниц, а не всё приложение. Подозреваю, что именно поэтому никто и не проводит таких сравнений, которое решил провести я. Единственное изменение, которое я внёс в приложение, было представлено заменой одной библиотеки стилизации на другую. Всё остальное осталось нетронутым.
Для запуска различных тестов, направленных на исследование двух страниц, которые используются чаще всего, я пользовался инструментами разработчика Chrome. Я всегда запускал тесты по три раза. Представленные здесь цифры — это средние показатели по трём запускам тестов. Во всех тестах я устанавливал, на вкладке
Вот какие испытания я провёл:
Начнём с анализа сетевой активности приложения. Одной из сильных сторон CSS-in-JS является тот факт, что при использовании этой технологии в приложение не попадает ненужных стилей. Верно? Ну, на самом деле, это не совсем так. Когда на странице имеется лишь один активный стиль, вместе с ним могут загрузиться и ненужные стили. Но эти стили находятся не в отдельном файле, а в JS-бандле.
Вот данные, полученные при исследовании домашней страницы двух вариантов приложения. Один из них, напомню, создан с использованием Styled Components, а второй — с помощью Linaria. Показатель до косой черты — это размер данных, сжатых gzip, а после косой черты идёт размер несжатых данных.
Сравнение сетевых показателей домашней страницы двух вариантов приложения.
Сравнение сетевых показателей поисковой страницы двух вариантов приложения.
Даже несмотря на то, что в Linaria-варианте приложения значительно возрос объём загружаемого CSS-кода, общий объём загружаемых данных снизился у обеих страниц (хотя в данном случае эта разница почти незаметна). Но самое важное тут то, что общий объём CSS- и JS-данных Linaria-варианта страниц меньше, чем размер JS-бандла того варианта приложения, в котором используется Styled Components.
Если проанализировать объём используемого кода, то окажется, что в Linaria-варианте приложения имеется большой объём (около 55 Кб) неиспользуемого CSS-кода. А в приложении, где применяется Styled Components это — всего 6 Кб (причём это — CSS из npm-пакета, а не из самой библиотеки Styled Components). Размер неиспользуемого JS-кода в Linaria-варианте приложения на 20 Кб меньше, чем в Styled Components-варианте. Но общий объём неиспользуемого кода больше там, где применяется Linaria. Это — один из компромиссов, на которые приходится идти тому, кто использует внешний CSS.
Анализ используемого кода домашней страницы.
Анализ используемого кода поисковой страницы.
Если уж мы говорим об анализе производительности — непростительно будет не взглянуть на то, что выдаёт Lighthouse. Сравнение показателей (средние значения после трёх запусков Lighthouse) можно видеть на нижеприведённых диаграммах. Тут, помимо показателей группы Web Vitals, имеются ещё два показателя — Main thread work и Execution time. Main thread work — это время парсинга, компиляции и запуска ресурсов, большая часть которого уходит на работу с JS, хотя вклад в этот показатель вносят и подготовка макета страницы, и вычисление стилей, и вывод данных, и другие процессы. Execution time — это время выполнения JS-кода. Я не включил сюда показатель Cumulative Layout Shift, так как он близок к нулю, и он выглядит практически одинаково для вариантов приложения, в котором используется Linaria и Styled Components.
Показатели Lighthouse для домашней страницы
Показатели Lighthouse для поисковой страницы
Как видите, Linaria-вариант приложения лучше, чем Styled Components-вариант, выглядит в Web Vitals-тестах (он показал худший результат лишь однажды, по показателю CLS). Иногда преимущество оказывается довольно-таки значительным. Например, на домашней странице показатель LCP оказывается лучше на 870 мс, а на поисковой странице — на 1,2 с. Страница, на которой используется обычный CSS, не только быстрее рендерится, но и требует меньше ресурсов. А время блокировки и время, необходимое на выполнение всего JS-кода, соответственно, меньше на 300 мс и примерно на 1,3 с.
Lighthouse может дать нам много интересных сведений о производительности приложений. Но нет лучшего средства для детального анализа производительности, чем вкладка инструментов разработчика Chrome
Профилирование производительности домашней страницы
Профилирование производительности поисковой страницы
На страницах, при создании которых используется библиотека Styled Components, имеется больше задач, выполняющихся длительное время. И на завершение этих задач, в сравнении с Linaria-вариантом страниц, нужно больше времени.
Для того чтобы рассмотреть данные профилирования производительности под несколько иным углом, ниже я привёл совмещённые графики загрузки Styled Components-варианта домашней страницы (выше) и её Linaria-варианта (ниже).
Сравнение процесса загрузки разных вариантов домашней страницы
Я решил сравнить страницы не только по показателям их загрузки, но и на предмет их быстродействия при работе с ними. А именно, я измерил производительность страниц при выполнении действий, предусматривающих перетаскивание элементов и размещение их по группам. Итоговые результаты приведены ниже. Как видно, даже в этом тесте Linaria побеждает Styled Components в нескольких категориях.
Сравнение процесса взаимодействия с разными вариантами страницы
Вот и всё. Как видите, использование технологии CSS-in-JS, предусматривающей вычисление стилей во время работы страницы, оказывает заметное воздействие на производительность. Это актуально, в основном, для недорогих устройств и для регионов с медленными или дорогими интернет-каналами. Поэтому, возможно, нам следует ответственнее подходить к тому, какие именно инструменты мы выбираем, и к тому, как именно ими пользуемся. Отличный «опыт разработчика» не должен достигаться ценой ухудшения «пользовательского опыта».
Я полагаю, что мы (разработчики) должны больше размышлять о том, каковы последствия выбора тех или иных инструментов. Когда я в следующий раз начну работу над новым проектом — технологией CSS-in-JS я больше пользоваться не буду. Я либо применю обычный CSS, либо воспользуюсь альтернативой CSS-in-JS, библиотекой, занимающейся обработкой стилей во время сборки проекта и извлекающей стили из JS-бандлов.
Я думаю, что следующим значительным феноменом мира CSS станут CSS-in-JS-библиотеки, обрабатывающие стили во время сборки проектов. Дело в том, что появляется всё больше и больше таких библиотек (например — свежайшая vanilla-extract от Seek). Да и крупные компании тоже двигаются в этом направлении, например — Facebook.
Как вы относитесь к CSS-in-JS?
Мне уже давно хотелось найти серьёзный материал, посвящённый сравнению производительности CSS-in-JS-библиотек, вроде Styled Components, и доброго старого CSS. Но я, к сожалению, ничего такого, вроде сравнения их производительности на реальном проекте, а не на каком-то простом наборе тестов, найти не смог. Поэтому я решил сам сделать такое сравнение. Я перевёл реальное приложение со Styled Components на Linaria, на библиотеку, которая выполняет извлечение CSS в файлы во время сборки проекта. В результате в приложении, использующем Linaria, не выполняется генерирование стилей во время работы этого приложения на компьютере пользователя.
Прежде чем мы приступим к делу — хочу прояснить некоторые вещи. Я не отношу себя к людям, которые ненавидят CSS-in-JS. Я признаю то, что эта технология отличается отличным «опытом разработчика» (Developer Experience, DX), и то, что она обладает замечательной моделью композиции, унаследованной от React. CSS-in-JS способна дать разработчикам много хорошего (почитать об этом можно здесь). Да и я сам пользуюсь библиотекой Styled Components в нескольких собственных проектах и в проектах, над которыми мне доводилось работать. Но мне всегда было интересно знать о том, сколько пользователям веб-проектов приходится платить за те удобства, которые даёт разработчикам CSS-in-JS.
Да, если вас интересуют лишь мои выводы — то вот они: не используйте CSS-in-JS с вычислением стилей во время работы программы в том случае, если вы заботитесь о скорости загрузки вашего сайта. Тут всё просто: чем меньше JavaScript-кода — тем быстрее сайт. И с этим ничего особо поделать нельзя. Если же вам интересно узнать о том, как я пришёл к таким выводам — продолжайте читать.
Что и как я измерял
Приложение, которое я использовал в тестах — это вполне обычный React-проект. Его основа создана с помощью Create React App (CRA), в нём используется Redux и Styled Components (v5). Это — достаточно большое приложение с множеством экранов, с настраиваемой панелью управления, с поддержкой тем и со многими другими возможностями. Так как оно было создано с помощью CRA — оно не поддерживает серверный рендеринг, в результате всё рендерится на стороне клиента (речь идёт о B2B-приложении, в перечне требований к нему серверного рендеринга не было).
Я взял это приложение и заменил Styled Components на библиотеку Linaria, которая, как мне казалось, имеет похожий API. Я полагал, что перейти со Styled Components на Linaria будет просто. Но, на самом деле, перевод приложения на новую библиотеку стилизации потребовал определённых усилий. А именно, на то, чтобы перевести приложение на Linaria, у меня ушло два месяца. Но даже после того, как у меня получилось что-то такое, с чем уже можно было работать, переведены были лишь несколько страниц, а не всё приложение. Подозреваю, что именно поэтому никто и не проводит таких сравнений, которое решил провести я. Единственное изменение, которое я внёс в приложение, было представлено заменой одной библиотеки стилизации на другую. Всё остальное осталось нетронутым.
Для запуска различных тестов, направленных на исследование двух страниц, которые используются чаще всего, я пользовался инструментами разработчика Chrome. Я всегда запускал тесты по три раза. Представленные здесь цифры — это средние показатели по трём запускам тестов. Во всех тестах я устанавливал, на вкладке
Performance
, значение 4x slowdown
для параметра CPU
и значение Slow 3G
для параметра Network
. Для исследования производительности я использовал отдельный профиль Chrome без каких-либо расширений.Вот какие испытания я провёл:
- Анализ сетевой активности приложения (размер JS- и CSS-ресурсов, анализ используемого кода, количество запросов).
- Исследование производительности в Lighthouse (аудит производительности с применением мобильных предустановок).
- Профилирование производительности (исследование загрузки страниц и особенностей drag-and-drop-взаимодействия с ними).
Анализ сетевой активности приложения
Начнём с анализа сетевой активности приложения. Одной из сильных сторон CSS-in-JS является тот факт, что при использовании этой технологии в приложение не попадает ненужных стилей. Верно? Ну, на самом деле, это не совсем так. Когда на странице имеется лишь один активный стиль, вместе с ним могут загрузиться и ненужные стили. Но эти стили находятся не в отдельном файле, а в JS-бандле.
Вот данные, полученные при исследовании домашней страницы двух вариантов приложения. Один из них, напомню, создан с использованием Styled Components, а второй — с помощью Linaria. Показатель до косой черты — это размер данных, сжатых gzip, а после косой черты идёт размер несжатых данных.
Сравнение сетевых показателей домашней страницы двух вариантов приложения.
Styled Components | Linaria | |
Общее количество запросов | 11 | 13 |
Общий размер | 361Кб/1,8MB | 356Кб/1,8Мб |
Размер CSS | 2,3Кб/7,2Кб | 14,7Кб/71,5Кб |
Количество CSS-запросов | 1 | 3 |
Размер JS | 322Кб/1,8Мб | 305Кб/1,7Мб |
Количество JS-запросов | 6 | 6 |
Сравнение сетевых показателей поисковой страницы двух вариантов приложения.
Styled Components | Linaria | |
Общее количество запросов | 10 | 12 |
Общий размер | 395Кб/1,9Мб | 391Кб/1,9Мб |
Размер CSS | 2,3Кб/7,2Кб | 16,0Кб/70,0Кб |
Количество CSS-запросов | 1 | 3 |
Размер JS | 363Кб/1,9Мб | 345Кб /1,8Мб |
Количество JS-запросов | 6 | 6 |
Даже несмотря на то, что в Linaria-варианте приложения значительно возрос объём загружаемого CSS-кода, общий объём загружаемых данных снизился у обеих страниц (хотя в данном случае эта разница почти незаметна). Но самое важное тут то, что общий объём CSS- и JS-данных Linaria-варианта страниц меньше, чем размер JS-бандла того варианта приложения, в котором используется Styled Components.
Анализ используемого кода
Если проанализировать объём используемого кода, то окажется, что в Linaria-варианте приложения имеется большой объём (около 55 Кб) неиспользуемого CSS-кода. А в приложении, где применяется Styled Components это — всего 6 Кб (причём это — CSS из npm-пакета, а не из самой библиотеки Styled Components). Размер неиспользуемого JS-кода в Linaria-варианте приложения на 20 Кб меньше, чем в Styled Components-варианте. Но общий объём неиспользуемого кода больше там, где применяется Linaria. Это — один из компромиссов, на которые приходится идти тому, кто использует внешний CSS.
Анализ используемого кода домашней страницы.
Styled Components | Linaria | |
Размер неиспользуемого CSS | 6,5Кб | 55,6Кб |
Размер неиспользуемого JS | 932Кб | 915Кб |
Общий размер | 938,5Кб | 970,6Кб |
Анализ используемого кода поисковой страницы.
Styled Components | Linaria | |
Размер неиспользуемого CSS | 6,3Кб | 52,9Кб |
Размер неиспользуемого JS | 937Кб | 912Кб |
Общий размер | 938,5Кб | 970,6Кб |
Аудит производительности в Lighthouse
Если уж мы говорим об анализе производительности — непростительно будет не взглянуть на то, что выдаёт Lighthouse. Сравнение показателей (средние значения после трёх запусков Lighthouse) можно видеть на нижеприведённых диаграммах. Тут, помимо показателей группы Web Vitals, имеются ещё два показателя — Main thread work и Execution time. Main thread work — это время парсинга, компиляции и запуска ресурсов, большая часть которого уходит на работу с JS, хотя вклад в этот показатель вносят и подготовка макета страницы, и вычисление стилей, и вывод данных, и другие процессы. Execution time — это время выполнения JS-кода. Я не включил сюда показатель Cumulative Layout Shift, так как он близок к нулю, и он выглядит практически одинаково для вариантов приложения, в котором используется Linaria и Styled Components.
Показатели Lighthouse для домашней страницы
Показатели Lighthouse для поисковой страницы
Как видите, Linaria-вариант приложения лучше, чем Styled Components-вариант, выглядит в Web Vitals-тестах (он показал худший результат лишь однажды, по показателю CLS). Иногда преимущество оказывается довольно-таки значительным. Например, на домашней странице показатель LCP оказывается лучше на 870 мс, а на поисковой странице — на 1,2 с. Страница, на которой используется обычный CSS, не только быстрее рендерится, но и требует меньше ресурсов. А время блокировки и время, необходимое на выполнение всего JS-кода, соответственно, меньше на 300 мс и примерно на 1,3 с.
Профилирование производительности
Lighthouse может дать нам много интересных сведений о производительности приложений. Но нет лучшего средства для детального анализа производительности, чем вкладка инструментов разработчика Chrome
Performance
. В данном случае то, что удалось выяснить с помощью инструментов этой вкладки, согласуется с тем, что мы уже видели после выполнения Lighthouse-испытаний. Взгляните на следующие диаграммы.Профилирование производительности домашней страницы
Профилирование производительности поисковой страницы
На страницах, при создании которых используется библиотека Styled Components, имеется больше задач, выполняющихся длительное время. И на завершение этих задач, в сравнении с Linaria-вариантом страниц, нужно больше времени.
Для того чтобы рассмотреть данные профилирования производительности под несколько иным углом, ниже я привёл совмещённые графики загрузки Styled Components-варианта домашней страницы (выше) и её Linaria-варианта (ниже).
Сравнение процесса загрузки разных вариантов домашней страницы
Сравнение особенностей drag-and-drop-взаимодействия со страницами
Я решил сравнить страницы не только по показателям их загрузки, но и на предмет их быстродействия при работе с ними. А именно, я измерил производительность страниц при выполнении действий, предусматривающих перетаскивание элементов и размещение их по группам. Итоговые результаты приведены ниже. Как видно, даже в этом тесте Linaria побеждает Styled Components в нескольких категориях.
Styled Components | Linaria | Разница | |
Показатель Scripting, мс | 2955 | 2392 | -563 |
Показатель Rendering, мс | 3002 | 2525 | -477 |
Показатель Painting, мс | 329 | 313 | -16 |
Общее время блокировки, мс | 1862,66 | 994,07 | -868 |
Сравнение процесса взаимодействия с разными вариантами страницы
Итоги
Вот и всё. Как видите, использование технологии CSS-in-JS, предусматривающей вычисление стилей во время работы страницы, оказывает заметное воздействие на производительность. Это актуально, в основном, для недорогих устройств и для регионов с медленными или дорогими интернет-каналами. Поэтому, возможно, нам следует ответственнее подходить к тому, какие именно инструменты мы выбираем, и к тому, как именно ими пользуемся. Отличный «опыт разработчика» не должен достигаться ценой ухудшения «пользовательского опыта».
Я полагаю, что мы (разработчики) должны больше размышлять о том, каковы последствия выбора тех или иных инструментов. Когда я в следующий раз начну работу над новым проектом — технологией CSS-in-JS я больше пользоваться не буду. Я либо применю обычный CSS, либо воспользуюсь альтернативой CSS-in-JS, библиотекой, занимающейся обработкой стилей во время сборки проекта и извлекающей стили из JS-бандлов.
Я думаю, что следующим значительным феноменом мира CSS станут CSS-in-JS-библиотеки, обрабатывающие стили во время сборки проектов. Дело в том, что появляется всё больше и больше таких библиотек (например — свежайшая vanilla-extract от Seek). Да и крупные компании тоже двигаются в этом направлении, например — Facebook.
Как вы относитесь к CSS-in-JS?
Kromeshnaja
«Особенно — в мире React.»
Хорошо бы, чтоб этот костыль там и оставался.
Ухудшается производительность, ухудшается читаемость, теряются нативные наработки работы с анализом, парсингом css. Как ни крути, это была попытка лишь решить проблему одного фреймворка и ничего хорошего я в этом не вижу.
justboris
Возможно, вы удивитесь, но CSS-in-JS используется даже в самом абсолютном воплощении веб-стандартов – в веб-копонентном фреймворке lit-element: https://lit.dev/docs/components/styles/
Так уж оказалось, что сочетание стилей и остального кода компонента в одом месте – это очень практично.
Kromeshnaja
Спорное субьективное утверждение. Мне, например, это максимально непрактично.
Это всегда воспринималось как антишаблон и большие компании всегда пытались разделять представление от реализации (даже если это css, html и JavaScript). Да про что говорить, если бы «всё в одом месте» было хоть как-то практично, то до сих пор верстали бы с использованием style атрибута, но к счастью этого не происходит и никто не жалуется.
Тот же компонент тоже можно поставлять как сборку из нескольких файлов, никакой проблемы с этим вообще нет.
По моему скромному мнению такой подход просто временное решение каких-то возникших проблем с незрелыми технологиями, что мы имеем сейчас. Это никто и никогда не потянет в стандарты.
justboris
Спорное – это на ваш взгляд. С точки зрения фреймворков видно консенсус, что стили принадлежат файлу с компонентом. Это происходит не только в Реакте, но и во Vue, Svelte и LitElement.
Asxer
Ну по крайней мере во Vue это не обязательно. Все проекты, которые я видел и команды с которыми работал рано или поздно приходят к хранению стилей отдельно от компонентов.
bakhirev
Поддержу. Так же во Vue стили загнаны в отдельную секцию вне JS, а не как строки в объекте.
justboris
Добавлю еще про "никто и никогда не потянет в стандарты". Гугл как раз активно продвигает такой стандарт: https://github.com/WICG/construct-stylesheets
Я понимаю откуда происходит ваше неприятие этого подхода. 10 лет назад всем внушили концепт разделения сущностей, и многие поняли его слишком буквально. С тех пор концепции поменялись, и то что работало для домашних страничек-визиток, уже не работает для веб-приложений.
Kromeshnaja
Я перечислил очевидные минусы.
В чем плюс?
justboris
Самый главный плюс – скрываются детали реализации. Пользователи работают с компонентами, как с черными ящиками, только посредством публичного API. В случае отдельного CSS он топорщится наружу и нарушает принцип черного ящика.
Второй плюс – в читаемости. Никто уже не пишет CSS вручную, вместо этого пользуются препроцессорами вроде SASS. У них свой особенный синтаксис, который нужно учить. Так почему бы не использовать для этого уже знакомый JS? На выходе будет все тот же CSS, со всеми его возможностями.
Третий – производительность. В случае CSS вы загружаете все сразу, даже для неиспользуемых сейчас компонентов. CSS-in-JS дает вам самораспаковывающийся CSS, который добавляется в документ только когда он нужен (а также динамически удаляется, когда нет).
Так что у вас там с минусами? ;) Я увидел только ваше субъективное мнение, ничего конструктивного.
Kromeshnaja
justboris
Вроде вы все складно объясняете, но это работатет только для небольших проектов с десятком файлов. В больших масштабах "простым контролем" уже не обойтись. С каким самым большим проектом вам доводилось иметь дело и сколько было человек в команде?
Вот например @Fi1osof ниже приводит пример СберТеха, где тоже выбрали Styled-Components и оно примерно понятно почему.
Kromeshnaja
Мне кажется, вы на это смотрите только в разрезе React. Там из-за необдуманой архитектуры самого фреймворка это в какой-то мере необходимо. Но также добавляет большие проблемы, в тех же больших проектах существуют коорпоративные стандарты линтирования, покрытия тестами и написанию кода, например, с репортами в SonarQubе. Те же линтеры не успевают дописывать за всеми библиотеками и нужно очень постараться, чтоб привести styles в JS к JavaScript\TypeScript подобному виду и правилам.
ИМХО, описывать стили в JS — это как стрелять из пушки по воробьям. И сейчас чистая спекуляция от меня — она не получит дальнейшего развития и всегда будет на третьих рядах после «нативный СSS» или «компиляция SASS подобных языков в СSS».
justboris
О каком разрезе React вы говорите? Я же уже приводил примеры других фреймворков выше.
SonarQube не решает обозначенные мной проблемы примерно никак, он только проверяет корректность CSS-синтаксиса, никаих более продвинутых правил, вроде обнаружения неиспользуемого кода, там нет.
Примерно так же думал и я, в 2016 году. Но сейчас уже 2021й, хорошие практики настоялись, технологии вышли на плато продуктивности, и говорить об их непригодности – это чистое ретроградство.
faiwer
Тоже побуду ретроградом. Не понимаю чем вам нравится CSS-in-JS. Большую часть проблем решает CSS-modules.
Учитывая как далеко скакнул CSS за последние лет 5-7, почти пропала необходимость подстраивать вёрстку под нужды стилизации. Стало меньше всяких wrapper-ов, и размещения блоков не исходя из логики, а исходя из визуальной составляющей. Поэтому держать стили отдельно от действительно сложных вещей (т.е. кода тех самых компонент) — очень удобно. Плюс, вот сколько я не верстал за последние лет 12, всегда было удобнее видеть всё картинку стилей в целом разом (т.е. открыть SCSS файл). Сам подход над компонентами был (и остался) — пишем data flow, пишем поведение, пишем стили. Зачем это всё перемешивать?
И чего лишаются пользователи CSS-modules в сравнении с CSS-in-JS? Ну по сути возможности засунуть какой-нибудь метод-генератор CSS, чего я бы рекомендовал настоятельно избегать пока на это нет очень весомой причины.
Мне кажется 2021г тут никакой роли не играет.
justboris
Для контекста, в начале 2020го в нашей команде были дебаты, что взять для новой версии нашей UI-библиотеки. После долгих дебатов победили CSS-модули, о чем мы сейчас немножечко жалеем.
Во-первых нет единого стандарта, как публиковать CSS-модули в npm. Для библиотеки нужно писать гайдлайн как правильно конфигурировать webpack, css-loader и иже с ними. А есть еще и другие бандлеры, а еще нужно Jest настроить... В CSS-in-JS все просто работает из коробки.
Во-вторых в более-менее сложной дизайн системе нужно генерировать стили (для разных варианов компонента). Циклы на SASS выглядят так громоздко, что нужно быть гуру SASS чтобы это разобрать (не говоря о том, чтобы это кто-то тестировал). На JS/TS это получается в разы читаемее.
В-третьих, темизация. На одних css-переменных далеко не уедешь, потому что бывают составные свойства (border + box-shadow или color + background-color) с правильным соотношением между ними. С помощью css-ного
calc
такое не выразить.В-четвертых, переиспользование токенов между CSS и JS. Чтобы прочесть css-переменную, нужен доступ к DOM, а современные фреймворки его тщательно оборачивают. Гораздо проще настроить переиспользование в обратную сторону, то есть CSS-in-JS
Теперь пройдемся по вашим аргументам
Тут то же самое, в статье показывается пример linaria, но можно и с другими. Большинство задач линтера прекрасно покрывается тайпскриптом и csstype, современные решения дают это из коробки.
Это про styled-components с их строковым синтаксисом, как я понимаю. Я тоже это не поддерживаю, и к счастью, есть много решений с объектным синтаксисом, например JSS. Там все удобнее некуда. Про неудобство циклов/условий на SASS уже писал выше.
Никто не мешает вам сделать отдельный файл
styles.ts
, и организовывать стили в нем точно так же.Остальные аргументы слишком субъективные, не знаю как на них ответить, кроме "а нам норм"
faiwer
А для чего вам потребовались циклы? Последний раз ими пользовался лет 5 назад. Нужно было для каждой иконки создать по стилю. С тех пор ни разу не пригодились. Большая часть "динамики" элементарно (и нативно!) решается через css-variables. Никакой подобной генерации CSS не используем ни в одном из проектов. Хотя тоже своя палитра компонентов с неадекватными требованиями по стилизации.
Это была шутка, да?
faiwer
Пропустил этот абзац. Да, это вот случай под dynamic css. Имхо для этого не нужен целый css-in-js фреймворк. У нас такой потребности не возникло ни разу, но были другие моменты, где нужно было генерировать стили в runtime. Чаще всего это стили позиционирования. Мне кажется это просто замечательно когда такая
дичьспецифика сделана ЯВНЫМ ОБРАЗОМ, чтобы это бросалось в глаза. Но понимаю что вопрос холиварныйfaiwer
Немного оффтопа. Кажется это плохая идея делать такие взаимосвязи на уровне формул. Из-за того что человеческое цветовосприятие очень плохо ложится на простые математические зависимости. Нельзя, условно, взять "{цвет фона кнопки}" + "20% затемнить" и получить хороший результат. Т.к. эти 20% в зависимости от положения на спектре и, вероятно, других параметров, будет сильно отличатся визуально. То как наш мозг это интерпретирует не совпадёт с тем что задумывал погроммист. Были вроде даже какие-то материалы на эту тему на хабре. Всё что касается цветов и их восприятия это бездонная сложная тема, не проще чем "время" :)
Но я понимаю, что это не нам решать и к обсуждаемой теме относится очень косвенно. Просто вспомнилось.
Kromeshnaja
Я не писал, что он что-то решает, наоборот добавляет проблем, но является стандартом для некоторых компаний. Просто линтеры в целом сходят с ума от CSS в JavaScript.
Именно, CSS-синтаксис подтянут, зарефакторят некоторые фрейморки и отпадет необходимость забивать гвозди пасатижами.
Это не ретроградство, CSS-in-JS, ИМХО, это тупиковая ветка развития технологии и выше я писал почему так считаю.
dreesh
можно пару вопросов для саморазвития? сейчас в html есть некие теневые элементы с собственнымы стилями которые не как не смогут пересечься с глобальными, их можно использовать для этого?
justboris
Да, можно использовать и ShadowDOM для этого. Но прикол в том, что для стили внутрь ShadowDOM обычно загружаются через тот самый пресловутый CSS-in-JS, про который тут говорят, что он "не нужон" :)
dreesh
Вы меня запутали еще больше, если есть изолированный кусок html то как к нему привязываеться css-in-js?
justboris
Дело в том, что этот изолированный кусок html конструируется в рантайме, то есть через javascript
Fi1osof
Я работал в СберТехе на проекте с 350 коллегами (не маленькая компания и не маленький проект). Не поверите, там тоже юзается SC.
DmitryKazakov8
А еще redux+saga? Собесился туда разок, показали кусок длинной функции с десятком
yield put-call-takeLatest-takeEvery
и попросили рассказать, что там происходит. Я сказал, что все там свистит-переливается и очень информативно, но мне срочно на другой собес надо) В такие проекты серьезные ребята все-таки не идут, по очень разнообразным причинам, и уверен, что SC внедряли не по трезвой голове.Fi1osof
Все-таки собесились туда? И по результатам собеса развернулись и ушли, и вердикт: «серьезные ребята все-таки не идут»? Такое… Думаю, личного опыта с порога маловато, чтобы решать ходят туда серьезные ребята или нет. Такое больше похоже на «я обиделся». Мое же мнение: там всяких хватает, но и серьезные там есть точно. А собеседование — это не отражение реальности проекта, это может быть просто проверка на спектр знаний.
И да, лично я не юзаю ни redux, ни saga. Всегда был против подобных компонентов.
DmitryKazakov8
Да, конечно, у вас больше экспертизы по бывшим коллегам — я видел только маленький кусок кода одного из многих проектов. Может и есть достаточно толковые проекты — сам работал в Домклике, там все очень пристойно было и по коду, и по процессам, и по коллегам. По крайней мере до определенного момента.
Но выбор SC однозначно делали "на попробовать хайповую штуку" без каких-либо трезвых аргументов, потому что после того, как поработаешь с несколькими реализациями, понимаешь, что этот подход некорректен в корне. Как и redux+saga. Есть намного более простые и эффективные решения.
Fi1osof
Я для себя выбираю не просто хайповые вещи, а те, которые эффективно решают свои задачи и которые слишком объемные по своему коду, чтобы их можно было просто так быстро написать самому. И как по мне, redux не нужен совсем, его вполне заменяют нативные контексты реакта. А вот со стилями лично мне удобней именно SC. Вероятно, это потому что я не очень силен в SASS и т.п., то есть я не умею вот прям с нуля сразу заложить весь uikit и от него далее плясать по компонентам. Я чаще всего закладываю основу и потом постепенно наращиваю. И вот мне проще SC использовать, потому что у меня здесь типизация работает хорошо и проще покрывать cover-тестами. А все эти CSS-ы (пусть в less, пусть в sass, что угодно), я потом не понимаю что мне нужно после рефакторинга, а что нет. С SC у меня этой проблемы практически нет.
DmitryKazakov8
Понимаю, чтобы эффективно чем-то пользоваться, требуется этому сначала обучиться, "выстрадать", придумать десять подходов, прочитать о сотне, найти самое лучшее… В программировании так фактически с каждым инструментом.
Насчет того, что "типизация работает хорошо" — это вряд ли, для этого нужны другие инструменты (stylelint), которые проверяют корректность и параметров, и значений. За редким исключением в css-in-js такого вообще нет, либо проверяются только названия параметров. Но зато действительно проверяется "используемость стилевых классов" и после рефакторинга можно с помощью ESLint плагина
увидеть неиспользуемые экспорты. Что такое cover-тест не знаю, Яндекс утверждает, что "тест на косоглазие", поэтому подтвержденной остается только эта маленькая фича с неиспользуемыми экспортами при рефакторинге. При этом недостатков ну просто море. Стоит ли оно того, и можно ли фичу с простотой удаления ненужного назвать "эффективным решением задач", хотя это вообще не относится к решению основной задачи… Думаю, точно нет.
Fi1osof
Вот тут в ответ можно прям ваши же слова приводить:
Вероятнее всего SC у вас не тот инструмент, который вы всячески изучили. Вот здесь мы с учеником разбирали конкретный пример реализации реакт-компонента со styled+параметры, то есть когда в SC передаешь параметры и они влияют на конечные стили. И там очень даже проверяется типизация. Если параметр обязательный, то не передать из реакта я не смогу (TypeScript будет ругаться), ровно как и передать не тот тип.
Есть еще много моментов (включая типизацию всей темы и автоподстановку вариантов в IDE даже для вложенных конструкций). CSS и т.п. этого не дают, там все просто живет своей жизнью.
DmitryKazakov8
Спасибо за ссылку, посмотрел и понял, что разговор наш если и состоится, то будет слишком долгим, так как буквально все там, на мой взгляд, неправильно — от обозначения проблем до выводов. Контраргументация потянет на статью, а времени на это сейчас нет, да и не то, чтобы хотелось прямо доказать свою правоту — время и так все по своим местам расставит.
Fi1osof
Ну да. Разные специалисты используют разные инструменты и имеют разные знания. И это нормально. Именно поэтому я говорю чем мне нравится CS, но не говорю, что все остальное — от лукавого и фтопку всё. Каждому своё, и своё не каждому. А закусился как раз по причине того, что не нравится когда кто-то приходит и говорит «Вот только так надо, а остальное нафиг!».
faiwer
Вот как ваш пример сделал бы я:
Что я получаю в итоге:
И нет вот этого ужаса (нагромождение разнообразного синтаксиса из разных языков, множество самых разных видов скобок, дубляж, лишние синт. конструкции и т.д.):
Стили остались простыми, декларативными. При желании можно написать тест в отрыве от стилей вообще. Вселенная "как оно выглядит" находится отдельно от "как оно работает". В случае чего легко добавить каких-нибудь анимаций открытия\закрытия прямо в SCSS файл, не трогая бизнес-логику.
При этом есть линтеры которые не дадут указать класс, которого нет в файле. Есть даже линтеры которые не позволят не задействовать все классы из файла (но вот тут уже может оказаться неудобно).
DmitryKazakov8
Удобное, лаконичное решение. Только забыли еще упомянуть про CSS Modules вида
css.popover
— то есть не будет никаких пересечений глобальных классов и "думать над названиями классов" тоже надо не больше, чем над названиями любых других сущностей и переменных (обычно исходят из семантики и читабельности). А эти два "недостатка CSS", судя по ссылке, и вынудили человека тащить js-надстройки в код и смешивать логику и представление.Fi1osof
>>
По проекту в нескольких компонентах используется [data-opened]=«false».
Потом по какой-то причине переименовали в [data-closed]=«true». В пяти компонентах нашли этот класс и переименовали, а в друх забыли. И как вы это дело в таком случае будет отслеживать? Аргументы типа «нефиг переделывать» не принимаются.
faiwer
Если речь идёт о чистом CSS на
@import
-ах, то ваш пример был бы логичен. Но чистый CSS (или даже SCSS) в SPA в 2021 это как-то уже совсем неудобно.Речь про
css-modules
. А с ним получается такая петрушка:data-opened
вdata-closed
data-opened
Т.е. ситуация почти зеркальная к
style-components
, но декларативно, а не императивно в runtime.Fi1osof
Так вот как раз этого-то и не нужно. И как раз это SC+TS и решает. Если я переименовал параметр, то я должен получить ошибку там, где я указываю несуществующий параметр и там, где я передаю не тот параметр (особенно это работает когда не просто Record<string, string> идет, как это часто в вашем примере происходит, а когда используются enum и прочие вложенные типы).
Есть и другой, менее критичный момент, но все же, типа
И передача дальне в className этих самых полученных классов. Это немного решает проблему в том плане, что если в styles.scss поменялся селектор, то и в импорте можно получить ошибку. Но это не решает того, что должно передаваться в конечную верстку. То есть если у вас там должно быть
вы это тут никак не обеспечите проверку. Если разработчик забыл прописать нужный класс, то он просто его забыл.
А если я делаю SC с указанием нужного типа, то там будет все обязательно и будет отлично проверять.
faiwer
Я право не очень вас понял. По сути примеры на
css-modules
иstyle-components
работают очень похожим образом. За исключением того что в случаеcss-modules
у вас появляетсяdata-attribute
, а вstyle-components
метод +inline style
(или всякий раз новый селектор + стиль). По сути ошибку можно совершить в:data-attribute
-а (тут уcss-modules
-1 бал, т.к. вstyle-components
будетinline-style
без аттрибута, и опечататься нельзя)display: none
. Тут вscss
у вас линтер может заругаться. Вstyle-components
возможно тоже есть какие-нибудь линтеры.В итоге почти паритет, за счёт динамики небольшой плюс в строгости у
style-components
, правда очень большой ценой.Ничего не понял если честно. Что мешает вам в случае
style components
написать<div/>
? Разве что если у вас есть линтер который категорически запрещает любые не style-components теги. Но это прямо какой-то эребор.К тому же в чём собственно проблема? Вот забыл я указать класс. Получаю ошибку что класс в стилях не используется. Ок, пусть я ещё и стиль забыл указать. Ну я ж не слепой, я же вижу что верстаю. Как это уйдёт в merge-request? А потом, когда вёрстка готова проблема тем более не актуальна — ведь класс уже на месте.
Мне кажется или эти "проблемы" ну совсем высосаны из пальца? Ну и кстати не имеют никакого отношения к типизации. Разве что к статической линковке и линтерам.
Fi1osof
Да, мы друг друга не поймем, скорее всего. Я тогда не знаю что вы вообще под типизацией подразумеваете. Если только наличие/отсутствие переменных, то это не так. Типизация подразумевает именно типы, то есть, к примеру, если у меня указано opened: boolean, то и передать можно только opened={true||false}. Если я потом меняю тип на opened: «true» | «false», то и передать можно только «true» | «false» (то есть именно один из этих строковых вариантов и никакой другой строчный вариант не пройдет). А если я enum прокину, та и вовсе придется передавать свойство его.
Если вы просто на своей стороне что-то переписываете, то конечно ничто не мешает. Но если юзаете готовый uikit, то будете все-таки компоненты из него юзать, верно?
Вот это как раз проблема, для решения которой и юзается SC с типизацией. Если вы фулстек и проект полностью готовите в одно лицо, то конечно, делайте как хотите и как знаете. Но если вы работает в команде 350+ человек, то поверьте моему опыту, такое мало прокатывает уже. И там более четко делится на членов UI team и на конечных программистов. Когда я, как программист, программирую какую-то логику и хочу результат вывести в готовый сторонний компонент, я не хочу думать о том, какие там классы надо передать. Я хочу увидеть необходимые параметры с комментариями к ним и передать необходимое.
faiwer
вот это:
Проблема в том что у вас это указано внутри компоненты и обеспечивается там же и теми же механизмами что и у меня. Т.е. в этом месте у нас нет никакой разницы в коде. У вас это отдельный компонент, и у меня. У вас это тип props-ов, и у меня. У вас там тип указан как boolean, и у меня. Всё одно и то же.
Не понимаю. У вас какой-то оторванный от жизни пример. Я беру и пишу тег без класса. Зачем я его пишу? Ну если такая проблема стоит — возьмите готовый (если есть) или напишите свой lint-rule который запретит теги без классов. В чём разница с css-modules?
Чуть ниже я вам привёл пример со статическое линковкой которая решит вашу проблему. Я правда снова не понимаю причём тут TS и типы. Ну да не важно. Вы хотели ошибку? Вы её получили.
Реальное отличие между css-modules и style-components только в том, что style-components умеют в динамически генерируемые стили, а css-modules нет. Но мы тут спорим не об этом.
Fi1osof
Нет, разница большая, в том, что у вас это два отдельных не связанных друг с другом компонента. Один генерит стили и кто хочет, тот пусть их и юзает, а не хочет — пусть не юзает. А кто хочет юзать, то пусть внимательно смотрят что именно передают. А в моем случае это два взаимосвязанных компонента, живущих совместной жизнью, и изменение одного влияет на другого.
Это из серии спора JS-разработчика и TS-разработчика. Вроде пишут практически на одном языке, а парадигмы совсем разные (по себе знаю, потому как не один год на чистом JS писал, прежде чем на TS перейти).
Отвечаю: нет, у меня очень даже не оторванный от жизни пример. Просто вы проблемы не видите, вот и решение вам не интересно. Так вот, в вашем случае проверка только на передачу класса, передан он или нет. При этом передаваемый класс (селектор) — это просто строка. Так вот, вы можете только проверить на то передан был класс или нет. При чем className="" — это как бы тоже передан, потому что параметр есть и он строковый, хоть это и пустая строка. А можно передать className=«dsf sdfhegr tr wefwef sdf dsf и еще много всего», и валидировать здесь нечего, есть значение и ладушки.
В моем же примере возможно использование нескольких отдельных переменных и конечный вызов может быть таким:
И я каждый параметр в отдельности могу валидировать и готовить под них нужные стили, а не просто проверять передан ли какой-то произвольный параметр или нет.
faiwer
Вы долго и упорно сравниваете разные куски программы и получается какой-то нелепый спор. Вы зачем-то сравниваете содержимое моего компонента, с вызовом в
React.createElement
вашего компонента. Но зачем?Гарантии TS предоставляет нам одни и те же. В одном и том же месте. И ошибку мы можем совершить в одном и том же месте.
Вот так мы вызываем компонент:
заметьте код одинаковый для обоих случаев. Ничего не поменялось. Те же самые типы. Те же самые ошибки в случае ошибки.
А вот уже внутри вы можете совершить какую-нибудь ошибку. Например не задать нужные стили, опечататься в имени property, упасть с ошибкой и пр.
У вас внутри идёт задание стилей напрямую. У меня указание классов из css файла. Я могу указать не те классы, или не указать те. Вы можете нахимичить что-то со стилями и макет сломается. Я могу тоже нахимичить что-то со стилями, но уже в отдельном файле.
Суть ведь от этого не меняется. Ну не даёт вам TS в случае style-components никаких дополнительных гарантий. Он просто тупо не умеет читать мысли.
Вы НЕПРАВИЛЬНО сравниваете ваш и мой код. У нас одни и те же гарантии, заданные в одном и том же месте.
DmitryKazakov8
Пять компонентов с маркером открытости — ок, пусть будут модалка, конферм, поповер, аккордеон и дропдаун. В поповере решили изменить на
[data-closed]="true"
, потом в остальных. Вроде правильно понял условие задачи?&[data-opened=false]
, переименовываем — работает. Git commit.Fi1osof
Вот когда-то и я делал примерно по вашему сценарию (он классический).
А сейчас я так не делаю. Если я что-то переименовал и зацепил, то я получил ошибку еще на уровне IDE, или на уровне прехука, или просто запустив скрипт проверки.
Более того, это работает и с импортируемыми сторонними компонентами, написанными в том же стиле. И это уже не черный ящик. И если сторонний компонент обновился и там что-то поменялось и зацепило у меня, мне не надо ходить с лупой по проекту или держать тестировщика, который целыми днями кликает проект (хотя где надо, я настраиваю cypress). И обновляюсь спокойно, а не в рулетку играю.
P.S. и все это — важная составляющая CI/CD. Когда я виливаю проект в гитхаб, там сробатвают экшены и все проверяется. И в большинстве случаев это решает проблемы типа «на моей тачке работало», особенно в случае использования воркспейсов и т.п…
faiwer
Ок. Давайте предположим, что вам нужна статическая линковка на ещё более глубоком уровне, чем в моём примере. И вы даже готовы пожертвовать краткостью и простотой кода.
Вуаля:
Всё равно куда приятнее чем в
style-components
, и без его недостатков. Всё ещё декларативныйcss
, разделение логики и пр. и пр. Не хочу повторяться. Теперь вы не можете забыть переименовать слово в двух местах.Но я сознательно так не пишу, ибо код с
data-attribute
-ми суммарно на кодовую базу оказывает (по нашему опыту) более благотворный эффект, нежели чуть больше статических проверок, за счёт ухудшения читаемости.Впрочем тут каждый решает сам.
Fi1osof
Еще раз: вы оперируете только css-селекторами. SC позволяет работать с произвольными параметрами и дополнительно использовать логику для формирования стилей.
При чем в ретурн можно не одну строчку вернуть, а много CSS-кода, включая медиа-квери и т.п.
faiwer
В кастомный класс вы можете засунуть не одну стоку кода, а много. Включая media-query. Вы, кажется, давно не писали на CSS
Fi1osof
Более развернутый вам пример, чтобы было понятней.
faiwer
Что изменилось?
Fi1osof
Смотрим комменты выше.
Давайте уже завязывать. Вы меня не убедили (хотя я вас скорее всего тоже). Пусть хабравчане рассудят доводы За и Против.
faiwer
Самое смешное — я пока даже не понимаю в чём я вас убеждаю. В том что css-modules лучше или хуже? Да я вроде не успел даже начать. Я пока пытаюсь вам показать что мы сравниваем "2+3" и "2+2+1". 5 === 5
Я прекрасно понимаю что гарантирует вам те ошибки, которые вы защищаете. И вижу что те же самые ошибки, я получу в том же самом месте. Без каких-либо "но".
Я вам умоляю. "Хабровчане" тут только первые пару дней после публикации статьи. Потом материал просто умирает.
Ещё раз. Единственное реальное преимущество, в рамках обсуждаемой темы, которое style-components имеют против css-modules, это поддержка настоящих динамических свойств. Те самые случаи когда выразить что-то статически декларативно либо невозможно, либо очень сложно. Вот вам пара примеров:
.width_999 { width: 999px; }
Объединяет их одно — эти вещи никак не ложатся на заранее сформированный статический стиль. Вот тут
style-components
кладут на лопатки заведомо более слабый в таких вопросахcss-modules
. Так как первый работает в runtime, а второй в compile time.Но это всё, как нетрудно заметить, не имеет отношения ни к линтингу, ни к типам.
Fi1osof
Если вы так хорошо знаете TS, то почему настойчиво закрываете глаза на приведенные примеры?
Я вам говорю, что у меня на вход 3 параметра (может больше, может меньше) и у меня валидация всех параметров как внутри SC, так и в вызывающих компонентах. Вы мне в ответ шлете реакт-компонент с отрисовкой div-а с передачей в него CSS-селекторов. Да, понятное дело, что можно заточить отдельный реакт-компонент, суть которого будет только в принятии указанных параметров и формирования конечного набора className, стили для которых уже сформированы и тут типа тогда проверка будет всего и все и очень похоже на то, что в моем примере. Но вопрос: а будет ли тогда это сильно быстрее работать, если суть логики все равно выполняется в реакт-компоненте (то есть в рантайме, против которого вы и топите?). Это очень похоже на одно и то же. И воторой момент, о котором я говорил выше: использование других styled-компонентов в качестве селекторов. SC это поддерживает нативно. А в вашей реализации я что должен делать? if(props.children instanceof OtherComponent) {...}? Так чтоли? Зачем мне все это переписывать, если SC имеет из коробки?
Вот и получается, что вы говорите «Вам это не нужно, потому что в целом это поддерживается там, почти все». А я в ответ говорю «Мне того почти всего не достаточно, мне надо все». И я точно знаю, что мне надо, а не выбираю из чего-то незнакомого. Я и то и другое уже изучал и выбор осознанно сделан, даже если вы этого не понимаете.
И говорю еще раз: можно завязывать с обсуждением, я не хочу жевать одно и то же без толку.
faiwer
Хотелось бы уточнить, а что вы подразумеваете под типизацией здесь? Пока что мне попадались на глаза только всевозможные вариации на
{ [key in string]: string | ... }
.Fi1osof
В комментарии выше дал ссылку и добавил аргументы.
faiwer
Но ведь там нет никакой типизации. А вот тут есть. И, кажется, больше нигде нет.
Fi1osof
Что значит нет? Вот вам даже картиночка отдельная, если не увидели.
faiwer
А какое отношение ваш скриншот имеет к обсуждаемому вопросу? В моём примере, не укажи вы
isOpened
, вы получите ровно ту же самую ошибку. А стили ваши как были нетипизированными, так и остались. Мы точно об одном и том же говорим?Fi1osof
Отношение такое имеет, что здесь говорит «Вы не указали opened», то есть обязывает меня указать opened={true||false}, а не как у вас, что просто нельзя передать несуществующий параметр. Здесь как раз можно свои параметры добавлять, рулить их типы и обязательность.
UPD: если интересно, вот сам исходный код:
github.com/Pivkarta/pivkarta.ru-2/blob/e9399f973243548b38e54d7760e1f3fce7554def/src/pages/_App/Layout/MainMenu/DropdownMenu/styles.ts#L19
github.com/Pivkarta/pivkarta.ru-2/blob/e9399f973243548b38e54d7760e1f3fce7554def/src/pages/_App/Layout/MainMenu/DropdownMenu/index.tsx
faiwer
В чём разница? Это же TS, он никак не зависит от styled-components. И от css-modules. Это просто типы. Они просто работают. И в вашем и в моём случаях. Потому что они практически идентичны
Fi1osof
Вот в чем разница:
Type '{ isOpened: boolean; }' is not assignable to type 'DetailedHTMLProps<HTMLAttributes, HTMLDivElement>'.
Property 'isOpened' does not exist on type 'DetailedHTMLProps<HTMLAttributes, HTMLDivElement>'.ts(2322)
От TS вообще почти ничто не зависит. Конечный JS все равно будет работать как JS, и можно забить на ошибки. Но TS вводят не для того, чтобы на него забивать, а чтобы он помогал, и чтобы было видно где что и как. И как раз в этом плане React+SC+TS — это как раз очень хороший союз. Если здесь TS исключать, то я бы вообще не стал спорить. Более того, так и сидел бы дальше на less.
faiwer
Какое отношение нижележащий код имеет к css-modules или зачем вы его привели? И главноо что вы хотели им сказать. Вы взяли просто
<div/>
и задали ему неправильное свойство, в которое он не умеет. Слава TS он выдал вам ошибку. А что вы хотели этим сказать? Тут ни css-modules, ни styled-components нет. Я решительно не понимаю о чём вы говорите.Поверьте я прекрасно знаю зачем нужен TS, и могу не один доклад про него рассказать. Я ни разу не топлю за "типы не нужны". Я топлю за — вы куда-то не туда смотрите, когда не видите ровно тех же самых гарантий у меня
dreesh
У меня ваша ссылка лептоп вешает...
Fi1osof
Возможность юзать Styled-components + TypeScript — для меня последний аргумент в пользу отказаться от сторонних CSS-файлов. Здесь SC дает больше чистоты проекту, особенно когда дело касается рефакторинга кода. В обычном режиме замахаешься сращивать где какой CSS у тебя используется, а где нет.
Ni55aN
тоже пришел к выводу, что Styled-components с TypeScript в плане DX удобнее и эффективнее, чем препроцессоры. Из коробки решаются те проблемы, которые в каких либо пост/препроцессорах решается установкой 100500 плагинов
Fi1osof
Тут можно еще одну важную фишку вспомнить: возможность использовать другие компоненты в качестве селекторов, а не придумывать кучу уникальных имен классов.
Amareis
Про vanilla-extract недавно написал статейку: https://m.habr.com/ru/post/555984/
dreesh
Что такое серверный рендеринг? Что вообще происходит?
У меня лично ощущение что, происходит какая то дичь в IT последние лет так 5 наверное... Сюда так же можно и железо приплести с их закрытыми инструментами разработки (эй, linux уже 30 лет существует, busybox с 1996 года, gcc 1987 год). Почему я не могу прошивку для купленных блютус наушников сам написать (qualcomm не дает мне документов на кремний в наушниках)? куда делись даташиты на современные чипы (бесполезные огрызки)? А теперь вы еще про серверный рендеринг говорите? Хотите сказать я не смогу сайт на ЛИЧНОМ роутере ДЛЯ ЛИЧНОГО ИСПОЛЬЗОВАНИЯ захостить (типа умный дом)? Мне теперь еще думать: А в этом роутере железо потянет серверный рендеринг?
Facebook гори синим пламенем!
fransua
Не переживайте Вы так, сможете сайт на личном роутере захостить, без серверного рендеринга
dreesh
название не интуитивно и вводит в заблуждение)
jodaka
styled components в некоторых специфичных кейсах могут не просто замедлять приложение, они его хоронят. Я в подобную ситуацию попал, когда использовал antd-tablе с 15 колонками и 150-200 строками. В каждой ячейке были какие-то компоненты, обёрнутые в styled. Так вот при некотором сочетании пропсов таблицы, она начинает пытаться динамически вычислять ширину колонок и sticky headers. Это приводит к тому, что она может попытаться перерендериться несколько десяток или сотен раз за секунду. И, будь в ячейках просто текст, это не убивало бы производительность так сильно. Но styled попытается добавлять/удалять из дома стили на каждый ререндер. И это просто намертво всё фризит.
Мне, в целом, нравится styled и отказываться от него не хочется. Но, в некоторых ситуациях эта штука может выстрелить в колено и разорвать не только ногу, но и всё остальное в радиусе 100 метров.
faiwer
Судя по вашему описанию проблема у вас не в styled components, а в самом в подходе к стилизации таблицы. А css-in-js просто позволили выявить проблему на меньших масштабах.