
组件故事格式
简单、可移植、面向未来的组件示例

Storybook 是世界上最流行的 UI 组件工作坊。它支持各种主流视图层(包括 React、Vue、Angular 等)的结构化 UI 开发和测试。
Storybook 5.2 引入了**组件故事格式 (Component Story Format, CSF)**,这是一种基于 ES6 模块编写故事的新方式。组件故事简单、易读,并且与 Storybook 的内部 API 解耦,因此你可以在任何地方使用它们。
继续阅读以了解更多信息
- 🏆 原因:巨大的机会
- 📄 格式:它是什么以及为什么更好
- 🚚 可移植性:Jest 嵌入示例
- 🔀 代码转换:我们如何让升级变得容易
- ⚡ 3 分钟安装:立即开始
- 🔭 未来展望?:前进之路
🏆 为什么需要新的格式?
想象一下,如果在 Storybook 中开发一个组件,可以自动解锁使用 Jest 进行测试、导入 Sketch 设计、粘贴到 InVision 原型以及在 Chromatic 中进行可视化测试的能力。如果你的组件库可以在所有你喜欢的工具中通用访问呢?
在过去的三年里,组件已崛起并主导了 UI 领域。随处可见新的面向组件的开发、测试、设计和原型制作工具。

这些工具参与了组件和组件示例(也称为故事)的创建和使用。但每个工具都有自己的专有格式,因为尚未存在一种简单、平台无关的方式来表达组件示例。
“故事”是组件示例的真相来源
Storybook 的流行源于其丰富的开源组件开发、测试和文档工具。这些丰富的功能使其成为 Airbnb、Slack、Squarespace、Lyft, Uber 和 Dropbox 等巨头公司前端工作流程中不可或缺的一部分。
然而,剥离一切外壳,Storybook 是基于一个核心构建:**故事**。
故事是一个代码片段,它以特定状态渲染组件的示例。
故事使用了提供给用户的生产代码,这使其成为组件示例最准确的表示。更重要的是,故事是用你用来构建应用程序的视图层表达的。
Tom Coleman、Norbert de Langen 和我最初旨在简化在 Storybook 中编写故事。在此过程中,我们意识到创建一个富有表现力、平台无关的格式将允许开发者在其他工具中使用故事,甚至独立于 Storybook 本身。这可以改善所有使用组件的人的体验!
📄 组件故事格式
我很高兴介绍组件故事格式。如果你使用过早期版本的 Storybook,你可能熟悉“经典”的 storiesOf
API
storiesOf('atoms/Button', module)
.add('text', () => <Button>Hello</Button>)
.add('emoji', () => <Button>😀😎👍💯</Button>);
这个久经考验的 API 能够完成任务。但在帮助成千上万的开发者捕获、记录和测试关键组件状态后,我们想出了一个更好的方法
export default { title: 'atoms/Button' };
export const text = () => <Button>Hello</Button>;
export const emoji = () => <Button>😀😎👍💯</Button>;
CSF 具有 storiesOf
API 的所有功能,并带来了许多额外的优势
💎 **简单**。编写故事就像从故事文件中以你熟悉和喜爱的干净、**标准**格式导出 ES6 函数一样简单。
🚚 **可移植**。组件故事可以轻松地在任何支持 ES6 模块的地方使用,包括你喜欢的测试工具,如 Jest 和 Cypress。
🔥 **优化**。组件故事除了你的组件外不需要任何其他库。而且因为它们是 ES6 模块,它们甚至可以进行 tree-shaking!
☝️ **声明式**。声明式语法与MDX 等更高级的格式同构,实现了干净、可验证的转换。
👾 **面向未来**。组件故事隐藏了 Storybook 的底层 API,使维护者可以灵活地改进 Storybook,而不会破坏任何契约。

🚚 故事的**可移植性**
组件故事不依赖于 Storybook,因此使用它们就像导入 ES6 模块一样简单。思考一下我们如何使用 Jest 和 react-testing-library 测试交互性。
这里是一个有状态 Counter
组件的 CSF 文件示例,它在每次点击时增加计数
export default { title: 'Counter' };
export const enabled = () => (
<Counter text="Enabled" />
);
export const disabled = () => (
<Counter disabled text="Disabled" />
);
这里是如何在交互测试中使用它
import { render, fireEvent } from '@testing-library/react';
import { enabled, disabled } from './Button.stories';
describe('counter interactivity', () => {
it('should increment when enabled', () => {
const comp = render(enabled());
fireEvent.click(comp.getByText('Enabled: 0'));
expect(comp.getByText('Enabled: 1')).toBeTruthy();
});
it('should do nothing when disabled', () => {
const comp = render(enabled());
fireEvent.click(comp.getByText('Disabled: 0'));
expect(comp.getByText('Disabled: 0')).toBeTruthy();
});
});
使用组件故事格式,这种集成变得简单而自然。如果使用 storiesOf
来实现同样的结果,将需要对代码进行重大重构。
🔀 方便的代码迁移
你现有的故事库怎么办?无需担心。鉴于我们所有现有用户都依赖 Storybook 的经典 API,我们将在可预见的未来继续支持 storiesOf
。
话虽如此,我们还是希望你进行升级,因此我们让升级变得异常简单。由于 storiesOf
API 中的一切在组件故事格式中都有直接对应的项,你可以在几秒钟内自动迁移现有故事。
例如,如果你的故事文件以 .stories.js
结尾,转换你的故事就像在Storybook CLI 中运行以下命令一样简单
npx sb migrate storiesof-to-csf --glob "**/*.stories.js"
Storybook 在底层使用了出色的 JSCodeshift,使得这种转换快速而简便。如果你正在从 storiesOf
API 迁移,还需要修改对 configure
的调用。
⚡ 3 分钟安装
立即在 Storybook 5.2 中尝试组件故事格式
npx npm-check-updates '/storybook/' -u && npm install
为了加载组件故事,Storybook 的 configure
API 有了小小的改进。这里是一个示例.storybook/config.js
import { configure } from ‘@storybook/react’;
configure(require.context(‘../src/’, true, /\.stories\.js$/), module);
最后,你可以添加一个新的故事来验证是否正常工作,然后在你的故事库上运行自动化迁移(见上文)。迁移会覆盖你的文件,因此请确保你的故事文件已纳入版本控制。
或者如果你想在一个新项目中尝试,Storybook 的默认设置现在默认包含组件故事
cd my-react-vue-angular-project
npx -p @storybook/cli@next sb init
大功告成!🎉
🔭 未来展望?
组件故事格式是 Storybook 迈出的基础性一步,带来了即时的好处,包括简单性、可移植性和可优化性。
该格式的长期益处将更加巨大。一种开放、可移植、基于标准的格式使得组件设计和开发工具的整个生态系统能够协同工作,为用户服务。
作为最受欢迎的组件探索器,Storybook 有能力推广一个通用标准。我们所知,有超过 20,000 个 GitHub 仓库依赖 Storybook,全球最大的公司都在使用它,涵盖了所有主要的前端视图层。它每月在 NPM 上安装超过 400 万次。
Storybook 用户已经在过渡到 CSF,以便他们可以在 Storybook 之外的其他工具和库中重用现有故事。
📣 在Medium 或 Twitter 上关注我们,了解项目进展。
💌 如果你正在创建一个可以从 CSF 或任何 Storybook 集成中受益的工具,我们非常乐意合作。请联系我:michael@hichroma.com。
感谢社区
组件故事格式由 Tom Coleman、Norbert de Langen 和 Michael Shilman(我!)开发,并得到了整个 Storybook 社区的测试和反馈。
Storybook 是 700 多名社区提交者的成果,由顶级维护者组成的指导委员会组织。还要感谢 Open Collective 上的慷慨捐赠。
如果 Storybook 让你的 UI 开发流程更轻松,请帮助 Storybook 变得更好。你可以贡献新功能、修复 bug 或改进文档。加入我们的 Discord,在 Open Collective 上支持我们,或直接在 Github 上参与。