1. 서론
배경
프론트엔드 개발자가 스토리북을 사용하는 이유는 크게 두가지로 생각합니다.
첫번째로는 컴포넌트의 Story를 작성하여 컴포넌트에 대한 document화를 간편하게 처리할 수 있다는 점, 두번째로는 컴포넌트의 재사용성을 높일수 있다는 점 입니다.
대부분의 프론트엔드 개발자는 컴포넌트를 개발할때 이 컴포넌트를 해당 프로젝트 뿐만 아니라
여러 프로젝트에서도 재사용할수 있도록 하기위해 개발을 진행하는 경우가 많습니다.
하지만 이 컴포넌트들은 기존 프로젝트의 라이브러리에 의존성을 가진 기능들이 들어가있는 경우가 많기 때문에 실제로 해당 컴포넌트를 다른 프로젝트에 import하여 사용할때 디자인이 깨지거나 기능이 동작하지 않는 문제가 발생하는 경우가 생깁니다.
하지만 Storybook을 이용하여 컴포넌트를 개발한다면 기존 프로젝트의 의존성을 없에고 개별의 기능만을 이용하여 재사용성이 높은 컴포넌트를 개발할 수 있게 됩니다.
목적
스토리북을 이용하여 현재 NEB의 컴포넌트를 문서화 하고 각 컴포넌트의 재사용성을 높이는 것이 목적입니다.
2. 선행작업
Storybook 설치
설치환경의 노드버전은 node v12.19로 진행을 하였습니다.
npm 5.2^ 부터 추가된 npx를 사용하여 간단하게 storybook을 설치할 수 있습니다.
현재 사용중인 React Project root에서 터미널을 실행한 뒤 아래와 같이 스크립트를 실행해줍시다.
실행이 완료되었다면 storybook 설치가 완료된것 입니다.
그럼 이후 아래 명령어를 이용하여 storybook을 실행해봅시다.
결과화면
최초 설치 시 기본적인 mdx example과 component stories example 을 추가해줍니다.
src/stories에 해당 stories 파일들과 example 컴포넌트를 확인하여 내용을 확인할 수 있습니다.
addon 설치
기본적인 storybook 설치는 완료되었지만 storybook에는 큰 기능을 가진 addon들이 많이 존재합니다.
sb init으로 설치한 경우 자동으로 필수적인 addon들을 설치해주지만 knobs같은 기능들은 포함하지 않기 때문에 따로 설치를 진행해야할 필요가 있습니다.
** knobs addon 의 경우 스토리북 화면내에서 컴포넌트에 동적으로 prop을 넘겨 처리할수 있는 기능을 가지고 있습니다.
** storybook v6.2^ 경우 controls addon을 포함하여 기본적인 동적인 동작을 수행할 수 있지만 완벽한 동적 처리를 원하는 경우 knobs이 강제됩니다.
설치된 addon을 추가하기 위해 .storybook/main.js에서 addons 내용을 수정한뒤 다시 실행해줍니다.
** essentials addon은 여러 필수 addon들을 포함하고있습니다. addon에 대한 설명은 링크 에서 확인이 가능합니다.
결과화면
정상적으로 설치가 완료되었다면 아래와 같이 addon탭에 knobs가 표시될 것 입니다.
** addon탭이 표시가 안된다면 키보드 shortcut A 키를 눌러봅시다.
** storybook 기본 설정이 변경된 경우에는 꼭 재실행을 해주어야 내용이 반영됩니다.
main.js 설정(webpack 설정)
storybook은 실제 프로젝트와 분리된 환경을 가지기 때문에 작업된 컴포넌트가 필수적으로 의존성을 가져야하는 경우 이에 대한 설정을 추가해줄 필요가 있습니다. neb의 경우 대부분의 컴포넌트들은 ant.design과 ant-design-pro에 의존성을 가지기 때문에 이러한 부분을 따로 설정을 해주어야 하는데 이러한 설정은 root/.storybook/main.js 파일에서 설정을 해줄 수 있습니다.
우선 ant-design-pro의 기본 스타일은 less형식을 사용하기 때문에 webpack의 rule을 추가해주는 작업이 필요합니다.
less를 사용할 style loader들을 설치해줍니다.
설치가 완료되었다면 main.js에 webpack 설정을 아래와 같이 수정해줍시다.
** 만약 sass를 사용하는 경우 그에 따른 loader를 추가해주셔야합니다.
** 이후 less import의 경우 preview 예제에서 진행하겠습니다.
그리고 현재 설치된 node_modules를 읽을 수 있도록 modules 경로를 추가해줍시다.
마지막으로 현재 프로젝트내에서 사용되는 alias들을 추가해줍시다.
현재 ant-design-pro에서는 @경로를 src 경로로 사용중이고 그외 umi library의 core를 @@경로로 사용하고 있습니다.
이렇게 기본적인 설정이 완료되었습니다.
preview 설정
preview.js는 기본 프로젝트의 app 파일과 같은 개념으로 생각해주시면됩니다.
가장먼저 Story들이 로드되고 해당 컴포넌트를 global 처리를 간편하게 해줄 수 있습니다.
우선 story를 감쌀 글로벌 스타일을 작성해줍시다.
neb는 styled-components를 사용하기 때문에 styled components 기반으로 스타일을 작성하였습니다.
** neb의 글로벌 스타일을 임포트하게 되면 기본 width, height 설정으로 인해 Story 화면이 꺠지는 문제가 발생하므로 unset 처리를 해주었습니다.
** 컴포넌트를 표시할 때 간격을 주거나 투명한 컴포넌트를 위해 개별의 class를 정의해주었습니다.
** neb와 개별로 실행되는 서버이기 때문에 public assets을 읽어오지 못하여 위처럼 폰트를 직접 추가해주었습니다.
이제 해당 GlobalStyle을 이용하여 preview에 decorators를 추가해줍니다.
ant-design과 neb의 style들과 ant-design-pro에서 사용하는 Router, intl Provider를 여기서 함께 추가하도록 하겠습니다.
** 최초 preview.js파일에는 parameters만 있을것입니다. 이부분은 공용으로 들어갈 arg parameter를 사용하는듯 하지만 실제로 사용되는 영역은 없으므로 지워도 상관이 없습니다.
** storybook 실행시 만약 less 파일 임포트로 인한 오류가 발생한 경우 main.js 쪽 webpackFinal 설정에 문제가 있는지를 확인해줍시다.
3. Story
Story 추가
storybook의 컴포넌트는 story단위로 추가가 가능합니다.
각 story에 설정된 형식대로 Storybook을 구성하게 됩니다.
story를 추가하는 방식은 간단합니다.
생성한 컴포넌트 경로 혹은 새로운 경로에 componentName.stories.tsx or jsx 로 추가해주는 것 입니다.
자동으로 stories가 들어간 파일을 인식하여 story로 추가해주는데 이러한 포맷에 대한 설정은 main.js의 stories 에서 설정이 가능합니다.
Story 작성
Story의 구성은 2가지로 나뉩니다.
첫번째로 Story Meta 정보, 기본적인 스토리의 경로, title을 설정하고 컴포넌트의 props를 읽어 doc을 구성 및 하위 story에 들어갈 공통 props를 설정해줄 수 있습니다.
아래는 neb의 Button 컴포넌트를 활용한 예제 입니다.
** title은 / 값을 기준으로 split하여 storybook doc의 서브메뉴를 추가해줍니다.
** argTypes를 이용하여 스토리내에서 공통으로 사용될 Props를 설정해줄 수 있습니다.
결과화면
스토리 메타의 작성이 완료되었다면 두번째 Story 구성요소인 스토리 컴포넌트를 작성할 차례입니다.
현재 예제의 Button 컴포넌트는 btype이라는 props를 기준으로 버튼의 디자인이 변경되도록 설정이 되어있습니다.(상세)
이를 기준으로 현재 등록된 btype 따른 버튼을 그리도록 예제를 작성해보도록 하겠습니다.
우선은 자주 사용될 스토리 템플릿을 아래와 같이 작성합니다.
** IButtonProps는 Button의 PropTypes 입니다.
그리고 해당 템플릿을 이용하여 PrimaryButton Story를 추가해줍니다.
ButtonTemplate를 이용하여 PrimaryButton을 생성하고 args key를 이용하여 props를 전달해주었습니다.
이러한 식으로 그외 여러 props값을 전달하여 아래와 같이 작성해줄 수 있습니다.
결과를 확인해 봅시다.
결과화면
** 다른 Story들은 기존에 작성된 스토리 입니다.
작성한 내용이 정상적으로 표시되는것을 확인할 수 있습니다.
이러한 식으로 stories.tsx내에서 export로 반환되는 Story 컴포넌트들은 자동으로 하위요소에 등록이 됩니다.
사전작업에서 추가한 class를 이용하여 layout을 꾸민다면 템플릿을 아래와 같이 커스텀 해줄 수 있습니다.
결과
btype값을 넘겨받아 투명한 타입의 버튼인 경우 배경을 어둡게하여 표시를 한다던지
Template내에서 args값을 넘겨받아 레이아웃을 원하는대로 커스텀 해줄 수 있습니다.
knobs addon을 이용하여 컴포넌트 작성하기
기존 작성 방식대로 사용한다면 storybook@6.2^ 이후부터는 controls addon이 적용되어 자동으로 모든 props 제어가능하여 동적으로 컴포넌트를 조작할수 있긴 하지만
위 버튼같이 children으로 문자열 값을 넘겨받아서 사용하거나 boolean값을 이용하여 특정값을 주입해주는 경우에는 사용이 불가합니다.
이러한 경우를 위해 knobs addon을 이용하여 Story를 추가한다면 모든 값을 원하는대로 제어할수 있도록 작성이 가능합니다.
사용방법은 간단합니다.
기존의 Template을 컴포넌트 형태로 변경해주고 props로 값을 넘겨주는 부분을 knobs 파라메터로 변경해주면 됩니다.
knobs를 이용한 예제를 보겠습니다.
** controls addon에서는 위 예제처럼 btnText children을 넘겨주거나 특정 스타일만을 저런식으로 변수화하여 넘겨받아 사용하기가 불가능합니다.
위 예제는 knobs의 text, select, number 등의 예제를 사용하였습니다.
이렇게 등록된 knobs 파라메터들은 addon 탭의 knobs 에서 확인이 가능합니다.
결과화면
4. 정리
스토리북에 대한 최초 설정부터 스토리 작성까지 일련의 작업이 마무리 되었습니다.
예제 자체는 스토리를 작성하는 과정만을 작성하였지만 실제 작업에서는 컴포넌트가 프로젝트와 분리되면서 의존성을 잃게되고 그에따라 문제가 발생하는 경우가 생길것입니다.
이러한 문제를 해결해나가면 분리된 환경에서도 100% 원하는 형식의 디자인과 원하는 형식의 기능을 수행할수 있도록 처리되어 컴포넌트는 분리된 환경에서도 사용할수 있는 높은 재사용성을 가진 컴포넌트로 진화하게 됩니다.
하지만 잘 생각해본다면 컴포넌트를 실제 프로젝트에서 먼저 작성하는 것이 아니라 순서를 반대로
스토리북에서 컴포넌트를 작성하고 프로젝트로 넘겼으면 어땠을까요?
프로세스가 바뀌게 된다면 컴포넌트의 스콥을 좀더 고민할것이고 재사용가능한 컴포넌트를 좀더 활용하여 화면을 구성하지 않을까 라는 생각이듭니다.
5. 차후 계획
기회가 된다면 이후에는 Storybook 기반의 sdd(storybook driven development) 를 적용하여 개발을 진행해보고자 합니다.
Story 기반의 화면설계 및 복잡한 컴포넌트를 모두 반할하는 작업이 필요하기 때문에 atomic design에 대한 조사가 필요합니다.
【1】 React Storybook 적용 및 story 개발 : kt NexR 기술블로그 ‘21 테크리포트
Reference
•
•
소스코드(NEB)
https://github.com/nexr/ne-bookshelf-ui
본 기술블로그에 게재되는 모든 컨텐츠의 저작권은 케이티넥스알(kt NexR)에서 가지고 있으며, 동의 없는 컨텐츠 수정 및 무단 복제는 금하고 있습니다. 컨텐츠(글/사진/영상 등)를 공유하실 경우 반드시 출처를 밝혀주시기 바랍니다. Copyright(c) 2021 kt NexR, Inc. All Rights Reserved.