返回部落格

Component Story Format 3.0

拋開樣板程式碼,迎接腳本互動!

loading
Michael Shilman
@mshilman
上次更新

Storybook 是基於一個核心概念:故事 (story)。每個使用 Storybook 的人都會為其元件範例編寫故事。Component Story Format (元件故事格式) 是我們富有表現力、與平台無關的格式,已被業界廣泛使用,從 Netflix 到 Shopify 及其他公司。

我很高興宣佈 Component Story Format 3.0。這是 CSF 的下一個主要迭代版本,它利用了一年來社群的回饋,大幅減少了樣板程式碼,讓您可以專注於故事的本質。

  • ♻️ 可擴展的故事物件以供重複使用
  • 🌈 預設渲染函式以求簡潔
  • 📓 自動標題以求便利
  • ▶️ 播放函式以實現腳本互動
  • ✅ 100% 向後相容於 CSF 2.0

CSF 3.0 今天起即可在實驗模式中使用。我們希望收到您的回饋,以在正式發佈之前使其變得更好。讓我們深入了解以下細節。

CSF 到底有什麼好處?

Component Story Format (CSF) (元件故事格式) 是一種簡單、基於 ES6 模組的檔案格式,用於元件範例。自兩年前推出以來,它已大獲成功。

在底層,CSF 是標準 JavaScript,與 Storybook 的 API 解耦。沒有工具鎖定。這表示您可以將故事匯入您最喜愛的 JS 程式庫。

去年,我們推出了 CSF Args:動態故事輸入,開創了新的使用案例,例如依賴注入和自動產生的控制項

Args 已成為 Storybook 及其擴充套件的強大建構區塊,也適用於第三方整合,例如 Testing LibraryCypress

更重要的是,由於 CSF 與平台無關,因此現在已獲得生態系統中令人難以置信的專案支援,例如 RedwoodJSReact StyleguidistUXPin

CSF 3.0 的新功能

Component Story Format 是一種基於 ES6 模組匯出的檔案格式:預設匯出包含關於範例的元數據,而每個具名匯出都是一個範例。

在 CSF 2.0 中,具名匯出始終是實例化元件的函式,並且這些函式可以使用組態選項進行註解。例如

// CSF 2.0
export default {
  title: 'components/Button',
  component: Button,
};

export const Primary = (args) => <Button {...args} />;
Primary.args = { primary: true };

這為 Button 宣告了一個 Primary 故事,該故事透過將 {primary: true} 擴展到元件中來渲染自身。default.title 元數據說明了在導覽階層中放置故事的位置。

以下是 CSF 3.0 的等效項

// CSF 3.0
export default { component: Button };
export const Primary = { args: { primary: true } };

它簡潔多了!讓我們逐一了解變更,以了解正在發生的情況。

可擴展的故事物件

您可能注意到的第一件事是,在 CSF 3.0 中,具名匯出是物件,而不是函式。這讓我們可以使用 JS 擴展運算符更有效率地重複使用故事。

考慮以下對簡介範例的補充,它建立了一個 PrimaryOnDark 故事,該故事在深色背景下渲染

以下是 CSF 2.0 實作

// CSF 2.0
export const PrimaryOnDark = Primary.bind({});
PrimaryOnDark.args = Primary.args;
PrimaryOnDark.parameters = { background: { default: 'dark' } };

Primary.bind({}) 複製了故事函式,但它沒有複製函式外部的註解,因此我們必須新增 PrimaryOnDark.args = Primary.args 以繼承 args。

在 CSF 3.0 中,我們可以擴展 Primary 物件以繼承其所有註解

// CSF 3.0
export const PrimaryOnDark = {
  ...Primary,
  parameters: { background: { default: 'dark' } },
};

這似乎是一件小事,但我們可以利用它做很多巧妙的事情,我們將在下面看到。

預設渲染函式

您可能注意到的下一件事是,在初始範例中,根本沒有任何函式!這是怎麼回事?

在 CSF 3.0 中,故事是物件,因此您指定故事渲染方式的方式是透過渲染函式。我們可以透過以下步驟將 CSF 2.0 範例重寫為 CSF 3.0。

讓我們從一個簡單的 CSF 2.0 故事函式開始

// CSF 2.0
export default {
  title: 'components/Button',
  component: Button,
};

export const Default = (args) => <Button {...args} />;

現在,讓我們在 CSF 3.0 中將其重寫為故事物件,並使用顯式渲染函式來告訴故事如何渲染自身。與 CSF 2.0 類似,這讓我們可以完全控制如何渲染元件甚至是元件集合。

// CSF 3.0 - explicit render function
export const Default = {
  render: (args) => <Button {...args} />
};

但在 CSF 2.0 中,許多 story 函式都是相同的:取得在預設匯出中指定的元件,並將 args 擴展到其中。這些故事的有趣之處不在於函式,而在於傳遞到函式中的 args。

因此,在 CSF 3.0 中,我們為每個框架提供預設渲染函式。如果您所做的只是將 args 擴展到您的元件中 (這是最常見的情況),則您根本不需要指定任何渲染函式

// CSF 3.0 - default render function
export const Default = {};

沒有比這更簡單的了。告別樣板程式碼!

自動產生標題

CSF 3.0 的另一個巨大便利之處是自動標題產生。

// CSF 2.0
export default { title: 'components/Button', component: Button }
// CSF 3.0
export default { component: Button }

您仍然可以像在 CSF 2.0 中一樣指定標題,但如果您不指定標題,則可以從故事在磁碟上的路徑推斷出來。

這由故事的組態方式控制。考慮舊式組態

// .storybook/main.js
module.exports = {
  stories: ['../src/**/*.stories.*']
};

現在考慮 Storybook 6.4 中提供的新式組態

// .storybook/main.js
module.exports = {
  stories: ['../src']
};

在給定此組態的情況下,故事檔案 ../src/components/Button.stories.tsx 將取得標題 components/Button

需要更多控制?以下內容將比對自訂檔案模式,並將自訂前綴新增至產生的標題

module.exports = {
  stories: [
   { directory: '../src', files: '*.story.tsx', titlePrefix: 'foo' }
  ]
};

播放函式

最後但並非最不重要的,我們為 CSF 3.0 帶來了一個全新的功能:播放函式。播放函式是在故事渲染後執行的少量程式碼片段。

雖然其他 CSF 3.0 功能最佳化了現有的故事結構,但播放函式啟用了以前不可能實現的場景。

考慮驗證表單的場景

及其 CSF 3.0 實作

// CSF 3.0
import userEvent from '@testing-library/user-event';

export default { component: AccountForm }

export const Empty = {};

export const EmptyError = {
  ...Empty,
  play: () => userEvent.click(screen.getByText('Submit'));
}

export const Filled = {
  ...Empty,
  play: () => {
    userEvent.type(screen.getById('user'), 'shilman@example.com');
    userEvent.type(screen.getById('password'), 'blahblahblah');
  }
}

export const FilledSuccess = {
  ...Filled,
  play: () => {
    Filled.play();
    EmptyError.play();
  }
}

Empty 故事渲染空白表單。

EmptyError 透過在故事渲染後立即發出使用者事件以使用 Testing Library 按一下提交按鈕來模擬驗證錯誤。感謝可擴展的故事物件,此故事繼承了 Empty 故事的所有 args 和參數。

Filled 故事使用 Testing Library 填寫表單。

最後,FilledSuccess 故事透過首先重複使用 Filled 故事的 play 函式,然後按一下提交按鈕來顯示提交狀態。

我們甚至可以在 CSF 3.0 中為整個序列製作動畫

這種場景也激發了 CSF 3.0 的可擴展物件語法。我們現在可以方便地複製故事的整個組態,並且僅修改我們關心的部分。

徵求回饋

CSF 3.0 以實驗性版本提供。我們希望收到您的回饋。

如果您使用的是 Storybook 6.3SB 6.4 預發佈版,請在您的 .storybook/main.js 組態中開啟 previewCsf3

// .storybook/main.js
module.exports = {
  features: {
    previewCsfV3: true,
  }
};

👉 針對自動標題產生功能,您必須使用 SB 6.4,並且您必須將 .storybook/main.js 中的 stories 組態更新為上面草擬的新格式 – 官方文件即將推出。

為了您的方便,有一個 codemod 可以升級您的故事

$ npx sb@next migrate csf-2-to-3 --glob="**/*.stories.js"

如需回饋,請參閱 GitHub 討論Storybook Discord 中的 #component-story-format 頻道。查看 Github 上標記為 csf3 的已知未解決問題。

我們計劃在 SB6.4 發佈週期中迭代 CSF,並在準備就緒後移除功能標誌。CSF 3.0 向後相容,因此所有 CSF 2.0 功能仍然可用。您可以盡情試用,而無需變更任何現有的故事。

參與其中

Component Story Format 3.0 由 Michael Shilman (我!)、Tom ColemanGert HengeveldPavan Sunkara 開發,並獲得了整個 Storybook 社群的測試和回饋。

Storybook 是超過 1320 位社群貢獻者的成果,並由頂級維護者的 指導委員會組織。

如果 Storybook 讓您的 UI 開發工作流程更輕鬆,請協助 Storybook 變得更好。您可以貢獻新功能、修正錯誤或改進文件。在 Discord 上加入我們、在 Open Collective 上支持我們,或直接在 Github 上參與。

加入 Storybook 電子郵件列表

取得最新的新聞、更新和發佈

6,730位開發人員並持續增加中

我們正在徵才!

加入 Storybook 和 Chromatic 背後的團隊。建構供數十萬名開發人員在生產環境中使用的工具。Remote-first (遠端優先)。

查看職缺

熱門文章

測試複合元件

防止小變更變成重大回歸
loading
Varun Vachhar

如何測試元件互動

學習如何模擬使用者行為並執行功能檢查
loading
Varun Vachhar

故事即測試

元件所做一切的單一事實來源
loading
Varun Vachhar
加入社群
6,730位開發人員並持續增加中
為何為何選擇 Storybook元件驅動的 UI
文件指南教學課程變更日誌遙測
社群擴充套件參與其中部落格
展示探索專案元件詞彙表
開放原始碼軟體
Storybook - Storybook 繁體中文

特別感謝 Netlify CircleCI