Next.js에서 스토리북(Storybook) 설정 및 활용 가이드 (version 8)

Next.js 프로젝트에서 스토리북(Storybook)을 설정하고 사용 방법을 자세히 설명합니다.

  • Next.js 15.2.3
  • Storybook 8.6.8
  • TypeScript ^5.0.0

소개

이번 글에서는 Next.js 프로젝트에서 스토리북(Storybook)을 설정하고 활용하는 방법을 자세히 설명합니다. 스토리북은 컴포넌트를 개발하고 테스트하는 데 유용한 도구로, 컴포넌트를 독립적으로 개발하고 테스트할 수 있습니다. 또한 스토리북을 사용하면 컴포넌트의 상태를 쉽게 관리하고, 필요한 컴포넌트 ui를 찾기도 쉬우며, 다양한 상황에서 컴포넌트를 테스트할 수 있습니다.

이번 글에서는 next.js 15.2.3 버전과 storybook 8.6.8 버전을 기준으로 설명합니다.

목차

Next.js 프로젝트 생성

먼저 Next.js 프로젝트를 생성합니다. Next.js 프로젝트를 생성하려면 다음 명령어를 실행합니다.

npx create-next-app@latest my-next-app

next js 설치시 나타나는 옵션은 취향껏 선택하시면 됩니다. 단, app router를 권장합니다. (본 가이드에서는 app router를 사용합니다.)

Storybook 설치

Next.js 프로젝트에서 스토리북을 사용하려면 먼저 스토리북을 설치해야 합니다. 스토리북을 설치하려면 다음 명령어를 실행합니다.

npm create storybook@latest

위 명령어를 입력하면 옵션이 나타나는데 Documentation: MDX, auto-generated component docs 옵션을 선택합니다.

Documentation: MDX, auto-generated component docs 옵션을 선택하면 스토리북에 MDX 문서를 사용할 수 있으며, 컴포넌트의 문서를 자동으로 생성할 수 있습니다.

설치 중 다음 옵션 질문이 나타납니다. The addon requires the use of @storybook/experimental-nextjs-vite to work with Next.js.

이 옵션에선 n(no)을 입력하여 설치를 진행합니다.

만약 Y를 입력하였다면 storybook 페이지가 나타나지 않을 수 있습니다. 이럴땐 다음과 같이 설치된 스토리북 파일에서 다음과 같이 설정합니다.

.storybook/main.js 파일을 열어 다음과 같이 설정합니다.

.storybook/main.js
  "framework": {
    "name": "@storybook/nextjs",
    "options": {}
  },

framework 라는 속성에서 name@storybook/nextjs로 설정합니다.

설치가 완료되면 자동으로 storybook 페이지가 열리며, 스토리북 문서를 볼 수 있습니다.

만약 스토리북 페이지가 열리지 않는다면 다음 명령어를 실행하여 스토리북 페이지를 열 수 있습니다.

npm run storybook

스토리북 설치 후 기본 url은 http://localhost:6006 입니다.

만약 port를 변경하고 싶다면 다음과 같이 명령어를 실행합니다.

npm run storybook -- -p 9000

위 명령어를 실행하면 스토리북 페이지가 http://localhost:9000으로 열립니다.

또한 package.json 파일에 다음과 같이 스토리북 스크립트를 추가할 수 있습니다.

package.json
{
  "scripts": {
    // ...
    "storybook": "storybook -p 9000"
    // ...
  }
}

스토리북이 설치되면 기본 컴포넌트가 생성되며, 스토리북 페이지에서 컴포넌트를 확인할 수 있습니다.

storybook.storybook 폴더와 stories 폴더를 생성합니다. .storybook 폴더에는 스토리북 설정 파일이 있으며, stories 폴더에는 스토리북 컴포넌트가 있습니다.

이제 스토리북 파일을 하나씩 살펴보겠습니다.

Storybook 설정 파일

스토리북 설정 파일은 .storybook 폴더에 있으며, main.js 파일입니다. main.js 파일은 스토리북의 설정을 관리하는 파일로, 스토리북의 설정을 변경할 수 있습니다.

main.js 파일은 다음과 같이 설정할 수 있습니다.

.storybook/main.js
import type { StorybookConfig } from "@storybook/nextjs";
 
const config: StorybookConfig = {
  stories: [
    "../stories/**/*.mdx",
    "../stories/**/*.stories.@(js|jsx|mjs|ts|tsx)",
  ],
  addons: [
    "@storybook/addon-essentials",
    "@storybook/addon-onboarding",
    "@chromatic-com/storybook",
    "@storybook/experimental-addon-test",
  ],
  framework: {
    name: "@storybook/nextjs",
    options: {},
  },
  staticDirs: ["../public"],
};
export default config;

위 설정은 스토리북의 기본 설정 파일입니다. 설정의 속성은 다음과 같습니다.

  • stories: 스토리북의 스토리 파일을 설정합니다.
  • addons: 스토리북의 애드온을 설정합니다.
  • framework: 스토리북의 프레임워크를 설정합니다.
  • staticDirs: 스토리북의 정적 파일을 설정합니다.

stories 속성은 스토리북의 스토리 파일을 설정합니다. 스토리 파일은 stories 폴더에 있으며, stories 폴더에는 *.stories.@(js|jsx|mjs|ts|tsx) 파일과 *.mdx 파일이 있습니다. 이는 허용된 파일 확장자로, 스토리북의 스토리 파일을 설정할 수 있습니다.

addons 속성은 스토리북의 애드온을 설정합니다. 애드온은 스토리북의 기능을 확장하는 도구로, 스토리북의 기능을 확장하거나, 스토리북의 기능을 추가할 수 있습니다.

framework 속성은 스토리북의 프레임워크를 설정합니다. 현재 next js 프레임워크를 사용하고 있으며, @storybook/nextjs 프레임워크를 설정합니다.

staticDirs 속성은 스토리북의 정적 파일을 설정합니다. 정적 파일은 스토리북 페이지에 로드할 수 있는 파일을 설정할 수 있습니다.

Configure.mdx 파일

stories 폴더에는 Configure.mdx 파일이 있습니다. Configure.mdx 파일은 스토리북 페이지 메인의 mdx 문서를 설정하는 파일입니다.

mdx 문서는 markdown 문서와 jsx 문서를 혼합한 문서로, mdx 문서를 사용하면 markdown 문서와 jsx 문서를 혼합하여 문서를 작성할 수 있습니다.

Configure.mdx 파일은 메인에 노출 되기때문에 보통 회사의 디자인 시스템 소개나 전체적인 소개글에 사용됩니다.

<Meta title="좌측 네비게이션 이름" /> 을 사용해 좌측 네비게이션 이름을 설정할 수 있습니다.

이제 스토리북 컴포넌트를 하나씩 살펴보겠습니다.

Storybook 컴포넌트

스토리북 컴포넌트는 stories 폴더에 있으며, *.stories.@(js|jsx|mjs|ts|tsx) 파일과 *.mdx 파일이 있습니다. 이 파일은 스토리북의 컴포넌트를 설정하는 파일로, 컴포넌트의 스토리를 설정할 수 있습니다.

스토리북 컴포넌트는 다음과 같이 설정할 수 있습니다.

예를 들어 버튼 스토리북 컴포넌트를 설정하려면 다음과 같이 설정합니다. (미리 설정된 버튼 컴포넌트를 예시입니다.)

stories/Button.stories.tsx
import type {Meta, StoryObj} from '@storybook/react';
import {fn} from '@storybook/test';
import {Button} from './Button';
 
const meta = {
  title: 'Example/Button', // 좌측 네비게이션 이름
  component: Button,
  parameters: {
    layout: 'centered',
  },
  tags: ['autodocs'],
  argTypes: {
    backgroundColor: { control: 'color' },
  },
  args: { onClick: fn() },
} satisfies Meta<typeof Button>;
 
export default meta;
type Story = StoryObj<typeof meta>;
 
export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
};
 
export const Secondary: Story = {
  args: {
    label: 'Button',
  },
};
 
// ...

위 설정은 버튼 컴포넌트의 스토리를 설정하는 파일입니다. Button.stories.tsx 파일은 버튼 컴포넌트의 스토리를 설정하며, 버튼 컴포넌트의 스토리를 설정할 수 있습니다.

Button.stories.tsx 파일은 다음과 같은 속성을 설정할 수 있습니다.

meta: 스토리의 메타 정보를 설정합니다.

meta 속성은 스토리의 메타 정보를 설정합니다. 메타 정보는 스토리의 제목, 컴포넌트, 레이아웃, 태그, 인수 타입을 설정할 수 있습니다.

meta 속성은 다음과 같은 속성을 설정할 수 있습니다.

title: 스토리의 제목을 설정합니다.

title 속성은 스토리의 제목을 설정합니다. 스토리의 제목은 스토리북 페이지에서 스토리의 제목으로 표시됩니다.

Example/Button 은 좌측 네비게이션의 이름을 설정합니다.

앞의 Example은 네비게이션에서 상위 카테고리를 의미하며, Button은 하위 카테고리를 의미합니다.

카테고리를 설정하려면 Example/Button 형식으로 설정합니다.

카테고리 없이 Button으로 설정하면 좌측 네비게이션에 Button이라는 이름으로 표시됩니다.

스토리북 네비게이션 예시

스토리북 네비게이션 예시

component: 스토리의 컴포넌트를 설정합니다.

component 속성은 스토리의 컴포넌트를 설정합니다. 컴포넌트는 스토리북 페이지에서 컴포넌트로 표시됩니다.

예를 들어 /components/Button.tsx 파일에 버튼 컴포넌트를 만들면 Button.stories.tsx 파일에서 component: Button으로 설정합니다.

버튼 컴포넌트를 스토리북 페이지에서 확인할 수 있습니다.

parameters: 스토리의 레이아웃을 설정합니다.

parameters 속성은 스토리의 레이아웃을 설정합니다. 레이아웃은 스토리북 페이지에서 스토리의 레이아웃을 설정할 수 있습니다.

layout: 'centered'로 설정하면 스토리의 레이아웃을 가운데로 설정합니다.

옵션은 다음과 같습니다.

  • centered: 스토리의 레이아웃을 가운데로 설정합니다.
  • fullscreen: 스토리의 레이아웃을 전체화면으로 설정합니다.
  • padded: 스토리의 레이아웃을 패딩으로 설정합니다.

tags: 스토리의 태그를 설정합니다.

tags 속성은 스토리의 태그를 설정합니다. 태그는 스토리북 페이지에서 스토리의 태그를 설정할 수 있습니다.

tags: ['autodocs']로 설정하면 스토리북에 자동으로 문서(Docs)를 생성합니다.

Docs는 컴포넌트의 문서를 자동으로 생성하는 기능으로, 컴포넌트의 문서를 자동으로 생성할 수 있습니다.

해당 stories 파일에서 내보내기 된 객체가 미리보기에 포함됩니다.

내보내기는 예를들어 다음과 같습니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
export const Primary: Story = {
  args: {
    primary: true,
    label: "Button",
  },
};
 
export const Secondary: Story = {
  args: {
    label: "Button",
  },
};

만약 Docs 페이지에서 제외하기 위해서 tags: ['!autodocs']를 사용할 수 있습니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
export const Primary: Story = {
  args: {
    primary: true,
    label: "Button",
  },
  tags: ["!autodocs"],
};

위와 같이 설정하면 Docs 페이지에서 Primary 스토리가 제외됩니다.

문서의 테이블에서 Description을 메모할 수 있습니다.

컴포넌트의 옵션에 문서를 추가하려면 JS doc 주석으로 설정할 수 있습니다.

주석은 해당 컴포넌트에서 interface안에서 사용해야합니다.

components/Button.tsx
export interface ButtonProps {
  /**
   * 버튼의 primary 속성을 설정합니다.
   */
  primary?: boolean;
  /**
   *  버튼의 배경색을 설정합니다.
   */
  backgroundColor?: string;
  /**
   * 버튼의 사이즈를 설정합니다.
   */
  size?: "small" | "medium" | "large";
  /**
   * 버튼의 라벨을 설정합니다.
   */
  label: string;
  /**
   * 버튼의 클릭 이벤트를 설정합니다.
   */
  onClick?: () => void;
}
 
// ... Button 컴포넌트 설정 생략
스토리북 Docs 페이지 예시

스토리북 Docs 페이지 예시

또한 다음에 설명할 argTypes 속성을 사용하여 description 속성을 설정할 수 있습니다.

argTypes: 스토리의 인수 타입을 설정합니다.

argTypes 속성은 스토리의 사용자가 설정할 수 있는 값을 설정하고 테스트 할 수 있습니다.

우선 argTypes는 자동으로 추론하여 설정됩니다.

Docs의 페이지에서 table로 표시되는 컴포넌트의 속성을 설정할 수 있습니다.

수동으로 설정하려면 다음과 같이 설정합니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
argTypes: {
  backgroundColor: { control: "color" },
  size: {
    control: {
      type: "select",
      options: ["small", "medium", "large"],
    },
  },
},
테이블의 설정된 agrType

테이블의 설정된 agrType

control 속성을 사용해서 Docs 페이지에서 테이블로 표시되는 제어들을 설정할 수 있습니다.

argTypes의 첫번째 속성은 interface에서 설정한 속성을 설정합니다. 즉 Docs에 표시된 table의 name과 일치해야합니다.

이전에 주석을 사용했던 description 속성을 설정하려면 다음과 같이 설정합니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
 
argTypes: {
  backgroundColor: { control: "color" },
  size: {
    control: {
      type: "select",
      options: ["small", "medium", "large"],
    },
  },
  label: {
    description: "버튼의 라벨을 설정합니다.",
  },
},

controltype 속성은 다음과 같습니다.

  • boolean: 불리언 입력란을 설정합니다.
  • date: 날짜 입력란을 설정합니다.
  • number: 숫자 입력란을 설정합니다.
  • color: 색상 입력란을 설정합니다.
  • file: 파일 입력란을 설정합니다.
  • check: 체크 입력란을 설정합니다.
  • text: 텍스트 입력란을 설정합니다.
  • select: 선택 입력란을 설정합니다.
  • radio: 라디오 입력란을 설정합니다.
  • range: 범위 입력란을 설정합니다.

등등 이 있습니다. 주로 input 태그의 type 속성과 비슷합니다.

이를 사용하여 커스텀을 통해 스토리북을 사용하는 사용자에게 옵션을 변경할 수 있는 기능을 제공할 수 있습니다.

args: 스토리의 인수를 설정합니다.

argsargTypes와 사용법이 비슷합니다.

각 스토리의 공통적인 부분을 설정할 수 있습니다.

예를 들어 onClick 이벤트를 설정하려면 다음과 같이 설정합니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
 
args: {
  onClick: fn(),
},

fn()@storybook/test에서 제공하는 함수로, 클릭 이벤트를 설정할 수 있습니다.

이 부분에 대해서는 이번 글에서는 자세히 다루지 않겠습니다.

스토리 설정

PrimarySecondary는 스토리의 설정을 설정합니다.

PrimarySecondary는 스토리의 이름을 설정하며, 스토리의 이름은 스토리북 페이지에서 스토리의 이름으로 표시됩니다.

다음과 같이 export 내보내기를 사용하여 스토리를 설정할 수 있습니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
 
export const Primary: Story = {
  args: {
    primary: true,
    label: "Button",
  },
};
 
export const Secondary: Story = {
  args: {
    label: "Button",
  },
};

meta에서 설정되지 않거나 args에서 설정되지 않은 속성을 개별로 설정할 수 있습니다.

내보내기로 설정된 스토리는 스토리북 페이지 개별 네비게이션에 표시되어 확인할 수 있습니다.

여기서 유용한 기능중 하나인 render를 사용하여 여러 컴포넌트를 렌더링할 수 있습니다.

stories/Button.stories.tsx
// ... 설정된 meta 내용 생략
export const Primary: Story = {
  args: {
    primary: true,
    label: 'Button',
  },
  render: (args) => <>
    <Button {...args} />
    <Button {...args} />
    <Button {...args} />
    <Button {...args} />
  </>,
};

개별 버튼을 사용할 수 있지만 render를 사용하여 여러 버튼을 렌더링할 수 있습니다. 이를 활용하여 하나의 스토리 페이지에서 일반 jsx 랜더링 처럼 커스텀한 컴포넌트를 렌더링할 수 있습니다.

여기까지 Next.js에서 스토리북을 설정하고 사용하는 방법을 설명해 보았습니다. 스토리북을 사용하면 컴포넌트를 독립적으로 개발하고 테스트할 수 있으며, 컴포넌트의 상태를 쉽게 관리하고, 필요한 컴포넌트 ui를 찾기도 쉽으며, 다양한 상황에서 컴포넌트를 테스트할 수 있습니다.

스토리북 배포에 대한 내용은 다음글을 참고해 주세요!

`React, Next js Storybook 배포 방법`

관련 태그