Panda CSS 에 대해 알아보자 (feat. vanilla extract)

dante Yoon·2023년 7월 2일
10

Panda

목록 보기
1/1
post-thumbnail

영상으로 보기:
https://www.youtube.com/watch?v=iG1ZeFzYWPQ

panda css in js thumbnail

https://panda-css.com/
https://github.com/chakra-ui/panda

Panda CSS

Panda CSS는 CSS-in-JS 라이브러리로, 웹 애플리케이션에서 현대적이고 반응형인 사용자 인터페이스를 구축하기 위한 유틸리티 클래스, 패턴, 레시피 등을 제공합니다.

자바스크립트 객체를 사용하여 컴포넌트에 스타일을 선언적으로 적용할 수 있어, 순수 문자열 기반의 접근법보다 가독성과 유지보수성이 높습니다.

Panda CSS의 주요 차별화 기능은 런타임 오버헤드가 없다는 점입니다. CSS-in-JS는 런타임 오버헤드가 있어 퍼포먼스를 해친다는 단점을 가지고 있습니다.
Panda CSS는 AST 파싱과 스캐닝을 통해 소스 코드에서 유틸리티 클래스와 패턴을 추출하고, 이를 정적으로 CSS 파일로 생성합니다. 따라서, 런타임에 스타일을 계산하거나 주입할 필요가 없으며, 번들 크기도 줄일 수 있습니다.
동적으로 생성되는 스타일들 또한 빌드타임에 미리 클래스로 생성됩니다.

설치 및 설정

npmCreate React App을 사용해서 테스트를 해보겠습니다.

  • 리엑트 설치
    npm install react-scripts@latest
  • 최신 버전의 판다 설치
    npm i -D @pandacss/dev

  • 판다 설정 파일과 사용하는데 필요한 postcss 설치
    npx panda init -p

여기까지 수행하면 아래와 같이 기본 코드들이 생성됩니다.

outdir

새로 생성된 폴더 이름이 styled-system이고 이 내부에 css, patterns, tokens, types 폴더가 있습니다.

각 폴더들은 아래와 같은 역할을 담당하는데요,

✔️ styled-system/css

스타일 작성을 위한 함수들이 있는 디렉토리

✔️ styled-system/tokens

css variables와 토큰들을 질의하기 위한 함수들이 있는 디렉토리

✔️ styled-system/patterns

공통 레이아웃 패턴을 적용하는데 사용하는 함수들
functions to implement apply common layout patterns

왜 하필 styled-system에 유틸 함수들이나 css variables가 생성되었을까요?

그것은 panda.config.mjs 파일 옵션 때문입니다.

import { defineConfig } from "@pandacss/dev"

export default defineConfig({
    // css reset을 사용할지 대한 유무 
    preflight: true,
    
    // panda.css 정의를 사용할 대상 파일들
    include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],

    // include에서 제외할 파일들
    exclude: [],

    // 커스텀 theme 사용을 위한 설정 장소
    theme: {
      extend: {}
    },

    // css system이 생성되는 장소 
    outdir: "styled-system",
    
    
})

package.json 에 다음과 같이 codegen 명령어를 기입하고 outdir 이름을 변경한다음 prepare 를 실행해보면 새로 기입한 디렉토리 하위에 파일이 생성되는 것을 확인할 수 있습니다.

"scripts": {
    ...
    "prepare": "panda codegen --clean"
  },

Setup and import the entry CSS file

프로젝트 루트 레이아웃 파일에서 import 하는 css 파일이름을 index.css라고 가정했을 때

다음과 같이 작성해줍니다.

index.css

@layer reset, base, tokens, recipes, utilities;

스타일 입혀보기

다음과 같이 App.js를 작성하여 기본적인 panda.css의 css 함수를 적용해보겠습니다.

function App() {
  return (
    <div className={css({ bg: 'red.400' })}>
      hi
      <img src={logo} className="App-logo" alt="logo" />
    </div>)

}

export default App;

하지만 백그라운드에 red 400 색상이 입혀지지 않았습니다.

build --watch

panda.config.mjs 파일을 다시 한번 살펴보겠습니다.

import { defineConfig } from "@pandacss/dev"

export default defineConfig({
    // Whether to use css reset
    preflight: true,
    
    // Where to look for your css declarations
    include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],

    // Files to exclude
    exclude: [],

    // Useful for theme customization
    theme: {
      extend: {}
    },

    // The output directory for your css system
    outdir: "./src/styled-system",
})

panda.css는
include 옵션에 명시해뒀던 파일들에 적용시킨 panda css의 스타일 문법들을 사용해
빌드타임에 atomic css를 생성하기 때문에 정상적인 스타일을 적용시키기 위해서는 빌드를 거쳐야 합니다.

package.json - scripts에 다음과 같이 명령어를 선언합니다.

panda는 프로덕션 배포 단계에서 사용할 명령어, panda:dev는 개발 환경에서 사용할 명령어입니다.

{
  "panda": "npx panda",
  "panda:dev": "npx panda --watch"
}

styled-system/styles.css

앱에 정상적으로 스타일을 입히기 위해서는 styles.css를 import 해야 합니다.

이 styles.css는 위에 panda.config.mjs에서 설정했던 outdir에 위치해 있습니다.

이 파일을 한번 볼까요?

@layer reset, base, tokens, recipes, utilities;

@import './global.css';

@import './reset.css';

@import './tokens/index.css';

@import './tokens/keyframes.css';

@layer utilities {
  .bg_red\.400 {
    background: var(--colors-red-400)
    }
}

App.js에서 선언했던 스타일이 css 클래스로 생성되어있습니다.

다음과 같이 App.js를 재작성해줍니다.

import { css } from "./styled-system/css"
import './App.css';
import logo from './logo.svg';
import "./index.css"
import './styled-system/styles.css'


function App() {
  return (
    <div className={css({ bg: 'red.400' })}>
      hi
      <img src={logo} className="App-logo" alt="logo" />
    </div>)

}

export default App;

Custom theme

예제 코드의 red.400은 어떻게 사용된 것일까요?

생성된 토큰에 있는 red.400의 모습

예제코드에서는 커스텀 테마를 사용하지 않았지만, panda.css의 panda.config.mjs에서 theme.extend를 설정할 수 있습니다.

import { defineConfig } from "@pandacss/dev"

export default defineConfig({
    // Whether to use css reset
    preflight: true,
    
    // Where to look for your css declarations
    include: ["./src/**/*.{js,jsx,ts,tsx}", "./pages/**/*.{js,jsx,ts,tsx}"],

    // Files to exclude
    exclude: [],

    // Useful for theme customization
    theme: {
      extend: {
        tokens: {
          colors: {
              dante: {
                50: { value: '#00FFFF'},
                100: { value: '#F0FFFF'},
                200: { value: '#89CFF0'},
                300: { value: '#0000FF'},
                400: { value: '#7393B3'},
                500: { value: '#088F8F'},
                600: { value: '##0096FF'},
                700: { value: '#5F9EA0'},
                800: { value: '#0047AB'},
                900: { value: '#6495ED'},
              },
            }
          }
      }
    },

    // The output directory for your css system
    outdir: "./src/styled-system",
    
    
})

App.js

function App() {
  return (
    <div className={css({ bg: 'dante.400' })}>
      hi
      <img src={logo} className="App-logo" alt="logo" />
    </div>)

}

Vanilla extract 와 차이점

Vanilla Extract와 비교하면, Vanilla Extract는 사실상 TypeScript로 CSS를 작성하는 라이브러리입니다.

Panda CSS와 Vanilla Extract 모두 zero-runtime CSS-in-JS 라이브러리로, 런타임에 CSS를 생성하지 않으면서 페이지를 더 빨리 로드할 수 있습니다.

Panda CSS와 Vanilla Extract는 비슷한 부분이 많습니다. 문서를 보아도 Vanilla Extract에서 많은 영감을 받았다고 하죠.

Vanilla Extract는 typescript로 CSS를 작성합니다. CSS-in-JS가 아닌 CSS-in-TS이죠.

8개월 전에 vanilla extract를 사용하는 방법에 대한 영상과 글을 공유했었습니다.

당시에는 국내에 많이 퍼지지 않았었는데 요근래 사용하시는 분들이 많아지는 것 같아서 나름 뿌듯한 기분도 듭니다.

BLOG: https://velog.io/@jay/css-in-ts-vanilla-extract
YOUTUBE: https://www.youtube.com/watch?v=74szuw5Qxrg

support server component

Pands CSS는 최신 CSS 라이브러리 답게 nextjs의 서버 컴포넌트를 공식적으로 지원합니다.
새롭게 프로젝트를 생성하시는 분들은 도입을 고려해볼만한 라이브러리라고 생각합니다.

profile
성장을 향한 작은 몸부림의 흔적들

3개의 댓글

comment-user-thumbnail
2023년 7월 5일

판다 .. 너무 귀여워요 ..

1개의 답글