Common UI Package (feat. Storybook)

Thomas·2022년 7월 30일
0

Intro

Common UI Component Package 에 Storybook 을 접목시켜 컴포넌트를 독립적으로 스토리를 짜서 테스트 및 개발 할 수 있는 환경을 구축해봤습니다.


이미지
Storybook 결과화면

Emotion 과 MUI 를 활용해 작업할 수 있도록 해당 라이브러리를 설치 했고 (@emotion/styled, @emotion/react, @mui/material, @mui/icon-material), 기타 다른 라이브러리에 의존성이 있는 컴포넌트를 위해서 다른 third-party-library 를 추후 설치할 예정입니다. (예를 들면 react-table 등 ..)

#. 패키지

Common UI Component Package 는 기존에 만들어 놓았던 프로젝트를 활용했습니다. 해당 프로젝트에 Storybook 을 접목해보겠습니다.

#. 설치

Storybook 을 활용하기 위해서 Storybook 을 프로젝트에 설치했습니다.

npx -p @storybook/cli sb init
npm install dotenv-webpack --save-dev

dotenv.env 파일에 선언한 변수를 process.env 에 로드 해주는 “무 의존성“ 모듈입니다.

#. 실행

npm run storybook

#. 설치 후..

설치 후 src 폴더 밑에 stories 폴더가 생겼습니다.

해당 라이브러리는 src/lib 폴더의 Typscript 파일들을 컴파일 하여서 패키징 하고 있습니다. Storybook 을 활용하기 위해서 컴포넌트를 stories 폴더 밑에서 생성할것이기 때문에 Typescript 컴파일 대상들을 변경 해줍니다.

아래 코드 중 includeexclude 를 변경했습니다.

//tsconfig.json
{
  "compilerOptions": {
    "target": "es5",
    "lib": ["dom", "dom.iterable", "esnext"],
    "allowJs": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "noFallthroughCasesInSwitch": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": false,
    "jsx": "react-jsx",
    "declaration": true,
    "outDir": "./dist"
  },
  // "include": ["./src/lib/**/*.tsx", "./src/lib/**/*.ts"]
  "include": [
    "./src/stories/**/*.tsx",
    "./src/stories/**/*.ts",
    "src/index.ts",
    "src/stories/index.js"
  ],
  "exclude": ["./src/stories/**/*.stories.tsx", "./src/stories/Template/**"]
}

#. 간단하게 적용해보기

테스트를 위해서 RoRo 에서 사용하고 있는 <Button>, <BlankLink>, <Spinner> 를 패키지에 담아봤습니다.

directory
디렉토리 구조

디렉토리는 index.ts, Component.tsx, Component.stories.tsx 를 담고있는 Component 폴더로 구성되어 있습니다.

//Button.tsx

import React, { ReactElement } from "react";
import {
  Button as MUIButton,
  ButtonProps as MUIButtonProps,
} from "@mui/material";

/**
 * Button Docs
 * MUI Component 활용
 */

export interface ButtonProps extends MUIButtonProps {
  text: string;
}

function Button(props: ButtonProps): ReactElement {
  return <MUIButton {...props}>{props.text}</MUIButton>;
}

Button.defaultProps = {
  variant: "outlined",
};

export default Button;

아래는 Storybook 을 위한 Story 작성 파일입니다.
//Button.stories.tsx

import React from "react";
import Button, { ButtonProps } from "./Button";

import { ComponentMeta, Story } from "@storybook/react";

export default {
  title: "Component/Button",
  component: Button,
} as ComponentMeta<typeof Button>;

const Templete: Story<ButtonProps> = (args) => {
  const { text = "default" } = args;
  return <Button text={text} {...args} />;
};

export const Basic = Templete.bind({});

마지막으로 export 를 위한 index.ts 입니다.

//index.ts

export { default } from "./Button";

Storybook 에서 docs 주석을 남기려면 Button.tsx 에 담겨있는 구조의 주석을 활용해야 합니다.

간단하게 컴포넌트를 작성하고, stories 에 작성한 컴포넌트를 매칭해줍니다.

ComponentMeta 타입에 제네릭으로 해당 컴포넌트를 연결시켜 줍니다. 프로퍼티 중 title 은 Storybook 에 나타낼 컴포넌트의 이름, component 는 Storybook 에 나타낼 컴포넌트를 매칭시켜 줍니다.

Templete 은 여러개 작성할 수 있습니다. Templete 을 통해서 해당 컴포넌트의 여러 스토리를 작성할 수 있습니다.

import React from "react";
import Button, { ButtonProps } from "./Button";

import { ComponentMeta, Story } from "@storybook/react";

export default {
  title: "Component/Button",
  component: Button,
} as ComponentMeta<typeof Button>;

const firstTemplete: Story<ButtonProps> = (args) => {
  const { text = "first" } = args;
  return <Button text={text} {...args} />;
};

const secondTemplete: Story<ButtonProps> = (args) => {
  const { text = "second" } = args;
  return <Button text={text} {...args} />;
};

const thirdTemplete: Story<ButtonProps> = (args) => {
  const { text = "third" } = args;
  return <Button text={text} {...args} />;
};

export const First = firstTemplete.bind({});
export const Second = secondTemplete.bind({});
export const Third = thirdTemplete.bind({});

#. 타입스크립트 컴파일

컴포넌트를 작성한 후 패키지를 퍼블리싱 하기 위해 npm run prepare실행 해줍니다.

after Compile
컴파일 후 directory

타입스크립트 컴파일 된 폴더의 모습입니다. stories 파일을 제외한 파일들이 컴파일 되었습니다.

After Searching…

UI Component Package 프로젝트에 Storybook 을 접목시켜 코드를 작성해보니, 독립된 컴포넌트 단위로 개발을 하는데 실시간으로 개발되는 컴포넌트를 시각적으로 체크할 수 있고 MUI 등 기타 라이브러리와 연동되는 Storybook 덕분에 개발 경험이 향상될 것 같다는 생각이 들었습니다.

해당 패키지를 다른 프로젝트에서 사용하려면 빌드하고 다른 프로젝트에서 install 해야 할 텐데, 해당 프로젝트를 npm 을 통해 관리하지 않는다면 어떻게 관리할 수 있을지 생각해봐야겠습니다.

profile
안녕하세요! 주니어 웹 개발자입니다 😆

0개의 댓글