





















최근 프로젝트에 Storybook을 도입하면서 덩달아 고민하게 되었던 것이 SCSS 변수를 JS에서 공유하는 문제였다.
혹자는 굳이 그런짓(?)을 왜 하려고 하느냐 할 수도 있겠으나, 현재 올려둔
Storybook Sample에 utils
항목처럼 디자이너가 정의해 둔 색상, 글꼴 등을 일목요연하게 볼 수 있도록 정리해 두고
싶어서였다. (물론, 일이 그렇게 커질지는 알지 못했다 ㅋㅋ)
처음에는 SCSS에서 :export { … }를 이용하는 방법도 생각해봤지만 변수를 일일이 두 번
작성하는 것도 불편할 뿐더러, map은 도무지 방법을 모르겠더라.
구글링에서 발견한 건 map을 수동으로 풀어서 작성하는 방법이었는데, nested map까지 있는 상황에서 이건 너무 비효율적인 방법이라 생각되어서 과감히 버리기로 했다.
그리고 다시 시도한 방법이 SCSS를 JS로 변환시키는 방법이었다. (이미 SCSS를 먼저 작성했기
때문에 이 방법을 우선으로 선택했다.) sass-to-js, sass-to-json,
node-sass-json-impoter등 온갖 패키지들을 찾아보고 적용해보고 했으나… nested map이
계속 발목을 잡았다.
왜 때문에 다들 nested map은 고려가 안되어있는것인지… ㅠ
계속 된 실패에 다시 눈을 돌려 이번에는 js에 먼저 변수를 작성하고 SCSS로 변환시키는 방법을 찾아보기 시작했다. js-to-scss, json-to-scss, json-sass, json-to-sass-map 등을 찾아보고 적용해보고 했지만, 역시 내가 원하는 형태의 결과물을 만들어주는 패키지는 존재하지 않았다. 하아…
배열을 list로, object를 map으로, nested object를 nested map으로 변환시켜야 하는데 이 모든 조건을 만족하는 패키지를 찾기 어려웠고 그마나 지원하는 걸 겨우 찾으면 이번에는 무조건 root key가 만들어지는 그런…
처음에는 그나마 가능한 패키지에 기이한 형태(?)로 JSON 파일을 만들어 적용했다. (nested map이 정상적으로 출력되게 하기 위해 JSON key값을 이중 따옴표로 묶어버리는…)
당시에는 프로젝트 일정 상 고민할 시간이 없어서 그걸로 만족했지만, 이제는 시간이 많으니까(?) storybook 관련 포스팅하는 김에 결국 그냥 내가 만들기로 했다. 내 입맛에 맞는 패키지가 없으면 방법이 없다. 목마른 놈이 우물을 팔 수 밖에.
그나마 내가 생각하는 가장 근접한 형태의 패키지를 이눔아는 어떻게 만들었나 뜯어보고 참고해서 한 땀 한 땀 만들기 시작했다. 대략 4시간 정도(?)를 투자하니 당장 돌아가는 결과물은 나오더라. (이럴거면 처음부터 그냥 만들걸… 왜 패키지 찾고 설치하고 적용해보고 지우고 반복하느라 며칠을 날려먹은 것인지… ㅠ)
만들어놓고 storybook에 scss 변수로 정의한 값들을 불러다가 controls option으로 적용시키니 잘 된다. 이제야 만족스럽다.
이걸 위해 그 많은 시간을 보냈구나 흑흑…
만들고 나니 사실 별거 없더라. 1depth key에 '$'를 접두사로 붙이고, 값들은 배열은 list로, 객체는 map으로, 그 외의 것들은 리터럴 값 그대로 처리하고 nested 된 것들을 처리하기 위해 재귀적으로 처리하는 방법이면 충분했다.
예를 들어, 다음과 같은 값을 변환시키면
const white = '#fff';
const text = {
size: {
base: '16px',
large: '24px',
},
weight: {
regular: 400,
bold: 600,
},
};
다음 코드를 가진 scss 파일이 생성된다.
$white: #fff;
$text: ('size': ('base': 16px,'large': 24px),'weight': ('regular': 400,'bold': 600));
물론, 별다른 옵션을 부여하지 않고 단순히 변환만 시키는 것이고 변수 값에 대한 정의만 처리하는 거라 굳이 들여쓰기 등은 고려하지 않아도 괜찮다고 생각했기 때문에 내 입맛에는 충분히 맞다 ㅋㅋ
코드 전체를 공개하기는 창피하니… 핵심 코드만 올려보면
const getSCSS = (entry) => {
if (Array.isArray(entry)) {
return `(${entry.join(', ')})`;
} else if (entry instanceof Object) {
const temp = reduceRight(entry, (acc, val, key) => {
return `'${key}': ${getSCSS(val)},` + acc;
}, '').replace(/,(\s|\S)?$/g, '');
return `(${temp})`;
} else {
return entry;
}
}
그냥 이 정도다. (정말로 단순하게 만들었…)
가장 잘 지원하지만 (옵션도 빵빵한?) root key가 무조건 생성되는 패키지 github에 나와 같이 root key를 제외시키는 방법을 묻는 사용자가 있었는데, 얼마전 거기에 혹 해결했는지를 묻는 코멘트를 달았더니 해당 패키지 주인(?)이 이 요구사항을 받아들이는 걸 고민해보겠다고 답글이 달렸다!! 만쉐!!
그나저나… 이번에 포스팅 한 것들 회사 프로젝트에도 역으로 다시 적용해야 하는데… 이건 또 언제하나… 하하…
此内容由惯性聚合(RSS阅读器)自动聚合整理,仅供阅读参考。 原文来自 — 版权归原作者所有。