4、开发环境搭建:Storybook配置、文档工具(MDX)集成、热更新调试、Mock服务搭建
好,咱们进入第四讲。说实话,开发环境搭建这件事,很多同学觉得「不就是装个包跑起来吗?」——嗯,我以前也这么想。直到有一次,我在一个组件库项目里折腾了整整两天,就为了把 Storybook 和 TypeScript 的路径别名搞通。从那以后,我养成了一个习惯:先把环境搭稳,再写一行业务代码。
这一章,我会带你一步步搭好四个核心模块:Storybook 作为组件开发与预览的沙箱,MDX 作为文档编写工具,热更新 保证开发效率,以及 Mock 服务 让组件在真实数据下跑通。你想想看,如果连这些基础设施都没弄好,后面写 50 个组件时得多痛苦?
4.1 Storybook 配置:从零到可运行
我个人习惯用 Storybook 7.x 版本,它比 6.x 快了不少,而且对 Vite 的支持更原生。咱们的项目是基于 Vite 的,所以直接装 @storybook/react-vite 这个包。
# 在项目根目录执行
npx storybook@latest init --type react-vite
这条命令会自动检测你的 package.json,安装依赖,并生成 .storybook 目录。里面有两个核心文件:main.js 和 preview.js。
main.js 负责配置 Storybook 的入口、插件和构建行为。我一般会这样改:
// .storybook/main.js
export default {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-links',
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@storybook/addon-a11y', // 可访问性检查,我强烈建议加上
],
framework: {
name: '@storybook/react-vite',
options: {},
},
docs: {
autodocs: 'tag', // 自动生成文档,后面会用到
},
};
4.2 文档工具集成:用 MDX 写组件文档
MDX 是什么?说白了就是 Markdown 里能写 JSX。你可以在文档里直接插入组件实例,还能实时交互。这对组件库来说太香了——文档即演示,演示即文档。
Storybook 7 对 MDX 的支持已经非常成熟。你只需要在 stories 目录下创建一个 .stories.mdx 文件,就能开始写文档了。
// Button.stories.mdx
import { Meta, Story, Canvas } from '@storybook/addon-docs';
import { Button } from './Button';
<Meta title="通用/Button" component={Button} />
# Button 按钮
这是一个基础按钮组件,支持 `primary`、`default`、`dashed` 三种类型。
## 基础用法
<Canvas>
<Story name="Primary">
<Button type="primary">主要按钮</Button>
</Story>
<Story name="Default">
<Button>默认按钮</Button>
</Story>
</Canvas>
## 属性说明
| 属性名 | 类型 | 默认值 | 说明 |
|--------|------|--------|------|
| type | 'primary' \| 'default' \| 'dashed' | 'default' | 按钮类型 |
| size | 'small' \| 'medium' \| 'large' | 'medium' | 按钮尺寸 |
| disabled | boolean | false | 是否禁用 |
这里要注意:MDX 文件里的 <Story> 标签,每个 name 必须唯一。我刚开始写的时候,复制粘贴忘了改 name,结果 Storybook 直接报「duplicate story id」——嗯,这种低级错误犯过一次就不会再犯了。
4.3 热更新调试:让开发飞起来
热更新(HMR)是开发体验的底线。没有热更新的组件库开发,就像没有刹车的赛车——能跑,但随时可能翻车。
Storybook 7 默认集成了 Vite 的 HMR,理论上你改完代码,浏览器会自动刷新。但实际项目中,我遇到过几次「改了代码但页面没反应」的情况。排查下来,大多是这两个原因:
- 文件路径大小写不一致:Windows 不区分大小写,但 Linux 区分。如果你在 Windows 上开发,部署到 Linux 上就可能找不到文件。我建议统一用小写加连字符命名,比如
my-button.tsx。 - 循环依赖:组件 A 引用了 B,B 又引用了 A。Storybook 的 HMR 遇到循环依赖会直接挂掉。解决办法是用
lazy加载或重构依赖关系。
另外,我习惯在 .storybook/preview.js 里加一段全局配置,让热更新更稳定:
// .storybook/preview.js
export const parameters = {
actions: { argTypesRegex: '^on[A-Z].*' },
controls: {
matchers: {
color: /(background|color)$/i,
date: /Date$/,
},
},
// 强制重新挂载组件,避免状态残留
layout: 'centered',
// 热更新时保留滚动位置
options: {
storySort: {
order: ['通用', '布局', '导航'],
},
},
};
@storybook/addon-styling 插件来管理样式注入时机。
4.4 Mock 服务搭建:让组件有数据可用
组件开发最怕什么?怕后端接口还没写好,你只能写死数据。写死数据又导致组件没法测试边界情况。所以,Mock 服务是组件库开发的标配。
我个人推荐用 MSW(Mock Service Worker)。它拦截网络请求,返回你定义的数据,而且不污染全局环境。更妙的是,它可以在 Storybook 里直接使用。
安装 MSW:
npm install msw --save-dev
然后在 .storybook/preview.js 里初始化:
// .storybook/preview.js
import { initialize, mswDecorator } from 'msw-storybook-addon';
// 初始化 MSW
initialize();
// 全局添加 MSW 装饰器
export const decorators = [mswDecorator];
接下来,在具体的 stories 文件里,你可以为每个组件定义不同的 Mock 数据:
// UserList.stories.js
import { UserList } from './UserList';
export default {
title: '数据展示/UserList',
component: UserList,
};
// 正常数据
export const WithData = {
parameters: {
msw: {
handlers: [
http.get('/api/users', () => {
return HttpResponse.json([
{ id: 1, name: '张三', email: 'zhangsan@example.com' },
{ id: 2, name: '李四', email: 'lisi@example.com' },
]);
}),
],
},
},
};
// 空数据
export const Empty = {
parameters: {
msw: {
handlers: [
http.get('/api/users', () => {
return HttpResponse.json([]);
}),
],
},
},
};
// 错误状态
export const Error = {
parameters: {
msw: {
handlers: [
http.get('/api/users', () => {
return new HttpResponse(null, { status: 500 });
}),
],
},
},
};
你看,这样每个 story 都可以独立控制接口返回的数据。我在项目中遇到过最头疼的情况是:组件在正常数据下跑得好好的,一遇到空数组就崩溃。有了 Mock,你可以在开发阶段就覆盖这些边界情况。
Content-Type 头,导致组件解析 JSON 失败。排查了半天才发现是 Mock 返回的响应头不对。所以,写 Mock 时一定要模拟真实的 HTTP 响应结构,包括状态码、响应头、响应体。
4.5 整合验证:跑通一个完整流程
环境搭好了,咱们来验证一下。写一个最简单的 Button 组件,然后启动 Storybook:
npm run storybook
你应该能看到:
- Storybook 界面正常加载,左侧有「通用/Button」目录
- 点击 Button 组件,能看到 MDX 文档和交互演示
- 修改 Button 的代码,页面自动热更新
- 如果组件有网络请求,Mock 服务能正确拦截并返回数据
如果哪个环节卡住了,别慌。先看控制台报错,再检查配置文件。我个人的排查顺序是:依赖版本 → 配置文件 → 代码语法。90% 的问题都出在前两步。
好,这一章的内容就到这里。下一章咱们会正式进入组件开发,从设计规范开始,一步步构建一个完整的 Button 组件。到时候,你会发现今天搭的环境有多重要——没有这些基础设施,后面的开发就是空中楼阁。