[Storybook] StoryBook을 이용한 컴포넌트 단위 개발 - 기본세팅(CRA + Redux + styled-Component)
기본 세팅(CRA + Redux + styled-Component)
CRA + Redux + styledComponent 로 구성된 프로젝트에 storybook 세팅하기
아래의 내용은 storybook 6.0.22 version을 기준으로 설명하고 있습니다.
1. Storybook 설치 및 기본세팅
- Storybook을 프로젝트에 설치하는 방법은 Project directory로 이동해서 터미널에서 아래 명령어를 입력하시면 됩니다
npx @storybook/cli sb init
-
설치를 하고나면 프로젝트 루트 디렉토리에 .storybook 디렉토리와 src디렉토리 하위에 stories라는 디렉토리가 생기고 package.json에 storybook 관련 dependencies, devDependencies, script명령어가 생긴것을 확인할 수 있습니다.
-
해당하는 디렉토리가 무엇이고 각 파일이 의미하는 것이 무엇인지 확인해보겠습니다.
.storybook
- .storybook 디렉토리에는 스토리북 관련 설정들을 setting할 수 있는 파일들이 생성되어 있습니다.
- 현재 main.js와 preview.js파일이 있습니다.
- storybook세팅에 관련된 예제들을 찾다가보면 config.js파일을 만들어서 안에 설정내용들을 넣으라는 예시가 있는데 이는 구버전 스토리북 기준으로서 main.js와 config.js파일이 같이 공존하면은 storybook에서 에러를 발생시키니 주의하셔야 합니다.(
경험담)
- 터미널에 npm run storybook을 통해 스토리북을 구동시켜 보면 위와 같은 화면으로 구성된 것을 볼 수 있는데
- storybook 전체의 세팅을 관리하는 파일이 main.js파일이며
- 위의 빨간색으로 하이라이팅 한 부분이 Preview부분이라고 명칭하는데 preview.js파일은 preview부분과 관련된 설정을 할 수 있습니다.
- 하나하나 설정을 보면서 알아보겠습니다.
main.js
CRA + Redux + styledComponent 로 구성된 프로젝트에 storybook 세팅하기
아래의 내용은 storybook 6.0.22 version을 기준으로 설명하고 있습니다.
npx @storybook/cli sb init
설치를 하고나면 프로젝트 루트 디렉토리에 .storybook 디렉토리와 src디렉토리 하위에 stories라는 디렉토리가 생기고 package.json에 storybook 관련 dependencies, devDependencies, script명령어가 생긴것을 확인할 수 있습니다.
해당하는 디렉토리가 무엇이고 각 파일이 의미하는 것이 무엇인지 확인해보겠습니다.
- main.js의 초기 구성은 위와 같이 되어 있습니다.
- stories부분과 addons부분으로 나눠진 것을 볼 수 있는데
-
stories부분은 stroybook에 표현할 컴포넌트들을 정의합니다.
- 현재 보시면
".stories.@js|jsx|ts|tsx"
으로 정의되있기에 src폴더 하위에 .stories가 파일명에 포함되 있으며 확장자가 js/jsx/ts/tsx로 되어있는 파일들을 모두 스토리북에 표현하겠다는 의미입니다. - config.js를 사용해 설정을 했던 구버전 스토리북에서는 모든 stories 파일이 ./src/stories 디렉토리에 있어야만 했고 그 외의 stories파일이 스토리북에 나오게하려면 추가적인 설정이 필요했지만 현재에는 기본설정만으로도 src 디렉토리 하위의 어떤 폴더에 있든 모두 스토리북에 표현되도록 변경되었습니다.
- 현재 보시면
-
addon 부분은 storybook에 어떤 addon을 추가시킬지 설정하는 부분입니다.
- addon이란 것은 extension과 유사한 개념인데 기본 스토리북에 추가적인 기능을 더 추가하는 것이라고 볼 수 있습니다.
- 하나의 예시를 들자면 컴포넌트들의 접근성을 확인할 수 있는 a11y에드온을 추가하려면
npm install @storybook/addon-a11y --dev
명령어를 통해서 에드온을 설치 및 devDependencies에 추가하고
addons: [ "@storybook/addon-links", "@storybook/addon-essentials", "@storybook/preset-create-react-app", "@storybook/addon-a11y", ],
- addons에 다음과 같이 @storybook/addon-a11y를 추가하면
- 위와 같이 preview부분에 accessibility 탭이 추가되어서 접근성 관련된 항목들이 추가된 것을 알 수 있습니다.
2. StoryBook에 Redux + Styled-Components 적용시키기
- StoryBook에 Redux의 Store와 Styled-Components의 theme을 적용시키기 위해서는 데코레이터를 추가시켜줘야 합니다.
- 이 부분은 preview.js파일에 해당하는 설정을 추가함으로서 구현할 수 있습니다.
preview.js
-
preview.js에서는 preview부분과 관련된 설정을 합니다.
-
이 부분을 이용하여 story에 데코레이터를 추가할 수 있습니다.
-
데코레이터란 story 컴포넌트가 storybook에 표현될 때 추가적으로 장식으로 들어가는 다른 컴포넌트들이나 Provider들을 추가할 수 있는 것입니다.
-
Redux나 styled-components를 사용할 경우에는 루트가 되는 스크립트 파일인 index.js에서 Provider를 통해서 store를 전역에 추가해주고, ThemeProvider를 통해서 theme파일을 전역에 추가하는 식으로 세팅을 많이 했을 것입니다.
Provider와 ThemeProvider가 추가된 index.js파일의 예시
-
storybook은 일반적으로 서버를 구동시킬때 index.js를 통해서 모든 컴포넌트가 Provider를 통해서 Provider를 제공받은 후 보여지는 것이 아니라
-
개별 컴포넌트가 스토리북에 보여지는 것이므로 저런 Provider가 제공된 상태가 아니기에 theme와 store를 사용하였을 경우에 에러가 발생하거나 원하는대로 동작하지 않습니다.
-
따라서 Decorator를 통해서 Provider를 개별 스토리에 다 제공해줘서 store와 theme을 제공받도록 해아합니다.
-
개별 스토리마다 decorator를 추가할 수도 있지만, 모든 스토리에 공통적으로 적용되어야 하는 decorator라면 Preview.js에 전체적으로 데코레이터를 추가해주는 방식이 간편합니다.
Preview.js 파일의 예시
-
위 preview.js파일을 보면 index.js에 Provider를 제공한것과 동일하지만 중간에 Story라는 컴포넌트가 들어가 있는 것을 볼 수 있습니다.
-
정확한 내용은 공식문서에서 해당하는 내용을 찾아봐야겠지만 제가 사용하고 세팅을 하면서 추측하기로는 decorator는 story라는 인자를 받는데 이 인자는 각 .stories파일들에서 export하는 컴포넌트들이고 그 Story파일에 데코레이터로 Provider, ThemeProvider, GlobalStyles를 감싸준 다음에 렌더시키는 방식으로 보입니다.
-
제 경우에는 모바일 사이즈를 개발하고 잇기에 width:360px을 가진 wrapper를 전체적으로 적용시켜준 모습을 볼 수 있습니다.
-
이 개념을 이해하면 이제 스토리북에 다양한 데코레이터를 추가해서 여러가지 기본적인 설정을 해줄 수 있습니다.
documentation 추가하기
-
Storybook에는 사용자를 위해서 docs를 추가할 수 있습니다.
-
mdx파일을 추가하는 방식과 PropTypes를 통해서 간단하게 표현해줄 수 있는 방법이 있습니다.
-
저의 경우에는 propTypes를 통해서 간략하게 문서화 하는 식으로 진행하였습니다.
-
React에서 기본적으로 제공하는 prop-types 라이브러리를 통해서 Props의 타입을 명시할 수 있고, 이와 주석을 결합하여 간략하게 해당하는 prop의 documentation을 스토리북에 포함할 수 있습니다.
Example.js 파일 --- import React from "react"; import styled from "styled-components"; function Example({ color }) { return <Container>Example</Container>; } export default Example; const Container = styled.p` width: 200px; color: blue; font-size: 36px; `;
Example.stories.js 파일 --- import React from "react"; import Example from "./Example"; export default { title: "Components", componenet: Example, }; export const Default = () => <Example />;
-
위와 같은 형식으로 하나의 컴포넌트파일을 만들고 .stories.js파일을 만들어서 storybook에 컴포넌트를 표현할 수 있습니다.
-
실제 스토리북에 들어가보면 컴포넌트의 모습은 보이지만 문서화가 되지 않아 사람들이 알아보기 어려운 것을 알 수 있습니다.
import React from "react"; import PropTypes from "prop-types"; import styled from "styled-components"; function Example({ color }) { return <Container color={color}>Example</Container>; } Example.defaultProps = { color: "black", }; Example.propTypes = { /** 글자의 색을 지정하는 Props */ color: PropTypes.string, }; export default Example; const Container = styled.p` width: 200px; color: ${({ color }) => color}; font-size: 36px; `;
-
위와 같이 propTypes를 통해서 defaultProps와 propTypes를 지정해주면 해당하는 주석을 문서로 출력해줍니다.
3. 겪었던 Issue들
1. Stories of
- 스토리북 파일을 작성하는 방법은 크게 두가지가 있는데 Stories of 를 사용하는 방식과, export default로 title과 component를 정의해준 다음, export const <표현하고싶은 이름> 을 통해서 하는 방식 2가지가 있는데 처음에는 Storiesof를 사용했으나 이 경우 propTypes를 통한 문서화가 표현되지 않는 이슈가 있어서 export default 와 export const를 사용하는 방식으로 변경하였습니다.
- Stories of가 더 간결하게 느껴져서 최신 문법인 줄 알고 있었으나 export default + export const를 사용하는 방식이 더 최신문법이고 권장사항이라고 공식문서에서 소개하는 글을 보고 모두 그 방식으로 수정했습니다.
2. Optional Chainig
- Optional Chaining문법을 쓰면 propTypes를 통한 문서화가 되지 않는 이슈를 겪었습니다.
현재 해결방법은 못찾은 상태여서 한줄 한줄 다 지워가면서 확인하다가 옵셔널체이닝을 쓰면 문서화가 표출되지 않는 다는 것을 발견하고 현재 &&문법을 사용하는 식으로 수정했습니다. - 관련해서 해결하는 방법을 찾으면 추가 포스팅 하겠습니다.
3.Position:fixed
- Storybook에서 컴포넌트를 보여주는 형태는 storybook페이지 안에 iframe을 통해서 다른 html문서를 추가하고 그 안에 컴포넌트가 있는 방식으로 보입니다.
- 그래서
position:fixed, bottom:0
이 설정되어있는 컴포넌트가 있을 경우에 docs페이지에서 docs페이지 전체의 bottom에 모든 컴포넌트가 위치해버리는 이슈가 있습니다.
Fixed의 예시
- 위의 사진을 보시면 docs탭 안에서 모든 컴포넌트가 다 bottom:0 에 위치해있어서 난잡하게 보이고 해당 컴포넌트의 이미지를 볼 수가 없는 상황입니다.
- 이 경우 Component를 싸고있는 iframe의 크기를 설정해줌으로서 해결할 수 있습니다.
import React from 'react'
import Example from "./Example";
export default {
title:"Test",
component:Example,
parameters: {
docs: {
inlineStories: false,
story: {
ifameHeight: 500,
},
},
},
}
export const Default = (args) => <Example {...args} />
export const Blue = () => <Example color="blue" />
- 위의 코드에서 default안에 parameters부분을 보면 docs탭에서 iframe의 height를 500으로 설정해준 것을 볼 수 있습니다.
- 위의 코드를 추가해주면 정상적으로 docs탭 안에서 정상적인 모습으로 출력이 되는 것을 볼 수 있습니다.
마무리
- 제가 스토리북을 처음 사용하면서 겪었던 시행착오와 Issue들을 정리해봤습니다.
- 이 글을 통해 한분이라도 더 제가 겪었던 시행착오를 조금이라도 빨리 해결할 수 있었으면 좋겠습니다.
- CRA만 사용하다가 처음으로 다른 라이브러리를 같이 세팅하는 과정을 겪어봤는데, 1주일 정도 걸린 것 같습니다.
- 개발에서 초기에 세팅단계에서 많은 시간이 소모되고 세팅이 꼬일 경우 어렵다는 것을 처음으로 느낀 경험이었습니다.
- 관련해서 storybook뿐만 아니라 babel, webpack 등 여러가지 세팅관련된 것들을 공부해서 개발환경 설정을 할 수 있는 능력을 갖춰야겠다는 생각을 했습니다.
Author And Source
이 문제에 관하여([Storybook] StoryBook을 이용한 컴포넌트 단위 개발 - 기본세팅(CRA + Redux + styled-Component)), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@younuk23/Storybook-StoryBook을-이용한-컴포넌트-단위-개발-기본세팅CRA-Redux-styled-Component저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)