[ Storybook ] Storybook 맛보기

·2023년 12월 14일

😶 Storybook이란?

Storybook is a frontend workshop for building UI components and pages in isolation.
Thousands of teams use it for UI development, testing, and documentation.
It’s open source and free.

컴포넌트 기반의 뷰를 위한 독립적인 UI 개발 도구
회사의 UI 라이브러리를 내부 개발자들을 위해 문서화하거나,
외부 공개용 디자인 시스템 개발을 위한 기본 플랫폼으로 사용한다.

기본 구성 단위는 Story 이며, 하나의 ui 컴포넌트는 보통 하나 이상의 story를 가진다.
Storybook을 사용하면, UI 컴포넌트가 각각 독립적으로 어떻게 실제 렌더링되는지 직접 시각적으로 테스트하면서 개발할 수 있다는 장점이 있다.

👍 Storybook 장점

Why Storybook?

  • 독립적인 UI 개발
    -> 복잡한 로직이나 CONTEXT 없이 독립적인 UI 컴포넌트 개발 가능

  • 특정 스냅샷을 스토리로 만들고 테스트 가능
    -> 재사용을 위해 만들어진 컴포넌트들을 story에서 조합하여 특정한 스냅샷을 만들어 개발이나 테스트, QA에 사용할 수 있음

👀 storybook 설치

npx sb init

☠️주의사항☠️
스토리북은 절대로 빈 프로젝트에 설치해서는 안됨

  • 스토리북을 설치하게 되면,
    package.json에 스토리북과 관련된 스크립트와 개발 의존성이 추가 된다.

스토리북 설치 이후,storybook을 실행하는 명령어를 입력한다.

yarn storybook // 6006 포트

☠️주의사항☠️
만약, 프로젝트가 vite를 사용하고 있다면, Storybook은 Webpack 기반의 프레임워크이기 때문에 vite builder를 따로 설치해주어야 한다.
Storybook+vite

👁️ Storybook 폴더 구조 및 실행

스토리북을 설치하면 다음과 같은 폴더 구조가 생성된다.

.storybook/main.ts/js

sotrybook을 위한 config 설정, 기본으로 설정되는 storis와 addons의 세팅이 포함된 파일

import type { StorybookConfig } from "@storybook/react-vite";

const config: StorybookConfig = {
  stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"],
  addons: [
    "@storybook/addon-links",
    "@storybook/addon-essentials",
    "@storybook/addon-onboarding",
    "@storybook/addon-interactions",
  ],
  framework: {
    name: "@storybook/react-vite",
    options: {},
  },
  docs: {
    autodocs: "tag",
  },
};
export default config;

preview.ts/js

모든 story에 global하게 적용될 포맷을 세팅하는 파일이며,
decorators, parameters, globalTypes를 각각 export 한다.

import type { Preview } from "@storybook/react";

const preview: Preview = {
  parameters: {
    actions: { argTypesRegex: "^on[A-Z].*" },
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
};

export default preview;
  • controls : 개발자가 코드를 변경하지 않고, storybook에서 arguments를 동적으로 바꾸어 가면서 인터렉션할 수 있도록 도와주는 기능
  • decorators: global decorator의 배열 (ex, GlobalStyle, ThemeProvider)
  • parameters: global parameter의 객체
  • globalTypesL globalTypes의 정의

Storybook을 실행하면,


다음과 같은 화면이 뜬다.

👀 Story 작성하기

🤪 Story가 위치할 장소

Story는 컴포넌트가 위치하는 폴더 안에 같이 위치시키는 것이 일반적이고, Story 파일은 development-only 이므로 production bundle에는 포함되지 않는다.

import { Button } from './Button';

export default {
  title: 'Example/Button',
  component: Button,
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: { control: 'color' },
  },
};

-> export default {}를 사용하여, 어떤 컴포넌트의 Story인지, 어떤 설정으로 렌더링 할 것인지 정의한다.

export const Primary = {
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary = {
  args: {
    label: 'Button',
  },
};

export const Large = {
  args: {
    size: 'large',
    label: 'Button',
  },
};

export const Small = {
  args: {
    size: 'small',
    label: 'Button',
  },
};

-> export const 이름 을 사용하여 새로운 Story를 생성할 수 있다.
하나의 컴포넌트에 위와 같이 여러 개의 story를 가질 수 있다.

🤩 Story 주요 속성

  • title: 스토리북 폴더 계층 구조
  • component: addon을 위해 써주는 것이 권장
  • args : story의 prop 이자 input
  • decorators: story를 래핑하는 추가 렌더링 기능
  • parameters: story에 대한 정적인 메타 데이터 정의

🙃 Args

Story는 렌더링된 UI 컴포넌트의 state를 캡쳐하여 어떻게 컴포넌트가 렌더링되는지 보여주는 function이다. 이때 react의 props와 비슷한 느낌으로 args를 가지는 것이다.
따라서, 다음의 코드와 같이 여러 개의 Story를 재사용할 수 있다.

const Template: Story<ButtonProps> = (args) => <Button {...args} />;

export const Primary = Template.bind({});
 Primary.args={
  args: {
    primary: true,
    label: 'Button',
  },
};

export const Secondary = Template.bind({});{
Secondary.args={
    label: 'Button',
  },
};

이때, Template.bind({}) 구문을 통해 만들어진 Template 이라닌 기본적인 틀으로,
을 만들면, args를 할당할 수 있고, 여기서 args만 다르게 해서 여러 개의 Story를 렌더링할 수 있다.

🙃 Decorator

기능적으로 추가적인 렌더링을 통해 감싸는 방법으로, 새로운 마크업으로 감싸기 위해 사용하거나 Context Provider로 감싸야 하는 경우 사용한다.

  1. 추가적인 컴포넌트를 새로운 마크업으로 감싸려는 경우

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

export default {
  component: YourComponent,
  decorators: [
    (Story) => (
      <div style={{ margin: '3em' }}>
        <Story/>
      </div>
    ),
  ],
} as Meta;

  1. Global Decorator과 같이 Context Provider로 감싸야 하는 경우
import { ThemeProvider } from 'styled-components';

export const decorators = [
  (Story) => (
    <ThemeProvider theme={theme}>
      <Story />
    </ThemeProvider>
  ),
];

theme 등을 사용할 경우, ThemeProvider로 감싸 주어야 한다.

Decorator에는 세 가지 레벨이 존재하는데,
1. Story Decorators : 하나의 Story 범위에만 적용
2. Component Decorators : stories.tsx 파일 범위에만 적용(story를 가진 component에만 적용)
3. Global Decorators: 모든 stories.tsx에 적용

🙃 Parameter

story의 정적인 메타 데이터를 뜻하며, 주로 feature와 addon을 조작한다.

export const Primary = Template.bind({});
Primary.args = {
  primary: true,
  label: 'Button',
};
Primary.parameters = {
  backgrounds: {
    values: [
      { name: 'red', value: '#f00' },
      { name: 'green', value: '#0f0' },
    ],
  },
};

마찬가지로 parameter에도 세 가질 레벨이 존재한다.
1. Story Parameters

export const Primary = Template.bind({});
Primary.args = {
  primary: true,
  label: 'Button',
};
Primary.parameters = {
  backgrounds: {
    values: [
      { name: 'red', value: '#f00' },
      { name: 'green', value: '#0f0' },
    ],
  },
};

Primary 라는 Story에만 parameter 적용

  1. Component Parameters
import Button from './Button';

export default {
  title: 'Button',
  component: Button,
  parameters: {
    backgrounds: {
      values: [
        { name: 'red', value: '#f00' },
        { name: 'green', value: '#0f0' },
      ],
    },
  },
};

stories.tsx에 속한 모든 story에 적용

  1. Global Parameters

export const parameters = {
  backgrounds: {
    values: [
      { name: 'red', value: '#f00' },
      { name: 'green', value: '#0f0' },
    ],
  },
};

preview.js에 정의하여 모든 파일에 parameter가 적용

출처:
https://velog.io/@seobbang/StoryBook
https://storybook.js.org/tutorials/intro-to-storybook/react/ko/simple-component/
https://storybook.js.org/
https://velog.io/@juno7803/Storybook-Storybook-200-%ED%99%9C%EC%9A%A9%ED%95%98%EA%B8%B0

profile
new blog: https://hae0-02ni.tistory.com/

8개의 댓글

comment-user-thumbnail
2023년 12월 16일

storybook이란 개념을 이번 아티클을 통해 처음 알게 되었는데요.
새로운 개념을 배워볼 수 있어서 좋았습니다.

이번 아티클을 읽으면서 왜 스토리북을 써야 하는 지가 궁금해져서 찾아봤습니다.

일단 큰 규모의 프로젝트에서 사용하기 좋다고 합니다.

장점
1. 각각의 컴포넌트를 독립적인 환경에서 빌드 및 테스트를 할 수 있습니다. 이는 개발 속도 향상 뿐 아니라, 각 컴포넌트가 의도된 역할을 하는 것을 보장할 수 있습니다.
2. 1번의 연장선 상인데, 개발자들이 각 컴포넌트에 대해 개별적으로 일을 할 수 있어 개발 속도 및 효율성이 증가합니다. 이는 프로젝트가 정해진 스케쥴을 지키는 걸 도와줍니다.
3. 모든 컴포넌트를 위한 centralized location이 제공됨으로써, 개발자가 그들의 컴포넌트를 관리하고 navigate하기 수월해집니다. 이는 컴포넌트의 목적과 기능을 이해하기 수월하게 합니다.
4. 각 컴포넌트의 visual representation을 제공하므로, 디자이너와 개발자 사이의 소통의 갭을 줄여줍니다.
5. 다양한 plugins이 있어서 개발자들이 본인의 기능에 맞게 customize 할 수 있습니다.
6. 컴포넌트를 테스팅하고 디버깅하는 걸 좀 더 수월하게 만듭니다. 개별 컴포넌트로 테스트 할 수 있어 테스트를 위해 전체 apllication을 찾아볼 필요가 없습니다.

여러 가지의 장점이 있으면 단점도 분명 있다고 생각해서 이에 대해서도 찾아보았습니다.

단점
1. 초기 세팅이 복잡합니다. 다양한 세팅들을 해야하고, 의존성을 설치해야 하고, 폴더 구조도 생성해주어야 합니다. 또한 새로운 컴포넌트가 추가되면 이를 storybook에도 업데이트를 해주어야 합니다. time-consuming이 발생합니다.
2. 많은 수의 story를 관리하는 것은 어려울 수 있습니다. 개발자들은 story를 카테고리화 하고 관리하는데 많은 시간을 소요해야 합니다.
3. 많은 라이브러리들을 지원하지만 아직 지원되지 않은 프레임워크들이 있습니다.

참고자료
https://cleancommit.io/blog/the-benefits-and-frustrations-of-using-storybook/

아티클 작성하느라 고생하셨습니다!!
잘 읽고 갑니다 ☺️

답글 달기
comment-user-thumbnail
2023년 12월 17일

요즘 디자인 시스템에 관심이 많고 곧 스토리북을 처음으로 써봐야 하는 일이 생겨서,, 정말 기다리던 주제였는데요!!! 대충 컴포넌트 UI 문서화하는 툴? 모아서 정리해놓을 수 있는 것? 정도로만 알고있었던 것을 실제 설치과정과 코드를 통해 실질적으로 이해할 수 있었습니다! 베이스 컴포넌트 위에 args들을 배리에이션해서 여러가지 상황들을 따져볼 수 있다는 점이, 프로젝트가 복잡해질 수록 프론트 개발자로서 정말 필요한 부분 같아요. 만들면서도 제가 만든 컴포넌트가 어떤 케이스들을 가지고 있는지 헷갈릴 때가 많단 말이죠...
그래서 저는 특히 스토리북을 통한 테스트에 관련해 궁금한 점이 많아서, 스토리북에서 컴포넌트를 테스트하는 방법에 대해 알아봤습니다.
컴포넌트 테스팅의 필요성에 관해서라면 제가 몸소 느낀 바가 있는데요,,, ASAP에서 시간표 뷰를 구현할 때, 사용자가 원하는 시간대로 [오전,오후,저녁]을 선택했는지, [오전,오후]를 선택했는지, [오전,저녁]을 선택했는지... 총 7가지 경우에 대해 각각 다른 뷰를 만들어줘야 했어요. 그러다보니 저도 점점 헷갈리고, 특히 [오전,저녁]을 선택했을 경우엔 오후 시간대에 대해서는 선택하지 못하게 하는 등의 예외처리를 놓치는 일도 발생했었구요. 이런식으로 컴포넌트의 조건화가 딥해진다면 예상치못한 예외처리를 빼먹을 수 있겠구나-라는 생각이 들어 컴포넌트 테스팅에 관심이 생겼어요.
스토리북에서 테스트를 해보려면 우선 [컴포넌트명].test.tsx파일을 만들고, 생성된 스토리들을 import해온 다음, 다음과 같이 이미 정의된 test라는 메소드를 통해 컴포넌트 테스팅을 진행해볼 수 있습니다.

test("should render RedButton", () => {
  render(<RedButton {...RedButton.args} />);
  expect(screen.getByRole("button")).toHaveTextContent(/Red/i);
  expect(screen.getByRole("button")).toHaveStyle("backgroundColor: red");
});

여기서 render함수는 어떤 컴포넌트를 출력하여 테스트할 건지를 넣어주고, expect를 이용해서 어떤 컴포넌트가 어떤식으로, 어떤 요소를 갖고있어야하는지 "예상"되는 값을 넣어줍니다. 위 예시에서는 button이라는 role을 가지고 Red라는 텍스트 컨텐츠를 갖고있어야 한다고 체크할 내용을 나열해준 걸 볼 수 있죠!
그러곤 scripts를 세팅 후 yarn test를 돌려주면, test메소드가 실행이되고, 테스트를 통과한 것에 대해서는 passed가, 통과하지 못한 것에 대헤서는 failed가 되는 식으로 테스트가 진행됩니다. 생각보다 굉장히 직관적인 과정이네요!!
앞으로 스토리북과 테스트북에 대해서도 관심을 가지고, 좀 더 규칙성있고 예외없는 컴포넌트들을 만들기 위해 노력해야겠습니다 ㅎㅎ 토이프로젝트 기간 중에도 좋은 아티클 정말 감사하고, 고생 많으셨습니다!

답글 달기
comment-user-thumbnail
2023년 12월 17일

StoryBook... 이름만 들어봤었는데 드디어 개념을 알게 되었어요!!

StoryBook을 사용하면 확실히 컴포넌트를 개발하기 훨씬 쉬워지겠네요 :)

설치 과정과 실행 결과를 직관적으로 보여주셔서 이해가 쏙쏙 된 아티클 같아요!!!!

저는 StoryBook과 비슷한 컴포넌트 작성 지원 도구에 대해 알아봤는데, 그 중 Framer에 대해 자세히 알아봤어요!! Framer는 실제로 토스에서 제품을 디자인할 때 사용하는 툴이라고 합니다. Framer는 React, TypeScript, JSX를 통해 구현된 디자인 웹 서비스입니다. Framer를 통해 디자이너는 코드로 구현된 컴포넌트로 화면을 디자인하고, 개발자는 개발 친화적인 환경에서 화면을 해석할 수 있게 해준다고 합니다.

아직 이런 컴포넌트 디자인 툴을 사용해본 적이 없어 개념도 생소하고 사용법도 생소한데, 기회가 된다면 꼭 써보고 싶고 매력적인 툴이라고 생각합니다!!

유익한 아티클 작성해주셔서 너무너무 감사합니다!! 고생하셨어요!!!!!! ☺️☺️

답글 달기
comment-user-thumbnail
2023년 12월 17일

말로만 들어봤던 스토리북,, 모호하게 알고 있던 개념들을 이번 아티클을 통해 배울수 있어 너무 좋았습니다!

개념들 뿐만 아니라 설치과정부터, 적용 예시까지 들어주셔서 더 이해하기 편했어용
저는 아티클에 종종 등장하는 'addon' 이라는 것이 무엇인지 궁금해져서 더 찾아봤습니다!

스토리북은 다양한 기능들을 활용할 수 있게 해주는 확장 프로그램, 플러그인을 제공해주고 있는데, 이것을 addon이라고 한다고 합니다. addon을 통해 스토리북 기본 기능에 추가 기능을 붙일 수 있고, 이 addon을 얼마나 잘 활용하느냐에 따라서 스토리북을 사용하는 효과가 달라진다고 하니 중요한 요소인것 같네요!

대표적으로인 addon들에는 다음과 같은 종류들이 있습니다.
1. Controls : 코드 없이 디자이너와 개발자가 인수(argument)를 바꿔보며 컴포넌트의 동작을 쉽게 할 수 있게 해주는 애드온. story 옆에 애드온 패널을 생성하므로 실시간으로 인수를 편집 가능하다. (스토리북을 설치하면 자동으로 설치 된다)
2. Actions : 컴포넌트를 통하여 특정 함수가 호출 됐을 때 어떤 함수가 호출 됐는지, 그리고 함수에 어떤 파라미터를 넣어 호출했는지에 대한 정보를 확인할수 있게 해주는 애드온. 간단한 함수 호출부터 시작해서, 나중에는 리액트 라우터의 주소가 변경될 때를 확인하거나 리덕스 스토어의 dispatch를 mocking하여 디스패치 되는 액션의 정보를 볼 수 도 있다. (스토리북을 설치하면 자동으로 설치 된다)
3. Knobs : 컴포넌트의 props를 스토리북 화면에서 바꿔서 바로 반영시켜줄수 있는 애드온. controls와 유사핟.
4. Designs : 애드온 패널에 디자인 미리보기를 삽입하기 위한 애드온. ex. 피그마 페이지 연동 등

이 외에도 많은 종류들이 있으니 나머지는 요기 공식 문서에서 확인 해보시면 좋을것 같습니다!

출처 : https://medium.com/@sg1004you/storybook-addon-476911a389c0

답글 달기
comment-user-thumbnail
2023년 12월 17일

사실 스토리북을 잘 몰랐었는데 언니가 추가 세션으로 가져와준 덕분에 처음알게될 수 있었어요!! !
솝트에서는 프로젝트를 Vite로만 빌드했었는데 스토리북이 웹팩 기반의 빌드 도구라는 것도 언니가 찝어준 덕분에 호환성 문제 미리 파악할 수 있었습니다 !

특히 그동안엔 조건부에 따라 다르게 스타일링 해줘야하는 경우 (대표적으로 호버나 클릭 액션 등) state를 생성하고 이를 스타일드 컴포넌트에게 props로 내려줘서 조건부 체크를 하는 식으로 늘상 구현했었는데, 그부분을 더 직관적으로 설정할 수 있다는 점이 가장 인상적인 것 같아요!

스토리북에 대해서 아는 것이 전무후무했는데, 이번 아티클을 보면서 느낀점은 고도화된 추상화툴이라는 생각도 들었어요!
저희가 그동안 직접 구현해주던 방식은 내부의 로직을 직접 만지는 방식이었는데, 스토리북을 활용하면 훨씬 더 직관적인 코드를 작성할 수 있음과 동시에, 적용형태가 기존 로직 코드와는 전혀 다른, 로직 코드의 생김새를 상상할 수 없는, 말그대로 블랙박스 형태로 만들어주는 툴인 것 같아요

따라서 추상화 및 컴포넌트 분리를 지향하는 리액트에서 사용하기 좋은 도구라는 생각이 들었습니다

답글 달기
comment-user-thumbnail
2023년 12월 18일

저 이 아티클을 통해 storybook을 처음 접해보았는데요..!

합동세미나도 그렇고 토이프로젝트도 그렇고 제 노트북의 문제일지는 모르겠지만, 아주 작은 스타일을 수정했음에도 불구하고 뷰를 확인하는데까지 시간이 엄청나게 오래 걸리는 것을 경험했습니다.. 아티클을 읽으면서 바로 이 storybook의 독립적인 UI개발이 가능하다는 이점이 그런 문제를 해결해줄 수 있을 것 같다는 생각이 들었습니다.

storybook을 이용하면 모든 UI 조각이 컴포넌트가 되며, 컴포넌트의 이점은 어떻게 렌더링되는지 보기 위해 전체를 돌릴 필요가 없다는 것입니다. 따라서 props, mock 데이터, faking event를 전달해 특정 변화에 따라 별도로 렌더링 할 수 있게 됩니다. 스토리는 컴포넌트의 변화를 시뮬레이션하기 위해 props와 mock 데이터를 제공하기 위한 선언적 구문이라 정의할 수 있겠네용.. storybook에다가 mock api까지 함께 활용하면 더이상 백엔드에 종속된 컴포넌트 개발을 하지 않아도 된다는 점..! 을 보니 한번 제대로 공부해서 사용해보고 싶다는 생각이 들었습니다.

요렇게 좋은 아티클 써준 혠언니한테 무한의 감사를 드립니다♡

답글 달기
comment-user-thumbnail
2023년 12월 18일

전 진짜 멋모를때 스토리북을 한번 사용해본적이있는데요 .. 당시 이미 부피가 많이 커진 프로젝트에 제가 중간에 들어갔던거라 컴포넌트 이해에 도움이되라고 스토리북 사용을 권장해주셨어요. 근데 앗차차 ,, 너무 감자라 오히려 더 어려웠었는데 이렇게 자세히 쉽게 설명해주셔서 넘 좋아요.. 그때의 내가 봤어야했는데 ,,

전 스토리북으로 컴포넌트 ui 직관화에 대해 흥미가 있어서, 스토리북으로 동적인 props를 어떻게 추가하는지 알아봤습니다. props 값을 storybook에서 받을 수 있도록 args 안에 props를 설정해주고, storybook에서 설정한 args 옵션을 받아와 해당 컴포넌트에 추가해주면 된다고 하네요! js 기준으로 찾아봐서 ts로 할땐 어떻게해야할지 더 공부해보고싶어욧

바쁜 앱잼과 토이플젝 기간에 이렇게 좋은 아티클 넘 넘 감사합니닷!!♡

답글 달기
comment-user-thumbnail
2023년 12월 19일

혜인님이 storybook을 다뤄주신 덕분에 개념과 튜토리얼을 잘배웠습니다. 댓글까지 유익한 것이 많아서 정말 많이 배웠는데 저에겐 이해가 쉽지 않아서 기초부터 공부해보았는데요
스토리북은 UI 라이브러리는 웹 개발을 단순화하지만 테스트 및 디버깅과 같은 새로운 복잡성도 도입한다고 합니다.
또한 스토리북은 UI 컴포넌트를 독립적으로 구현하여 각 컴포넌트 작업을 위한 깔끔한 인터페이스를 제공할 수 있습니다. 저 역시 여러 분기로 다뤄지는 컴포넌트 상태에 대해 어려움을 느낀적이 있었고 특히 다른 사람의 코드를 볼 때 일일히 개발서버를 열어서 확인하는 것이 아니라 “문서화” 되어있다는 것이 큰 장점이 될 수 있을 것이라고 생각이 됐습니다. 또 구현 세부사항을 확인하기 쉽다는 장점이 있어서 꼭 한 번 활용해보고 싶네요

StoryBook은 컴포넌트 중심 개발 (CDD) 방법론을 사용하여 UI 구성요소를 만드는데 이 방법론에 따라 필수 구성요소부터 시작하여 점진적으로 복잡한 화면과 앱으로 결합하는 모듈식 구축이 가능하다고 하네요. 마지막으로 이 CDD가 무슨 장점이 있는지가 궁금해서 찾아보았는데
품질 (Quality) 독립적으로 컴포넌트를 분리하여 관련 상태를 정의하여 UI가 다양한 시나리오에서 작동하는 지 확인 가능합니다.
내구성 (Durability) 컴포넌트 수준에서 테스트하여 세부 사항까지 버그를 정확하게 찾아낼 수 있습니다. 테스트 보다 작업량이 적습니다.
속도 (Speed) 컴포넌트 라이브러리 또는 디자인 시스템의 컴포넌트를 재사용하여 UI를 보다 빠르게 조립할 수 있습니다.
효율성 (Efficiency) UI를 개별 컴포넌트로 분해 한 다음 서로 다른 팀 구성원 간에 공유하여 개발 및 디자인을 병렬 처리합니다.
이상 4가지를 언급하고 있습니다. 적응하게 된다면 꽤 많은 장점을 가져갈 수 있을 것 같다는 생각이 들었습니다!

답글 달기