你想知道的storybook都在这里

1,044 阅读3分钟

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解析时的路径别名有两种方式

  1. 直接在.storybook/main.js中配置
  2. 先在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的过程中也遇到了一些问题,欢迎在文章下方评论,感谢!