✅ 본 게시글은 스토리북 7.1.0 버전과 TypeScript를 기반으로 작성되었습니다.
Storybook으로 컴포넌트를 문서화해보자
치스톡에서 디자인 시스템을 만들면서 신경쓰고 있는 부분 중 하나가 스토리북 활용이다.
스토리북은 컴포넌트를 서비스 로직과 독립된 UI를 실행, 테스트하는 용도로도 사용할 수 있지만,
컴포넌트를 설명하기 위한 문서로도 사용할 수 있다.
오늘은 이 문서 용도에 집중에서 스토리북으로 어떻게 컴포넌트 문서를 작성할 수 있는지 알아보려고 한다.
1️⃣ Autodocs & JSDoc로 문서 작성하기
- `'autodocs'` 태그
스토리북은 컴포넌트를 자동으로 문서화해주는 기능을 가지고 있다.
바로 autodocs 기능인데 이는 스토리북의 메타 정보에 tag에 `'autodocs'` 태그를 추가해주면 바로 사용할 수 있다.
// Component.stories.tsx
const meta = {
...,
tags: ["autodocs"],
} satisfies Meta<typeof Component>;
`'autodocs'` 태그가 적용된 컴포넌트는 자동으로 스토리북 상에 Docs가 추가된다.
이 Docs 문서는 스토리북에서 자체적으로 생성한 문서로
처음 작성한 스토리를 가장 위에 두고 밑으로 매개변수에 대한 Controls 패널과 이후 작성한 스토리들이 쭉 나열되는 형태를 가진다.
⚠️ 스토리북 7버전부터 @storybook/addon-docs가 기본적으로 포함되었으며,
스토리별로 Docs 문서가 나타나는 것이 아닌 컴포넌트 별로 한 개의 문서만 생성되도록 변경되었습니다.https://storybook.js.org/blog/storybook-7-docs/
- JSDoc으로 설명 및 추가 정보 제공하기
위에서 문서를 만들었지만 아쉬운 부분들이 있다.
자동 생성된 문서에는 컴포넌트와 파라미터들 그리고 스토리만 띡 하고 만들어져 있을 뿐 구체적인 설명이 적혀있지는 않기 때문이다.
이를 보완하는 방법으로 JSDoc을 이용해서 스토리북에 설명이나 추가 정보를 제공할 수 있다.
스토리북은 이 JSDoc을 바탕으로 추가적인 정보를 갱신하거나 설명을 추가한다.
간단하게 컴포넌트에 JSDoc 주석을 추가해보자.
// Button.tsx
/**
* 버튼을 표시합니다.
*/
const Button = (props) => {
return <button>버튼</button>
}
JSDoc은 설명하고 싶은 부분 바로 위에 `/** 주석 내용 */`의 형태로 작성한다.
이렇게 작성해두면 Button에 마우스 호버 시, 이에 관한 설명으로 표시된다.
스토리북은 이 내용을 자동으로 불러와 문서 상에 표시한다.
JSDoc 설명은 마크다운을 기반으로 렌더링 된다.
이렇게 설명을 추가하는 기능은 컴포넌트 뿐만 아니라 개별 스토리에 대해서도 동작할 뿐더러 props 속성들에 대해서도 동작한다.
// Button.types.ts
export type ButtonBasePropsType = NonNullableProps<VariantProps<typeof buttonVariants>> & {
/** 버튼 비활성화 여부
* @default false
*/
disabled?: boolean;
/** 렌더링할 Icon 컴포넌트
*
* @type Icon
*/
...
};
위와 같이 PropsType에서 각 속성들에 설명과 `@default`를 통해 기본값에 대한 정보를 제공해주자.
이를 스토리북에서는 아래와 같이 불러온다.
- argsType으로 추가 정보 제공 및 제한 걸기
JSDoc만으로 추가정보를 제공할 수 없는 경우가 있다.
공용적으로 쓰이는 타입으로부터 상속받은 속성이라거나
아니면 스토리북에서 속성을 너무 잘 추출한 바람에 보여주고 싶지 않은 속성들까지 표시하는 경우인데
스토리파일의 meta 정보에 argsType을 이용해 이에 추가적인 정보를 제공하거나 혹은 제한을 걸 수도 있다.
// Button.stories.tsx
const meta = {
...
argTypes: {
renderAs: {
description: "버튼 컴포넌트가 렌더링될 수 있는 종류",
table: {
defaultValue: { summary: "button" },
type: {
summary: `"button" | "a" | "next/Link"`,
},
},
},
},
} satisfies Meta<typeof Button>;
예를 들어 메타 정보에 renderAs 속성에 추가 정보를 제공해보자.
renderAs의 기본값을 button으로, 타입을 'button' | 'a' | 'next/Link'로 설정하면
스토리북에서 아래와 같이 반영된다.
만약 특정 속성을 숨기고 싶을 경우 아래와 같이 작성하면 된다.
// Button.stories.tsx
const meta = {
...
argTypes: {
hiddenArg: {
table: {
disabled: true,
},
},
},
} satisfies Meta<typeof Button>;
- AutoDocs Template 설정하기
기본적으로 제공되는 Autodocs 문서의 형태가 불만족스럽다면, 문서의 템플릿을 설정할 수 있다.
// .storybook/StorybookTemplate.tsx
import { ArgTypes, Description, Primary, Stories, Title } from "@storybook/blocks";
import React from "react";
const StorybookTemplate = () => {
return (
<>
<br />
<br />
<br />
<br />
<Title />
<Description />
<Primary />
<ArgTypes />
<Stories />
<br />
<br />
</>
);
};
export default StorybookTemplate;
먼저 .storybook 폴더에 StorybookTemplate.tsx 파일을 만들고 내부에 템플릿 컴포넌트를 선언해준다.
스토리북에서 `@storybook/blocks`를 통해 스토리북 상에서 제공하는 기본 컴포넌트를 불러올 수 있다.
(자세한 blocks의 종류는 Storybook - API - Doc blocks를 참조)
이를 이용해 스토리북 커스텀 템플릿을 구성한다.
// .storybook/preview.tsx
import React from "react";
import StorybookTemplate from "./StorybookTemplate";
const preview: Preview = {
parameters: {
...,
docs: { // 추가
page: StorybookTemplate,
},
},
...
};
export default preview;
이후 preview.tsx로 파일 확장자를 수정하고, parameters에 위와 같이 docs 속성을 추가해준다.
다시 스토리북을 열면 해당 템플릿이 적용되어 있을 것이다.
(템플릿은 mdx 파일로도 작성 가능)
2️⃣ MDX로 문서 작성하기
MDX는 마크다운을 기반으로 JSX 문법을 사용할 수 있게 해주는 파일 포맷이다.
스토리북 역시도 MDX 형태의 문서 작성을 지원한다.
VS Code에서 MDX를 바로 사용할 수 있지만 Syntax Highlighting을 위해서 MDX 익스텐션을 설치할 것을 추천한다.
MDX - Visual Studio Marketplace
Extension for Visual Studio Code - Language support for MDX
marketplace.visualstudio.com
- mdx 설정하기
MDX의 가장 큰 장점은 Autodocs가 컴포넌트 기반으로 생성되는 컴포넌트 종속적인 문서라는 점과 달리
컴포넌트와 독립적으로 문서를 생성할 수 있다는 점이다.
mdx 형태의 스토리를 적기 위해서 스.storybook/main.ts를 수정해준다.
// .storybook/main.ts
import type { StorybookConfig } from "@storybook/nextjs";
const config: StorybookConfig = {
stories: ["../src/**/*.mdx", "../src/**/*.stories.@(js|jsx|mjs|ts|tsx)"], //mdx 추가
...
};
export default config;
- 디자인 토큰 문서화하기
먼저, 컴포넌트가 아닌 디자인 시스템에서 사용되는 테두리 반경에 관한 문서를 작성해보자.
// BorderRadii.mdx
import { Meta } from "@storybook/blocks";
<Meta title="Token/BorderRadii" />
먼저 스토리북의 Meta 블록을 사용해서 문서의 메타 정보들을 작성해준다.
이 블록은 story 파일의 meta 객체와 같은 역할로, 필수적으로 작성해줘야한다.
import { Canvas, Meta } from "@storybook/blocks";
<Meta title="Token/BorderRadii" />
<br />
<br />
<br />
<br />
# Border Radii
치스톡에 사용되는 테두리 반경을 정의합니다.
<Canvas withSource="none">
<div className="flex flex-col gap-2xl ml-xl">
<div className="flex gap-l">
<div className="flex gap-2xl items-center">
<div className="w-[64px] h-[64px] bg-[#0A5AFA] rounded-none" />
</div>
<div className="flex gap-2xl items-center">
<div className="w-[64px] h-[64px] bg-[#0A5AFA] rounded-xs" />
</div>
<div className="flex gap-2xl items-center">
<div className="w-[64px] h-[64px] bg-[#0A5AFA] rounded-s" />
</div>
<div className="flex gap-2xl items-center">
<div className="w-[64px] h-[64px] bg-[#0A5AFA] rounded-m" />
</div>
<div className="flex gap-2xl items-center">
<div className="w-[64px] h-[64px] bg-[#0A5AFA] rounded-l" />
</div>
<div className="flex gap-2xl items-center">
<div className="w-[64px] h-[64px] bg-[#0A5AFA] rounded-circle" />
</div>
</div>
<div className="flex gap-l">
<div className="w-[64px] text-center text-l font-bold">none</div>
<div className="w-[64px] text-center text-l font-bold">xs</div>
<div className="w-[64px] text-center text-l font-bold">s</div>
<div className="w-[64px] text-center text-l font-bold">m</div>
<div className="w-[64px] text-center text-l font-bold">l</div>
<div className="w-[64px] text-center text-l font-bold">circle</div>
</div>
</div>
</Canvas>
그 다음 전체 문서를 작성하면 끝난다.
사용되는 블록에 대한 정보는
이후 스토리북을 실행해보면 스토리북 내에서 BorderRadii라는 문서가 작성된 것이 보인다.
(자세한 blocks의 종류는 Storybook - API - Doc blocks를 참조)
- 컴포넌트 문서화하기
물론 mdx로 컴포넌트 역시 문서화할 수 있다.
const meta = {
...
// tags: ["autodocs"], // autodocs 삭제
} satisfies Meta<typeof Button>;
먼저, 기존에 autodocs를 통해서 문서를 생성해주고 있었다면, autodocs 부분을 story meta 정보에서 삭제해준다.
// Button.mdx
import { Meta } from "@storybook/blocks";
import * as ButtonStories from "./Button.stories";
<Meta of={ButtonStories} />
그다음 mdx 파일을 만들고 스토리 파일을 불러와 Meta 블록의 of 속성에 넣어준다.
이렇게 기존 스토리 파일의 메타 정보를 mdx 문서의 Meta 블록으로 불러올 수 있다.
import { Canvas, Meta, Description, Story, Title } from "@storybook/blocks";
import * as ButtonStories from "./Button.stories";
...(생략)
# Storybook 예제
### Title
타이틀을 불러옵니다.
<Title />
### Description
설정된 JSDoc 설명을 불러옵니다.
<Description of={ButtonStories.Default} />
### Story
스토리 파일에 정의된 특정 스토리를 가져와서 인라인으로 보여줍니다.
JSDoc으로 설정한 주석은 불러와지지 않습니다.
<Story of={ButtonStories.Default} />
---
### Canvas
스토리 파일에 정의된 특정 스토리를 가져와서 Canvas 안에 담아 보여줍니다.
JSDoc으로 설정한 주석은 불러와지지 않습니다.
<Canvas of={ButtonStories.Default} />
---
스토리를 보여주는 방식 역시 Meta 정보와 비슷한데
필요한 블록을 불러와 of에 불러온 스토리파일에서 특정 스토리를 넣어줄 수 있다.
위 코드의 경우 아래처럼 보여진다.
이 외에도 필요한 블록이 있다면 `@storybook/blocks`에서 가져와 사용하면 된다.
(자세한 blocks의 종류는 Storybook - API - Doc blocks를 참조)
단순히 storybook의 blocks 뿐만 아니라 내가 정의한 리액트 컴포넌트들 역시 불러올 수 있다.
이를 통해 문서를 내가 원하는데로 커스터마이징 할 수 있다.
🆚 Autodocs vs MDX
Autodocs와 MDX는 서로가 상호 보완하는 문서 형태이다
이 둘을 비교해보면 아래와 같다.
Autodocs | MDX |
- 👍자동 문서 생성 - 👍Template 설정 가능 - 👍TypeScript 지원 - 👎스토리 파일이 있는 컴포넌트에 대해서만 자동 생성 - 👎커스터마이징의 한계 |
- 👍자유로운 커스터마이징 - 👍컴포넌트 이외의 요소들에 대해서도 문서화 가능 - 👎Template 적용 불가 - 👎별도의 파일을 만들어서 관리해야하는 번거로움 - 👎TypeScript 미지원(혹은 불충분) |
각각의 장단점을 고려해보고 필요에 따라 더 좋은 쪽을 선택해서 문서를 작성하면 되겠다.
'Frontend > 기타' 카테고리의 다른 글
Chromatic으로 시각적 회귀 테스트 구축하기 (0) | 2023.09.13 |
---|---|
Create Issue Branch로 이슈 브랜치 자동 생성하기 (0) | 2023.09.01 |
prettier로 import 정렬하기 (0) | 2023.09.01 |
husky로 git hook 만들기(with lint-staged, git-cz) (0) | 2023.08.25 |
Next.js와 Storybook에 SVGR 설정하기 (0) | 2023.08.06 |