build time css는 왜 중요해졌는가?
프론트엔드의 추세가 csr -> ssr의 흐름으로 가면서 수많은 서버사이드렌더링 프레임워크가 등장했습니다.
next.js, nuxt.js sveltekit , remix 등등이 있지요
대표적인 프레임워크 중 하나인 next.js의 경우
'use client'를 사용한 컴포넌트에서만 리액트 훅과 이벤트 리스너를 사용할 수 있습니다.
이는 app router의 서버컴포넌트 동작이 리액트의 서버컴포넌트 기반으로 동작하기 때문인데요
이 서버컴포넌트는 간략하게 설명하면
서버에서 렌더링 과정이 이루어지며(HTML로 생성하는건 아닙니다.)
Stream을 생성하여 점진적으로 클라이언트에게 스트림을 쏴줍니다.
이러한 동작방식은 기존 CSR의 패러다임과 비교했을 때 명확한 차이를 낳습니다.
1. app 라우터의 서버컴포넌트는 서버사이드에서 실행된다.
2. 또한 그 실행의 결과물은 stream의 형태로 클라이언트에게 점진적 전송된다.
3. 서버컴포넌트는 정적으로 동작해야한다.
이러한 흐름의 변화는 기존 csr 방식에 최적화 된 형태로 돌아가던
emotion, styled 진영에 큰 영향을 끼쳤습니다.
왜냐하면 css-in-js가 동적으로 생성하는 스타일들은 사용자의 상호작용이 어떻게 이루어지냐에따라
예측할 수 없을 만큼 다양한 경우의 수를 가지고있었거든요
따라서 서버사이드에서 정적으로 스타일을 생성할 수 없다는 한계가 있었습니다.
?? 그러면 정적으로 생성할 수 있게 코드를 짜면 되지 않냐구요?
맞습니다. 이 맥락으로 cssints , 테일윈드가 서버에서도 동작하는 것입니다
물론 위 프레임워크 , 라이브러리들의 대표적인 단점으로 알다시피 그만큼 런타임 동작을 할때만큼의 유연성은 기대할 수 없어집니다.
결국 trade off인 것이지요
또한 서버컴포넌트가 나온지 얼마안되었던 시기에는 정적생성하면 되는거아니냐를 차치하고도 css-in-js 라이브러리들의 다른 기술적 문제가 있었습니다
예컨대 스타일드 컴포넌트의 경우엔 싱글톤으로 관리되는데
서버사이드에서 생성한 객체와 클라이언트사이드에서 생성한 객체가 서로 달라
하이드레이션 에러가 발생하는 문제가 있었고
-> 이것도 해결됐습니다
스트림을 반환하는 리액트서버컴포넌트의 동작원리때문에 발생하는 문제도 있었습니다
-> 이건 해결됐습니다
https://nextjs.org/docs/app/building-your-application/styling/css-in-js
그런데 서버컴포넌트에서 쓸 수 있냐 없냐를 차치하고도 css-in-js 방식은 trade off가 명확한 방식입니다.
이 두 라이브러리들은 런타임에 브라우저에서 동작할 것을 가정하고 만들어진 라이브러리였기 때문인데요
런타임에 동작한다는 방식을 선택한 덕에 더 다양하고 확장된 스타일링이 가능해졌지만
반대급부로 번들크기가 증가했고, 런타임 오버헤드가 생겼으며 서버사이드렌더링에는 취약한 형태가 되었습니다.
하지만 그와 별개로도 css를 자바스크립트로 관리하자는 발상은 개발자 경험을 크게 상승시켜주는데요
자바스크립트의 객체를 활용하여 디자인토큰을 만들고 그 디자인 토큰을 기반으로 관리하는 전략은
css의 유지보수성을 크게 끌어올려주었습니다.
next.js의 경우에는 빌드타임에 모든 css가 생성되는 tailwindcss를 기본적으로 추천하게 되어있습니다.
저는 tailwindcss를 굉장히 사랑하는 사람이지만 모든 개발자가 저와 같지는 않지요
css-in-js를 서버사이드렌더를 지원하는 프레임워크와 사용할 수 없을까?
라는 생각이 들게 됩니다.
열심히 메인테이너들이 노력하고 있지만 아직 emotion, styled 등은
까다로운 설정들을 많이 해줘야하죠
실제로는 아닐 수 있지만 저는 빌드타임 css-in-js가 이러한 흐름에서 나왔다고..
제마음대로 생각하고 있습니다. 아닐수도 ㅎㅎ;;
이번에 소개할 PandaCSS의 경우에는 AST 파싱 , 스캐닝을 통하여
소스 코드에서 유틸리티 클래스와 패턴을 추출하고,
이를 정적으로 css 파일로 생성하는 형태로 동작합니다.
- dante.log -
덕분에 판다, 바닐라익스트랙과 같은 빌드타임 css-in-js는 런타임 동작을 포기한 대신
런타임 오버헤드를 피할 수 있고 서버 환경에서도 잘 사용가능하다는 이점을 얻게되었습니다.
pandacss vs vanila extract
https://www.libhunt.com/compare-vanilla-extract-vs-chakra-ui--panda
위 사이트에서 간단한 비교를 제공해줍니다.
포스트 작성 시점 (2023.08.02) 기준으로 pandacss의 성장세가 눈에띕니다.
vanila extract는 아무래도 나온지 좀 된 라이브러리이다보니 성장세가 눈에띄지는 않는 모습이네요
둘 다 빌드타임 css를 지원한다는 장점이 있는데
바닐라 익스트랙트는 타입스크립트와의 통합을 더욱 강조한 반면
panda css는 타입스크립트, 자바스크립트를 모두 아울러주는 느낌이네요
TS가 사실상 표준이 되어버린 지금은 크게 의미없어 보이기도 하지만
판다 css가 매력적이어 보이는 것은 최근 많은 하입을 받고있다보니
여러가지 유용한 레퍼런스들을 쉽게 얻을 수 있다는 것이었습니다.
바닐라 익스트랙트 같은 경우에는... 이름을 좀 바꿔줬으면 좋겠어요..
검색하면 먹는 바닐라만 잔뜩 나옴..
https://www.youtube.com/watch?v=fKSemrudovo
반면 pandacss의 경우에는 제가 즐겨보는 유튜버가 얼마전에
app router에서의 초기 세팅 방법을 다룬 글도 올려줬읍니다.
https://panda-css.com/docs/concepts/recipes
그와 별개로도 공식문서가 굉장히 잘 작성되어 있는 라이브러리이며
특히 제 입장에서 흥미로운 점은 라이브러리 차원에서 cva를 지원해준다는 것입니다.
cva는 제가 정말 좋아하는 라이브러리 중 하나인데요
비록 class variance authority 라이브러리와 완전히 동일한 함수를 제공하는 것은 아니고
panda에서 자체적으로 제작한 함수라고 합니다.
디자인 토큰과 유틸리티에 연결되는 아토믹 레시피를 만들기 위해 사용할 수 있다고 하네요
문법 자체는 cva와 굉장히 유사합니다.
import { cva } from '../styled-system/css'
const button = cva({
base: {
display: 'flex'
},
variants: {
visual: {
solid: { bg: 'red.200', color: 'white' },
outline: { borderWidth: '1px', borderColor: 'red.200' }
},
size: {
sm: { padding: '4', fontSize: '12px' },
lg: { padding: '8', fontSize: '24px' }
}
}
})
결론
vanila extract 와 panda css 둘 다 코어 컨셉 자체에는 큰 차이가 있다고 느껴지진 않았습니다.
pandacss의 공식문서에도 stitches, vanilla extract, class variance authority
라이브러리에 영감을 얻어 만들어졌다고 소개하는 만큼이요!
좀 더 마음에 드는 라이브러리를 사용하면 될 듯 한데
저는 자체 cva를 제공해주는 panda css가 너무...너무 마음에 드네요
다음 포스트는 panda css로 돌아와보겠습니다.
참고한 레퍼런스
https://velog.io/@jay/Panda-CSS
https://vanilla-extract.style/documentation/getting-started/
'css' 카테고리의 다른 글
shadcn/ui 사용법 익히기 (0) | 2023.08.21 |
---|---|
요즘 핫한 panda css next.js app 라우터에서 시작하기 (0) | 2023.08.02 |
swiper/react를 이용하여 반응형 캐러셀 만들기 (5) | 2023.07.31 |
mui 개념과 사용 방법 시작하고 sx 프로퍼티 알아보기 (0) | 2023.07.27 |
Radix UI로 Headless UI 맛보기 (1) | 2023.07.21 |