从 Styleguidist 迁移到 Storybook
提供一流的开发者体验是 Yelp 基础设施和工程效率团队的核心原则之一。随着开发人员不断创建新的 React 组件,我们的 React 代码库一直在增长,但我们现有的 React Styleguidist(本文简称 Styleguidist)开发环境无法并行扩展。从 Styleguidist 到 Storybook 的过渡让我们能够为 React 组件提供一个更快、更加友好的开发环境,并更好地协调开发人员和设计人员的工作流程。在这篇文章中,我们将深入探讨我们是如何以及为什么要迁移到 Storybook。
Styleguidist 是一个交互式 React 组件开发环境,开发人员用它来开发和查看用户界面。Styleguidist 还可以用于生成静态文档页面(样式指南),并分享给其他利益相关者。文档是用 Markdown 创建的,带有代码块,这些代码块在一个单独的交互式沙盒中渲染 React 组件。一个简单的例子如下所示:
The `<ButtonGroup />` component is used to arrange multiple `<Button />`components side-by-side.
```jsx
const Button = require('../Button').default;
<ButtonGroup>
<Button text="Foo" />
<Button text="Bar" />
<Button text="Baz" />
</ButtonGroup>
```
一个Styleguidist沙盒示例
在 Yelp,我们在使用 Styleguidist 时遇到了各种各样的问题,这些问题导致 React 开发体验欠佳:
由于没有得到广泛的 Web 社区的支持,Styleguidist 缺少插件生态系统,因此 Styleguidist 的插件必须自己从头开发。
在使用大型包时,Styleguidist 不能很好地伸缩,因为它会为包中的每一个示例渲染一个独立的沙盒,导致初始化加载时间和热加载时间变长。
开发人员必须为每个组件创建许多排列,以显示组件可能支持的每一种状态。
通过编辑 Markdown 来修改组件状态对于开发人员和非技术用户来说并不直观。
Storybook 是一个开源的 UI 开发和文档工具,过去几年在 Web 社区中越来越流行。它拥有强大的社区支持和丰富的插件生态系统,可用于易访问性测试、跨浏览器测试和其他用途。
在 Storybook 中,用户可以通过 Story 来逐个浏览和开发组件示例。Story 捕获了 React 组件的渲染状态,就像 Styleguidist 的 Markdown 示例一样。这与性能糟糕的 Styleguidist 形成了对比,Styleguidist 总是会渲染包中的每一个组件的每一个示例。
在 Styleguidist 中,开发人员经常需要为组件的每一个可视化排列创建一个示例,从而增加了维护负担(例如,在修改组件 API 后需要更新每一个示例)。在 Storybook 中,开发人员可以通过 react-docgen 自动生成控件,用户可以在文档 UI 中直接修改和预览组件。与 Styleguidist 相比,这进一步简化了用户体验,因为文档用户不再需要通过编辑 Markdown 来修改组件的状态。
一个Styleguidist沙盒示例
我们的 React 代码库包含了数千个 Styleguidist 文件,每个文件中都有许多个组件示例。手动迁移它们是不可行的,强制要求开发人员手动用新的 Storybook 格式重写他们的示例也是不合理的。为了保持现有 React 组件示例并减少开发人员在迁移过程中的负担,我们列出了以下这些需求:
我们现有的 Styleguidist 文件使用了 ES5 风格的导入和语法。我们希望新的 Storybook 语法与组件源代码保持一致,所以将使用 ES6。
应该让使用过 Styleguidist 的开发人员对 Storybook 中的文档也感到熟悉。
Storybook 支持 MDX,这是一种结合了 Markdown 和 JSX 的文件格式,可以用 Markdown 为文档页面渲染 React 组件,我们可以将现有的 Styleguidist Markdown 转成 MDX。
Styleguidist 中的每一个示例代码块都应该被翻译成一个 Story,组件的 stories.js 文件应该包含所有的示例。
为了实现这些目标,我们决定使用 Codemods 将我们的 Styleguidist 文件重构为 Storybook 格式。Codemods 是一系列基于脚本的操作,通过编程的方式对代码库进行转换,在不需要手动介入的情况下进行大规模的自动化修改。
首先,我们提取 Styleguidist 代码块,Markdown 文件中的其余内容(例如文字描述)可以直接逐字复制到新的 MDX 文件中。为了实现一对一的迁移,我们将每个代码块视为一个 Story。我们可以利用现有的工具,比如用 remark-code-blocks 来提取 JavaScript 代码块,用 5to6-codemod 将这些代码块中的 ES5 语法转换为 ES6 语法。
// 之前的代码:
// const Button = require('../Button').default;
import Button from '../Button';
为了减少开发人员在迁移过程中的负担,我们决定将一个组件的所有 Story 都包含在同一个 component.stories.js 文件中,然后显示在 component.stories.mdx 文档页面中。然后我们发现 MDX 代码块是在相同的上下文中运行的,而且我们关于保持沙盒与 Styleguidist 隔离的假设是不对的。在将多个 Styleguidist 示例转换到同一个文件中时,这个问题尤为严重,因为将多个代码块连接在一起会导致重复导入:
```jsx
import Button from '../Button';
Full width `ButtonGroup` example:
<ButtonGroup fill>
(omitted for brevity)
```
```jsx
import Button from '../Button'; // <-- 这与上面的导入重复了!
Disabled `ButtonGroup` example:
<ButtonGroup disabled>
(omitted for brevity)
```
在将上面的 Story 合并到同一个 JS 文件中之后,Button 的导入就重复了。我们的 Codemod 需要解析并对这些导入进行去重,以防止出现运行时错误。另外,我们还需要包含 Styleguidist 隐式导入的组件:
// ButtonGroup.stories.js
import Button from '../Button'; // 去重
import { ButtonGroup } from './'; // 显式添加隐式导入的组件
<ButtonGroup>
<Button text="Foo" />
<Button text="Bar" />
<Button text="Baz" />
</ButtonGroup>
接下来,我们将提取的 Markdown 代码块、去重的导入语句以及 ES 语法写到 component.stories.js 中,并在 component.stories.mdx 文件中写入标准的 Storybook 模板代码:
// ButtonGroup.stories.mdx
import { ArgsTable, Canvas, Description, Meta, Story } from '@storybook/addon-docs';
import * as stories from './ButtonGroup.stories.js';
import { ButtonGroup } from './';
<Meta
title="yelp-react-component-button/ButtonGroup"
component={ButtonGroup}
/>
The `<ButtonGroup />` component is used to arrange multiple `<Button />`
components side-by-side.
<Canvas>
<Story name="Example0" story={stories.Example0} />
</Canvas>
最后,我们需要通过 Storybook 让开发人员知道如何构建组件。我们可以用生产环境现有的 webpack 配置来扩展 Storybook 的构建配置,这样就可以保留 Storybook 的自动 docgen 功能,以及其他一些特性,比如代码块预览。使用现有的 webpack 配置也意味着组件的外观和行为与实际页面中的完全一样。
将 React 组件示例从 Styleguidist 迁移到 Storybook 极大地提升了开发者体验和组件性能。我们能够利用 Storybook 的特性,如按需加载,通过在编译时生成更小的包来提升性能,从而缩短沙盒的启动时间。基于我们的 Codemod 迁移策略,我们能够转换代码库中几乎所有的示例,而且不会出现运行时错误,在迁移过程中也不会对开发人员造成阻碍。
切换到 Storybook 为 Yelp 打开了新的大门,我们很高兴能在上面添加插件,进一步提升前端开发人员的工作效率。
我们希望我们的分享能够为其他面对类似迁移的团队带来有用的信息!
原文链接:
https://engineeringblog.yelp.com/2022/07/migrating-from-styleguidist-to-storybook.html
声明:本文为 InfoQ 翻译,未经许可禁止转载。
微信扫码关注该文公众号作者