Component Story Format (CSF)
这是一个实验性功能,(虽然不太可能)API 在未来版本中可能会更改。我们欢迎反馈和贡献,以帮助改进此功能。
CSF 工厂是 Storybook 组件 Story Format (CSF) 的下一步演进。这个新的 API 使用一种称为工厂函数的模式,为你的 Storybook stories 提供完全的类型安全,使其更容易正确配置插件,并释放 Storybook 功能的全部潜力。
本参考将概述 API 和从 CSF 3 升级的迁移指南。
概述
CSF 工厂 API 由四个主要函数组成,以帮助你编写 stories。请注意,其中三个函数作为工厂运行,每个工厂都生成链中的下一个函数(definePreview
→ preview.meta
→ meta.story
),在每个步骤提供完全的类型安全。
defineMain
使用 CSF 工厂,你的主要的 Storybook 配置由 defineMain
函数指定。此函数是类型安全的,并将自动推断项目的类型。
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, experimental-nextjs-vite)
import { defineMain } from '@storybook/your-framework/node';
export default defineMain({
framework: '@storybook/your-framework',
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|mjs|ts|tsx)'],
addons: ['@storybook/addon-a11y'],
});
definePreview
同样,definePreview
函数指定项目的 story 配置。此函数也是类型安全的,并将推断整个项目的类型。
重要的是,通过在此处指定插件,它们的类型将在整个项目中可用,从而启用自动完成和类型检查。
你将在你的 story 文件中导入此函数的结果 preview
,以定义组件元数据。
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, experimental-nextjs-vite)
import { definePreview } from '@storybook/your-framework';
import addonA11y from '@storybook/addon-a11y';
export default definePreview({
// 👇 Add your addons here
addons: [addonA11y()],
parameters: {
// type-safe!
a11y: {
options: { xpath: true },
},
},
});
当通过 npx storybook add <addon-name>
安装插件或运行 storybook dev
时,预览配置将自动更新以引用必要的插件。
preview.meta
preview
对象上的 meta
函数用于定义你的 stories 的元数据。它接受一个包含 component
、title
、parameters
和其他 story 属性的对象。
// Learn about the # subpath import: https://storybook.org.cn/docs/api/csf/csf-factories#subpath-imports
import preview from '#.storybook/preview';
import { Button } from './Button';
const meta = preview.meta({
component: Button,
parameters: {
// type-safe!
layout: 'centered',
}
});
export default meta;
meta.story
最后,meta
对象上的 story
函数定义 stories。此函数接受一个对象,其中包含name
、args
、parameters
和其他 story 属性。
// ...from above
const meta = preview.meta({ /* ... */ });
export const Primary = meta.story({
args: {
// type-safe!
primary: true,
},
});
子路径导入
CSF 工厂利用子路径导入来简化从预览文件导入构造。虽然你仍然可以使用相对路径导入,但子路径导入提供了一种更方便和可维护的方法
// ✅ Subpath imports won't break if you move story files around
import preview from '#.storybook/preview';
// ❌ Relative imports will break if you move story files around
import preview from '../../../.storybook/preview';
有关配置必要的子路径导入的详细信息,请参阅手动迁移步骤。
有关更多详细信息,请参阅子路径导入文档。
从 CSF 1、2 或 3 升级
你可以逐步或一次性升级项目的 story 文件到 CSF 工厂。但是,在 story 文件中使用 CSF 工厂之前,你必须升级你的 .storybook/main.js|ts
和 .storybook/preview.js|ts
文件。
1. 在 package.json
中添加子路径导入
为了能够从项目中的任何位置一致地导入预览文件,你需要在 package.json
中添加子路径导入。有关更多信息,请参阅子路径导入文档。
{
"imports": {
"#*": ["./*", "./*.ts", "./*.tsx"],
},
}
2. 更新你的主要 Storybook 配置文件
更新你的 .storybook/main.js|ts
文件以使用新的 defineMain
函数。
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, experimental-nextjs-vite)
+ import { defineMain } from '@storybook/your-framework/node';
- import { StorybookConfig } from '@storybook/your-framework';
+ export default defineMain({
- export const config: StorybookConfig = {
// ...current config
+ });
- };
- export default config;
3. 更新你的预览配置文件
更新你的 .storybook/preview.js|ts
文件以使用新的 definePreview
函数。
哪些插件应该在 preview
中指定?
插件提供注解类型(parameters
、globals
等)的能力是新的,并非所有插件都支持它。
如果插件提供注解(即,它分发 ./preview
导出),则可以通过两种方式导入
-
对于官方 Storybook 插件,您需要导入默认导出:
import addonName from '@storybook/addon-name'
-
对于社区插件,您应该导入整个模块并从中访问插件:
import * as addonName from 'community-addon-name'
// Replace your-framework with the framework you are using (e.g., react-vite, nextjs, experimental-nextjs-vite)
+ import { definePreview } from '@storybook/your-framework';
- import { Preview } from '@storybook/your-renderer';
// 👇 Import the addons you are using
+ import addonA11y from '@storybook/addon-a11y';
+ export default definePreview({
- export const preview: Preview = {
// ...current config
// 👇 Add your addons here
+ addons: [addonA11y()],
+ });
- };
- export default preview;
4. 更新您的 story 文件
Story 文件已更新,以提高可用性。使用新格式
- 从 Storybook preview 文件导入 preview 构造
- meta 对象现在通过
preview.meta
函数创建,并且不必作为默认导出导出 - Stories 现在从 meta 对象创建,通过
meta.story
函数
下面的示例显示了将 story 文件从 CSF 3 升级到 CSF Factories 所需的更改。您也可以使用类似的步骤从 CSF 1 或 2 升级。
// Learn about the # subpath import: https://storybook.org.cn/docs/api/csf/csf-factories#subpath-imports
+ import preview from '#.storybook/preview';
- import { Meta, StoryObj } from '@storybook/your-renderer';
import { Button } from './Button';
+ const meta = preview.meta({
- const meta = {
// ...current meta
+ });
- } satisfies Meta<typeof Button>;
- export default meta;
- type Story = StoryObj<typeof meta>;
+ export const Primary = meta.story({
- export const Primary: Story = {
// ...current story
+ });
- };
请注意,不再需要导入或手动将任何类型应用于 meta 或 stories。 感谢工厂函数模式,现在可以自动推断类型。
4.1 重用 story 属性
以前,当在另一个 story 中重用 story 属性(例如 Story.args
或 Story.parameters
)时,会直接访问它们。虽然仍然支持像这样访问它们,但在 CSF Factories 中已弃用。
所有 story 属性现在都包含在一个名为 composed
的新属性中,应该从该属性访问。例如,Story.composed.args
或 Story.composed.parameters
。
// ...rest of file
+ export const Primary = meta.story({
- export const Primary: Story = {
args: { primary: true },
+ });
- };
+ export const PrimaryDisabled = meta.story({
- export const PrimaryDisabled: Story = {
args: {
+ ...Primary.composed.args,
- ...Primary.args,
disabled: true,
}
+ });
- };
选择属性名称 “composed” 是因为其中的值是由 story、其组件 meta 和 preview 配置组合而成的。
如果您想访问 story 的直接输入,可以使用 Story.input
而不是 Story.composed
。
5. 更新您的 Vitest 设置文件
无论您是使用 Storybook 的 Test 插件 还是 Vitest 中的 portable stories,您都可以使用 Vitest 设置文件来配置您的 stories。此文件必须更新为使用新的 CSF Factories 格式。
请注意,这仅在您对所有测试的 stories 使用 CSF Factories 时适用。如果您混合使用 CSF 1、2 或 3 以及 CSF Factories,则必须维护两个单独的设置文件。
import { beforeAll } from 'vitest';
// 👇 No longer necessary
- import { setProjectAnnotations } from '@storybook/react';
- import * as addonAnnotations from 'my-addon/preview';
+ import preview from './.storybook/preview';
- import * as previewAnnotations from './.storybook/preview';
// No longer necessary
- const annotations = setProjectAnnotations([previewAnnotations, addonAnnotations]);
// Run Storybook's beforeAll hook
+ beforeAll(preview.composed.beforeAll);
- beforeAll(annotations.beforeAll);
6. 在测试文件中重用 stories
Storybook 的 Test 插件 允许您直接在 Storybook 内部测试您的组件。所有 stories 都会自动转换为 Vitest 测试,从而在您的测试套件中实现无缝集成。
如果您不能使用 Storybook Test,您仍然可以使用 portable stories 在您的测试文件中重用 stories。在之前的 story 格式中,您必须先组合 stories,然后在测试文件中渲染它们。 使用 CSF Factories,您现在可以直接重用 stories。
import { test, expect } from 'vitest';
import { screen } from '@testing-library/react';
- import { composeStories } from '@storybook/react';
// Import all stories from the stories file
import * as stories from './Button.stories';
+ const { Primary } = stories;
- const { Primary } = composeStories(stories);
test('renders primary button with default args', async () => {
// The run function will mount the component and run all of Storybook's lifecycle hooks
await Primary.run();
const buttonElement = screen.getByText('Text coming from args in stories file!');
expect(buttonElement).not.toBeNull();
});
Story
对象还提供了一个 Component
属性,使您能够使用您选择的任何方法(例如 Testing Library)渲染组件。 您还可以通过 composed
属性访问其组合属性(args
、parameters
等)。
以下是如何通过渲染组件在测试文件中重用 story 的示例
import { test, expect } from 'vitest';
import { render, screen } from '@testing-library/react';
// Import all stories from the stories file
import * as stories from './Button.stories';
const { Primary, Secondary } = stories;
test('renders primary button with default args', async () => {
// Access the story's component via the .Component property
render(<Primary.Component />);
const buttonElement = screen.getByText('Text coming from args in stories file!');
expect(buttonElement).not.toBeNull();
});
test('renders primary button with overridden props', async () => {
// You can override props by passing them directly to the story's component
render(<Primary.Component>Hello world</Primary.Component>);
const buttonElement = screen.getByText(/Hello world/i);
expect(buttonElement).not.toBeNull();
});
常见问题 (FAQ)
我是否必须将所有 stories 迁移到这种新格式?
在可预见的未来,Storybook 将继续支持 CSF 1、CSF 2 和 CSF 3。 这些以前的格式均未被弃用。
在使用 CSF Factories 时,您仍然可以使用旧格式,只要它们不在同一个文件中混合使用即可。 如果您想将现有文件迁移到新格式,请参阅上面的升级部分。
此格式是否适用于 MDX 文档页面?
是的,用于在 MDX 文件中引用 stories 的 文档块 支持 CSF Factories 格式,无需任何更改。
如何了解有关此格式的更多信息并提供反馈?
有关此实验性格式的原始提案的更多信息,请参阅其 GitHub 上的 RFC。 我们欢迎您的评论!