Component Story Format (CSF)
這是一項實驗性功能,(雖然不太可能) API 在未來版本中可能會變更。我們歡迎提供意見回饋與貢獻,以協助改進此功能。
CSF Factories 是 Storybook 的 Component Story Format (CSF) 的下一代演進。這個新的 API 使用稱為 factory functions 的模式,為您的 Storybook stories 提供完整的型別安全,使其更容易正確設定附加元件,並釋放 Storybook 功能的全部潛力。
本參考文件將概述 API,並提供從 CSF 3 升級的遷移指南。
概觀
CSF Factories API 由四個主要函式組成,以協助您撰寫 stories。請注意,其中三個函式作為 factories 運作,每個函式都會產生鏈中的下一個函式 (definePreview
→ preview.meta
→ meta.story
),在每個步驟提供完整的型別安全。
defineMain
使用 CSF Factories,您的主要 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
,以定義元件 meta。
// 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 的 metadata。它接受一個包含 component
、title
、parameters
和其他 story 屬性的物件。
// Learn about the # subpath import: https://storybook.dev.org.tw/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 Factories 利用子路徑匯入來簡化從預覽檔案匯入建構。雖然您仍然可以使用相對路徑匯入,但子路徑匯入提供更方便且可維護的方法
// ✅ 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 Factories。但是,在 story 檔案中使用 CSF Factories 之前,您必須升級 .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 預覽檔案匯入預覽建構
- meta 物件現在透過
preview.meta
函式建立,並且不必作為預設匯出 - Stories 現在從 meta 物件透過
meta.story
函式建立
以下範例顯示從 CSF 3 升級到 CSF Factories 所需的變更。您也可以使用類似的步驟從 CSF 1 或 2 升級。
// Learn about the # subpath import: https://storybook.dev.org.tw/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。由於 factory function 模式,現在會自動推斷型別。
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 和預覽設定組成的。
如果您想存取 story 的直接輸入,可以使用 Story.input
而不是 Story.composed
。
5. 更新您的 Vitest 設定檔
無論您是使用 Storybook 的 Test addon 還是 Vitest 中的可攜式 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 addon 允許您直接在 Storybook 內測試您的元件。所有 stories 都會自動轉換為 Vitest 測試,使整合在您的測試套件中無縫接軌。
如果您無法使用 Storybook Test,您仍然可以使用 可攜式 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
屬性存取其 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。我們歡迎您的評論!