
이 플러그인을 사용하면 가장 좋은 점은(+ 토큰을 피그마에서 관리하면 좋은 점)
이 두 기능을 활용해서
디자이너가 토큰을 변경했을 때, 일일이 개발자에게 알리지 않아도 되고 개발자도 git 시스템을 통해서 더 체계적인 관리가 가능해진다
개발자에게 좋은 점은 json 으로 데이터를 받을 수 있다는 것이다.
node 진영이라면, 특별한 변환 과정을 거칠 필요 없이 그냥 import해서 사용할 수 있고, 심지어 타입 지원도 된다(사용하는 node버전, ts설정 등에 따라 다를 수 있습니다)
json 형식의 토큰 데이터를 css,android,ios 등의 사용 플랫폼에 맞게 변환해주는 라이브러리도 있다
유명한 라이브러리로는
style-dictionary - 아마존에서 만든 라이브러리
transform tokens using style-dictionary
github과의 연동을 직접 구현해야 함
유료 모드가 아니면 각 토큰 데이터를 테마별로 선언할 수 없음
예를 들어 Color 라는 변수 대해 light,dark,mobile 등 테마에 따라 다른 값을 저장하고 싶다면 유료 모드에서만 가능하다(plugin도 동일하게 유료 결제를 해야 함)


물론 plugin도 무료버전이고, 유료버전과의 차이가 있지만 무료버전끼리 비교해봤을 때 굳이 넘어가야 할 이유를 못 느꼈다
하지만 이건 개발자인 나의 생각이고.. 디자이너가 작업하기에는 variables가 좀더 편하지 않을까? 싶다
나는 pandacss 를 통해 디자인 시스템을 구축하고 있는데, type-safe하게 토큰을 적용하고 싶으면 pandacss에서 요구하는 타입에 맞게 변환을 해야 한다
import { defineConfig } from '@pandacss/dev'
export default defineConfig({
theme: {
// 👇🏻 Define your tokens here
extend: {
tokens: {
colors: {
primary: { value: '#0FEE0F' },
secondary: { value: '#EE0F0F' }
},
fonts: {
body: { value: 'system-ui, sans-serif' }
}
}
}
}
})
pandacss 공식문서 예시인데, 이런 식으로 config 파일에 적용해야만 토큰 사용이 가능해진다.
그래서 기존에는 코드에서 토큰 파일을 직접 정의했기 때문에, 객체 형태로 어떤 라이브러리를 사용하던 변환하기 쉽게 정의해놓은 다음
export type Color = typeof color
const color = {
white: { light: "#FFFFFF", dark: "#FFFFFF" },
blue_100: { light: "#E1F5FF", dark: "#0077C8" },
blue_200: { light: "#7DD5FF", dark: "#00A9FF" },
blue_300: { light: "#0C356A", dark: "#0C356A" },
red_100: { light: "#FFEEF1", dark: "#D73F2F" },
red_200: { light: "#FF6F61", dark: "#FF6557" },
red_300: { light: "#E45141", dark: "#FFD3D6" },
grey_100: { light: "#FEFEFE", dark: "#121212" },
grey_200: { light: "#F7F8F9", dark: "#2E363A" },
grey_300: { light: "#646F6C", dark: "#999FA4" },
grey_400: { light: "#374553", dark: "#C5C8CE" },
grey_500: { light: "#161D24", dark: "#FDFDFD" },
} as const
const semanticColor = {
bg_main: { light: color.white.light, dark: color.grey_100.dark },
bg_elevated: {
light: color.white.light,
dark: color.grey_200.dark,
},
border_basic: {
light: color.grey_300.light,
dark: color.grey_200.dark,
},
border_basic2: {
light: color.grey_300.light,
dark: "none",
},
text_primary: {
light: color.grey_400.light,
dark: color.grey_400.dark,
},
text_secondary: {
light: color.grey_400.light,
dark: color.grey_500.dark,
},
text_danger: {
light: color.red_200.light,
dark: color.red_200.dark,
},
}
type ObjValue = { value: { base: string; _dark: string } }
type Obj = Record<string, ObjValue>
//pandacss config 타입에 맞추기 위해 변환하는 함수
export const colors: Obj = Object.entries({
...color,
...semanticColor,
}).reduce<Obj>((acc, [key, value]) => {
acc[key] = { value: { base: value.light, _dark: value.dark } }
return acc
}, {})
이를 변환하는 함수를 하나 만들어서 변환을 시켜주면 된다.
이제는 figma token 에서 제공해주는 json파일의 데이터를 활용해서 pandacss 에서 요구하는 타입에 맞게 직접 변환해야 하는데, 모든 토큰이 하나의 json파일에 담겨 내용을 파악하기가 어려웠다
그래서 내가 선택한 방법은
1. token-transformer 를 통해서 일차적으로 하나의 json 파일을 테마에 따라 분리한다
2. json의 데이터 타입을 pandacss 에서 요구하는 타입에 맞게 변환하는 함수를 통해 변환 후, config 파일에 등록한다
import { existsSync, mkdirSync, readFile, writeFileSync } from "fs"
import { join } from "path"
import { transformTokens } from "token-transformer"
import { fileURLToPath } from "url"
import { dirname } from "path"
// 현재 파일의 디렉토리 경로 가져오기
const __filename = fileURLToPath(import.meta.url)
const __dirname = dirname(__filename)
// 추출 대상 파일 경로
const filePath = "./src/theme/tokens"
const dir = join(__dirname, filePath)
// 만약 없다면 생성
if (!existsSync(dir)) {
mkdirSync(dir, { recursive: true })
}
// 변환 옵션
const transformerOptions = {
expandTypography: true,
}
// 파일 읽기
readFile("tokens.json", "utf8", (err, data) => {
if (err) throw err
const tokens = JSON.parse(data)
// $metadata에 token key가 있음
const tokenKeys = [...tokens.$metadata.tokenSetOrder]
tokenKeys.forEach((key) => {
// 변환 작업
const resolved = transformTokens(
tokens, // 변환할 파일
key === "light" || key === "dark" ? ["core", key] : tokenKeys, // 참조 대상
[...tokenKeys].filter((k) => k !== key), // 추출 제외 대상
transformerOptions, // 변환 옵션
)
// 파일 생성
writeFileSync(
`${filePath}/${key}.json`,
JSON.stringify(resolved),
(err) => {
if (err) throw err
},
)
})
})
이 과정을 거치면, tokens 라는 폴더 안에 내가 정의해놓은 테마별로 파일이 나뉜다.
//dark.json
{
"bg_main": { "value": "#121212", "type": "color" },
"bg_elevated": { "value": "#2E363A", "type": "color" },
"border_basic": { "value": "#2E363A", "type": "color" },
"border_basic2": { "value": "#FFFFFF", "type": "color" },
"text_primary": { "value": "#C5C8CE", "type": "color" },
"text_secondary": { "value": "#FDFDFD", "type": "color" },
"text_danger": { "value": "#FF6557", "type": "color" }
}
이제 각 json파일에서 원하는 데이터를 가져와서, config에서 요구하는 타입으로 바꿔주면 된다
pandacss는 각 속성마다 요구하는 타입이나, 사용되는 API가 조금 다르기 때문에 이에 맞게 컬러,textStyle,radius 등에 따라 각각 변환 함수를 만들었다
github actions를 통해서 push된 토큰을 변환하는 작업을 자동화시킬수도 있다
# design 브랜치의 tokens.json 파일에 대한 push 감지
on:
push:
branches:
- token
paths:
- "tokens.json"
jobs:
createPullRequest:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version-file: ".nvmrc"
- name: install dependencies
run: npm ci
- name: Run Token Transformer
run: |
node transformToken.js // 변환 스크립트 실행
git config --global user.name ""
git config --global user.email ""
git add .
git commit -m '피그마 디자인 토큰 변환'
git push
env:
GITHUB_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN}}
- name: Create Pull Request
run: gh pr create -B main -H token --title '.'
env:
GITHUB_TOKEN: ${{ secrets.CHROMATIC_PROJECT_TOKEN }}
나의 경우 figma에서 token이라는 브랜치에 push ->
이를 감지하는 github actions를 통해 변환 로직이 들어있는 transformToken.js 를 실행시키고 ->
변경된 파일들을 main 브랜치에 PR을 올리는 작업을 자동화했다