Style Dictionary 사용 방법 정리(feat. 피그마 디자인 토큰 가공하기)
이번 글에서는 Style Dictionary가 무엇인지와 사용 방법을 간단히 정리하고자 한다
1. 디자인 시스템과 Style Dictionary
Style Dictionary가 무엇인지 알기 전에, 디자인 시스템이 무엇인지 알 필요성이 있다.
쉽게 설명하자면, 디자인 시스템은 디자인과 개발을 좀 더 쉽게, 일관되게, 효율적으로 만들고 관리하는 방법이라고 할 수 있다.
그러면 Style Dictionary와 디자인 시스템이 무슨 상관이 있는 걸까?
Style Dictionary는 디자인 시스템에서 사용되는 디자인 토큰을 관리하고 적용하는 오픈 소스이다.
* 디자인 토큰: 디자인에서 사용되는 요소(글꼴, 색상, 그림자 등)을 표준화 한 요소
그럼 디자인 토큰이 왜 필요한 걸까?
디자인 토큰은 css변수를 설정하는 것과 같은 이치라고 볼 수 있다.
예를 들어, 본문의 color를 #f5f5f5라고 정해놨다고 하자.
만약 우리가 본문이 있는 곳마다 color: #f5f5f5라고 작성을 해놓았는데
맙소사, 갑자기 본문의 color가 #f6f6f6으로 바뀌어버리면 우리는 #f5f5f5가 있는 곳마다 일일이 다 바꿔줘야 할 것이다.
하지만 우리가 mainColor: #f5f5f5 라고 정해놓고 color를 mainColor라고 지정해놨으면
mainColor 색상만 바꾸면 쉽게 전체 색상을 바꿀 수 있을 것이다.
2. 피그마의 디자인 토큰 추출
https://www.figma.com/community/file/876022745968684318
부트스트랩의 figma를 보며 디자인 토큰을 추출하고, style Dictionary로 가공해보자
피그마에서 디자인 토큰을 추출할 수 있는 곳은 styles와 variables 두 종류가 있다.
보통은 Local styles 많이 이용한다. (위 Bootstrap도 styles를 이용하고 있다)
피그마를 열어서 우측 패널을 보면 Local styles라고 Text style, color 등을 정의해 둔 부분이 있다.
우리는 저 요소를 json으로 추출하여 style dictionary로 가공 할 것이다.
styles를 json형태로 추출하는 방법은 플러그인을 이용하는 방법이 제일 간단하다 !
좌측 상단 패널에서 저 아이콘을 클릭하면 플러그인을 검색하고, 사용할 수 있다.
token이라고 검색하면 여러 플러그인들이 많이 나오는데, 우리는 저 노란색 아이콘을 가진 Design Tokens를 이용할 것이다.
클릭해서 export design token files를 누르면 아래 창이 뜬다
여기서 Figma Variables(BETA)를 제외하고는 styles에 정의한 부분들이다.
추출해서 json 파일을 보면 아래와 같다.
{
"color": {
"primary": {
"color": {
"description": "",
"type": "color",
"value": "#7749f8ff",
"blendMode": "normal",
"extensions": {
"org.lukasoppermann.figmaDesignTokens": {
"styleId": "S:a4a48d4ec66ef0f05bfa6d36fcb36361ca79ab4c,",
"exportKey": "color"
}
}
},
"color dark": {
"description": "",
"type": "color",
"value": "#5227ccff",
"blendMode": "normal",
"extensions": {
"org.lukasoppermann.figmaDesignTokens": {
"styleId": "S:0a2a37c25b70236776ff632aa7ff581a98b60a02,",
"exportKey": "color"
}
}
},
...
}
}
color를 살펴보면 ...
primary라고 정의한 color가 value에 #7749f8ff 형태로 들어가 있는 것을 볼 수 있다.
3. Style Dictionary로 디자인 토큰을 CSS 변수 형태로 변환
사실 피그마 플러그인을 잘 찾아보면, styles -> css variables 로 바꿔주는 플러그인이 많이 있다.
하지만 해당 플러그인의 단점은 변수 이름이나 나오는 포맷을 커스텀하기 힘들다는 점이다.
style dictionary를 사용하면, 우리가 원하는 형태로 filter하고, format을 정하여 원하는 형태로 변환할 수 있다.
자! 새 프로젝트를 만들어서 style dictionary를 설치해 주자
$ npm install -D style-dictionary
설치한 후, 우리가 직접 config 파일을 만들어서 가공할 형태를 정의해줘야 한다
transformToken.js를 만들어서(파일 이름 자유) 아래 코드를 복붙 해주자 !
const StyleDictionary = require('style-dictionary').extend({
source: ['tokens/**/*.json'],
platforms: {
scss: {
transformGroup: 'scss',
buildPath: 'build/',
files: [{
destination: 'variables.scss',
format: 'scss/variables'
}]
}
// ...
}
});
StyleDictionary.buildAllPlatforms();
위 코드가 node에서 가장 기본적인 형태다. (https://amzn.github.io/style-dictionary/#/quick_start?id=node)
위 코드를 간략하게 설명하자면,,,
- source : 디자인 토큰이 저장된 장소
- platforms : 디자인 토큰을 변환할 형태를 정의한 부분 (플랫폼 이름: 객체 형태)
- 위 코드에선 scss라는 이름을 가지고 내부 속성에 따라 변환한다.
- transformGroup : color, size, time 등 해당 속성들을 어떻게 변환할 껀지 한꺼번에 정의한 형태
- buildPath : 어디에 변환되어 저장될 건지
- files
- destination : 변환될 파일 이름
- format: 변환될 형태를 정의한 포맷
Style Dictionary 공식 문서를 살펴보면 모든 속성에 대해 아주 자세하게 설명되어 있으니 참고하시길..
https://amzn.github.io/style-dictionary/#/
우리는 bootstrap token을 css변수 형태로 변환할 꺼니까 아래처럼 코드를 수정해준다.
const StyleDictionaryExtended = require('style-dictionary').extend({
source: ['./bootstrap-token.json'],
platforms: {
css: {
transformGroup: 'css',
buildPath: 'build/',
files: [{
destination: 'variables.css',
format: 'css/variables'
}]
}
// ...
}
});
StyleDictionaryExtended.buildAllPlatforms();
transformToken.js을 실행해주면 ! ($ node transformToken.js)
build/css/variables.css파일이 생성된다.
/**
* Do not edit directly
* Generated on Sat, 23 Sep 2023 08:47:51 GMT
*/
:root {
--color-primary-color: #7749f8;
--color-primary-color-dark: #5227cc;
--color-primary-light: #ebe5fc;
--color-secondary-color: #6c757d;
--color-secondary-dark-color: #54595e;
--color-secondary-light-color: #abb5be;
--color-status-color-success: #28a745;
--color-status-color-danger: #dc3545;
--color-status-color-warning: #ffc107;
--color-status-color-info: #17a2b8;
--color-gray-100: #f8f9fa;
...
}
style dictionary가 정의해둔 포맷으로 변환되어 나온다.
하지만 우리는 이 포맷이 아니라, 우리가 원하는 형태로 포맷팅하여 변환할 것이다.
4. 실습) 변수이름 바꾸기 (RegisterFormat)
변수 이름을 바꿀려면 Styledictionary.registerFormat 메서드를 이용을 해야한다.
https://amzn.github.io/style-dictionary/#/api?id=registerformat
StyleDictionary.registerFormat({
name: 'json',
formatter: function({dictionary, platform, options, file}) {
return JSON.stringify(dictionary.tokens, null, 2);
}
})
위 형태는 style dictionary의 registerFormat 사용 예제이다.
- name : config에 작성한 format 값에 들어갈 이름 (해당 이름을 참조하게 됨)
- formatter: 우리가 변환할 형태를 커스텀할 수 있는 부분, return하는 내용으로 결과물에 보이게 된다.
그러면 이제 대충 사용법을 알았으니, CSS 변수 이름을 바꿔보자!
--color-primary-color 를 primary로 보일 수 있게 formatter을 정의할 것이다.
그러면, 우리의 customFormatter을 작성해보자
const StyleDictionary = require('style-dictionary');
StyleDictionary.registerFormat({
name: 'customCss',
formatter: ({dictionary, options}) => {
console.log(dictionary);
return "";
},
});
위 형태로 작성해주고, 우리가 아까 작성한 StyleDictionaryExtended의 format 이름을 customCss로 바꿔주자
(css/variables -> customCss)
그리고, 다시 TransformToken.js를 실행시켜주면?
styleDictionary가 파싱한 형태의 dictionary를 볼 수 있다.
styledictionary.allProperties의 내용을 보면, styledictionary가 변수이름을 어떻게 설정했는지 알 수 있다.
{
description: '',
type: 'color',
value: '#7749f8',
blendMode: 'normal',
extensions: { 'org.lukasoppermann.figmaDesignTokens': [Object] },
filePath: './bootstrap-token.json',
isSource: true,
original: {
description: '',
type: 'color',
value: '#7749f8ff',
blendMode: 'normal',
extensions: [Object]
},
name: 'color-primary-color',
attributes: { category: 'color', type: 'primary', item: 'color' },
path: [ 'color', 'primary', 'color' ]
},
name과 path 속성을 보면, styledictionary에서는 단순히 변수이름을 path를 케밥케이스로 이어준 것이라는 걸 확인할 수 있다.
그러면, 우리가 primary라는 key 이름을 얻을려면, path 배열에서 color를 제외하고 케밥 케이스로 이어주면 되겠다.
그리고 value는 StyleDictionary가 잘 파싱하여 value라는 속성에 color값을 잘 넣어주었기에 해당 값을 활용하면 된다.
위 내용 바탕으로, registerFormat을 정의해주자.
StyleDictionary.registerFormat({
name: 'customCss',
formatter: function({dictionary, platform, options, file}) {
const variablesObject = dictionary.allProperties.reduce((acc,{value,type, path}) => {
// type에 따라 어떻게 파싱할 껀지 처리 해주면 됨 ! (현재는 color에 대해서만 파싱)
if(type === 'color') {
const key = path
.map((name) => name.replace('color', '').trim())
.filter((name) => name.length !== 0).join("-");
acc[key] = value;
}
return acc;
}, {});
const cssString = Object.entries(variablesObject)
.map(([key, value]) => ` --${key}: ${value};`)
.join("\n");
return `:root {\n${cssString}\n}`;
}
})
사실 파싱로직을 작성하는 건 알고리즘?문제 푸는거랑 비슷한거라...
자신이 알아서 어떤 형태로 나오게 할건지 정의하면 된다.
위 형태로 정의한 registerFormat을 이용해 styleDictionary를 실행시켜주면,
:root {
--primary: #7749f8;
--primary-dark: #5227cc;
--primary-light: #ebe5fc;
--secondary: #6c757d;
--secondary-dark: #54595e;
--secondary-light: #abb5be;
--status-success: #28a745;
...
}
이런 형태로 파싱되어 나오게 된다. !
registerFormat외에도,
https://amzn.github.io/style-dictionary/#/api
해당 api 문서를 보면, 파일 헤더를 정의하거나 템플릿을 정의한다던가 등의 action이 가능하다.
그리고 우리가 처음 bootStrap 피그마에서 디자인 토큰을 추출한 플러그인 깃헙에 가보면
https://github.com/lukasoppermann/design-tokens/blob/main/examples/build.js
StyleDictionary를 이용한 예제 코드들이 있다.
코드들을 참고해서, 어떤 형태로 파싱코드를 작성하는지 참고 할 수있다!
이번 글은 여기 까지 !!!!
궁금한 점 있으면 언제든지 댓글 달아주세요 :)