写这篇文章呢,要先给一些同学道个歉,因为最近换了工作,事情比较多,有些同学给我发的gmail(也有因为GFW的原因,时断时续)和提的issue,过了很久才回复。也有位同学让我建个QQ群之类的讨论问题,但是因为工作关系,基本不能用QQ,所以在这里发个帖子,回答一些问题,并且说下后面的规划吧。
有了ant-design这样NB的库,是否还有必要继续react-ui
第一个问题,算是自问自答。
react-ui写了一大半的时候,发现蚂蚁金服开源了ant-design这个项目,当时觉得挺迷茫的,因为只有一个人,基本上把工作之余的时间都搭进去了,才做到这个程度。和蚂蚁金服相比,一堆牛人,有很NB的设计,官网很酷炫,文档也很健全。
那个时候反复的思考,这个项目还有没有继续下去的必要。仔细对比了一下,发现还是可以做下去的。
react-ui是一个完全从易用性的角度去思考的一个库,原则是调用的时候,越简单越好,写的代码越少越好,即使某些地方不符合react思想的。
比如select,react-ui的调用方式
<Select placeholder="Group by continent"
groupBy="continent"
filterAble={true}
optionTpl='<img src="images/flags/{code}.png" /> {country}-{en}'
valueTpl="{country}-{en}"
data={dataSource("json/countries.json", null, {cache: true})} />
ant-design的调用方式
<Select defaultValue="lucy"
style={{width:200}}
showSearch={false}
onChange={handleChange}>
<OptGroup label="Manager">
<Option value="jack">jack</Option>
<Option value="lucy">lucy</Option>
</OptGroup>
<OptGroup label="Engineer">
<Option value="yiminghe">yiminghe</Option>
</OptGroup>
</Select>
同样的还有CheckboxGroup,Tree等等。
有人说ant的方式是更符合react的思想的,同时更加的灵活。我同意。
但是我的想法是,一个好用的组件,使用者只需要传一组数据进去,并不要知道组件内部的结构是什么,就可以完成这个组件的调用。并且同一组数据,只改一下调用,就可以实现类似Select到Radio的转换。
<RadioGroup textTpl={'{country}-{en}'} data={dataSource("json/countries.json", null, {cache: true})} />
为了更加方便的调用,创建了FormControl这个组件,把所有的表单组件注册到FromControl,在这个FormControl上实现自动的validate,自动的tip。这样从而避免在表单组件外面再加一个Validator,这个是我不愿意接受的。
同样的,还有Modal,Message这样的组件,使用的时候完全不像React的组件,更接近传统的JS库,只提供了静态方法,在任意的地方调用。
另外,大家都说,有redux,有flux,所有的数据都应该通过props传入,这样才符合规范,才是现代化的。但是对我来说,就是喜欢简单粗暴的传入一个链接地址自动获取数据。我只是想给select几个选项值,要去写action,写store,写reducer,connect……OMG!
当然,如果你喜欢props,你仍然可以直接传入data。
为什么要用purecss
最初的版本里,css部分是用的bootstrap,慢慢的发现不能接受了,因为bootstrap差不多有100多kb的体积,而那个时候整个js库的文件也才60多kb。当时想了很多方案,最后选了yahoo的purecss,因为非常的小,只有20kb不到,并且官网的文档里也明确说明可以和bootstrap搭配使用。
不过purecss确实是比较简陋,所以在项目里加了一个theme的模块,可以对css进行扩展。是有打算做一些热门ui的皮肤,但是一直搁置中。
另外在某个版本里,使用了css module的方式来防止css污染,不过这样不能方便的扩展,所以又换回了’rct-'这个前缀。现在还是会比较纠结是否使用css module的问题,打算等后面重构css部分的时候再做决定。
为什么没有拆分成独立的子项目
这个问题也困扰了我一段时间,因为有些同学用react-ui,只是看重了某一个组件。而且,从理论上来说,一个单独的组件比整个UI库更好维护啊。
于是就建了一个rctui的group,把整个项目分拆。后来发现随着组件的拆分维护工作进入了一个地狱,比如utils这个库改了一行代码,用到它的Button要升级,用到Button的其他库也要升级,都要push到github,publish到npm。然后发现其他所有用到utils的库都在等着升级……
所以又回到一个库的状态,但是还是有点纠结。直到后来听了一个facebook大神的讲课,说facebook只有一个仓库,全部的代码都在上面。
好吧,不纠结了。
最后就是发布到npm之前费点事,把代码从src挪到根目录下面,只需要某个组件的话可以单独引用。
尽可能的轻
这个是react-ui保持一个完整的库的另一个原因,如果拆分成很多库,再通过一个项目合起来的时候,不可避免的会增加很多冗余的代码。
从一开始,就一直在避免整个项目变得太庞大。因此放弃了underscore、lodash这样的神器,所有的utils都是自己写,或者从别的库里一点一点的剥出来。也因为这个原因,迟迟没有升级到es6(babel转换后大约会增加1/4左右的体积),后来终于没有忍住,一下升到es7(再后来,这变成了一个悲伤的故事)。
其他的部分,比如Grid,使用了一个动态的方法生成css,用几kb实现了一个任意多列等分、支持responsive的栅格系统,从而减少了几十kb css的加载。不过因为生成了很多style标签,暂时没有想清楚是否有问题。
此外,ajax库的选择,最初的时候是用了superagent,算是比较轻量的了,差不多20多kb,但是还是觉得比较重,那个时候js部分只有60多kb。选了n个ajax库,最后选了一个几乎没多少人知道的qwest,因为它是Promise A+P规范,因为它只有7kb。
不能解决所有问题
我给一个同事讲(吹嘘)我的table的时候(因为我觉得react-ui的table写的还蛮NB的),他就问如果要多层表头,你怎么办?如果要合并单元格,你怎么办?我就哑口无言咧。
后来就慢慢想通了,react-ui的实现方式,在灵活性上是有一些缺失的,确实有很多问题解决不了的。事实上,也没必要去解决所有的问题,只要去解决大多数场景的问题。如果可以用20%的时间解决80%的问题,那就很完美了。
下一个版本的规划
有个同学给发邮件给我说,0.5.0到0.5.2,改了很多代码,其实90%是因为babel从5升到6,发现一些es7的语法不支持了,所以干脆把所有es7的代码全改了。这个事情说明,步子迈大了,确实会扯到蛋的……
0.6 应该会是真正的改很多代码,目前的规划以重构为主:
- 在线build的部分,facebook已经官方推荐babel了,也没精力维护,就去掉了。
- 任意等分的Grid,这个0.5.2已经实现了。
- 对dataSource和qwest还是不太满意,在qwest的基础上封装了一个refetch,Promise A+规范,不需要polyfill,支持jsonp,cache。
- dataSource不再从data传入(接口会保留两三个版本吧),使用一个新的属性fetch,支持promise和options两种方式,内部使用higherorder component方式封装。
- validate从FormControl拆分到各个表单组件,目前的这种方式对于一行多个组件实现起来有问题。应该也是higherorder component的方式。
- 因为封装了两层higherorder component的原因,FormControl的getValue应该会取消,并且直接调用组件内部的方法并不太好。取消了会带来一些问题,获取Form值是否通过组件的name来实现?还得想另一个方法来实现Form提交前自动的validate。
0.7 会以css为主,使用autoprefixer代替目前的mixins,考虑加一两套皮肤。
另外,单元测试。目前utils下面基本所有的代码都通过了单元测试。component的测试比较麻烦,一直也没精力完成,但是后面也要做的。
很多同学的问题都是webpack打包的,其实很多大神,Dan啊,tj啊都写了start kit的,可以参考他们的,后面有空也会写个简单的。
最后,大家对react-ui这个库有什么看法、建议和问题,或者希望增加哪些组件,都可以在这里提出来,我会尽力解决的。发issue和邮件也可以。