🍀 들어가기에 앞서..
💖 해당 글은 nextjs(14.1.0) + storybook(^8.0.8) 버전을 바탕으로 한 프로젝트입니다.
😄 학습과 병행하여 작성한 내용이므로 오류가 있을 수 있습니다. (댓글 피드백 환영합니다!)
🔗 해당 프로젝트의 리포지터리 : 깃헙
🗣️ 내용 전달의 간결함을 위해 아래의 내용부터는 비격식체를 사용하도록 하겠습니다.
간단하게 말해서 스토리북이란, UI 컴포넌트와 페이지를 독립적으로 생성하여, 직접 접근하기 어려운 state나 엣지 케이스를 애플리케이션 전체를 살피지 않고도 쉽게 개발하고 공유하도록 해주는 도구다.
핵심 개념은 아래와 같다.
- Stories: UI 컴포넌트의 랜더링된 상태를 스냅샷처럼 캡쳐한 것.
각 컴포넌트는 여러개의 스토리가 존재할 수 잇고, 각 스토리는 다른 컴포넌트 state를 나타낸다.
위의게시물 카드
컴포넌트에서Default
,No Image
각각 stories에 해당된다.- Docs: 스토리북은 stories와 함께 컴포넌트를 분석할 수 있는 문서를 자동적으로 생성할 수 있도록 한다. Docs 문서생성 자동화는 UI 라이브러리 가이드라인, 디자인 시스템 사이트 등을 생성하기 용이하게 한다.
- Testing: UI 테스팅의 실용적인 진입점이다. UI 개발을 하면서 자연스럽게 스토리를 작성하기 때문에 UI버그를 방지할 수 있는 저비용 테스팅 방법이다.
- Sharing: 스토리북을 출간하여 동료들과 함께 공유할 수 있으며, notion과 figma 등에 embed가능하다.
$ npx storybook@latest init
설치를 하면 터미널에 아래와 같이http://localhost:6006/
에 접속하면
아래와 같이 예시 스토리가 생성된다.
그리고 프로젝트 최상단에 .storybook
폴더가 생성된다.
이 파일들은 스토리북을 위한 설정을 담은 부분이다.
// main.ts
import type { StorybookConfig } from '@storybook/nextjs';
const config: StorybookConfig = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: [
'@storybook/addon-onboarding',
'@storybook/addon-links',
'@storybook/addon-essentials',
'@chromatic-com/storybook',
'@storybook/addon-interactions',
'@storybook/addon-styling-webpack',
'storybook-dark-mode',
'@storybook/addon-styling',
'storybook-addon-mantine',
'@tomfreudenberg/next-auth-mock/storybook',
],
framework: {
name: '@storybook/nextjs',
options: {},
},
docs: {
autodocs: 'tag',
},
staticDirs: ['../public'],
};
export default config;
$ npm i -D storybook-addon-mantine
// preview.ts
import '@mantine/core/styles.css';
import '@mantine/tiptap/styles.css';
import 'reactflow/dist/style.css';
import type { Preview } from '@storybook/react';
const preview: Preview = {
parameters: {
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/i,
},
},
nextjs: {
appDirectory: true,
},
},
};
export default preview;
// preview.tsx
import { MantineProvider } from '@mantine/core';
import { withThemeFromJSXProvider } from '@storybook/addon-themes';
import React from 'react';
import { GlobalStyle } from '../src/styles/globalStyle';
import { ModalsProvider } from '@mantine/modals';
import '@mantine/tiptap/styles.css';
import 'reactflow/dist/style.css';
import { ThemeProvider } from 'styled-components';
import SessionWrapper from '../src/providers/SessionProvider';
import StyledComponentsProvider from '../src/providers/StyledComponentsProvider';
import { theme as colortheme } from '../src/styles/theme';
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
};
const GlobalStyles = GlobalStyle;
export const decorators = [
(renderStory: any) => (
<ThemeProvider theme={colortheme}>
<MantineProvider>
<SessionWrapper>
<ModalsProvider>
<StyledComponentsProvider>{renderStory()}</StyledComponentsProvider>
</ModalsProvider>
</SessionWrapper>
</MantineProvider>
</ThemeProvider>
),
withThemeFromJSXProvider({
Provider: ThemeProvider,
GlobalStyles,
}),
];
// app/stories/ItemCard.stores.tsx
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import ItemCard from '@/components/shared/ItemCard';
import { POST } from '@/constants';
import { omit } from '@/utils/shared';
const queryClient = new QueryClient();
export const decorators = [
(story: any) => (
<QueryClientProvider client={queryClient}>{story()}</QueryClientProvider>
),
];
export default {
title: '홈/게시물 카드',
component: ItemCard,
args: { article: POST },
argTypes: {
product: 'object',
description: '로드맵 정보',
},
layout: 'fullscreen',
tags: ['autodocs'],
decorators,
};
export const Default = {};
export const NoImage = {
args: { article: { ...omit(POST, 'thumbnailUrl'), thumbnailUrl: null } },
};
QueryClientProvider
로 감싸줘야 에러가 발생하지 않는다.export default {
title: '홈/게시물 카드',
component: ItemCard,
args: { article: POST },
argTypes: {
product: 'object',
description: '로드맵 정보',
},
layout: 'fullscreen',
tags: ['autodocs'],
decorators,
};
Default
, NoImage
등으로 컴포넌트의 state를 조작하여 랜더링된 모습을 확인할 수 있다.default 포스트
이미지가 없는 포스트
Docs
✨ 이번에는 간단하게 설치와 세팅, 스토리 생성을 해봤습니다.
🤔 스토리 폴더를 컴포넌트 폴더 내에 위치하고 싶은데 현재 프로젝트의 구조는 정돈이 안된 상태라 프로젝트 구조를 정리해야겠다는 생각이 들었습니다.
🙋 다음 포스팅은 프로젝트 구조 변경(아키텍쳐 적용) 및 router mock + auth 스토리북 생성으로 돌아오겠습니다!