Figma 디자인 토큰을 vanilla-extract로 변환하기

Stoic Park·

디자인 시스템을 코드로 옮기는 과정에서 가장 시간이 많이 들고 반복적인 작업 중 하나는 디자인 토큰을 개발 코드에 반영하는 일입니다.

초기에는 디자이너 분이 Figma에 익숙하지 않아, 실제 디자인 시안에서 스타일 값을 추출해 프론트엔드 팀이 수작업으로 스타일을 구현하는 방식으로 진행했습니다. 이 과정은 디자이너와 개발자 간의 의도 전달 오차가 생기기 쉬웠고, 디자인 변경이 생길 때마다 코드를 직접 수정해야 했기 때문에 협업 비용이 높았습니다.

특히 문제가 되었던 점은 다음과 같았습니다:

  1. 디자이너의 Figma 사용 러닝커브
  2. 디자인 변경사항을 매번 수작업으로 코드에 반영해야 함
  3. 협업 비용 증가

저의 경우 디자이너가 1명이었고 여러 제품을 병행하는 상황이었기 때문에, 디자인 시스템에 많은 리소스를 투자하기 어려운 환경이었습니다. 그럼에도 불구하고 프론트엔드 팀 내부에서는 디자인 시스템에 대한 필요성과 개선 욕심이 있었고, 최소한의 리소스로 이를 도입할 방법을 찾던 중 Tokens Studio for Figma를 도입하게 되었습니다.

🎨 Tokens Studio for Figma란?

Tokens Studio는 Figma 내에서 디자인 토큰을 생성·편집·관리할 수 있는 강력한 플러그인입니다.

디자이너는 Tokens Studio를 통해 색상, 타이포그래피, 간격, 그림자 등 다양한 스타일 정보를 **"디자인 토큰"**으로 정의하고,
이를 JSON 형태로 export하여 개발자와 쉽게 공유할 수 있습니다.

Tokens Studio 토큰 설정 화면

Tokens Studio에서 다양한 종류의 디자인 토큰을 설정하고 관리하는 화면입니다.

핵심 기능:

  • 다계층 토큰 구조 관리 (color.primary, spacing.large 등)
  • JSON으로 export (Style Dictionary 포맷 포함)
  • GitHub 연동 가능
  • Typography, Shadows, Border 등 확장 가능

Figma 내에서 바로 사용할 수 있으며, 디자인 시스템을 개발과 연결하는 실질적인 다리 역할을 합니다.

✍️ 수동 방식 기반 스크립트 개발

Tokens Studio에서는 다음과 같은 구조의 JSON을 export할 수 있습니다:

{
 "color": {
  "primary": { "value": "#FF0000" },
  "secondary": { "value": "#00FF00" }
 }
}

그러나 vanilla-extract에서는 다음과 같은 형태의 코드가 필요합니다:

export const vars = createGlobalTheme(':root', {
 color: {
  primary: '#FF0000',
  secondary: '#00FF00',
 },
})

이를 수작업으로 매번 변환하는 것은 비효율적이기 때문에,
JSON 파일을 읽어 자동으로 vanilla-extract 코드로 변환하는 스크립트를 작성했습니다.

🧪 변환 스크립트 요약

// 1. JSON 구조 평탄화
function flattenTokens(json: any, path: string[] = []) {
 return Object.entries(json).flatMap(([key, value]) => {
  if (value?.value) {
   return [{ path: [...path, key], value: value.value }]
  }
  return flattenTokens(value, [...path, key])
 })
}

// 2. 중첩 구조로 복원
function nestTokens(flatTokens: { path: string[]; value: string }[]) {
 const nested: Record<string, any> = {}
 for (const { path, value } of flatTokens) {
  let curr = nested
  path.forEach((key, idx) => {
   if (idx === path.length - 1) {
    curr[key] = value
   } else {
    curr[key] = curr[key] || {}
    curr = curr[key]
   }
  })
 }
 return nested
}

// 3. vanilla-extract 코드 생성
function generateThemeCode(nested: object) {
 return `import { createGlobalTheme } from '@vanilla-extract/css';

export const vars = createGlobalTheme(':root', ${JSON.stringify(nested, null, 2)});
`
}

⚙️ 스크립트 실행 예시

import fs from 'fs'

const raw = JSON.parse(fs.readFileSync('./tokens.json', 'utf-8'))
const flat = flattenTokens(raw)
const nested = nestTokens(flat)
const output = generateThemeCode(nested)

fs.writeFileSync('./styles/tokens.css.ts', output)

🛠 변환 결과 및 실제 적용 방식

이 스크립트를 통해 매번 tokens.json만 갱신하면 tokens.css.ts 파일이 자동으로 생성되고, 아래처럼 프로젝트 코드에 바로 사용할 수 있습니다. 또한 실제 사용 과정에서는 다음과 같은 흐름을 따르게 됩니다:

import { vars } from './tokens.css.ts'

style({
 backgroundColor: vars.color.primary,
})

디자인 토큰을 일관성 있게 유지할 수 있었고,
수정사항도 쉽게 반영할 수 있어 디자인 시스템 유지보수 비용을 줄일 수 있었습니다.


실제 사용 흐름 요약

  1. 디자이너는 Figma 내 Tokens Studio 플러그인에서 토큰을 설정하고 tokens.json으로 export합니다.
  2. 프론트엔드 개발자는 해당 파일을 /design-tokens/tokens.json 위치에 복사하거나 덮어씁니다.
  3. npm run generate:tokens 명령어를 실행하면 tokens.css.ts 파일이 자동으로 생성됩니다.
  4. 프로젝트 내에서는 아래처럼 vars를 불러와 바로 사용할 수 있습니다:
import { vars } from '@/styles/tokens.css'

export const buttonStyle = style({
 backgroundColor: vars.color.primary,
 padding: vars.spacing.medium,
})
  1. 디자이너가 토큰을 변경하더라도 프론트엔드는 토큰 파일만 업데이트하면 되므로, 스타일 반영 주기가 훨씬 짧아졌습니다.

이처럼 디자인 시스템이 점점 확장될수록 토큰 기반 스타일 관리가 더욱 유리하며, 컴포넌트 재사용성과 유지보수성을 높이는 데 큰 역할을 합니다.


컴포넌트에 토큰을 적용하기 전과 후의 UI 예시입니다. 색상, 간격 등이 토큰을 통해 일관되게 적용된 모습을 확인할 수 있습니다.

실제로 아래와 같은 방식으로 스타일에 토큰을 활용하고 있습니다:

변경 전 (하드코딩된 스타일)변경 후 (디자인 토큰 적용)
backgroundColor: '#FF0000'backgroundColor: vars.color.primary
padding: '16px'padding: vars.spacing.medium

✅ 컴포넌트 전/후 비교 예시

Before (디자인 시스템 적용 전)

const Button = () => (
 <button style={{ backgroundColor: '#FF0000', padding: '16px' }}>
  Click me
 </button>
)

After (디자인 토큰 적용 후)

import { vars } from '@/styles/tokens.css'

const Button = () => (
 <button
  className={style({
   backgroundColor: vars.color.primary,
   padding: vars.spacing.medium,
  })}
 >
  Click me
 </button>
)

이처럼 컴포넌트 스타일을 디자인 토큰으로 일원화하면 유지보수 시 변경 범위가 줄어들고, 디자이너와 개발자 간의 커뮤니케이션도 훨씬 수월해졌습니다.

토큰 값이 수정되면, 다시 tokens.json을 반영하고 변환 스크립트를 실행한 후 바로 반영된 결과를 확인할 수 있어 워크플로우가 훨씬 유연해졌습니다.

🤖 GitHub Actions 기반 자동화 도입

추후, 개인적으로 GitHub Actions를 활용해
디자인팀이 tokens.json을 갱신할 때마다 tokens.css.ts가 자동 생성되도록 개선해보았습니다.

# .github/workflows/generate-tokens.yml
name: Generate Tokens

on:
  push:
    paths:
      - 'design-tokens/tokens.json'

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v3
      - uses: actions/setup-node@v3
        with:
          node-version: 18
      - run: npm ci
      - run: npm run generate:tokens
      - run: git config user.name 'github-actions'
      - run: git config user.email 'actions@github.com'
      - run: git add styles/tokens.css.ts
      - run: git commit -m 'chore: auto generate tokens' || echo "No changes"
      - run: git push

이렇게 자동화하고 나니 디자인 시스템이 더 유연하게 유지관리되고,
디자인-개발 간 협업 비용도 줄어드는 효과를 체감할 수 있었습니다.

✅ 마무리 및 회고

  • Tokens Studio를 통해 디자이너가 관리한 디자인 토큰을
  • 간단한 Node 스크립트로 vanilla-extract 코드로 변환하고
  • GitHub Actions로 자동화까지 확장한 경험을 통해

실제 디자인 시스템 구축/유지보수 시 발생하는 문제들을 자연스럽게 해결할 수 있었습니다.

디자인-개발 협업을 체계화하고 싶은 팀이라면 Tokens Studio와 vanilla-extract 조합을 적극 추천드립니다.

향후에는 Tokens Studio의 API나 Style Dictionary 기반의 확장도 검토하고 있습니다.

참고