0%

react组件文档生成介绍 & 业务实践

前言

由于业务快速发展,业务组件库也在快速迭代。当组件Props等发生变化时,开发人员需要额外的消耗一定精力去保持代码和文档的统一。
此时,我们就可以利用TypeScript的静态类型检查与代码提示能力,通过自动生成文档工具,来增强开发的生产力,解放双手,提高工作效率。

背景

团队内部组件库文档年久失修,组件规范不统一,导致对很多组件的修改是牵一发而动全身,痛定思痛,于是经过小组商议后决定从组件文档着手,逐 步统一业务组件风格规范和组件文档。

调研

通过调研以及过往经验,发现市面上有几款插件可供选择,分别是Docz、StoryBook、dumi、react-docgen、react-docgen-typescript,根据与目前项目匹配度最终dumi和react-docgen-typescript进入了决赛圈,最终根据灵活的和对目前的项目整体的副作用,选择了react-docgen-typescriptreact-styleguidist配合生成文档。

dumi

dumi,中文发音嘟米,是一款为组件开发场景而生的文档工具,与 father 一起为开发者提供一站式的组件开发体验,father 负责构建,而 dumi 负责组件开发及组件文档生成。

  • 特性
    • 开箱即用,将注意力集中在组件开发和文档编写上
    • 基于 TypeScript 类型定义,自动生成组件 API
    • 丰富的 Markdown 扩展,不止于渲染组件 demo
    • 支持移动端组件库研发,内置移动端高清渲染方案
    • 一行命令将组件资产数据化,与下游生产力工具串联

react-docgen

  • 来自Facebook开源
  • 基于Babel解析源码,对propTypes支持良好
  • 虽然新版本支持 TypeScript,但从其它文件导入的类型信息无法被获取
  • 不解析JSDoc部分,整个注释都作为描述部分,不过可以添加自己handler来补充解析

react-docgen-typescript

  • 来自styleguidist开源,主要目标是服务TS React组件的API文档生成
  • 基于TS解析源码,不支持propTypes,Props interface继承的类型都可以拿到
  • 会读取JSDoc的@type、@default作为类型和默认值信息

业务实践阶段

安装

1
2
3
4
5
6
7
8
9
10
11
// package.json
"devDependencies": {
"react-docgen-typescript": "^1.9.0",
"react-styleguidist": "^7.3.7",
}

// 可根据配置文件,自行设置、执行启动和构建命令
"scripts": {
"styleguide:dev": "cross-env STYLEGUIDE_ENV=development styleguidist server --config styleguide.config.js",
"styleguide:build": "cross-env STYLEGUIDE_ENV=production styleguidist build --config styleguide.config.js"
}

配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// styleguide.config.js
const path = require('path');
const glob = require('glob');
const STYLEGUIDE_ENV = process.env.STYLEGUIDE_ENV

module.exports = {
title: 'components',
styleguideDir: 'dist',
components: function () {
return glob.sync(path.resolve(__dirname, 'src/componets/**/*.tsx'))
.filter(function (module) {
return /\/[A-Za-z]\w*\.tsx$/.test(module);
});
},
resolver: require('react-docgen').resolver.findAllComponentDefinitions,
propsParser: require('react-docgen-typescript').withDefaultConfig({ propFilter: { skipPropsWithoutDoc: true } }).parse,
webpackConfig: Object.assign({}, STYLEGUIDE_ENV === 'production' ? require('./config/styleguide.webpack.config.prod') : require('./config/styleguide.webpack.config.dev')),
dangerouslyUpdateWebpackConfig: function (config, env) {
return {
...config,
output: {
...config.output,
filename: 'build/[name].bundle.js', // 默认是生成hash,公司部署平台要求入口文件不带hash
chunkFilename: 'build/[name].js',
},
}
}
};

组件内部配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
import React from 'react';

// 在原有interface基础上,每个属性添加上jsdoc即可

/**
* Select properties.
*/
export interface ISelectProps {
/**
* 传入的数据源,可以动态渲染子项
*/
dataSource: string[];
/**
* Select发生改变时触发的回调
*/
onChange?: (item: string) => void;
/**
* 是否只读,只读模式下可以展开弹层但不能选
*/
readOnly?: boolean;
/**
* 选择器尺寸
*/
size?: 'small' | 'medium' | 'large';
/**
* 当前值,用于受控模式
*/
value?: string | number;
}

/**
* Component is described here.
*
* @visibleName Select
* @version
* @author
*/
class Select extends React.Component<ISelectProps> {
static defaultProps = {
readOnly: false,
size: 'medium',
};

render() {
return <div>Test</div>;
}
}
export default Select;

部署

执行build命令后,会生成dist文件,可根据自己的需求部署到指定位置。

总结

TypeScript给js带来了类型,做到静态类型检查和代码提示,经过上面一顿的折腾,把类型又用了一遍。整个过程中,我们已经拿到了组件中的所有想要拿到的数据并生成文档,不足的是子属性的类型并不能很好的显示,还需要后续完善,但是已经满足基础的需求。