Photo by Hal Gatewood on Unsplash
[FE쥬니어의 Design System] 01. Personal Design System, `Storybook`, `Vite`로 환경 설정하기
Storybook
+React
로 DesignSystem/ComponentLibrary 만드는 튜토리얼은 이미 블로그, Youtube에 널려있다Airbnb, GitHub 등 개발팀에서 만든
Storybook
은 물론이고, GitHub가 공개된 경우도 있다 (아래 references 참고)
Motivation
요즘 차트 컴포넌트 구현을
Storybook
기반으로 진행중(zum-stock-line-stories)인데, 생각보다 엄청난 생산성 향상을 맛보며 재미를 느낌- 별도의 페이지를 구성하지 않아도 컴포넌트 구현 결과를 HMR로 볼 수 있음 (이건 당연한 거!)
- 개발자 도구 들어가서 ➡️ 메뉴를 클릭하고 ➡️ 뭔가를 조정해야 하는 수고들을 덜어줌!
- Measure & Outline: 컴포넌트 사이즈, 아웃라인 등 확인 가능
- Viewport: mobile viewport preset 가능
- Docs로 한번에 여러 렌더링 상태 확인 가능
- addon 생태계가 활성화되어있음
- Jest, Cypress 등 다양한 툴과의 통합
Storybook
을 따로 빌드, 배포 가능- 현재까지 개발 진행상황 공유 가능
색상, 크기, 데이터값 등 속성들을
controls
로 바꿔서 바로 확인 가능 👉 디자이너/기획자와의 보다 빠른 소통 가능할 듯?!
거의 1년째 방치 중인 개인 블로그는 물론이고, 셋팅만 열심히 했던 개인 프로젝트들 빠르게 완성도를 높이기 위해 디자인 시스템을 만들어보자
- 단기적으로 1년 정도는 컴포넌트 라이브러리 구축 위주 방향이 될 듯, 아무래도 디자인/UX에 대한 지식이 없기 때문
- 장기 프로젝트로 디자인 시스템으로 발전시켜 나가자
- 회사 업무에 적용하기 전 다양한 테스트를 위한 도구로 사용할 수 있음
- 하고 싶은 거 다하자!!
- 얼마전
당근마켓 프론트엔드 개발자 라이브 QnA 세션
에서 얻은 인사이트- 회사 코드를 포트폴리오로 사용할 수는 없으니 유사한 구현 내용을 개인 GitHub에 올려놓는 것도 방법이다!
Design Patterns & Techs I Used
Atomic Design Pattern & Monorepo
- 기본적으로 컴포넌트 라이브러리이기 때문에, atoms, molecules, organisms 정도까지만 하면 될 듯
- 이 단계에 따라 각각의 패키지 구성;
atoms/button
,atoms/text
등
- 이 단계에 따라 각각의 패키지 구성;
- 디자인 시스템 중 단일 Repo로 구성하는 경우도 많지만, 추후
Svelte
,Solid
등 다양한 프레임워크/라이브러리 및rollup
,esbuild
등 다양한 빌드 툴 사용해볼 수 있도록 Monorepo로 구성 Yarn berry
PnP 모드에서 workspace 플러그인 사용getit-ui/ ┣ atoms/ # atom packages ┃ ┣ button/ ┃ ┃ ┣ src/ ┃ ┃ ┣ package.json ┃ ┃ ┣ tsconfig.json ┃ ┃ ┣ tsconfig.node.json ┃ ┃ ┗ vite.config.ts ┃ ┗ text/ ┃ ┣ src/ ┃ ┣ package.json ┃ ┣ tsconfig.json ┃ ┣ tsconfig.node.json ┃ ┗ vite.config.ts ┣ molecules/ # molecules packages ┣ stories/ # storybook package ┃ ┣ .storybook/ ┃ ┃ ┣ main.ts ┃ ┃ ┗ preview.ts ┃ ┣ src/ ┃ ┃ ┣ Introduction.stories.mdx ┃ ┃ ┣ react-app-env.d.ts ┃ ┃ ┗ setupTests.ts ┃ ┣ .gitignore ┃ ┣ package.json ┃ ┗ tsconfig.json ┃ # root configs ┣ .editorconfig ┣ .eslintignore ┣ .eslintrc.js ┣ .gitignore ┣ .pnp.cjs ┣ .pnp.loader.mjs ┣ .prettierrc ┣ .yarnrc.yml ┣ Dockerfile.dev ┣ README.md ┣ package.json ┣ tsconfig.components.json ┣ tsconfig.json ┗ yarn.lock
- 기본적으로 컴포넌트 라이브러리이기 때문에, atoms, molecules, organisms 정도까지만 하면 될 듯
Storybook
- 구현된 컴포넌트들 시각 테스트
- 회귀, E2E 등 다양한 테스트, 문서화
- 별도의 전용 패키지(
stories
)를 만들어서 실행
Vite
+React
- 일단은
React
컴포넌트 위주 구성 Vite
라이브러리 모드로 빌드
- 일단은
CSS(SCSS) Module
- 개인적으로
CSS
를 활용할 때 가장 선호하는 방식 styled-component
/emotion
보다CSS
그 자체를 사용하면서,JS
방식으로className
적용을 컨트롤 할 수 있음- Real-world CSS vs. CSS-in-JS performance comparison; 성능 면에서
CSS-in-JS
가 좋지 않다는 이야기도..
- Real-world CSS vs. CSS-in-JS performance comparison; 성능 면에서
특히 이번 대선 차트 구현할 때 이점을 크게 맛보게 되었는데, IE에서
grid(-ms-grid)
가 생각대로 컨트롤 하기 어렵다는 점 때문에, IE 전용 클래스를 따로 만들어userAgent
에 따라 분기처리해 적용함// 모던 브라우저 클래스 .line { @extend .line-default; display: grid; grid-template-columns: 13px minmax(36px, auto) minmax(46px, auto); } // IE 전용 클래스 .line-ie { @extend .line-default; display: -ms-flexbox; div { margin-right: 5px; } p { width: 47px; } }
// line 컴포넌트 (VanillaJS) classNames: [IS_IE ? styles['line-ie'] : styles['line'], ...classNames]; // ...
- 개인적으로
Problem & Solutions
Vite
라이브러리 모드 빌드 -> 모노레포에서 사용시 CSS
를 가져오지 않는 문제?
Problem
- HTML 파일을 생성하는 게 아닌, JS로 컴포넌트 렌더링 로직만 만드는 것
- 일반적인 페이지를 빌드하는 경우,
Webpack
등 번들러가HTML
에link
태그를 자동삽입하고, 렌더링시 스타일을 반영함 - 그런데 라이브러리 모드에서 빌드시 JS에
CSS Module
클래스명만 가져오고, CSS 파일(import 'styles.css'
)을 가져오지 않음 다른 패키지에서 사용시 스타일 적용 안됨
Solution
vite-plugin-css-injected-by-js 사용
vite.config.ts
에서 플러그인 추가
import cssInject from 'vite-plugin-css-injected-by-js'; export default defineConfig({ plugins: [react(), cssInject()], /** 기타 설정 */ });
빌드시 아래와 같이
style
태그 생성 로직을 생성, 빌드된 파일 상단에 삽입- 동일 컴포넌트를 여러개 호출하더라도 하나의
style
태그만 생성함
- 근데 이렇게 되면
CSS-in-JS
를 쓰는 방식과 성능면에서 차이가 없어질 수도 있지 않을까하는 의문이..
- 동일 컴포넌트를 여러개 호출하더라도 하나의
Storybook 전용 stories
패키지에서 Vite 사용시 빌드 오류
Problem
- 현재 각각의 컴포넌트 패키지 +
Storybook
전용 패키지가 있는 상황 - 컴포넌트 패키지들이 이미
Vite
를 사용하고 있고, (왠만하면)Webpack
보다는Vite
가 빌드 타임이 짧기 때문에 Vite 빌더를 써보려고 시도 함 - 문제는
Yarn berry
환경에서Vite
빌더가 의존성 제대로 못 찾고 빌드가 안됨- https://github.com/eirslett/storybook-builder-vite/issues/141; '22.3.2. 현재 아직 해결되지 않은 이슈😭
Solution
- 아쉽지만
stories
패키지만 빌더를CRA
+Webpack5
로 지정해 사용 중 - 내 생각에 베스트는,
Storybook
전용 패키지를 별도로 분리하지 않고, 각각의 컴포넌트 패키지에서story
파일를 만들어서 root에서 preview를 실행하도록 하는 것- 다만 Monorepo 구조의 root에서는 뭔가 설정하기가 까다로움
Storybook
자체가 빈 프로젝트에서 실행하는 게 아니기 때문인듯Storybook needs to be installed into a project that is already set up with a framework. It will not work on an empty project.(https://storybook.js.org/docs/react/get-started/install)
- 좀더 연구해봐야 할 듯..?
- 한편 패키지를 분리했기 때문에, 다른 패키지에서
import
했을 때 잘 되는지 확인 할 수 있다는 장점은 있는 듯
- 다만 Monorepo 구조의 root에서는 뭔가 설정하기가 까다로움
References
Design System Overview
Real-World Cases
- awesome-storybook
- awesome-design-systems
- 쿠팡: 이커머스에 최적화된 디자인 시스템, RDS - 주로 UX 디자인에 대한 이야기
- 토스
- TDS로 UI 쌓기 : 그 많던 코드는 누가 다 치웠을까? - 토스 안드로이드
- Do more, with less. - 디자인 시스템, 그다음은? - 토스 FE
- 배민: [6월 우아한테크세미나] 디자인시스템이 가져온 변화 - 배민 FE
- LINE: 개발자와 디자이너의 협업을 위한 LINE 디자인 시스템, LDS 소개
- SOCAR: [SOCAR FRAME 만들기 #1] 쏘카의 디자인 시스템 맛보기1~5
- 카카오: FE개발자의 성장 스토리 03 : 카카오 어드민 UI 컴포넌트를 모노레포로 개발하여 얻은 것들
- AirBnB: Building (And Re-Building) the Airbnb Design System | Maja Wichrowska & Tae Kim - 2016년 이후 AirBnB에서 React 기반 디자인 시스템을 만들게 된 배경