storybook-configuration

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Storybook - Configuration

Storybook - 配置指南

Configure Storybook for optimal development experience with the right addons, builders, and framework integrations.
通过合适的插件、构建工具和框架集成,配置Storybook以获得最佳开发体验。

Key Concepts

核心概念

Main Configuration

核心配置文件

.storybook/main.ts
is the primary configuration file:
typescript
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-a11y',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
};

export default config;
.storybook/main.ts
是主要的配置文件:
typescript
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
    '@storybook/addon-a11y',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  docs: {
    autodocs: 'tag',
  },
};

export default config;

Preview Configuration

预览配置

.storybook/preview.ts
configures how stories are rendered:
typescript
import type { Preview } from '@storybook/react';
import '../src/index.css';

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
  globalTypes: {
    theme: {
      description: 'Global theme for components',
      defaultValue: 'light',
      toolbar: {
        title: 'Theme',
        icon: 'circlehollow',
        items: ['light', 'dark'],
        dynamicTitle: true,
      },
    },
  },
};

export default preview;
.storybook/preview.ts
用于配置故事的渲染方式:
typescript
import type { Preview } from '@storybook/react';
import '../src/index.css';

const preview: Preview = {
  parameters: {
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
    },
  },
  globalTypes: {
    theme: {
      description: 'Global theme for components',
      defaultValue: 'light',
      toolbar: {
        title: 'Theme',
        icon: 'circlehollow',
        items: ['light', 'dark'],
        dynamicTitle: true,
      },
    },
  },
};

export default preview;

Addons

插件(Addons)

Addons extend Storybook functionality:
  • @storybook/addon-essentials - Core addons bundle
  • @storybook/addon-interactions - Interaction testing
  • @storybook/addon-a11y - Accessibility testing
  • @storybook/addon-links - Story navigation
  • @storybook/addon-coverage - Code coverage
  • storybook-dark-mode - Dark mode toggle
插件可扩展Storybook的功能:
  • @storybook/addon-essentials - 核心插件包
  • @storybook/addon-interactions - 交互测试
  • @storybook/addon-a11y - 无障碍测试
  • @storybook/addon-links - 故事导航
  • @storybook/addon-coverage - 代码覆盖率
  • storybook-dark-mode - 深色模式切换

Best Practices

最佳实践

1. Use TypeScript Configuration

1. 使用TypeScript配置

Type-safe configuration prevents errors:
typescript
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {
      builder: {
        viteConfigPath: './vite.config.ts',
      },
    },
  },
};

export default config;
类型安全的配置可避免错误:
typescript
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {
      builder: {
        viteConfigPath: './vite.config.ts',
      },
    },
  },
};

export default config;

2. Configure Story Patterns

2. 配置故事路径规则

Specify where stories are located:
typescript
const config: StorybookConfig = {
  stories: [
    '../src/**/*.mdx',
    '../src/**/*.stories.@(js|jsx|ts|tsx)',
    // Include specific directories
    '../components/**/*.stories.tsx',
    '../features/**/*.stories.tsx',
    // Exclude patterns
    '!../src/**/*.test.stories.tsx',
  ],
};
指定故事文件的位置:
typescript
const config: StorybookConfig = {
  stories: [
    '../src/**/*.mdx',
    '../src/**/*.stories.@(js|jsx|ts|tsx)',
    // 包含特定目录
    '../components/**/*.stories.tsx',
    '../features/**/*.stories.tsx',
    // 排除规则
    '!../src/**/*.test.stories.tsx',
  ],
};

3. Enable Autodocs

3. 启用自动文档生成

Generate documentation automatically:
typescript
const config: StorybookConfig = {
  docs: {
    autodocs: 'tag',  // Autodocs for stories with 'autodocs' tag
    // OR
    autodocs: true,   // Autodocs for all stories
  },
};
自动生成组件文档:
typescript
const config: StorybookConfig = {
  docs: {
    autodocs: 'tag',  // 为带有'autodocs'标签的故事生成文档
    // 或者
    autodocs: true,   // 为所有故事生成文档
  },
};

4. Configure Essential Addons

4. 配置核心插件

Customize addon behavior in preview:
typescript
import type { Preview } from '@storybook/react';

const preview: Preview = {
  parameters: {
    // Actions addon
    actions: { argTypesRegex: '^on[A-Z].*' },

    // Controls addon
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
      exclude: ['className', 'style'],
    },

    // Viewport addon
    viewport: {
      viewports: {
        mobile: {
          name: 'Mobile',
          styles: { width: '375px', height: '667px' },
        },
        tablet: {
          name: 'Tablet',
          styles: { width: '768px', height: '1024px' },
        },
      },
    },

    // Backgrounds addon
    backgrounds: {
      default: 'light',
      values: [
        { name: 'light', value: '#ffffff' },
        { name: 'dark', value: '#1a1a1a' },
      ],
    },
  },
};
在预览配置中自定义插件行为:
typescript
import type { Preview } from '@storybook/react';

const preview: Preview = {
  parameters: {
    // Actions插件
    actions: { argTypesRegex: '^on[A-Z].*' },

    // Controls插件
    controls: {
      matchers: {
        color: /(background|color)$/i,
        date: /Date$/i,
      },
      exclude: ['className', 'style'],
    },

    // Viewport插件
    viewport: {
      viewports: {
        mobile: {
          name: 'Mobile',
          styles: { width: '375px', height: '667px' },
        },
        tablet: {
          name: 'Tablet',
          styles: { width: '768px', height: '1024px' },
        },
      },
    },

    // Backgrounds插件
    backgrounds: {
      default: 'light',
      values: [
        { name: 'light', value: '#ffffff' },
        { name: 'dark', value: '#1a1a1a' },
      ],
    },
  },
};

5. Add Global Decorators

5. 添加全局装饰器

Wrap all stories with providers:
typescript
import { Preview } from '@storybook/react';
import { ThemeProvider } from '../src/theme';

const preview: Preview = {
  decorators: [
    (Story) => (
      <ThemeProvider>
        <div style={{ padding: '2rem' }}>
          <Story />
        </div>
      </ThemeProvider>
    ),
  ],
};
使用提供者包裹所有故事:
typescript
import { Preview } from '@storybook/react';
import { ThemeProvider } from '../src/theme';

const preview: Preview = {
  decorators: [
    (Story) => (
      <ThemeProvider>
        <div style={{ padding: '2rem' }}>
          <Story />
        </div>
      </ThemeProvider>
    ),
  ],
};

Common Patterns

常见配置模式

Next.js Configuration

Next.js配置

typescript
import type { StorybookConfig } from '@storybook/nextjs';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/nextjs',
    options: {
      nextConfigPath: '../next.config.js',
    },
  },
  staticDirs: ['../public'],
  typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      shouldExtractLiteralValuesFromEnum: true,
      propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
    },
  },
};
typescript
import type { StorybookConfig } from '@storybook/nextjs';

const config: StorybookConfig = {
  stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-interactions',
  ],
  framework: {
    name: '@storybook/nextjs',
    options: {
      nextConfigPath: '../next.config.js',
    },
  },
  staticDirs: ['../public'],
  typescript: {
    reactDocgen: 'react-docgen-typescript',
    reactDocgenTypescriptOptions: {
      shouldExtractLiteralValuesFromEnum: true,
      propFilter: (prop) => (prop.parent ? !/node_modules/.test(prop.parent.fileName) : true),
    },
  },
};

Vite Configuration

Vite配置

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

const config: StorybookConfig = {
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  async viteFinal(config) {
    return mergeConfig(config, {
      resolve: {
        alias: {
          '@': '/src',
        },
      },
      define: {
        'process.env.STORYBOOK': JSON.stringify(true),
      },
    });
  },
};
typescript
import type { StorybookConfig } from '@storybook/react-vite';
import { mergeConfig } from 'vite';

const config: StorybookConfig = {
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
  async viteFinal(config) {
    return mergeConfig(config, {
      resolve: {
        alias: {
          '@': '/src',
        },
      },
      define: {
        'process.env.STORYBOOK': JSON.stringify(true),
      },
    });
  },
};

Webpack Configuration

Webpack配置

typescript
import type { StorybookConfig } from '@storybook/react-webpack5';
import path from 'path';

const config: StorybookConfig = {
  framework: {
    name: '@storybook/react-webpack5',
    options: {},
  },
  webpackFinal: async (config) => {
    config.resolve = {
      ...config.resolve,
      alias: {
        ...config.resolve?.alias,
        '@': path.resolve(__dirname, '../src'),
      },
    };
    return config;
  },
};
typescript
import type { StorybookConfig } from '@storybook/react-webpack5';
import path from 'path';

const config: StorybookConfig = {
  framework: {
    name: '@storybook/react-webpack5',
    options: {},
  },
  webpackFinal: async (config) => {
    config.resolve = {
      ...config.resolve,
      alias: {
        ...config.resolve?.alias,
        '@': path.resolve(__dirname, '../src'),
      },
    };
    return config;
  },
};

Accessibility Testing

无障碍测试配置

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

const preview: Preview = {
  parameters: {
    a11y: {
      config: {
        rules: [
          {
            id: 'color-contrast',
            enabled: true,
          },
          {
            id: 'aria-required-attr',
            enabled: true,
          },
        ],
      },
      options: {
        runOnly: {
          type: 'tag',
          values: ['wcag2a', 'wcag2aa'],
        },
      },
    },
  },
};
typescript
import type { Preview } from '@storybook/react';

const preview: Preview = {
  parameters: {
    a11y: {
      config: {
        rules: [
          {
            id: 'color-contrast',
            enabled: true,
          },
          {
            id: 'aria-required-attr',
            enabled: true,
          },
        ],
      },
      options: {
        runOnly: {
          type: 'tag',
          values: ['wcag2a', 'wcag2aa'],
        },
      },
    },
  },
};

Theme Switching

主题切换配置

typescript
import { Preview } from '@storybook/react';
import { useDarkMode } from 'storybook-dark-mode';

const preview: Preview = {
  decorators: [
    (Story) => {
      const isDark = useDarkMode();
      return (
        <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
          <Story />
        </ThemeProvider>
      );
    },
  ],
};
typescript
import { Preview } from '@storybook/react';
import { useDarkMode } from 'storybook-dark-mode';

const preview: Preview = {
  decorators: [
    (Story) => {
      const isDark = useDarkMode();
      return (
        <ThemeProvider theme={isDark ? darkTheme : lightTheme}>
          <Story />
        </ThemeProvider>
      );
    },
  ],
};

Code Coverage

代码覆盖率配置

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

const config: StorybookConfig = {
  addons: [
    '@storybook/addon-coverage',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
};

// In .storybook/test-runner.ts
import type { TestRunnerConfig } from '@storybook/test-runner';

const config: TestRunnerConfig = {
  async postRender(page, context) {
    // Add coverage collection
    await page.coverage.startJSCoverage();
  },
};

export default config;
typescript
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  addons: [
    '@storybook/addon-coverage',
  ],
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
};

// 在 .storybook/test-runner.ts 中
import type { TestRunnerConfig } from '@storybook/test-runner';

const config: TestRunnerConfig = {
  async postRender(page, context) {
    // 添加覆盖率收集
    await page.coverage.startJSCoverage();
  },
};

export default config;

Advanced Patterns

高级配置模式

Multi-Framework Setup

多框架配置

typescript
// .storybook/main.react.ts
const config: StorybookConfig = {
  stories: ['../src/react/**/*.stories.tsx'],
  framework: '@storybook/react-vite',
};

// .storybook/main.vue.ts
const config: StorybookConfig = {
  stories: ['../src/vue/**/*.stories.ts'],
  framework: '@storybook/vue3-vite',
};
typescript
// .storybook/main.react.ts
const config: StorybookConfig = {
  stories: ['../src/react/**/*.stories.tsx'],
  framework: '@storybook/react-vite',
};

// .storybook/main.vue.ts
const config: StorybookConfig = {
  stories: ['../src/vue/**/*.stories.ts'],
  framework: '@storybook/vue3-vite',
};

Custom Addon Development

自定义插件开发

typescript
// .storybook/addons/custom-addon/register.tsx
import { addons, types } from '@storybook/manager-api';
import { AddonPanel } from '@storybook/components';
import React from 'react';

addons.register('custom-addon', () => {
  addons.add('custom-addon/panel', {
    type: types.PANEL,
    title: 'Custom Panel',
    render: ({ active, key }) => (
      <AddonPanel active={active} key={key}>
        <div>Custom addon content</div>
      </AddonPanel>
    ),
  });
});

// .storybook/main.ts
const config: StorybookConfig = {
  addons: ['./addons/custom-addon/register'],
};
typescript
// .storybook/addons/custom-addon/register.tsx
import { addons, types } from '@storybook/manager-api';
import { AddonPanel } from '@storybook/components';
import React from 'react';

addons.register('custom-addon', () => {
  addons.add('custom-addon/panel', {
    type: types.PANEL,
    title: 'Custom Panel',
    render: ({ active, key }) => (
      <AddonPanel active={active} key={key}>
        <div>Custom addon content</div>
      </AddonPanel>
    ),
  });
});

// .storybook/main.ts
const config: StorybookConfig = {
  addons: ['./addons/custom-addon/register'],
};

Manager Configuration

管理器配置

typescript
// .storybook/manager.ts
import { addons } from '@storybook/manager-api';
import { themes } from '@storybook/theming';

addons.setConfig({
  theme: themes.dark,
  panelPosition: 'right',
  showPanel: true,
  selectedPanel: 'storybook/actions/panel',
  initialActive: 'sidebar',
  sidebar: {
    showRoots: true,
    collapsedRoots: ['other'],
  },
});
typescript
// .storybook/manager.ts
import { addons } from '@storybook/manager-api';
import { themes } from '@storybook/theming';

addons.setConfig({
  theme: themes.dark,
  panelPosition: 'right',
  showPanel: true,
  selectedPanel: 'storybook/actions/panel',
  initialActive: 'sidebar',
  sidebar: {
    showRoots: true,
    collapsedRoots: ['other'],
  },
});

Anti-Patterns

错误配置示例

❌ Don't Skip Framework Type

❌ 不要省略框架类型定义

typescript
// Bad - No type safety
const config = {
  framework: '@storybook/react-vite',
};
typescript
// Good - Type-safe
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
};
typescript
// 错误示例 - 无类型安全
const config = {
  framework: '@storybook/react-vite',
};
typescript
// 正确示例 - 类型安全
import type { StorybookConfig } from '@storybook/react-vite';

const config: StorybookConfig = {
  framework: {
    name: '@storybook/react-vite',
    options: {},
  },
};

❌ Don't Hardcode Paths

❌ 不要硬编码绝对路径

typescript
// Bad
const config: StorybookConfig = {
  stories: [
    '/Users/username/project/src/**/*.stories.tsx',
  ],
};
typescript
// Good
const config: StorybookConfig = {
  stories: [
    '../src/**/*.stories.tsx',
  ],
};
typescript
// 错误示例
const config: StorybookConfig = {
  stories: [
    '/Users/username/project/src/**/*.stories.tsx',
  ],
};
typescript
// 正确示例
const config: StorybookConfig = {
  stories: [
    '../src/**/*.stories.tsx',
  ],
};

❌ Don't Include Unnecessary Addons

❌ 不要添加不必要的插件

typescript
// Bad - Too many addons slow down Storybook
const config: StorybookConfig = {
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-actions',      // Included in essentials
    '@storybook/addon-controls',     // Included in essentials
    '@storybook/addon-backgrounds',  // Included in essentials
  ],
};
typescript
// Good - Just essentials covers most needs
const config: StorybookConfig = {
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-a11y',  // Additional specialized addon
  ],
};
typescript
// 错误示例 - 过多插件会拖慢Storybook
const config: StorybookConfig = {
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-actions',      // 已包含在essentials中
    '@storybook/addon-controls',     // 已包含在essentials中
    '@storybook/addon-backgrounds',  // 已包含在essentials中
  ],
};
typescript
// 正确示例 - 仅保留核心插件和必要的专用插件
const config: StorybookConfig = {
  addons: [
    '@storybook/addon-essentials',
    '@storybook/addon-a11y',  // 额外的专用插件
  ],
};

Related Skills

相关技能

  • storybook-story-writing: Writing stories for configured Storybook
  • storybook-component-documentation: Using documentation addons
  • storybook-play-functions: Setting up interaction testing addon
  • storybook-story-writing: 为已配置的Storybook编写故事
  • storybook-component-documentation: 使用文档类插件
  • storybook-play-functions: 配置交互测试插件