Hello Kitty Eyes Shut
๋ณธ๋ฌธ ๋ฐ”๋กœ๊ฐ€๊ธฐ

๐Ÿ’ป ํ”„๋กœ์ ํŠธ/๐Ÿ“Œ BaLaw

Storybook ์„ค์น˜ํ•˜๊ธฐ

๋ฐ˜์‘ํ˜•

 

 

 

 

(ํ˜„์žฌ ์ €๋Š” pnpm + React + TypeScript ํ™˜๊ฒฝ์—์„œ ๊ฐœ๋ฐœ ์ค‘์ž…๋‹ˆ๋‹ค ๐Ÿ‘ฉ๐Ÿป‍๐Ÿ’ป)

 

๐ŸŸฅ Storybook ์„ค์น˜

์ผ๋‹จ ํ”„๋กœ์ ํŠธ ๋ฃจํŠธ์—์„œ ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•œ๋‹ค.

pnpm dlx storybook@latest init

 

์ด๋ ‡๊ฒŒ ํ•˜๋ฉด Storybook์ด ํ˜„์žฌ ํ”„๋กœ์ ํŠธ์˜ ํ™˜๊ฒฝ์„ ์ž๋™์œผ๋กœ ๊ฐ์ง€ํ•˜๊ณ ,

.storybook ํด๋”์™€ ๊ธฐ๋ณธ ์Šคํ† ๋ฆฌ ํŒŒ์ผ๋“ค์„ ์ƒ์„ฑํ•ด์ค€๋‹ค.

 

์ž˜ ์„ค์น˜๋˜์—ˆ๋Š”์ง€ ํ™•์ธํ•˜๊ณ  ์‹ถ๋‹ค๋ฉด, ์•„๋ž˜์˜ ๋ช…๋ น์–ด๋ฅผ ์‹คํ–‰ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.

pnpm run storybook

 

์ดํ›„ ๋ธŒ๋ผ์šฐ์ €์—์„œ http://localhost:6006 ์— ์ ‘์†ํ•˜๋ฉด Storybook UI๋ฅผ ํ™•์ธํ•  ์ˆ˜ ์žˆ์„ ๊ฒƒ์ด๋‹ค.

 

 

 


๐ŸŸง Storybook ๊ธฐ๋ณธ ํŒŒ์ผ๋“ค

๐Ÿ“‚ .storybook

์ด๊ฑฐ๋Š” ์Šคํ† ๋ฆฌ๋ถ์˜ ํ™˜๊ฒฝ์„ค์ • ๋””๋ ‰ํ† ๋ฆฌ๋กœ,

๊ธฐ๋ณธ์ ์œผ๋กœ ์•„๋ž˜์˜ ํŒŒ์ผ๋“ค์ด ํฌํ•จ๋˜์–ด ์žˆ๋‹ค.

 

1) main.ts

์ด๋Š” Storybook์˜ ํ•ต์‹ฌ ์„ค์ •ํŒŒ์ผ๋กœ,

์–ด๋–ค ์Šคํ† ๋ฆฌ๋ฅผ ๋ถˆ๋Ÿฌ์˜ฌ์ง€, ์–ด๋–ค ์• ๋“œ์˜จ์„ ์‚ฌ์šฉํ• ์ง€๋ฅผ ์ •์˜ํ•œ๋‹ค.

Vite alias ๊ฐ™์€ ์ปค์Šคํ„ฐ๋งˆ์ด์ง•๋„ ์—ฌ๊ธฐ์—์„œ ํ•˜๋ฉด ๋œ๋‹ค !

 

๋‚ด ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@chromatic-com/storybook',
    '@storybook/addon-docs',
    '@storybook/addon-onboarding',
    '@storybook/addon-a11y',
    '@storybook/addon-vitest',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
};
export default config;

 

  • stories
    • ../src/**/*.mdx ๐Ÿ‘‰๐Ÿป src/ ์•„๋ž˜์— ์žˆ๋Š” ๋ชจ๋“  .mdx ํŒŒ์ผ์„ ์Šคํ† ๋ฆฌ๋กœ ์ธ์‹
    • ../src/**/*.stories.@(js|jsx|mjs|ts|tsx) ๐Ÿ‘‰๐Ÿป src/ ์•„๋ž˜์— ์žˆ๋Š” *.stories.tsx ๊ฐ™์€ ํŒŒ์ผ์„ ์Šคํ† ๋ฆฌ๋กœ ์ธ์‹
    • ์ฆ‰, ์šฐ๋ฆฌ๊ฐ€ ์ปดํฌ๋„ŒํŠธ ์˜†์— Button.stories.tsx ๊ฐ™์€ ํŒŒ์ผ์„ ๋‘๋ฉด ์Šคํ† ๋ฆฌ๋ถ์ด ์ž๋™์œผ๋กœ ์žก์•„์ฃผ๊ฒŒ ๋œ๋‹ค.
  • addons
    • @chromatic-com/storybook ๐Ÿ‘‰๐Ÿป Storybook์„ ๋ฐฐํฌ/์‹œ๊ฐ ํ…Œ์ŠคํŠธ ์„œ๋น„์Šค์ธ Chromatic๊ณผ ์—ฐ๊ฒฐํ•ด์ฃผ๋Š” ์• ๋“œ์˜จ
    • @storybook/addon-docs ๐Ÿ‘‰๐Ÿป ๊ฐ ์Šคํ† ๋ฆฌ์— ๋Œ€ํ•ด Docs ํƒญ์„ ๋งŒ๋“ค์–ด์ฃผ๋Š” ์• ๋“œ์˜จ
    • @storybook/addon-a11y ๐Ÿ‘‰๐Ÿป ์›น ์ ‘๊ทผ์„ฑ ๊ฐ€์ด๋“œ๋ผ์ธ์— ๋งž๋Š”์ง€ ์ž๋™์œผ๋กœ ์ฒดํฌํ•ด์ฃผ๋Š” ์• ๋“œ์˜จ
    • @storybook/addon-vitest ๐Ÿ‘‰๐Ÿป Vitest ํ…Œ์ŠคํŠธ ๊ฒฐ๊ณผ๋ฅผ ์Šคํ† ๋ฆฌ๋ถ๊ณผ ํ†ตํ•ฉํ•  ์ˆ˜ ์žˆ๊ฒŒ ํ•ด์ฃผ๋Š” ์• ๋“œ์˜จ
  • framework
    • ์Šคํ† ๋ฆฌ๋ถ์ด ์–ด๋–ค ๋นŒ๋“œ ํˆด๊ณผ ํ”„๋ ˆ์ž„์›Œํฌ๋ฅผ ๊ธฐ๋ฐ˜์œผ๋กœ ๋™์ž‘ํ• ์ง€๋ฅผ ๊ฒฐ์ •ํ•ด์ค€๋‹ค.

 

 

2) preview.ts

์ด๊ฑฐ๋Š” ์Šคํ† ๋ฆฌ๋ถ ์ „์ฒด์— ๊ณตํ†ต์œผ๋กœ ์ ์šฉ๋˜๋Š” ์„ค์ •์œผ๋กœ,

CSS import, ๋ ˆ์ด์•„์›ƒ ์˜ต์…˜, Docs / Controls ์„ค์ • ๋“ฑ์„ ๋‹ด๋‹นํ•œ๋‹ค.

 

๋‚ด ๊ฒฝ์šฐ ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

import type { Preview } from '@storybook/react-vite';

import '../src/styles/index.css';

const preview: Preview = {
  parameters: {
    layout: 'centered',

    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },

    a11y: {
      // 'todo' - show a11y violations in the test UI only
      // 'error' - fail CI on a11y violations
      // 'off' - skip a11y checks entirely
      test: 'todo',
    },
  },
};

export default preview;
  • import '../src/styles/index.css'; ๐Ÿ‘‰๐Ÿป ์ „์—ญ ์Šคํƒ€์ผ์„ Storybook์—๋„ ์ ์šฉํ•ด์ค€๋‹ค.
  • parameters ๐Ÿ‘‰๐Ÿป ์Šคํ† ๋ฆฌ๋ถ ์ „์ฒด ๋™์ž‘์„ ์ œ์–ดํ•˜๋Š” ์˜ต์…˜๋“ค์˜ ๋ชจ์Œ์ด๋‹ค.
    • layout
      • centered : ์ปดํฌ๋„ŒํŠธ๋ฅผ ์บ”๋ฒ„์Šค ์ค‘์•™์— ํ‘œ์‹œ
      • fullscreen : ์ „์ฒด ํ™”๋ฉด์„ ์ฐจ์ง€ํ•˜๋„๋ก ํ‘œ์‹œ
      • padded : ์บ”๋ฒ„์Šค ์•ˆ์ชฝ์— ์—ฌ๋ฐฑ์„ ์ค˜์„œ ํ‘œ์‹œ
    • controls ๐Ÿ‘‰๐Ÿป ์Šคํ† ๋ฆฌ๋ถ UI์—์„œ props๋ฅผ ์กฐ์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” Controls ํŒจ๋„์„ ์ž๋™ ์ƒ์„ฑํ•  ๋•Œ ์“ฐ๋Š” ์˜ต์…˜์ด๋‹ค.
      • color : props ์ด๋ฆ„์— background๋‚˜ color๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ์ƒ‰์ƒ ์„ ํƒ๊ธฐ๊ฐ€ ์ž๋™์œผ๋กœ ๋ถ™๋Š”๋‹ค.
      • date : props ์ด๋ฆ„์— Date๊ฐ€ ๋“ค์–ด๊ฐ€๋ฉด ๋‹ฌ๋ ฅ ์ปจํŠธ๋กค๋Ÿฌ๊ฐ€ ์ž๋™์œผ๋กœ ๋ถ™๋Š”๋‹ค.
    • a11y ๐Ÿ‘‰๐Ÿป ์ ‘๊ทผ์„ฑ ์• ๋“œ์˜จ์˜ ์ „์—ญ ์„ค์ •์ด๋‹ค.
      • todo : ์ ‘๊ทผ์„ฑ ์œ„๋ฐ˜์ด ์žˆ์œผ๋ฉด ํ˜„์žฌ UI์—์„œ๋งŒ ๋ณด์—ฌ์คŒ
      • error : ์œ„๋ฐ˜์ด ์žˆ์œผ๋ฉด CI๋„ ์‹คํŒจ ์ฒ˜๋ฆฌํ•จ
      • off : ์ ‘๊ทผ์„ฑ ๊ฒ€์‚ฌ๋ฅผ ์•„์˜ˆ ๋น„ํ™œ์„ฑํ™”ํ•จ

 

 

3) vitest.setup.ts

์Šคํ† ๋ฆฌ๋ถ+ Vitest ํ™˜๊ฒฝ์—์„œ ํ…Œ์ŠคํŠธํ•  ๋•Œ ํ•„์š”ํ•œ ์„ค์ •์ด๋‹ค.

import * as a11yAddonAnnotations from '@storybook/addon-a11y/preview';
import { setProjectAnnotations } from '@storybook/react-vite';

import * as projectAnnotations from './preview';

// This is an important step to apply the right configuration when testing your stories.
// More info at: https://storybook.js.org/docs/api/portable-stories/portable-stories-vitest#setprojectannotations
setProjectAnnotations([a11yAddonAnnotations, projectAnnotations]);

 

 


๐ŸŸจ ์Šคํ† ๋ฆฌ๋ถ์— Material Symbols ์•„์ด์ฝ˜ ์ถ”๊ฐ€ํ•˜๊ธฐ

๋‚˜๋Š” ์ด๋ฒˆ ์„œ๋น„์Šค UI์—์„œ ๊ตฌ๊ธ€ ๋จธํ„ฐ๋ฆฌ์–ผ ์•„์ด์ฝ˜์„ ์ž์ฃผ ์“ธ ์˜ˆ์ •์ด๊ธฐ ๋•Œ๋ฌธ์—

์Šคํ† ๋ฆฌ๋ถ์—์„œ๋„ ๋™์ผํ•˜๊ฒŒ ๋ณด์ผ ์ˆ˜ ์žˆ๋„๋ก ์•„๋ž˜์™€ ๊ฐ™์ด ์„ค์ •ํ•ด์ฃผ์—ˆ๋‹ค.

(.stories ํด๋” ์•ˆ์— preview-head.html ํŒŒ์ผ์„ ๋งŒ๋“ค์–ด์„œ ์ถ”๊ฐ€ํ•ด์ฃผ๋ฉด ๋œ๋‹ค.)

<link
  href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:opsz,wght,FILL,GRAD@20..48,100..700,0..1,-50..200"
  rel="stylesheet"
/>
๋ฐ˜์‘ํ˜•