기존 진행된 CRA+Typescript 환경에서 Storybook 6 세팅하기

Whis·2021년 7월 27일
0

알쓸신잡

목록 보기
4/4

Install

기존 프로젝트의 루트에서 아래의 명령어를 입력한다.

npx -p @storybook/cli sb init

명령어를 입력해서 설치를 하면, 루트 경로에 .storybook이라는 폴더가 생성 되며, 이 폴더의 하위에는 storybook을 세팅하는 기본적인 파일들이 들어있다.또한 src 폴더 하위에 stories폴더가 생성되며 stories 폴더 하위에는 예시 스토리북 파일들이 들어있다.
명령어를 입력하여, 스토리북을 실행하면 잘 실행되는 것을 확인 할 수 있다.

Problem

스토리북은 잘 실행은 되지만, 기존의 프로젝트를 실행하면 아마 실행이 안되고 오류가 날 가능성이 높을 것이다.
뭔지 모를 빌드에러가 생기는데, 이는 CRA의 dependency들과 storybook dependency의 버전이 충돌이 나서 생기는 문제였다.(아마 CRA버전이 최신이 아닐경우 이와같은 문제가 생길 것이라고 생각한다.)
버전 충돌이 나는 패키지는 아래와 같다.

  1. @svgr/webpack
  2. babel-loader
  3. file-loader
  4. style-loader
  5. css-loader
  6. postcss-loader

lock파일의 의존성 패키지 버전들을 쭉 보면 react-script의 의존성 패키지 버전들이 고정되어 있는 것을 확인 할 수 있다.
때문에, 나는 react-script의 의존성 패키지들 버전 기준으로 하여 package.json에 resolutions 옵션에 해당 버전들을 고정하여 넣었다.

resolutions 옵션은 resolutions에 등록된 패키지들은 해당 버전만 설치하게 하는 옵션이다.
이를 세팅해주고 기존 설치된 node_modules와 lock파일을 지우고 다시 인스톨을 하면 스토리북, 기존 프로젝트 모두 잘 설치되는 것을 확인 할 수있을 것이다.

Setting

Storybook 6version에서 부터 추구하는 컨셉은 zero-config이다.
사용자가 설정하는 것은 최소화하고, 왠만한 것들은 전부 제공하는 목적이다.
따라서 옜날 공식적으로 지원하지 않았던 타입스크립트를 별도의 설정없이도 사용할 수 있게 되었으며,
Storybook을 사용하는 사용자들이 자주 사용하는 add-on들을 addon-essentials로 묶어 제공을 한다.
따라서 기존의 addon-control,addon-docs 등을 별도로 설치하지 않아도 이용할 수 있게 되었다.

setting 파일은 크게 두가지로 나뉜다.

  1. main.js
  2. preview.js

main.js는 typescript, webpack 설정을 추가하는 곳이며, addon을 추가적으로 설치했을 경우 등록하는 파일이다.
preview.js는 global로 스토리 전체를 decorating할 수있는 파일이며, 이곳에는 global context를 세팅하거나, 스토리들의 디폴트 파라미터를 설정할 수 있다.

기존 프로젝트에서 사용하는 context, 예를들어 theme이나, 다국어 등을 사용해야하는 컴포넌트를 스토리북에 반영하고 싶은 경우 preview.js에 꼭 설정을 해줘한다. 설정하는 방법은 아래와 같다.

import React from 'react';

import { SomeContextProvider } from '../src/context/something';

export const decorators = [
	Story => (
    	<SomeContextProvider>
          <Story />
        </SomeContextProvider>
    )
]

Static file을 load하는 방법

간혹 node-sass로 sass 파일들을 빌드해서 해당 static file을 사용하는 경우가 있는데,
해당 static file을 storybook에 사용하는 방법은 아래와 같다.

  1. 실행 스크립트 수정
    기본 스토리북 실행 스크립트는 start-storybook 일 것 이다. 여기에 -s <dir-name>의 옵션을 주면 옵션에 준 dir-name을 기준으로 static file을 가져올 수 있다.

  2. static file 가져오기
    방법은 두 가지가 있다.

    1. preview-head.html을 .storybook하위에 생성
      생성 후 아래와 같이 링크를 삽입한다.

      <link rel='stylesheet' href='css/styles.css' />

      만약 node-sass로 빌드한 파일이 예를들어 build-sass/css/styles.css의 경로로 생성되는 경우, build-sass를 스크립트 옵션에 넣으면, html파일에 넣는 링크의 href의 주소를 위와같이 작성하면 된다.
      2.main.js에 previeHead 옵션을 추가하여 넣는다.

      module.exports = {
        stories: [...],
        addons: [...],
        previewHead: head => `
          ${head}
          <link rel="stylesheet" href="css/styles.css" />
        `
      };

Story 작성

스토리 작성하는 부분은 다행히도, 이전 버전과 크게 달라지는 것은 없다. (typescript 세팅된 스토리북 기준으로...)

Problem 1: Navbar menu 이름 변경

다만 실행 후 Navbar에 보이는 메뉴 이름은 이 곳의 규칙을 따르는데, 요는 컴포넌트의 메뉴 이름은 기본적으로 lodash의 startCase로 바뀌어서 들어간다는 것이다.

// sample.stories.tsx

import React from 'react';
import { Meta } from '@storybook/react';

import SampleComponent, {
	ISampleComponentProps
} from 'components/sample';

export const StorySampleComponent = (props: ISampleComponentProps) => {
	...
}
    
export default {
	title: 'Sample-Component',
  	component: StorySampleComponent
}
  
// 결과 : Sample-Component 아래에 'Story Sample Component'의 이름으로 메뉴가 생성된다.

여기서 보면 확인 할 수 있지만 title과 story이름이 다르면 하위 메뉴로 추가되어 페이지가 구성된다.

이 룰을 따르고 싶지 않으면, 스토리에 storyName이라는 프로퍼티를 생성하고 여기에 원하는 타이틀을 넣어주면 된다.

// sample.stories.tsx

import React from 'react';
import { Meta } from '@storybook/react';

import SampleComponent, {
	ISampleComponentProps
} from 'components/sample';

export const StorySampleComponent = (props: ISampleComponentProps) => {
	...
}
    
// add
StorySampleComponent.storyName = 'Sample-Component'
    
export default {
	title: 'Sample-Component',
  	component: StorySampleComponent
}
  
// 결과 : Sample-Component메뉴만 생성

Problem 2: props interface의 type을 가져오지 못하는 경우.

version6에서 부터는 docs와 control이 기본으로 설치되어 있기때문에, 원래대로라면 props interface를 자동으로 가져와야 맞다.
좀 에러 케이스가 다양해서, 지금은 기억이 좀 흐릿한데 요는, story를 작성할때, story에 type을 지정하면 interface를 제대로 못가져오는 이슈가 있었던 것 같다.

import React from 'react';
import { Meta, Story } from '@storybook/react';

import SampleComponent, {
	ISampleComponentProps
} from 'components/sample';

export const StorySampleComponent = (props: ISampleComponentProps): Story => {
	...
}

인 경우인데, 이 경우에 함수 표현식(화살표 함수)으로 되어있는 컴포넌트는 타입을 못가져오고, 함수 선언식으로 되어있는 컴포넌트만 타입을 가져왔다.
해결 방법은 그냥 타입지정을 안하면 된다.

마치며

스토리북 자체도 볼륨이 매우 커서, add-on 마다 설정을 찾아보려면 공식문서로는 많이 부족했고,
결국 각 add-on 깃헙 들어가서 설정방법들을 보거나, 이슈들을 쭉 훑어보거나 했던 일이 많았다.
이슈도 스토리북에서 나아가 웹팩 의존성 문제인 경우도 있어서, 그쪽도 훑어보고 하는 등... 리서치 하는데도 정신이 없이 한지라, 결국 기록하려고 보니 남은 것이 별로 남지 않아보인게 조금 스스로 아쉬웠다.

여튼 덕분에 웹팩 설정도 들여다보게되었고,
리서치를 할 때, 기존에도 깃헙 소스코드를 들여다 본 일은 많지만, 릴리즈 노트까지 읽어본 것은 이번이 처음이었던 것 같다.
할 때는 고생했지만, 어느정도 지나와보니 배운것도 그만큼 많아서 좋았던 프로젝트였다.
현재는 내가 작업했던 것보다 버전이 올라가있는데, 자잘한 버그픽스와 몇가지 기능이 추가된 듯하다.
생각보다 알파 버전 등 수정도, 버전업도 빠른 편이다보니 이런 저런 문서를 참고할 때 버전을 꼭 확인하고 참고하면 좋을 것 같다.

profile
Developer

0개의 댓글