在 React 大生态下,一个比较成熟的前端团队,都会面对一个问题:如何提升团队的开发效率?css
一个系统拥有大量的业务场景和业务代码,类似的页面和代码层出不穷,如何管理和抽象这些类似的代码和模块,这确定是诸多团队都会遇到的问题。
不断的拷代码?仍是抽象成 UI 组件或业务组件?显而后者更高效。前端
那么如今就面临一个选择:一是选择 React 生态中已有的组件库,例如 antDesign、Material-UI 等比较成熟的组件库;二是团队再开发一套属于本身的组件库。有赞前端团队选择了后者,产出并开源了 Zent ,Zent 提供了一整套基础的 UI 组件以及经常使用的业务组件,目前咱们有 45+ 组件,这些组件都已经在有赞的各种 PC 业务中普遍使用。本文咱们就来聊一聊如何开发一套优秀的 React 组件库以及一套完整组件库的构成。vue
React 大环境里面有不少优秀的 UI 组件库,国内比较有名的 antDesign,国外的 Material-UI,都是比较稳定和优秀的组件库。那么咱们为何还要本身去开发一套组件库呢?缘由大体以下:node
Design
和 SKU
组件。构建一个完整的组件库须要考虑:react
组件是对一些具备相同业务场景和交互模式代码的抽象,组件库首先应该保证各个组件的视觉风格和交互规范保持一致,X
组件在 A
业务场景是一个交互,在 B
业务场景是另外一个 UI 风格,这样就没法对 X
进行抽象,极大的增长了组件的构建成本。因此,设计组件之初,首先须要抽象和约定一套统一的视觉风格和交互规范。git
其次,组件库的 props 定义须要具有足够的可扩展性,并且组件内部彻底受控,保持组件具备统一的输入和输出,让咱们来看一个 Button 的例子。es6
// Button is a react component of Zent <Button type="primary" className="customer-classname" loading={true} disabled={false} size="large" onClick={this.handleClick} > {children} </Button>
这是一个 Button 组件,咱们定义了不少标记状态的 props,好比 type 表示 Button 的视觉风格,size 表示尺寸,disabled 禁用,loading 状态等,这些状态在组件内部都不会维护 state,全部的状态由传入的 props 来决定,自定义 className 方便咱们作样式自定义,children 方便咱们自定义 Button 的显示内容。github
Button 甚至提供了a
标签的功能,只要在Button上传入 props:href。app
// Button as <a> <Button type="primary" className="customer-classname" href="https://www.youzan.com" target="_blank" > 有赞首页 </Button>
咱们须要作几个约定:框架
有赞前端内部组件库,使用的是开源 lint 工具-- felint 。
felint 是一个集成了 eslint、stylelint、git hook 的前端代码检查工具。felint 为你的项目作如下三件事:
具体使用能够参考官方 doc -- felint 文档地址 。
约定好组件的设计思路和代码规范之后,接下来咱们就能够参与开发组件了,组件库的基本开发流程,包括如下几点:
Zent 里面有一个组件初始化命令:yarn new-component
,这个命令完成了组件大部分初始化工做,包括自动建立组件须要的目录和模版代码,添加组件 js 和 css 代码。而后,咱们就能够开始写组件代码,代码风格和规范严格按照 lint 的规范编写,若是不符合规范,是不能提交代码的。写完组件之后,须要写组件 Demo 并运行,方式是本地启动 server 来运行组件 Demo,这个能够组件做为组件的调试工具。
js 单元测试框架有不少,chai、jest、mocha、karma 等等,Zent 组件库使用的是 jest + enzyme 的组合,下面来看一个例子:
// Button UI test import { mount } from 'enzyme'; describe('Button', () => { it('Button UI test', () => { const wrapper = mount(<Button>OK</Button>); expect(wrapper.hasClass('zent-btn')).toBe(true); expect(wrapper.text()).to.equal('OK'); }); });
使用 jest 作 UI 测试有局限性,只能测试基本的 dom 结构 和样式,一些逻辑交互没法测到,只能覆盖大部分的状况。yarn test
用来执行测试脚本,测试结果会显示在终端。
组件平常维护占整个组件库生命周期的很大一部分,组件库作起来了之后,组件功能后续会不断迭代,也许是 bug fix,也多是 new feature,这些组件的迭代咱们经过 PR 和 issue 来管理,同时,咱们须要管理好组件的 changelog。
总的来讲,组件维护主要包括:PR / issue 的处理,发包和管理 changelog。
下面以 Zent 为例,来介绍一下 PR 规范。
PR 标题规则:[ bug fix / breaking change / new feature ] 组件名字:修改内容描述
PR 用来生成 changelog,规范的 PR 有助于生成比较清晰的 changelog,一目了然,来看一下 Zent 的例子:
<img src="https://img.yzcdn.cn/public_f...; alt="zent-components" width="616" height="960" />
组件发包只有拥有发包权限的人才能操做,Zent 是以组件库为单位发包的,yarn build
会将整个 Zent 的代码打包,使用命令 yarn publish
发包,在发包以前会跑组件测试,只有测试经过之后才能发包。
一份好的 doc 是一个优秀组件库的标准,良好的文档可以提高组件库的总体品质和好感度,愿意花时间好好写 doc 的团队,那么他们产出的组件库应该也不会差到哪去,组件库文档维护也是组件库生命周期里重要的一环,有时候你甚至须要作到中英文双语 doc。
这里附上 Zent 组件库的 doc 地址:Zent。
在本文中,咱们从组件的设计思路、编码规范、开发流程、测试、平常维护这五个方面阐述了如何构建一个 React 组件库,而且以 Zent 为例讲述了有赞是如何作的,任何一个组件库都须要的通过这个生命周期,但咱们须要思考的是:如何营造一个良好的组件库生态环境? 咱们须要想办法让更多的人参与其中,共同做为组件库的维护者,选择开源是为了给 React 生态环境作输出,在前端组件化已经成为了既定事实的今天,咱们不须要重复的造轮子,而是须要在组件化方面尝试新的突破,脱离前端技术的束缚,站在工程师的高度去抽象本身手头的代码。组件化这条路上,咱们还有不少事情要作,Zent 只是一个开始。