일 | 월 | 화 | 수 | 목 | 금 | 토 |
---|---|---|---|---|---|---|
1 | 2 | 3 | 4 | 5 | ||
6 | 7 | 8 | 9 | 10 | 11 | 12 |
13 | 14 | 15 | 16 | 17 | 18 | 19 |
20 | 21 | 22 | 23 | 24 | 25 | 26 |
27 | 28 | 29 | 30 |
- react server component
- Concurrent Mode
- sprinkles
- 목킹
- 리액트쿼리
- 컴포넌트
- next.js
- react-query
- mockoon
- Basic
- amplify
- MSW
- 아키텍처
- 비동기
- async
- CSS-in-JS
- Babel
- thread
- Cache
- SWC
- styled-component
- front-end mocking
- 쓰레드
- 기본
- react-native
- mock service worker
- JavaScript
- 리액트
- React
- Critical Rendering Path
- 기초
- 캐쉬
- 최적화
- next hydration
- 자바스크립트
- 동기
- 리액트네이티브
- 개발자
- vanilla-extract
- link
- Today
- Total
Don’t worry about failures
migrate from Styled-component to vanilla-extract 본문
사이드 프로젝트 리펙토링 과정에서 마이그레이션 작업이 하나가 추가 됐다.
styled-component에서 vanilla-extract
처음에는 styled-component가 개발경험에 있어 개인적으로 좋다고 생각했다. 컴포넌트로 표현되는 것과 javascript과 함께 컨트롤를 할 수 있다는게 좋다고 생각했기 때문에 사용했었다.
하지만 다른 측면으로도 생각을 해보았다. styled-component의 경우 동작하는 방식이 runtime 때 동적으로 스타일이 적용이 된다. 이는 csr과 어울리는 방식이다.
하지만 지금 사용하고자 하는 Next.js라는 프레임워크는 ssr, rsc와 같이 서버 사이드에서 렌더링을 진행하고자한다. 이를 보았을 때 동작하는 방식이 차이가 있다고 생각했다. styled-component를 next에서 사용하기 위해서는 서버에서 스타일을 적용할 수 있도록하기 위해 별도의 작업이 필요하다. 이러한 행위 자체가 끼워 맞춰야한다는 생각이 들었다.
이와 더불어 runtime 때 동작함에 따라 성능 이슈와 useInsertEffect와 같은 훅을 활요한 관리 등 단점이 존재하기 때문에 migration을 하고자 했다.
그렇다면 어떤 라이브러리로 migration을 해야할까? 라는 고민을 했을 때 tailwind, vanilla-extract 이 둘중에 고민을 했다.
이 두 라이브러리 모두 위에서 고민했던 runtime 시에 동작되는 것이 아니기 때문에 server 사이드에서 별다른 이슈가 존재하지않는다. Next.js에서는 tailwind를 더 추천하고있다.
이 둘 모두 인기도 장점이 명확한 좋은 라이브러들이다. 하지만 내가 선택한 라이브러리는 vanilla-extract를 사용하기로 했다.
선택하게 된 이유는 다음과 같다.
1. 기존에 css-in-js를 편리하게 사용하고 있었다.
2. css-in-js와 다르게 런타임에 동작되는게 아니라 빌드 타임에 스타일이 생성이 된다.
3. tailwind는 utility-first라는 큰 강점이 있지만 단점도 있다고 생각한다. 이미 생성되어있는 것을 빠르게 사용하여 개발 생산성을 높일 수 있지만, util이라는 것에 무엇이 있는지 파악을 완벽히 해야한다. 또한 내가 사용을 안해도 이미 생성이 되어있다. 빌드 사이즈를 보면 다른 라이브러리보다 사이즈가 크다. 다른 라이브러리들은 kb단위이지만 tailwind는 2mb 정도 된다.
4. tailwind는 스타일이 많을 경우 코드의 가독성이 떨어질 수 있다.
위와 같은 이유를 통해 선택을 하게 되었다.
다음은 작업을 통해 vanilla-extract를 경험해보자.
1. install
next를 사용함에 따라 부가적으로 적용해야할 것이 있다. 해당되는 부분은 아래의 공식문서를 통해 확인.
( next-plugin을 설치할 때 invalid url에러가 났다. 처음에는 yarn에서 코드 주소가 잘못됐나 했지만, node 자체 문제가 있어 버전을 변경하면서 해결이 됐다 )
https://vanilla-extract.style/documentation/integrations/next/
yarn add @vanilla-extract/css
// next를 사용하고 있기 때문에 플러그인 설치
yarn install @vanilla-extract/next-plugin --dev
2. css reset
reset.css파일 생성 후 해당 css 값을 복사.
3. global Theme css
테마에 대한 css선언
createGlobalTheme
해당 API를 통해 선언. createThemeContract를 활용하지는 않음.
현재 테마가 하나밖에 없어 사용을 하지는 않았따. createThemeContract를 활용하게 되면, split code를 구현할 수 있게된다. 사용중인 theme만 호출하여 사용하게 되어 불필요한 css를 불러오지 않아도 되는 장점이 있다.
4. packages 파악
vanilla-extract의 경우 Sprinkles, recipes, Dynamic, Css Utils의 패키지를 제공해준다.
이에 대해 파악해보고, 필요한 것을 install을 해보자.
4-1 Sprinkles
Generate a static set of custom utility classes and compose them either statically at build time, or dynamically at runtime, without the usual style generation overhead of CSS-in-JS.
css-in-js의 단점이었던 런타임시 생성되는 오버헤드 없이, 빌드 타임에 정적으로 또는 런타임에 동적으로 스타일을 생성하는 것.
간단한 예시로 봐보자.
import {
defineProperties,
createSprinkles
} from '@vanilla-extract/sprinkles';
const spaces = {
'space-1' : 3,
'space-2' : 5
}
const colors = {
'primary' : '#ffff',
'secondary' : '#cccc'
}
const spaceProperty = defineProperties({
properties: {
padding: spaces
}
});
const colorProperty = defineProperties(
properties: {
color: colors
}
);
export const sprinklesEx = createSprinkles(
spaceProperty,
colorProperty
);
const button = sprinklesEx({
color: 'primary',
padding: 'space-1'
});
위와 같이 사용이 될 수 있다.
즉, property를 미리 정의해놓은 상태에서 미리 정의해 놓은 것을 기반으로 사용하도록하여, 재사용성, 개발 편의성을 증가 시킬 수 있다.
4-2 Recipes
이는 단어 의미와 비슷하다. 말그대로 레시피를 만들어 놓고 사용한다고 생각하면 편하다.
recipe에는 property로 base, variants, compoundVariants, defaultVariants의 값을 받는다.
base: variant에 상관없이 공통적으로 적용.
variants: variant를 적용. 예) color, size.
compoundVariants: variant의 특정 조합이 적용이 되었을 때 적용.
defaultVariants: variant의 기본값을 설정할 때 사용.
위와 같은 package를 통해 버튼을 아래와 같이 구현해보았다
import { recipe } from "@vanilla-extract/recipes";
import { sprinkles } from "@src/style/sprinkles.css";
export const button = recipe({
base: [
{ borderRadius: "10px", height: "48px" },
sprinkles({
display: "flex",
placeItems: "center",
}),
],
variants: {
color: {
primary: [
sprinkles({
backgroundColor: "primary",
color: "white",
border: "none",
}),
],
secondary: [
sprinkles({ backgroundColor: "black", color: "white", border: "none" }),
],
tertiary: [
sprinkles({
backgroundColor: "white",
color: "primary",
border: "primary",
}),
],
},
size: {
large: {
width: "296px",
},
small: {
width: "48px",
},
},
},
defaultVariants: { size: "large", color: "primary" },
});
사용
<button className={button({ color: "primary", size: "large" })}>
test
</button>
결과
recipe를 통해 color, size를 디자인 시스템에 맞춰 구성하여 사용하는 쪽에서는 사용하고자 하는 값만 던져주면 된다.
safe-type이기 때문에 넣어야할 값이 유추가 가능하여 개발 경험에 있어서도 큰 장점을 보일 수 있다.
간단한 버튼을 통해 vanilla-extract를 경험해보았을 때 기본 틀만 잘 만들어 놓는다면 개발생산성도 매우 좋을 것으로 생각이 든다.
추가로 sprinkles와 함께 사용하여 active, hover, disable 상태에 따른 스타일링 구성하였다.
import { recipe } from "@vanilla-extract/recipes";
import { buttonSprinkles } from "@src/component/button/buttonSprinkles.css";
export const button = recipe({
base: [
{ borderRadius: "10px", height: "48px" },
buttonSprinkles({
display: "flex",
placeItems: "center",
}),
],
variants: {
color: {
primary: [
buttonSprinkles({
backgroundColor: "primary",
disabled: "primary",
hover: "primary",
click: "primary",
color: "white",
border: "none",
}),
],
secondary: [
buttonSprinkles({
backgroundColor: "black",
disabled: "secondary",
hover: "secondary",
click: "secondary",
color: "white",
border: "none",
}),
],
tertiary: [
buttonSprinkles({
backgroundColor: "white",
disabled: "tertiary",
hover: "tertiary",
click: "tertiary",
color: "primary",
border: "primary",
}),
],
},
size: {
large: {
width: "296px",
},
small: {
width: "48px",
},
},
},
defaultVariants: { size: "large", color: "primary" },
});
아래와 같이 sprinkles와 함께 사용하게 되면 추상화도 잘되면서 사용하는 쪽에서는 변수 추론도 되어 개발 경험이 매우 좋다고 판단이 된다. 코드 또한 매우 깔끔하게 active, disable hover, nomal 상태에 따른 처리가 가능하다.
아직 버튼에 대한 경험만 해보았지만 지금까지는 vanilla-extract에 대해 긍정적인 생각을 가지게 된다.
'toy project' 카테고리의 다른 글
URURL 리팩토링의 서막 (1) | 2024.03.22 |
---|---|
ururl.me 성능에 대해 (0) | 2022.03.17 |
UrUrl.me 1차 배포 회고 (0) | 2022.03.15 |
next.js amplify git 레파지토리 권한 (0) | 2021.08.28 |
Cracker Book Toy Project Log(2) (0) | 2021.06.05 |