목차
개요
이번 블로그 포스트에서는 TypeScript
를 기반으로 하는 Next.js
프로젝트에서 Storybook
를 사용하여 컴포넌트 주도 개발(Component Driven Development)을 해 봅시다.
여기서 소개한 소스코드는 아래에 링크를 통해 확인할 수 있습니다.
블로그 리스트
이 블로그 포스트는 시리즈로 제작되었습니다. 다음은 Next.js
의 시리즈 리스트입니다.
- [Next.js] 시작하기
- [Next.js] TypeScript
- [Next.js] Prettier
- [Next.js] 절대 경로로 컴포넌트 추가
- [Next.js] 테스트
- [Next.js] Storybook
- [Next.js] Storybook 배경색 변경
- [Next.js] 다국어 지원
- [Next.js] MUI
TypeScript 기반 Next.js 프로젝트 생성
TypeScript
가 적용된 Next.js
에서 Storybook
을 사용하기 위해, 다음 명령어를 실행하여 TypeScript
가 적용된 Next.js
프로젝트를 생성합니다.
npx create-next-app --typescript start-storybook
Storybook 설치
TypeScript
가 적용된 Next.js
프로젝트에서 Storybook
을 사용하여 컴포넌트 주도 개발을 하기 위해서는 Storybook
을 설치할 필요가 있습니다. 다음 명령어를 실행하여 Storybook
을 설치합니다.
# cd start-storybook
npm install --save-dev sb
Storybook 초기화
Storybook
을 사용하기 위해서는 Storybook
을 초기화하여 필요한 라이브러리를 설치할 필요가 있습니다. 다음 명령어를 사용하여 Storybook
을 초기화합니다.
npx sb init --builder webpack5
그럼 다음과 같이 자동으로 Storybook
이 초기화 되는 것을 확인할 수 있습니다.
sb init - the simplest way to add a Storybook to your project.
• Detecting project type. ✓
There seems to be a Storybook already available in this project.
Apply following command to force:
sb init [options] -f
🔎 checking 'cra5'
🔎 checking 'webpack5'
🔎 checking 'angular12'
🔎 checking 'mainjsFramework'
Unable to find storybook main.js config, skipping
🔎 checking 'eslintPlugin'
마지막으로 다음과 같은 질문이 나옵니다.
? Do you want to run the 'eslintPlugin' fix on your project? › (y/N)
ESLint
를 사용하여 코드를 검사하는 경우 y
를 눌러 진행하고, 그렇지 않은 경우는 N
을 눌러 진행합니다. 이 블로그에서는 y
를 눌러 진행하였습니다.
그럼 다음과 같이 Storybook
이 자동으로 필요한 라이브러리를 설치하고, Storybook
을 실행하는 스크립트를 자동으로 작성된 것을 확인할 수 있습니다.
{
...
"scripts": {
...
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
...
"devDependencies": {
"@babel/core": "^7.17.7",
"@storybook/addon-actions": "^6.4.19",
"@storybook/addon-essentials": "^6.4.19",
"@storybook/addon-interactions": "^6.4.19",
"@storybook/addon-links": "^6.4.19",
"@storybook/builder-webpack5": "^6.5.0-beta.8",
"@storybook/manager-webpack5": "^6.5.0-beta.8",
"@storybook/react": "^6.4.19",
"@storybook/testing-library": "^0.0.9",
"babel-loader": "^8.2.3",
"eslint-plugin-storybook": "^0.5.7",
...
}
}
또한, 다음과 같이 Storybook
을 사용하는 방법을 알려주기 위해, 샘플 코드가 함께 생성되는 것을 확인할 수 있습니다.
./.storybook/...
:Storybook
에 대한 설정 파일입니다../stories/...
:Storybook
의 샘플 코드입니다.
public 폴더 설정
Next.js
의 public
폴더에 위치한 static
파일들(이미지)을 Storybook
에서 인식하도록 하기 위해 scripts
를 다음과 같이 수정합니다.
{
...
"scripts": {
...
"storybook": "start-storybook -p 6006 -s ./public",
"build-storybook": "build-storybook -s public"
},
...
}
Storybook 실행
이제 지금까지 설정한 Storybook
을 실행하여, Storybook
이 잘 설치되었는지 확인해 봅시다. 다음 명령어를 실행하여 Storybook
을 실행합니다.
npm run storybook
그럼 브라우저에 http://localhost:6006/
이 자동으로 열리며, 다음과 같은 화면을 확인할 수 있습니다.
해당 화면은 ./stories/Introduction.stories.mdx
파일이 표시된 화면입니다.
Storybook 확인
실행된 Storybook
의 왼쪽 메뉴의 Button > Primary
를 선택하면 다음과 같은 화면을 볼 수 있습니다.
해당 화면은 ./stories/Button.stories.tsx
파일이 표시된 화면입니다.
샘플 코드 확인
좀 더 자세히 알아보기 위해 샘플 코드를 확인해 봅시다. Button
컴포넌트(./stories/Button.tsx
)는 다음과 같습니다.
import React from 'react';
import './button.css';
interface ButtonProps {
primary?: boolean;
backgroundColor?: string;
size?: 'small' | 'medium' | 'large';
label: string;
onClick?: () => void;
}
export const Button = ({
primary = false,
size = 'medium',
backgroundColor,
label,
...props
}: ButtonProps) => {
...
};
Button
컴포넌트는 primary
, backgroundColor
등 다양한 Props
를 가지고 있는 것을 확인할 수 있습니다. 다음으로 Storybook
파일(./stories/Button.stories.tsx
)의 내용을 확인해 봅시다.
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { Button } from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof Button>;
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Button',
};
export const Secondary = Template.bind({});
Secondary.args = {
label: 'Button',
};
export const Large = Template.bind({});
Large.args = {
size: 'large',
label: 'Button',
};
export const Small = Template.bind({});
Small.args = {
size: 'small',
label: 'Button',
};
우선, Storybook
에 표시할 컴포넌트를 준비합니다.
import React from 'react';
import { ComponentStory, ComponentMeta } from '@storybook/react';
import { Button } from './Button';
export default {
title: 'Example/Button',
component: Button,
argTypes: {
backgroundColor: { control: 'color' },
},
} as ComponentMeta<typeof Button>;
const Template: ComponentStory<typeof Button> = (args) => <Button {...args} />;
...
argTypes
의 backgroundColor
에 control: 'color'
을 설정하면, 다음과 같이 Storybook
에서 색상을 선택할 수 있습니다.
그런 다음 화면에 표시할 Story
를 작성합니다.
...
export const Primary = Template.bind({});
Primary.args = {
primary: true,
label: 'Button',
};
...
여기서 args
에 Button
컴포넌트의 Props
를 설정하여 다양한 Story
를 만들 수 있습니다.
Storybook 설정
우선 Next.js
의 globals.css
를 Storybook
에서도 사용할 수 있도록 설정할 필요가 있습니다. ./storybook/preview.js
파일을 열고 다음과 같이 수정합니다.
import '../styles/globals.css'
export const parameters = {
...
}
현재는 Storybook
을 작성하기 위해서는 ./stories
폴더에 작성해야 합니다. 하지만, 보통 컴포넌트는 ./components
폴더를 생성하고 관리하게 됩니다.
이렇게 Storybook
을 다른 폴더에서 작성하기 위해서는 ./.storybook/main.js
파일을 수정할 필요가 있습니다. ./.storybook/main.js
파일을 열고 다음과 같이 수정합니다.
module.exports = {
"stories": [
"../**/*.stories.mdx",
"../**/*.stories.@(js|jsx|ts|tsx)"
],
...
}
이제는 어떠한 폴더에서든 .stories.tsx
파일명을 가지면, Storybook
이 이를 인식하여 화면에 표시하게 됩니다. 이를 확인하기 위해 ./components/SampleButton
폴더를 생성하고 다음 파일들을 복사합니다.
./stories/button.css
>./components/SampleButton/index.css
./stories/Button.stories.tsx
>./components/SampleButton/index.stories.tsx
./stories/Button.tsx
>./components/SampleButton/index.tsx
그리고 ./components/SampleButton/index.tsx
파일을 열어서 다음과 같이 수정합니다.
...
import './index.css';
...
export const SampleButton = ({
...
}: ButtonProps) => {
...
};
그리고 ./components/SampleButton/index.stories.tsx
파일을 열어서 다음과 같이 수정합니다.
...
import { SampleButton } from '.';
...
export default {
title: 'Example/SampleButton',
component: SampleButton,
...,
} as ComponentMeta<typeof SampleButton>;
const Template: ComponentStory<typeof SampleButton> = (args) => (
<SampleButton {...args} />
);
...
Storybook
의 설정을 변경하였으므로 이를 반영하기 위해, 현재 실행중인 Storybook
을 종료하고 다시 실행합니다. Storybook
이 다시 실행되면 다음과 같이 우리가 만든 SampleButton
이 잘 표시되는 것을 확인할 수 있습니다.
완료
이번 블로그 포스트에서는 TypeScript
를 기반으로 하는 Next.js
프로젝트에서 컴포넌트 주도 개발을 하기 위해, Storybook
을 설정하는 방법에 대해서 알아보았습니다. 이제 앱을 개발할 때, Storybook
을 보면서, 컴포넌트에 집중하여 개발할 수 있게 되었습니다.
제 블로그가 도움이 되셨나요? 하단의 댓글을 달아주시면 저에게 큰 힘이 됩니다!
앱 홍보
Deku
가 개발한 앱을 한번 사용해보세요.Deku
가 개발한 앱은 Flutter로 개발되었습니다.관심있으신 분들은 앱을 다운로드하여 사용해 주시면 정말 감사하겠습니다.