๐ ๋ค์ด๊ฐ๋ฉฐ
๊ธฐ์กด ํ๋ก์ ํธ์์ Next.js 14๋ฒ์ ์ ์ฑ ๋ผ์ฐํฐ์์ styled-components๋ฅผ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค.
์ด์ ์ Next.js 11๋ฒ์ ์์ 14๋ฒ์ ์ผ๋ก ๋ง์ด๊ทธ๋ ์ด์ ์ ์งํํ๋ฉด์ ๋จ์์๋ ๋ถ๋ถ์ด์์ต๋๋ค.
์ฑ ๋ผ์ฐํฐ์์ ์๋ฒ ์ปดํฌ๋ํธ๋ฅผ ์ง์ํ๊ธฐ ์์ํ๋ฉด์, ์๋ฒ ์ปดํฌ๋ํธ ํ์ฉ ํด๋ณด๊ณ ์ ๋ง์ด๊ทธ๋ ์ด์ ์ ์งํํ์ต๋๋ค.
๊ทธ๋ผ ๋จผ์ ์ ๋ง์ด๊ทธ๋ ์ด์ ์ ์งํํ๊ณ , ์ vanilla-extract๋ฅผ ์ ํํ๋์ง ๊ฐ๋ตํ ์ค๋ช ํด ๋ณผ๊ฒ์.
๐ ์ฑ ๋ผ์ฐํฐ(app router)์์ styled-components์ ๋ฌธ์ ์
styled-components๋ ์๋ฒ ์ปดํฌ๋ํธ๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์, styled-components๋ฅผ ์ฌ์ฉํ๋ ค๋ฉด 'use client'๋ฅผ ๋ช ์ํจ์ผ๋ก์จ ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ฅผ ๊ฐ์ ์ ์ผ๋ก ์ฌ์ฉํด์ผ ํ์ต๋๋ค.
๋ํ, ๋ฐํ์ ํ๊ฒฝ์์ ์คํ๋๊ธฐ ๋๋ฌธ์ ์ ๋ก ๋ฐํ์ ํ๊ฒฝ์์ ๋์ํ๋ ๊ฒ๋ณด๋ค ์๋์ ์ผ๋ก ๋ ๋๋ง์ด ๋ฆ์ ์ ์์ต๋๋ค.
โ๏ธ vanilla-extract ์ ํ ์ด์
์ ์๋ง์ ์คํ์ผ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์์ vanilla-extarct๋ฅผ ์ ํํ์๊น์?
์ฒ์์๋ Next.js ๊ณต์๋ฌธ์์์ ์์ฒด์ ์ผ๋ก ์ถ์ฒํด ์ฃผ๋ Tailwind Css๋ฅผ ๊ณ ๋ คํด ๋ดค์ต๋๋ค.
ํ์ง๋ง Tailwind css๋ ์ถ๊ฐ ๋ฌธ๋ฒ์ ์๋์น ์๊ฒ ์ธ์์ผ ํ๋ ์ํฉ์ ๊ณ ๋ คํ๊ฒ ๋์๊ณ ,
๊ฐ์ธ์ ์ผ๋ก CSS-in-JS ํ์์ด ๊ฐ๋ ์ฑ ๋ถ๋ถ์์ ๋ ์ข๋ค๊ณ ์๊ฐํ์ฌ ์ ํธํ๋ ํธ์ด์์ต๋๋ค.
styled-components์ CSS-in-JS๋ฅผ ๋ฐ๋ผ๊ฐ๋ฉด์ ์ ๋ก ๋ฐํ์ ํ๊ฒฝ์์ ๋์ํ๋ฉฐ ์๋ฒ์ปดํฌ๋ํธ๋ฅผ ์ง์ํ๋ ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์ค์
panda css์ vanilla-extract ์ค์์ ๊ณ ๋ฏผ์ ํ์ต๋๋ค.
ํ์ฌ ์ ํ๋ก์ ํธ๋ Typescript ํ๊ฒฝ์ด์์ต๋๋ค.
vanilla-extract๋ Typescript๋ก css๋ฅผ ์์ฑํ๋ฉฐ ์ ํํ CSS-in-JS๊ฐ ์๋ CSS-in-TS๋ผ๊ณ ๋ณผ ์ ์์ต๋๋ค.
์ด๋ฌํ ๋ฉด์์ ๊ฐ๋ ฅํ ํ์ ์คํฌ๋ฆฝํธ ์ง์์ด ๋๋ค๊ณ ํ๋จํ์ฌ ๋ ๋๋ฆฌ๊ฒ ๋์์ต๋๋ค.
๋ํ, npm trends๋ฅผ ํ์ธํด ๋ดค์ ๋ vanilla-extract๊ฐ ์๋์ ์ผ๋ก ๋ง์ด ์ฌ์ฉ๋ ๋ฟ๋๋ฌ, pandacss๊ฐ vanilla-extract์ ์๊ฐ์ ๋ฐ์๋ค๊ณ ํฉ๋๋ค.
์ด๋ฌํ ์ด์ ๋ก vanilla-extarct๋ฅผ ์ ํํ์ต๋๋ค.
โ๏ธ vanilla-extract์ ์ ํํจ์ผ๋ก์จ ๊ธฐ๋ํ๋ ๋ถ๋ถ
- ์๋ฒ ์ปดํฌ๋ํธ ํ์ฉ์ผ๋ก ์ธํ ๋ฒ๋ค ํฌ๊ธฐ ๊ฐ์ ๋ฐ ๋คํธ์ํฌ ๋น์ฉ ๊ฐ์ ๊ธฐ๋
- ๋ฐํ์์ CSS๋ฅผ ์์ฑํ์ง ์๊ธฐ ๋๋ฌธ์ ๋ ๋น ๋ฅธ ํ์ด์ง ๋ก๋ ๊ธฐ๋ (์ ๋ก ๋ฐํ์)
โ๏ธ ์งํ ๊ณผ์
๋จผ์ vanilla-extract๊ฐ ์ ์ ์ฉ๋๋์ง ํ์ธํ๋ฉด์ ์์ ํ๊ธฐ ์ํด ์์ ์ปดํฌ๋ํธ๋ถํฐ ์ ์ง์ ์ผ๋ก ์ ์ฉํ๊ธฐ๋ก ํ์ต๋๋ค.
โ๏ธ ์ค์น ๋ฐ ์ ์ฉ
https://vanilla-extract.style/documentation/integrations/next/
์ ๊ณต์๋ฌธ์๋ฅผ ๋ณด๋ฉฐ ์ค์น๋ฅผ ํ๊ณ ์ ์ฉํ๋ ๊ณผ์ ์ ๊ฑฐ์ณค์ต๋๋ค.
next.config.js์ ํด๋น ์ฝ๋๋ฅผ ์ถ๊ฐํ์ต๋๋ค.
๋น์ ์ฝ๋๋ฅผ ๋ณด๋ฉด styled-componetns๋ฅผ ์ฌ์ฉํ๊ธฐ ์ํ ์ฝ๋๊ฐ ๊ณต์กดํ๊ณ ์๋ ๊ฒ์ ๋ณผ ์ ์์ต๋๋ค.
โ๏ธ theme ์ ์
๊ธฐ์กด styled-comopnents์์๋ GlobalStyles.ts์์ ์ ์ญ ์คํ์ผ์ ์ ์ํด์ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค.
๋ํ theme์ ์์ฃผ ์ฌ์ฉ๋๋ ์คํ์ผ ์ฝ๋๋ ์ ์ํ์ฌ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค.
์๋๋ styled-comopnents๋ฅผ ์ฌ์ฉํ ๋น์ ์ฝ๋์ ์ผ๋ถ์ ๋๋ค.
// theme.ts
const margin = {
small: '.5rem',
base: '1rem',
medium: '1.5rem',
large: '2rem',
xLarge: '3rem',
};
const padding = {
small: '.5rem',
base: '1rem',
large: '2rem',
xLarge: '3rem',
};
...
// GlobalStyle.ts
...
const GlobalStyle = styled.createGlobalStyle`
${reset};
* {
box-sizing: border-box;
}
${({ theme }) => {
return styled.css`
body {
background-color: ${theme.color.mainBackground};
font-family: ${notoSansKr.style.fontFamily};
font-size: ${theme.font.size.small};
color: ${theme.color.mainFontColor};
user-select: none;
transition: all 0.25s linear;
}
`;
}}
a {
text-decoration: none;
color: inherit;
}
`;
export default GlobalStyle;
vanilla-extract ๋ํ ๊ฐ๋ ฅํ theme ๊ธฐ๋ฅ์ ์ ๊ณตํด ์ฃผ๊ธฐ ๋๋ฌธ์ ๋งค์ฐ ์ข์์ต๋๋ค.
// globalTheme.css.ts
...
export const global = createGlobalTheme(':root', {
fontFamily: {
notoSansKR: `var(--font-noto-sans-kr)`,
},
fontSize: {
xLarge: '48px',
large: '36px',
medium: '28px',
regular: '18px',
small: '16px',
micro: '14px',
},
..
margin: {
small: '.5rem',
base: '1rem',
medium: '1.5rem',
large: '2rem',
xLarge: '3rem',
},
padding: {
small: '.5rem',
base: '1rem',
large: '2rem',
xLarge: '3rem',
},
...
});
globalStyle('*', {
boxSizing: 'border-box',
});
globalStyle('body', {
fontSize: global.fontSize.small,
...
userSelect: 'none',
transition: 'all 0.25s linear',
});
globalStyle('a', {
textDecoration: 'none',
color: 'inherit',
});
createGlobalTheme์ ํตํด ๊ธ๋ก๋ฒ ์คํ์ผ๋ก css ๋ณ์๋ฅผ ์ฝ๊ฒ ์ง์ ํ์ต๋๋ค.
๋ํ, globalStyle์ ํตํด ์ ์ญ ์คํ์ผ์ ์ง์ ํ ์ ์์์ต๋๋ค.
๋ฌผ๋ก ๋คํฌ๋ชจ๋ ๊ด๋ จํ ์ฝ๋๋ ์กด์ฌํฉ๋๋ค.
vanilla-extarct ๋คํฌ๋ชจ๋ ๊ด๋ จํด์๋ ๋ค์ ํฌ์คํ ์์ ๋ค๋ฃฐ ์์ ์ ๋๋ค.
โ๏ธ reset css
๊ธฐ์กด์ styled-components๋ฅผ ์ฌ์ฉํ ๋๋ styled-reset ๋ผ์ด๋ธ๋ฌ๋ฆฌ๋ฅผ ์ค์นํ์ฌ GlobalStyles.ts์ ์ ์ฉํ์ต๋๋ค.
ํ์ง๋ง vanilla-extract์์๋ ๋ํดํธ๋ก reset CSS๋ฅผ ์ง์ํ์ง ์๊ธฐ ๋๋ฌธ์, ์ง์ reset.css ํ์ผ์ ์์ฑํ๊ณ reset ์คํ์ผ์ ์ ์ฉํด์ผ ํ์ต๋๋ค.
reset.css๋ฅผ layout ์ปดํฌ๋ํธ์์ import ํ์ฌ ์ ์ฉํ๊ณ , ์ฐ์ ์์๋ฅผ ๋์ด๊ธฐ ์ํด globalTheme.css๋ณด๋ค ์์ ์ ์ธํ์ต๋๋ค.
import 'src/styles/reset.css';
import 'src/styles/globalTheme.css';
https://meyerweb.com/eric/tools/css/reset/
โ๏ธ ์ ์ง์ ์ ์ฉ
๋จผ์ layout ์ปดํฌ๋ํธ๋ถํฐ ์ ์ง์ ์ผ๋ก ์ ์ฉํ์ต๋๋ค.
// layout.css.ts
import { style } from '@vanilla-extract/css';
import { global } from 'styles/globalTheme.css';
export const container = style({
width: '100%',
maxWidth: global.device.mobile,
minHeight: '100vh',
margin: 'auto',
padding: global.padding.base,
});
CSS-In-TS ํ์์ผ๋ก ๊ธฐ์กด styled-components ์ฝ๋์ ๋ฌธ๋ฒ์ ์ผ๋ก ํฐ ์ฐจ์ด๊ฐ ์์ด์ ๋งค์ฐ ํธํ์ต๋๋ค.
๋์ ํ์ผ ์ ์ธ์ 'ํ์ผ์ด๋ฆ.css.ts'๋ก ์์ฑํฉ๋๋ค.
์ดํ ์คํ์ผ ์ ์ฉ์ ์๋์ ๊ฐ์ด ์ ์ฉํ ์ ์์ต๋๋ค.
import * as style from './layout.css';
<div className={style.container}>
<DarkModeBtn />
{children}
<Footer />
</div>
์ ์ฉ ํ ๋ธ๋ผ์ฐ์ ์์ ํ์ธํ ๊ฒฐ๊ณผ ์๋์ ๊ฐ์ด ์ ์ ์ฉ๋์์ต๋๋ค.
vanilla-extarct๋ ๊ฐ class๋ง๋ค ๊ณ ์ ํ class๋ฅผ ์์ฑํด์ ๋ถ์ฌํ๊ธฐ ๋๋ฌธ์ class๊ฐ ์ค๋ณต๋๋ ๋ถ๋ถ์ ๋ฐ๋ก ๊ณ ๋ คํ์ง ์์๋ ๋์์ต๋๋ค.
styled-compoents์ ๋ค๋ฅด๊ฒ css ๋ณ์๋ก ์ ์ ์ฉ์ด ๋์ด ์๋ ๋ชจ์ต์ ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋ธ๋ผ์ฐ์ ์ฝ์๋ก head๋ฅผ ํ์ธํด ๋ณด๋ฉด layout.css์ ๋ํ stylesheet๊ฐ ๋ถ๋ฌ์ค๊ณ ์์ต๋๋ค!
์ด๊ฒ์ด ๋ฐ๋ก ๋น๋ ์์ ์ CSS ํ์ผ์ ์์ฑํ์ฌ ์ ์ ์ฉํ๊ณ ์๋ค๋ ์๋ฏธ์ ๋๋ค.
๋ํ, ์ด์ ์ ์ ์ฉํ๋ ๊ธ๋ก๋ฒ ๋ณ์๋ ์๋์ ๊ฐ์ด ์ ์์ฑ๋์ด ์ฌ์ฉ๋๊ณ ์์ต๋๋ค.
โ๏ธ ๋์ ์คํ์ผ๋ง
์ ํ๋ก์ ํธ์์๋ ๋์ ์คํ์ผ๋ง์ ํตํด ์ฌ์ฌ์ฉ ๊ฐ๋ฅํ Button ์ปดํฌ๋ํธ๋ฅผ ์์ฑํด์ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค.
๋จผ์ ๊ธฐ์กด styled-components๋ฅผ ์ฌ์ฉํ Button ์ปดํฌ๋ํธ์ ๋๋ค.
// Button.tsx
'use client'
import styled, { css } from 'styled-components';
type Color =
| 'contentBackground'
| 'white'
| 'whiteYellow'
| 'yellow'
| 'whiteBlue'
| 'bluePuple'
| 'lightBlue'
| 'lightGray'
| 'whiteGray'
| 'darkGray'
| 'laime'
| 'lightRed'
| 'pink'
| 'red'
| 'black';
const SButton = styled.button<{
bgColor: Color;
fontColor: Color;
borderColor: Color;
}>`
${({ theme, bgColor, fontColor, borderColor }) => {
return css`
width: 100%;
padding: ${theme.padding.small} ${theme.padding.base};
margin-bottom: ${theme.margin.medium};
border: 2px solid ${theme.color[borderColor]};
border-radius: 4px;
color: ${theme.color[fontColor]};
font-size: ${theme.font.size.small};
font-family: ${theme.font.family.base};
background-color: ${theme.color[bgColor]};
cursor: pointer;
`;
}}
`;
interface IButtonProps {
children: React.ReactNode;
bgColor?: Color;
fontColor?: Color;
borderColor?: Color;
onClick?: (event: React.MouseEvent<HTMLElement>) => any;
name?: string;
}
const Button = ({
children,
onClick,
bgColor = 'contentBackground',
fontColor = 'lightBlue',
borderColor = 'whiteBlue',
name,
}: IButtonProps) => (
<SButton onClick={onClick} {...rest}>
{children}
</SButton>
);
export default Button;
๋์ ์คํ์ผ๋ง์ ์ฌ์ฉํ๊ธฐ ์ํด ์ถ๊ฐ๋ก vanilla-extract/dynamic์ ์ค์นํด ์คฌ์ต๋๋ค.
https://vanilla-extract.style/documentation/packages/dynamic/
๋์ ์ผ๋ก css variables๋ฅผ ์์ฑํ๊ธฐ ์ํด @vanilla-extract/dynamic์์๋ assignInlineVars api๋ฅผ ์ ๊ณตํฉ๋๋ค.
๋ฐํ์์ ์์ฑํ์ง๋ง ๋ผ์ด๋ธ๋ฌ๋ฆฌ ์์ฒด๋ ๋งค์ฐ ๊ฐ๋ฒผ์ฐ๋ฉฐ ์ฑ๋ฅ ์ ํ๋ฅผ ์ผ์ผํค์ง ์์ต๋๋ค.
createVar์ assignInlineVars๋ฅผ ํ์ฉํด์ ๋์ ์คํ์ผ๋ง์ด ๊ฐ๋ฅํ๋๋ก ํด์คฌ์ต๋๋ค.
// button.css.ts
import { style, createVar } from '@vanilla-extract/css';
import { global } from 'src/styles/globalTheme.css';
export const backgroundColor = createVar();
export const fontColor = createVar();
export const borderColor = createVar();
export const button = style({
display: 'flex',
justifyContent: 'center',
alignItems: 'center',
width: '100%',
padding: `${global.padding.small} ${global.padding.base}`,
marginBottom: global.margin.medium,
border: `2px solid ${borderColor}`,
borderRadius: 4,
color: fontColor,
fontSize: global.fontSize.small,
fontFamily: global.fontFamily.notoSansKR,
backgroundColor,
cursor: 'pointer',
});
// Button.tsx
import { global, vars } from 'src/styles/globalTheme.css';
import { assignInlineVars } from '@vanilla-extract/dynamic';
import * as style from './button.css';
...
const Button = ({
children,
onClick,
bgColor,
fontColor = 'lightBlue',
borderColor = 'whiteBlue',
name,
}: IButtonProps) => (
<button
className={style.button}
style={assignInlineVars({
[style.backgroundColor]: bgColor
? global.color[bgColor]
: `hsl(${vars.themeColor.color.contentBackground})`,
[style.fontColor]: global.color[fontColor],
[style.borderColor]: global.color[borderColor],
})}
onClick={onClick}
name={name}
>
{children}
</button>
);
export default Button;
๋ํ, 'use client'๋ฅผ ์ ๊ฑฐํจ์ผ๋ก์จ ์๋ฒ ์ปดํฌ๋ํธ๋ก ๋์ํ ์ ์๊ฒ ๋์์ต๋๋ค.
์ด๋ฌํ ๋ฐฉ์์ผ๋ก ๋ค๋ฅธ ์ปดํฌ๋ํธ ์ ์ง์ ์ผ๋ก vanilla-extarct๋ฅผ ์ ์ฉํ์ต๋๋ค.
โ๏ธ next/font ์ ์ฉ ๋ฌธ์
next/font๋ฅผ ๊ธ๋ก๋ฒ ๋ณ์๋ก ์ ์ฉํ๋ ๋ฐ ์์ด์ ๋ฌธ์ ๋ฅผ ๋ง์ดํ์ต๋๋ค.
๊ธฐ์กด styled-components์์๋ ์๋์ ๊ฐ์ด ์ ์ธ ํ ์ฌ์ฉํ๊ณ ์์์ต๋๋ค.
// GlobalStyle.ts
import { Noto_Sans_KR } from 'next/font/google';
import * as styled from 'styled-components';
import reset from 'styled-reset';
export const notoSansKr = Noto_Sans_KR({
weight: ['300', '400', '500'],
subsets: ['latin'],
});
const GlobalStyle = styled.createGlobalStyle`
..
${({ theme }) => {
return styled.css`
body {
..
font-family: ${notoSansKr.style.fontFamily};
..
}
`;
}}
..
`;
export default GlobalStyle;
๊ทธ๋์ ํด๋น ํฐํธ๋ฅผ ์ ์ฉํ๊ธฐ ์ํด์ ๋ค์๊ณผ ๊ฐ์ด ์๋ํด ๋ดค์ต๋๋ค.
layout ์ปดํฌ๋ํธ์์ next/font๋ฅผ ์ ์ธ ํ globalTheme.css.ts์์ import ํ ํ ๋์ผํ๊ฒ ์ฌ์ฉํด์ผ ํ๋์ง..?
๋๋ฌด์ง ๊ฐ์ด ์กํ์ง ์์์ ๊ตฌ๊ธ๋ง ํด ๋ณธ ๊ฒฐ๊ณผ ๊ฐ์ ๋ฌธ์ ๋ฅผ ๊ฒช๊ณ ์๋ issue๋ฅผ ํตํด ํด๊ฒฐํ ์ ์์์ต๋๋ค.
https://github.com/vanilla-extract-css/vanilla-extract/discussions/1019#discussioncomment-6776002
๋จผ์ layout ์ปดํฌ๋ํธ์์ ์ฌ์ฉํ next/font๋ฅผ ์์ฑํ์ต๋๋ค.
export const notoSansKr = Noto_Sans_KR({
display: 'swap',
weight: ['300', '400', '500'],
subsets: ['latin'],
variable: '--font-noto-sans-kr',
});
์ฌ๊ธฐ์ variable์ ๊ผญ ๋ช ์ํด์ค์ผ ํฉ๋๋ค.
์ด๊ฒ css์์ ์ฌ์ฉํ ๋ณ์๋ช ์ด ๋ฉ๋๋ค.
๊ทธ๋ฆฌ๊ณ ๋จผ์ body์ ํด๋น ํฐํธ๋ฅผ ์ ์ฉํ๊ธฐ ์ํด ์๋์ ๊ฐ์ด className์ ์ ์ฉํ ์ ์๋๋ก ํ์ต๋๋ค.
export default function RootLayout({
children,
}: {
children: React.ReactNode;
}) {
return (
<html lang="ko" suppressHydrationWarning>
<body className={`${notoSansKr.className}`}>
...
</body>
..
</html>
);
}
์ดํ ํด๋น ๋ณ์๋ช ์ ์ฌ์ฉํด ์ค๋๋ค.
export const global = createGlobalTheme(':root', {
fontFamily: {
notoSansKR: `var(--font-noto-sans-kr)`,
},
๊ทธ๋ฆฌ๊ณ ์ฌ์ฉํ๋ ค๋ css ํ์ผ์์ ์๋์ ๊ฐ์ด ํฐํธ๋ฅผ ์ ์ฉํ ์ ์์์ต๋๋ค.
import { style, createVar } from '@vanilla-extract/css';
import { global } from 'src/styles/globalTheme.css';
export const button = style({
...
fontFamily: global.fontFamily.notoSansKR,
...
});
โ๏ธ styled-components ๊ด๋ จ ์ฝ๋ ๋ฐ ์ข ์์ฑ ์ ๊ฑฐ
๋ชจ๋ ์ปดํฌ๋ํธ์ ์ ์์ ์ผ๋ก vanilla-extract๋ฅผ ์ ์ฉํ ํ ๋๋์ด styled-compnents๋ฅผ ๊ฑท์ด๋ผ ์ ์์์ต๋๋ค.
์ด๋ ๊ฒ styled-components ๋๋ฌธ์ ๊ฐ์ ์ ์ผ๋ก ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์ฌ์ฉํด์ผ ํ๋ ๋ฌธ์ ๋ฅผ ํด๊ฒฐํ์ต๋๋ค.
์ด์ ์ ๋ง๋ก ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก๋ง ๋์ํด์ผ ํ๋ ์ปดํฌ๋ํธ๋ง ํด๋ผ์ด์ธํธ ์ปดํฌ๋ํธ๋ก ์๋ํ๊ณ , ๋๋จธ์ง๋ ์๋ฒ ์ปดํฌ๋ํธ๋ก ์๋ํ๊ฒ ๋์์ต๋๋ค.
๐ง ๊ฒฐ๊ณผ
๋ง์ด๊ทธ๋ ์ด์ ์ ์งํํ ๊ฒฐ๊ณผ ์๋ฒ ์ปดํฌ๋ํธ๋ก ์๋์ด ์ ๋์์ต๋๋ค.
์ด๋ก ์ธํด์ ์ด๊ธฐ์ ๋ค์ด๋ก๋ํ๋ ์๋ฐ์คํฌ๋ฆฝํธ ํ์ผ๊ณผ ํฌ๊ธฐ๊ฐ ์ค์ด๋๋ ๊ฐ์ ํจ๊ณผ๋ฅผ ๋ณผ ์ ์์์ต๋๋ค.
styled-comopnent (๋ง์ด๊ทธ๋ ์ด์ ์ด์ ) | vanilla-extract (๋ง์ด๊ทธ๋ ์ด์ ์ดํ) |
vanilla-extract๋ก ๋ง์ด๊ทธ๋ ์ด์ ์ ์งํํ ๊ฒ์ ์ต๊ณ ์ ์ ํ์ด์์ต๋๋ค.
ํ๋ก์ ํธ์ ๋จ์ ์ ๋ฑํ ์๊ณ ์ฅ์ ๋ง ๋จ์ ๋ง์ด๊ทธ๋ ์ด์ ์ด ๋ ๊ฒ ๊ฐ์ต๋๋ค.
๋์ ์ ๊ฐ๋ฐํ๋ฉด์ ๋จ์ ๋ ๋ถ๋ช ์กด์ฌํ์ต๋๋ค.
์๋ฌด๋๋ styled-components๋ก ๊ฐ๋ฐํ ๋๋ณด๋ค ์ฐธ๊ณ ์๋ฃ๊ฐ ๋ถ์กฑํ์ต๋๋ค.
๊ทธ๋์ ๊ณต์๋ฌธ์์ ๊นํ๋ธ issue์ ๋ง์ด ์์กดํ์ฌ ๊ฐ๋ฐ์ ์งํํ์ต๋๋ค.
๋์ ๋ฌธ๋ฒ์ ์ผ๋ก๋ ๋ณต์กํ ๊ธฐ์ ์ด ์๊ตฌ๋์ง ์๊ธฐ ๋๋ฌธ์ ๊ธฐ์กด์ CSS-in-JS ๋ฐฉ์์ ์ต์ํ๋ค๋ฉด ๊ธ๋ฐฉ ์ ์์ด ๊ฐ๋ฅํ ๊ฒ ๊ฐ์ต๋๋ค.