## styled-components через SWC
### Назначение интеграции
Библиотека **styled-components** предоставляет механизм CSS-in-JS, позволяющий описывать стили непосредственно внутри JavaScript и React-компонентов. Для корректной работы в production-среде и удобства разработки styled-components использует специальные преобразования исходного кода во время сборки.
Исторически такие преобразования выполнялись через Babel-плагин `babel-plugin-styled-components`. С появлением SWC аналогичные возможности стали доступны без Babel, используя встроенный трансформер SWC.
Интеграция обеспечивает:
* генерацию понятных имён компонентов;
* поддержку Server-Side Rendering (SSR);
* улучшенную отладку;
* оптимизацию выходного кода;
* корректную работу гидратации React-приложений;
* уменьшение времени сборки по сравнению с Babel.
---
## Почему styled-components требует трансформации
Рассмотрим простой пример:
```jsx
const Button = styled.button`
background: royalblue;
color: white;
`;
```
Во время выполнения styled-components создаёт CSS-классы динамически. Однако для полноценной работы необходимо дополнительно внедрить метаинформацию в код.
После обработки трансформером код получает дополнительные данные:
```jsx
const Button = styled.button.withConfig({
displayName: "Button",
componentId: "sc-abc123"
})`
background: royalblue;
color: white;
`;
```
Появляются:
* уникальный идентификатор компонента;
* отображаемое имя для React DevTools;
* информация для SSR;
* стабильная генерация классов.
Без трансформации приложение может работать, но часть возможностей styled-components будет недоступна.
---
## Поддержка styled-components в SWC
SWC содержит встроенный трансформер styled-components.
В отличие от Babel не требуется устанавливать отдельный пакет:
```bash
npm install styled-components
```
Достаточно включить соответствующую опцию в конфигурации SWC.
Базовая настройка выглядит следующим образом:
```json
{
"jsc": {
"transform": {
"react": {
"runtime": "automatic"
}
}
}
}
```
Для styled-components добавляется специальный раздел:
```json
{
"jsc": {
"transform": {
"react": {
"runtime": "automatic"
}
},
"experimental": {
"plugins": []
}
}
}
```
В большинстве современных фреймворков настройка выполняется через собственные конфигурационные файлы.
---
## Использование в Next.js
Одним из наиболее распространённых сценариев является использование styled-components вместе с Next.js.
Начиная с современных версий Next.js, поддержка SWC является стандартным механизмом компиляции.
Для включения трансформации необходимо изменить файл:
```js
next.config.js
```
Настройка:
```js
module.exports = {
compiler: {
styledComponents: true
}
};
```
После этого Next.js активирует встроенный SWC-трансформер.
---
## Что делает параметр styledComponents
Следующая конфигурация:
```js
module.exports = {
compiler: {
styledComponents: true
}
};
```
эквивалентна включению нескольких возможностей одновременно:
* генерация displayName;
* SSR-поддержка;
* стабильные идентификаторы компонентов;
* улучшенная отладка;
* оптимизация стилей.
Таким образом отпадает необходимость подключать Babel только ради styled-components.
---
## Проверка displayName
Рассмотрим компонент:
```jsx
const Header = styled.header`
padding: 20px;
`;
```
После обработки SWC создаётся дополнительная информация:
```jsx
displayName: "Header"
```
В React DevTools вместо анонимного элемента отображается:
```text
Header
```
а не:
```text
Styled(header)
```
или
```text
Anonymous
```
Это значительно упрощает анализ дерева компонентов.
---
## Поддержка SSR
### Проблема серверного рендеринга
Во время SSR HTML генерируется на сервере.
Например:
```html
```
После передачи страницы браузеру React выполняет гидратацию.
Если идентификаторы CSS-классов на клиенте и сервере различаются, появляются ошибки:
```text
Warning: Prop className did not match.
```
или
```text
Hydration failed
```
Для предотвращения подобных ситуаций styled-components внедряет стабильные идентификаторы компонентов ещё на этапе компиляции.
SWC автоматически добавляет необходимую информацию для согласованной генерации классов.
---
## Генерация componentId
Исходный код:
```jsx
const Card = styled.div`
border-radius: 12px;
`;
```
После обработки может получить вид:
```jsx
const Card = styled.div.withConfig({
componentId: "sc-kd82fd"
})`
border-radius: 12px;
`;
```
Значение:
```text
sc-kd82fd
```
является стабильным идентификатором.
На его основе формируются итоговые CSS-классы.
---
## Отображение имён файлов
Для отладки бывает полезно знать происхождение компонента.
Допустим существует структура:
```text
components/
├─ Button.jsx
├─ Card.jsx
└─ Modal.jsx
```
При включённой поддержке styled-components SWC может использовать информацию о файле для формирования диагностических данных.
В результате инструменты разработки позволяют быстрее находить источник конкретного стиля.
---
## Минификация выходного кода
Одной из возможностей трансформера является сокращение служебной информации в production-сборках.
Исходный код:
```jsx
const Button = styled.button`
color: white;
background: blue;
`;
```
После компиляции часть вспомогательных конструкций может быть оптимизирована.
Преимущества:
* меньший размер бандла;
* более быстрая загрузка;
* сокращение количества выполняемого кода.
---
## Использование ThemeProvider
Трансформация SWC полностью совместима с системой темизации styled-components.
Создание темы:
```jsx
const theme = {
colors: {
primary: "#2563eb",
danger: "#dc2626"
}
};
```
Подключение:
```jsx
import { ThemeProvider } from "styled-components";
function App() {
return (
);
}
```
Использование внутри компонента:
```jsx
const Button = styled.button`
background: ${(props) => props.theme.colors.primary};
`;
```
SWC не изменяет логику работы темы и корректно обрабатывает подобные конструкции.
---
## Работа с динамическими свойствами
styled-components активно использует интерполяции.
Пример:
```jsx
const Button = styled.button`
background: ${(props) =>
props.primary ? "royalblue" : "gray"};
`;
```
Использование:
```jsx
```
Результат:
```css
background: royalblue;
```
или
```css
background: gray;
```
SWC сохраняет динамическую природу таких выражений и одновременно добавляет служебные метаданные для стабильной генерации классов.
---
## Поддержка вложенных селекторов
Трансформация никак не ограничивает возможности CSS.
Пример:
```jsx
const Card = styled.div`
padding: 20px;
h2 {
margin-bottom: 10px;
}
p {
color: gray;
}
`;
```
Вложенные селекторы продолжают работать так же, как и при использовании Babel.
---
## Псевдоклассы
Пример:
```jsx
const Button = styled.button`
background: royalblue;
&:hover {
background: navy;
}
&:active {
transform: scale(0.98);
}
`;
```
После компиляции SWC сохраняет всю структуру CSS.
---
## Медиа-запросы
Поддерживаются любые конструкции CSS.
Пример:
```jsx
const Sidebar = styled.aside`
width: 300px;
@media (max-width: 768px) {
width: 100%;
}
`;
```
SWC не вмешивается в содержимое CSS-правил и выполняет лишь необходимые преобразования для styled-components.
---
## Использование attrs
Метод `attrs` позволяет задавать атрибуты по умолчанию.
Пример:
```jsx
const Input = styled.input.attrs({
type: "text"
})`
padding: 10px;
`;
```
Либо:
```jsx
const Input = styled.input.attrs((props) => ({
size: props.large ? 20 : 10
}))`
border: 1px solid #ccc;
`;
```
Трансформер SWC корректно обрабатывает оба варианта.
---
## Глобальные стили
Создание глобального CSS:
```jsx
import { createGlobalStyle } from "styled-components";
const GlobalStyles = createGlobalStyle`
body {
margin: 0;
font-family: sans-serif;
}
`;
```
Подключение:
```jsx
function App() {
return (
<>
>
);
}
```
SWC полностью поддерживает данный механизм.
---
## Создание анимированных компонентов
Использование keyframes:
```jsx
import { keyframes } from "styled-components";
```
Описание анимации:
```jsx
const fadeIn = keyframes`
from {
opacity: 0;
}
to {
opacity: 1;
}
`;
```
Применение:
```jsx
const Modal = styled.div`
animation: ${fadeIn} 300ms ease;
`;
```
Во время компиляции SWC корректно сохраняет связи между компонентом и анимацией.
---
## Отличия от Babel Plugin
### Babel
```json
{
"plugins": [
["styled-components"]
]
}
```
Особенности:
* требует Babel;
* увеличивает время сборки;
* добавляет дополнительный этап обработки.
### SWC
```js
module.exports = {
compiler: {
styledComponents: true
}
};
```
Особенности:
* встроен в современный Next.js;
* реализован на Rust;
* работает значительно быстрее;
* требует меньше конфигурации.
---
## Производительность сборки
Одной из причин популярности SWC стала высокая скорость компиляции.
При крупных кодовых базах могут присутствовать:
```text
1000+
React-компонентов
```
или:
```text
10000+
styled-components
```
Babel выполняет обработку через JavaScript-плагины, тогда как SWC реализован на Rust и использует более эффективную архитектуру.
Результатом становятся:
* ускоренный запуск dev-сервера;
* быстрое обновление страниц;
* сокращение времени production-сборки;
* уменьшение нагрузки на процессор.
---
## Типичные ошибки
### Одновременное использование Babel и SWC
Нежелательная конфигурация:
```js
compiler: {
styledComponents: true
}
```
и одновременно:
```json
{
"plugins": [
["styled-components"]
]
}
```
Такой подход может приводить к двойной обработке компонентов.
Следует использовать только один механизм трансформации.
---
### Неправильная настройка SSR
Если сервер и клиент используют разные механизмы генерации классов, возможны ошибки гидратации:
```text
Hydration mismatch
```
или
```text
className mismatch
```
Использование единого SWC-трансформера устраняет данную проблему.
---
### Устаревшие конфигурации Babel
Во многих проектах можно встретить настройки вида:
```json
{
"presets": ["next/babel"],
"plugins": [
["styled-components"]
]
}
```
После перехода на SWC подобные конфигурации зачастую становятся ненужными и лишь усложняют процесс сборки.
---
## Практический пример
Создание темы:
```jsx
export const theme = {
colors: {
primary: "#2563eb",
secondary: "#64748b"
}
};
```
Провайдер:
```jsx
import { ThemeProvider } from "styled-components";
function App({ children }) {
return (
{children}
);
}
```
Кнопка:
```jsx
import styled from "styled-components";
export const Button = styled.button`
background: ${(props) =>
props.theme.colors.primary};
color: white;
border: none;
padding: 12px 20px;
border-radius: 8px;
&:hover {
opacity: 0.9;
}
`;
```
Конфигурация Next.js:
```js
module.exports = {
compiler: {
styledComponents: true
}
};
```
После сборки SWC автоматически:
* создаёт displayName;
* генерирует componentId;
* обеспечивает SSR-совместимость;
* оптимизирует выходной код;
* сохраняет удобство отладки;
* ускоряет процесс компиляции по сравнению с Babel-подходом.