storybook是组件库文档搭建工具,用于整理描述项目中的业务组件,方便开发者快速查找自己需要的组件和熟悉组件用法
1. storybook的优势
- 配置简单,可以在项目内快速搭建起一套业务组件文档项目
- 无代码侵入性,独立于原有项目的一套打包、运行机制
- 支持浏览组件的文字说明和样式
- 交互式测试组件
- 组件文档书写方式多样化
2. 搭建流程(重点踩坑区)
2.1基础框架
建议将可复用的业务组件单独抽离出来到子项目中,方便使用和维护
在需要引入组件文档库的项目中的根目录执行以下脚本命令
# Add Storybook:
npx storybook init
storybook会自动安装依赖、添加脚本命令,完成初始化
"scripts": {
...
"storybook": "start-storybook -p 6006",
"build-storybook": "build-storybook"
},
"devDependencies": {
...
"@storybook/addon-actions": "^6.5.12",
"@storybook/addon-essentials": "^6.5.12",
"@storybook/addon-interactions": "^6.5.12",
"@storybook/addon-links": "^6.5.12",
"@storybook/builder-webpack4": "^6.5.12",
"@storybook/manager-webpack4": "^6.5.12",
"@storybook/react": "^6.5.12",
"@storybook/testing-library": "0.0.13",
}
另外,会在项目中生成两个文件夹“.storybook”和“stories”
- “.storybook”:负责storybook的运行和打包配置
- “stories”:存放各业务组件的描述文件(可以根据实际场景删除)
2.2 组件文档项目配置
2.2.1 路径别名
配置路径storybook解析时的路径别名有两种方式
- 直接在.storybook/main.js中配置
- 先在webpack.config.js中添加配置,然后再引入到main.js文件中
// .storybook/webpack.config.js
const path = require('path');
module.exports = {
resolve: {
alias: {
'@common': path.resolve(__dirname, '../common'), // 路径依赖于实际场景,这里仅做演示
'@utils': path.resolve(__dirname, '../utils'),
'@components': path.resolve(__dirname, '../components'),
'@store': path.resolve(__dirname, '../store'),
'@constants': path.resolve(__dirname, '../constants/index.ts'),
},
},
}
// .storybook/main.js
const path = require('path');
const myConfig = require('./webpack.config');
module.exports = {
...
webpackFinal: async (config) => {
return { ...config, resolve: { ...config.resolve, ...myConfig.resolve } };
},
}
2.2.2 文件解析
以less文件为例,可以配置用于解析这些文件的loader
// .storybook/main.js
const path = require('path');
const myConfig = require('./webpack.config');
module.exports = {
...
webpackFinal: async (config) => {
config.module.rules.push({
test: /.less$/,
use: [
'style-loader',
{
loader: 'css-loader',
options: {
modules: {
auto: true,
localIdentName: '[name]-[local]--[hash:base64:5]',
exportLocalsConvention: 'camelCaseOnly',
exportGlobals: true,
},
}
},
{
loader: 'less-loader',
options: {
javascriptEnabled: true // 支持在 Less 中编写 JavaScript
}
}
],
});
return { ...config, resolve: { ...config.resolve, ...myConfig.resolve } };
},
}
2.2.3 描述文件的存放位置
module.exports = {
"stories": [
"../stories/*.stories.mdx", // 正则匹配路径,可以将原有的stories文件删掉
"../stories/**/*.stories.mdx",
"../stories/**/*.stories.@(js|jsx|ts|tsx)"
],
...
}
2.2.4 按需引入
如果项目还有依赖其他组件库,可以借助babel的能力实现样式的按需引入
module.exports = {
...options,
plugins: [
[
"import",
{
"libraryName": "ant-design",
"libraryDirectory": "es",
"style": true
}
]
]
}
3. 后续
storybook中文档代码开发过程中的坑
3.1 修改xxx.stories.mdx文件中<meta>的title属性或者<story>的name属性时页面报错
import GoodList from './index.jsx';
<Meta title="GoodList" component={GoodList}/>
<Story name="Primary">
<GoodList name={"abc"} count={11} />
</Story>
如果在项目运行过程中,修改Meta里的title属性或者<story>的name属性时,发现触发热更新后页面出现报错,Couldn't find story matching 'xxx' after HMR,这个时候不用担心是不是自己的代码问题,只需要重新启动项目即可解决
3.2 为什么自己写的组件没有“Show code”按钮 ?
如果是在mdx文件中编写代码,需要将代码包裹在<Canvas></Canvas>标签内,这样在Docs菜单栏内展示的内容才会出现“Show code”按钮
未完待续。。。
如果大家在使用storybook的过程中也遇到了一些问题,欢迎在文章下方评论,感谢!