stack-analysis
CHAPTER 12 / 90
읽기 약 2분
FUNCTION
Storybook: 컴포넌트 문서화
핵심 개념
Story 작성·Args/Controls·디자인 시스템 — 5개 컴포넌트 Storybook.
본문
Storybook 설치
pnpm dlx storybook@latest init기본 Story
// Button.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { Button } from './Button';
const meta = {
title: 'UI/Button',
component: Button,
parameters: {
layout: 'centered',
},
tags: ['autodocs'],
argTypes: {
variant: {
control: 'select',
options: ['primary', 'secondary', 'danger', 'ghost'],
},
size: {
control: 'radio',
options: ['sm', 'md', 'lg'],
},
onClick: { action: 'clicked' },
},
} satisfies Meta<typeof Button>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Primary: Story = {
args: {
variant: 'primary',
children: '클릭',
},
};
export const Secondary: Story = {
args: {
variant: 'secondary',
children: '취소',
},
};
export const Danger: Story = {
args: {
variant: 'danger',
children: '삭제',
},
};
export const AllSizes: Story = {
render: (args) => (
<div style={{ display: 'flex', gap: '1rem' }}>
<Button {...args} size="sm">Small</Button>
<Button {...args} size="md">Medium</Button>
<Button {...args} size="lg">Large</Button>
</div>
),
};
export const Disabled: Story = {
args: {
variant: 'primary',
children: '비활성',
disabled: true,
},
};Form Story
// SignupForm.stories.tsx
import type { Meta, StoryObj } from '@storybook/react';
import { userEvent, within, expect } from '@storybook/test';
import { SignupForm } from './SignupForm';
const meta = {
title: 'Forms/SignupForm',
component: SignupForm,
} satisfies Meta<typeof SignupForm>;
export default meta;
type Story = StoryObj<typeof meta>;
export const Default: Story = {};
// 자동 인터랙션 테스트 + 시각화
export const FilledIn: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.type(
canvas.getByLabelText(/이메일/i),
'alice@example.com'
);
await userEvent.type(
canvas.getByLabelText(/비밀번호/i),
'Pass1234'
);
expect(canvas.getByRole('button', { name: /가입/i })).toBeEnabled();
},
};
export const ValidationError: Story = {
play: async ({ canvasElement }) => {
const canvas = within(canvasElement);
await userEvent.type(canvas.getByLabelText(/이메일/i), 'invalid');
await userEvent.tab();
expect(await canvas.findByText(/올바른 이메일/i)).toBeInTheDocument();
},
};디자인 시스템 — 컴포넌트 카탈로그
// stories/DesignSystem.stories.tsx
const meta = {
title: 'Design System / Overview',
} satisfies Meta;
export default meta;
export const Colors = () => (
<div>
<h2>Colors</h2>
{Object.entries({
primary: '#6366f1',
secondary: '#8b5cf6',
success: '#10b981',
warning: '#f59e0b',
danger: '#ef4444',
}).map(([name, color]) => (
<div key={name} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
<div style={{ width: 50, height: 50, background: color }} />
<span>{name}: {color}</span>
</div>
))}
</div>
);
export const Typography = () => (
<div>
<h1>Heading 1 — 2.5rem</h1>
<h2>Heading 2 — 2rem</h2>
<h3>Heading 3 — 1.5rem</h3>
<p>Body — 1rem</p>
<small>Small — 0.875rem</small>
</div>
);배포
# 정적 빌드
pnpm build-storybook
# Chromatic (자동 배포 + 시각 회귀)
pnpm dlx chromatic --project-token=<token>
# 또는 Vercel/Netlify에 storybook-static/ 배포다음 모듈
CH.13~20 "Next.js 프로덕션 해부" — App Router·SSR·SEO.
AI 프롬프트
🤖 AI에게 잘 물어보는 법 — 모델·전략별 프롬프트
Claude
무료: Sonnet 4.6 / Pro $20/mo: Opus 4.6
내 코드의 Storybook 디자인 시스템 부분을 분석해서 실전 분석 + 개선 우선순위를 알려줘.
ChatGPT
무료: GPT-5.5 / Plus $20/mo: GPT-5.5 Pro
Storybook 디자인 시스템 관련 인기 라이브러리/패턴 5개를 비교 분석해서 패턴 추출를 알려줘.
Gemini
무료: 2.5 Flash / Pro $19.99/mo: 3.1 Pro
내 프로젝트 전체에서 Storybook 디자인 시스템 최적화 가능 위치를 보고해줘.
Grok
무료: Grok 4.1 / SuperGrok $30/mo
2026년 한국 프론트엔드 시장의 Storybook 디자인 시스템 트렌드를 솔직히 알려줘.
⭐ 이것만 기억하세요
Storybook: 컴포넌트 문서화는 이 3가지만 확실히 잡으세요
1.Storybook은 컴포넌트 카탈로그 + 인터랙션 테스트 + 시각 회귀 — 디자인 시스템 표준
2.play function으로 자동 인터랙션 테스트 → Vitest 테스트와 별개 시각 검증
3.다음 모듈(CH.13~20)에서 Next.js 프로덕션 — App Router·SSR·SEO
공유하기
진행도 12 / 90