为利益相关者编写文档
专业 前端 团队 通过采用率来衡量设计系统的成功程度。为了充分发挥设计系统节省工作量的优势,组件必须得到广泛传播。否则,意义何在?
在本章中,我们将创建一个设计系统“用户手册”,以帮助利益相关者在其应用中重用组件。在此过程中,我们将揭示 Shopify、Microsoft、Auth0 和英国政府团队使用的 UI 文档最佳实践。
编写文档令人疲惫
显而易见,文档对于协作式 UI 开发至关重要。它可以帮助团队了解如何以及何时使用通用 UI 组件。但为什么需要付出如此多的努力呢?
如果您曾经创建过文档,您可能将时间投入到非文档任务中,例如站点基础设施或与技术文档撰写者争论。即使您找到时间发布这些文档,在开发新功能的同时维护它们也是一项艰巨的任务。
大多数文档在创建出来的那一刻就已过时。过时的文档会削弱对设计系统组件的信任,从而导致开发人员选择创建新组件而不是重用现有组件。
要求
创建和维护文档可能具有挑战性,因此尽量减少任何障碍非常重要。以下是文档应该做到的:
- 🔄 通过使用最新的生产代码保持更新
- ✍️ 使用熟悉的编写工具(如 Markdown)简化编写过程
- ⚡️ 减少维护时间,使团队可以专注于编写
- 📐 提供样板代码,使开发人员无需重写常用模式
- 🎨 为特别复杂的用例和组件提供可定制性
作为 Storybook 用户,我们具有先发优势,因为组件变体已经记录为 stories——一种文档形式。一个 story 展示了组件在给定不同输入(props)的情况下应该如何工作。Stories 易于编写并且可以自我更新,因为它们使用生产组件。更重要的是,可以使用上一章中的工具对 stories 进行回归测试!
当您编写 stories 时,您可以免费获得组件 prop 文档和使用示例!– Justin Bennett,Artsy 工程师
编写 stories,生成文档
借助 Storybook Docs 插件,我们可以从现有的 stories 生成丰富的文档,以减少维护时间并获得开箱即用的默认设置。与我们在构建章节(Controls 和 Actions)中介绍的插件一样,Docs 插件也包含在每个 Storybook 安装中并已配置,因此我们可以专注于编写优秀的文档。
每次打开 Storybook 时,您应该会在侧边栏中看到一个名为“Docs”的新条目
在幕后,Storybook 使用通过 tags
元数据属性配置的每个组件 story 的“Docs”条目填充侧边栏,从而创建一个自动生成的文档页面,其中包含最常用的部分,例如交互式预览、源代码查看器和 args 表。您会在 Shopify 和 Auth0 的设计系统文档中找到类似的功能。所有这些都在不到 2 分钟的时间内完成。
生成文档
到目前为止,我们已经付出了很少的努力就取得了很大的进展,确保我们的设计系统在代码方面保持最新。然而,文档仍然缺乏人情味。我们需要对其进行配置,并为其他开发人员提供更多上下文(原因、时间和方式)。首先,在 src/Avatar/Avatar.stories.jsx
中的 Avatar
组件 story 中添加一个 tags
属性
import { Avatar } from './Avatar';
export default {
title: 'Design System/Avatar',
component: Avatar,
+ tags: ['autodocs'],
/*
* More on Storybook argTypes at:
* https://storybook.org.cn/docs/react/api/argtypes
*/
argTypes: {
size: {
control: {
type: 'select',
},
options: ['tiny', 'small', 'medium', 'large'],
},
},
};
接下来,让我们添加一些额外的元数据来解释组件的作用。在我们的例子中,我们将添加一个副标题来描述 Avatar 的用途
import { Avatar } from './Avatar';
export default {
title: 'Design System/Avatar',
component: Avatar,
tags: ['autodocs'],
+ parameters: {
+ docs: {
+ subtitle: 'Displays an image that represents a user or organization',
+ },
+ },
/*
* More on Storybook argTypes at:
* https://storybook.org.cn/docs/react/api/argtypes
*/
argTypes: {
size: {
control: {
type: 'select',
},
options: ['tiny', 'small', 'medium', 'large'],
},
},
};
现在,您应该拥有 Avatar 组件的最低可行文档,该文档由 Storybook 的 args 表自动生成,默认值从组件的 propTypes
和 JSdoc 中获取,这是减少维护时间并确保文档保持最新的第一步。
然而,我们还没有完成。由于我们正在为其他利益相关者(包括设计师或设计系统的使用者等非技术人员)构建文档,因此我们不能假设他们知道每个 story 代表什么。让我们在 src/Avatar/Avatar.stories.jsx
中为 stories 添加一些描述性文本
import { Avatar } from './Avatar';
export default {
title: 'Design System/Avatar',
component: Avatar,
tags: ['autodocs'],
parameters: {
componentSubtitle:
'Displays an image that represents a user or organization',
},
/*
* More on Storybook argTypes at:
* https://storybook.org.cn/docs/react/api/argtypes
*/
argTypes: {
size: {
control: {
type: 'select',
},
options: ['tiny', 'small', 'medium', 'large'],
},
},
};
export const Standard = {
args: {
size: 'large',
username: 'Tom Coleman',
src: 'https://avatars2.githubusercontent.com/u/132554',
},
};
/**
* 4 sizes are supported.
*/
export const Sizes = {
args: {
username: 'Tom Coleman',
src: 'https://avatars2.githubusercontent.com/u/132554',
},
render: (args) => (
<>
<Avatar {...args} size='large' />
<Avatar {...args} size='medium' />
<Avatar {...args} size='small' />
<Avatar {...args} size='tiny' />
</>
),
};
/**
* Shows the user's initials as a fallback when no image is provided.
*/
export const Initials = {
render: (args) => (
<>
<Avatar username='Tom Coleman' />
<Avatar username='Dominic Nguyen' />
<Avatar username='Varun Vachhar' />
<Avatar username='Michael Shilman' />
</>
),
};
/**
* Shows a loading indicator.
*/
export const Loading = {
args: {
loading: true,
},
render: (args) => (
<>
<Avatar {...args} size='large' />
<Avatar {...args} size='medium' />
<Avatar {...args} size='small' />
<Avatar {...args} size='tiny' />
</>
),
};
/**
* Shows the user's avatar when provided with a `src` prop or in various states and sizes.
*/
export const Large = {
render: () => (
<>
<Avatar loading size='large' />
<Avatar size='large' username='Tom Coleman' />
<Avatar
size='large'
username='Tom Coleman'
src='https://avatars2.githubusercontent.com/u/132554'
/>
</>
),
};
/**
* Avatar component using Controls
*/
export const Controls = {
args: {
loading: false,
size: 'tiny',
username: 'Dominic Nguyen',
src: 'https://avatars.githubusercontent.com/u/263385',
},
};
现在您应该看到这个
使用 Markdown/MDX 增强文档功能
每个组件都有独特的文档要求,这可能难以解决。我们利用 Storybook 的自动文档功能和 Docs 插件来简化此过程。这使我们能够在遵循行业最佳实践的同时创建全面的文档,而无需产生任何额外费用。展望未来,我们可以通过识别在使用组件时可能出现的任何潜在挑战或问题来进一步增强我们的文档流程。
Markdown 是一种用于编写文本的简单格式。MDX 允许您在 Markdown 中使用交互式代码 (JSX)。Storybook Docs 使用 MDX 为开发人员提供对文档呈现方式的最终控制权。
作为 Storybook 安装工作流程的一部分,MDX 文件默认注册。您的 .storybook/main.js
应该如下所示
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
stories: ['../src/**/*.mdx', '../src/**/*.stories.@(js|jsx|ts|tsx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
'@storybook/addon-coverage',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
};
export default config;
创建一个新的 src/Avatar/Avatar.mdx
文件并提供一些详细信息。我们将从 Avatar.stories.jsx
文件中删除 tags
和 parameters
,并在 mdx 文件中重新创建我们的文档。
import {
Canvas,
Controls,
Description,
Meta,
Subtitle,
Story,
} from '@storybook/blocks';
import * as AvatarStories from './Avatar.stories';
# Avatar
<Meta of={AvatarStories} />
<Subtitle>Displays an image that represents a user or organization</Subtitle>
Use an avatar for attributing actions or content to specific users.
The user's name should _always_ be present when using Avatar – either printed beside the avatar or in a tooltip.
<Canvas>
<Story of={AvatarStories.Standard} />
</Canvas>
## Additional variants
### Sizes
<Description of={AvatarStories.Sizes} />
<Story of={AvatarStories.Sizes} />
### Initials
<Description of={AvatarStories.Initials} />
<Story of={AvatarStories.Initials} />
### Loading
<Description of={AvatarStories.Loading} />
<Story of={AvatarStories.Loading} />
### Playground
Interact with the component and see how it responds to the different input properties.
<Canvas>
<Story of={AvatarStories.Controls} />
</Canvas>
<Controls of={AvatarStories.Controls} />
在 Storybook 中,您的 Avatar 组件的“Docs”条目应替换为我们稀疏的 MDX 页面。
Storybook Docs 附带 “Doc Blocks”,即开箱即用的组件,例如 交互式预览、图标等等。默认情况下,它们在幕后用于自动生成的文档页面,也可以提取出来供个人使用。我们的目标是在不重新做所有事情的情况下自定义 Avatar 的文档,因此让我们尽可能重用 Doc Blocks。
让我们将 ArgTypes
Doc Block 添加到我们的 MDX 文件中。它将自动生成一个包含组件所有属性及其类型的表格。
import {
+ ArgTypes,
Canvas,
Controls,
Description,
Meta,
Subtitle,
Story,
} from '@storybook/blocks';
{/* Same content as before */}
<Canvas>
<Story of={AvatarStories.Standard} />
</Canvas>
+ <ArgTypes of={AvatarStories} />
很好!我们回到了起点,但现在可以完全控制排序和内容。自动化文档生成的好处仍然存在,因为我们正在使用 Doc Blocks。
使用关于用例的注释自定义 Avatar 的文档。它可以为开发人员提供有关如何利用此组件的上下文。我们可以像在任何其他 markdown 文档中一样添加 markdown
{/* Same content as before */}
<Canvas>
<Story of={AvatarStories.Standard} />
</Canvas>
<ArgTypes of={AvatarStories} />
+ ## Usage
+ Avatar is used to represent a person or an organization. By default the avatar shows an image and gracefully falls back to the first initial of the username. While hydrating the component you may find it useful to render a skeleton template to indicate that Avatar is awaiting data. Avatars can be grouped with the AvatarList component.
{/* Same content as before */}
自定义页面
每个设计系统都带有一个封面页。Storybook Docs 允许您使用 MDX 创建独立的页面。
创建一个新文件 src/Intro.mdx
import { Meta } from '@storybook/blocks';
<Meta title='Design System/Introduction' />
# Introduction to the Storybook design system tutorial
The Storybook design system tutorial is a subset of the full [Storybook design system](https://github.com/storybookjs/design-system/), created as a learning resource for those interested in learning how to write and publish a design system using best practice techniques.
Learn more in the [Storybook tutorials](https://storybook.org.cn/tutorials/)
我们在此处创建的封面页是 “未附加文档”的一个示例,它在侧边栏中的显示方式与其他自动生成的文档页面不同。
为了使其首先出现,我们必须告诉 Storybook 在 .storybook/main.js
中加载 Introduction 文件
/** @type { import('@storybook/react-vite').StorybookConfig } */
const config = {
stories: [
+ '../src/Intro.mdx',
'../src/**/*.mdx',
'../src/**/*.stories.@(js|jsx|ts|tsx)',
],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y',
'@storybook/addon-coverage',
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag',
},
};
export default config;
在线发布文档
如果您编写的文档无人阅读,那有用吗?没用。仅仅创建高质量的学习材料是不够的,我们需要将这些材料呈现给利益相关者和同事。目前,我们的文档隐藏在仓库中,这意味着人们必须在本地运行设计系统的 Storybook 才能查看文档。
在上一章中,我们在线发布了 Storybook 以进行视觉评审。使用相同的机制来发布我们的组件文档也很容易。让我们在 package.json
中添加一个新的脚本,以在文档模式下构建我们的 Storybook
{
"scripts": {
"build-storybook-docs": "storybook build --docs"
}
}
保存并提交。
在命令行或持续集成工具中运行 build-storybook-docs
将在“docs”配置中输出一个静态站点。设置一个静态站点部署工具 Netlify 或 Vercel,以便在每次提交时部署文档站点。
在其他应用中导入设计系统
到目前为止,我们专注于内部。首先,创建持久的 UI 组件。然后,进行评审、测试和记录它们。现在我们将视角转向外部,以检查团队如何使用设计系统。
第 7 章介绍了如何打包设计系统以在其他应用中使用。学习如何将 JavaScript 包管理器 npm 与节省时间的发布管理工具 Auto 结合使用。