这一年,对于我来说真是压力空前,之前公司接需求的时候大部分情况是看排期,如果排期紧张再协调安排处理。
BUT! 来这边以后概况大致如下:
这边有个需求来处理下,什么?有其他任务?那不是很正常;
优先级?并行!都很重要,并行很正常,我这里也有好几个事并行呢,DeadLine是xxx号;
做的差不多了您看看?整理好一份文档描述清楚,以便沉淀;
你上次做的那个需求有地址吗,有相关介绍吗,有实现步骤,组件放在哪里了?这样聊不清楚,你写一份文档;
Hi all,这里有个地方我觉得这样处理非常零散,这不好…那不好…,我觉得可以这样!——好这件事,你负责跟进就按照你的想法处理。
这里我重新做了一个库,可以把这些收集统一处理。
哇,不错啊,那可以把我们框架的加载都使用这个处理,你抽空处理下?
可是,这样影响面会不会….
重构完了,已经发到预发半个月了,有一些业务需求已经对这部分改动有依赖了,需要准备一波上线了?
这样直接发不行,风险太高了,你去梳理一份上线计划书,对现在线上的几个域的支持页面都做一份回归测试;
这里有一项新的技术?你抽时间研究一下,写一份文档,准备一次分享会;
最近招聘怎么没动静了?这样,大家以后晚上21-21.30大家一起集体捞简历。
KPI沟通。你近半年做的事情挺多,做的效果也不错,同事对你的评价也挺高。但是都是比较零散的点,没有一个面输出,期待你后面有更杰出的表现;
怎么才能有一个面的输出,给点指导意见?这样吧,你先把你近半年所有做过的事情详细的写一份文档给我看看,我给你点意见;
华丽丽的分割线
好了,本来是想随便唠两句引言一下,没想到一下子写了这么多。呼~ 突然有种排出一身毒素的感觉,爽!哈哈哈
我想了很久,这一年的工作我有什么地方做的不够好,或者说什么地方我做的没有像别人做的那么好。
嗯,从这点来讲,至少我现在还是在思考如何进步,不像之前觉得自己已经做的非常不错,无人能及了。
趁着休息日,还有点空闲时间,咱们来聊点技术吧!
背景
19年6月左右,我发布过一篇文章《Bit初体验》 。在梳理这篇文章的过程中,我可以说深度体验了一把 bit 所提出的概念和做法,就像一颗种子种在我的脑海中,一开始我觉得这东西没什么。
我还记得我第一次与我的同事分享 bit 后,他说:
emm,虽然你讲了这么多,但是我觉得好像没有那么…有体感?
感觉没什么卵用?
啊,emm,既然你说了,就像你说的。我觉得我们现在如果引入bit 会不会对我们的日常工作带来很多额外的工作量。
这种反应很正常,我是在18年初,就在Vue的官网见到过 bit ,当时我点进去大致浏览过一下。我当时的感受就是,没什么卵用,无非就是 ” 前端垂直领域的 git “。对国内的支持情况还不咋地,连一篇像样的中文文档都找不到。
在我们的团队中一下子直接切换到 bit 的工作流,这确实不现实,在公司有那么多的基础建设都不知道bit这么个玩意。
但是,bit 的做法和概念,却是非常非常有价值和可以借鉴的!
所以,我想做一件事情,一步一步的把 bit 的玩法用我们熟悉的方式引入进来甚至有所延伸扩展,让大家认同其中的好处和价值。
认识组件
随着近些年”微前端“概念的不断酝酿,越来越多的团队开始着手将自己的业务处理为不同组件,然后通过一定的为前端做法,编排到一个业务页面中去。
那么对于组件的维护就会变得越来越重要。所以,先来看看现在大多数团队是怎么维护组件的吧!
- 大库型,Antd、Element标准的大库型
- 一次型,完全业务组件,用完一次再也不维护
- 高复用型,一看就应该单独封装以后给其他人用,比如:视频播放器
- 二次封装型,一些库拿原生js写的,拿来包装一下当做组件直接引入
- 项目融合型,与业务项目在一起,混合store,不分你我
我暂时能想到的就这几种类型的组件,如果你的团队也在维护自己的一套组件库,那么应该很容易理解我上面所说的。
我相信,既然这么做了,肯定有这么做的理由和好处,没有人会闲着没事找麻烦做不是,那么这些做法都有什么好处和痛点呢?我从几个方面入手分别分析一下。
方便、快捷
组件嘛,当然是最快能跑起来,最方便能看到效果最好咯。就这点来讲,还有什么比直接在业务项目里撸组件更快的方式吗!?
现在用个展示的面板,立马去components目录撸一个。
数据?不是有store吗?引入进来不就拿到数据了!
所见即所得,现在改完马上看到页面上的效果!无法反驳..
这么看确实开发这个组件是好快了,但是从整个业务需求实现来看,这么做真的是最快的吗?如果这样的做法是最快捷的,那为什么那么多团队在强调沉淀、封装、抽象呢?
其实很多组件当时看起来,这辈子就只可能用一次,不用封装。可是往往交互稿过来的时候就会发现,这个样式好像我在哪里见过。然后去各种业务项目里一顿翻,哇终于找到了,复制过来发现各种爆红,定睛一看,store???
所以,聪明的团队早已洞察这一切,让我们把组件都维护到同一个地方,然后大家写好文档,用的时候从库里面取就可以了,有Bug的话统一修复就是,棒👍!
可维护性
于是乎,大家便如火如荼的开始的组件抽象,组件整改的浩大工程。
一开始,一般会有一个团队中较为靠谱、能力突出的小伙子(嗯?怎么是我?)去把Webpack、Babel、TypeScript、Sass\Less、目录结构、单元测试结构、代码规范、Review规范、发布规范这些梳理好,然后写一个标准的组件出来,最后再强调一下大家一定要按照规范认真维护组件,书写文档,编写单元测试。
从维护性上来讲,大家把组件都写在一个库里面,然后再用到的项目中直接引入,业务上的问题逐渐被分为组件问题还是项目问题,甚至有些需求可以用这个交互在组件库中有相似的,用那个组件就可以了,来反驳产品和设计😏。
就在大家用的不亦乐乎的时候,有一天发现,呀,我们的组件库怎么打包出来有10m啊😱!
然后找一个靠谱、能力突出的小伙子(没错又是我)就去查了下,这个库是谁引入的?这个组件不是已经有一个了吗?lodash不是这么用的呀!这个组件是干什么的,怎么没文档?
面对上百个业务组件,只能感叹一声业务迭代的可真快啊。
所以,大库维护固然有大库维护的好处和适用场景,大家能够有这样的抽象思维已经是技术上的突破了,现在只是遇到了另外一个问题,解它!
组件大小、加载性能
接触webpack的一些周边工具,比如analyzer
很容易可找出具体是什么包”霸占“了这么多的流量。
发现原来组件包中还有一些个组件,看上去不应该放在大库中进行维护,比如那种一次性组件,二次封装型组件。
因为这种组件可能会引入一个很大的第三方依赖,比如视频播放器、Banner Swiper 等。
对于这样的组件,最好的处理方式应该是创建一个独立的仓库,封装完善后,写好README,发布至内网NPM,供业务项目使用。
But you know ,这样做成本太高,如果有时间的话,我肯定…..balabala…(一般来说,如果你对程序员说一个更好的方案时,除非这个方案他有参与设计,否则大部分回复都是这样🙄)
当然组件大小这方面也可以通过很多其他方式解决,比如:异步加载,NPM引入,按需加载等等啦…那么,让我们谈谈下面另外一个很重要、又很容易被忽略的部分吧。
组件说明及可索引性
老板,我们今年沉淀了组件200+,其中有几个组件写的特别好,同时支撑了20+项目。
哇,这么棒!来给我看看你们写的组件长什么样?啊,这,这样来看看我们做的这个页面,这个页面里面用了这几个组件,balabala …
设计:听说你们已经沉淀了200+组件,能给我们看看有哪些组件吗?我们在下次设计的时候可以参考这些组件进行输出,减少沟通成本。
前端:@所有人 这个组件我们库里面有吗?有,CascadeSelect。哦,怎么用的?有文档吗?…….看下源码吧。well..😅
组件的说明及可索引性,其实仅次于组件的可用性,甚至更高。
试想下如果今天你写了个巨牛的组件,复用性、接口设计和交互设计都非常棒,但是你有什么渠道能让大家一下子就知道吗,难道你要专门为此拉大家开个会?来今天占用大家1个小时的宝贵时间,介绍下我今天写的巨牛组件。🤕
反过来想,如果我在写组件的时候,反正我这个组件也没啥亮点,别人应该也不会用到,就不用补充文档了吧,应该也没人会知道。哦豁,丸蛋🙃
索引组件,来给大家分享一张图:
如果有一天你团队的组件库也能像这样,一板一眼有图有真相,那该是多么幸福和享受的一件事情!
我也知道这样好啊!谁不知道!如果我有时间,我肯定会….balabala…
所以你的意思是让我们每写一个组件不但要补充文档,还要补充用法说明,还要截图!?
对,还要单独建库,还要考虑配置Webpack、Babel、TypeScript、Sass\Less、目录结构、单元测试结构、代码规范、Review规范、发布规范这些😎
哈!F*CK !!AWAY!!🤜
最*实践
说这么多呢,主要是想带读者们一起思考,也是我写作的风格(喜欢讲故事),大部分内容其实是 前端er 都会遇到的问题。
接下就进入正题,说了一大堆问题,总得有点办法来解决吧!
先看看bit是怎么做的吧,bit首先自身有一定的编译能力,内置了webpack及一些插件式loader来解决React、Vue等编译问题。
对于我们团队来说,都是使用React,所以咱们就先从一个编译React的脚手架开始。
如果把每一个组件都作为单独的NPM项目发布,首先要考虑的是,前端一系列的编译环境。如果我有N个前端组件项目,每个前端组件库的webpack、babel这些都需要重复配置,那真是要头大的事情,我只是想写一个组件而已,为什么要考虑这些。所以我们的脚手架首先要具备一些基础的编译命令。
啊对了,脚手架还没有名字,那就暂时叫它:comp 吧 😷
comp new 处理按照模板新建一个标准组件
初始化一个标准组件项目结构,所有接入所有 comp 命令
初始化 Git 仓库
初始化 CI/CD 云构建配置
comp start 处理日常开发,附加单个组件展示及调试能力
comp watch 处理 babel 及 scss 监听编译,用于 npm link 场景
comp babel 处理编译 npm 包
comp dev 处理监听编译 umd 包,用于代理调试
comp build 处理最后编译过程
webpack 编译 UMD 包
Babel 包
CI\CD过程中自动截图组件
CI\CD过程中自动生成 README
其他Hook
comp test 处理 jest 单元测试
那么等组件初始化以后,目录结构就长这样:
项目结构中没有任何webpack\babel配置,当然如果有特殊配置需求,可以建立 comp.config.js
进行配置(此处借鉴很多已有的cli处理方式)。
这样处理的好处是,在项目初始化后,用户能见到的目录结构非常清晰明了,项目中不有很多允许配置的地方,所有组件的编译环境基本可以保证统一。
这都是些非常基础的功能,当然又是不可缺少的部分,这些基础命令我就不详细介绍了,重点在后面。
通过这几个问题来介绍功能:
你平时开发组件的流程是什么样子?
平时,一般就是根据设计稿,切分到组件后。
然后去创建组件,最后通过项目引入,一边看着一边开发啊。
你开发组件的时候对于你提供的Props是如何验证的?
最简单的给一个mock看看效果呗。
或者写一个单元测试?
那写Mock的过程算不算是在写Usage呢?
这个,应该也算吧,但是这些都是散落在各个项目里面,有些mock验证完就删掉了。
谁会闲的没事在开发的时候把这些补充到README里面去啊。
为什么他们不写文档?
这还用说?因为懒呗?
那你为啥不写?emm,那是因为….写文档这事儿吧,写了不一定有人看,还费时间呀!业务需求那么多!我要是有时间的话,我肯定….balabala…
OK,那我们来看下一个问题
一个好的组件文档需要那几部分?
开发组件背景,注意事项啥的,这个没啥太大的必要,有的组件需要的话就补充下,没有的话就不用补充。
主要需要的一些介绍有 :用法,Props入参,最好能有个截图!
还有安装、开发、编译的命令介绍得有吧。
锦上添花的话最好还能有几个badge,介绍下源码是TypeScript,下载量多少。
但是,要补充这些文档是在太麻烦了,要一个一个整理,Props这些信息,用的人可以在组件里面找到啊,我都有些注释和类型定义的呀!
完成一轮心灵拷问之后,就会发现在整个组件的开发过程中,开发者本人之所以对这个组件这么清楚,是因为开发者其实已经为自己写过一份README了。
- 用法:组件开发过程中需要看到效果,写过一些mock数据,已经知道什么样的props传进去会产生什么样的效果
- Props入参:组件有哪些Props,所代表的含义是什么,每个Props入参类型是什么,已经在TypeScript的Interface及注释中有体现
- 截图:有mock数据还不知道长什么样?已经看过N多边了
有了这三个最重要的介绍后,相信大部分开发者也都能知道这个组件是怎么个情况了。
所以,如果我们能把上面这些数据都收集到,是不是就可以利用脚本 自动生成README文档 了呢?
用法 / Usage
要收集用法其实很简单,如果让组件有独立开发的能力,不就可以保留这些Usage的Mock数据了吗
有些人可能没理解我说的”组件独立开发的能力“是什么意思,我解释一下下:我们平时开发一个组件,一般都是把这个组件放置于某个页面中,一遍调试页面一遍调试组件。独立开发组件的意思是,直接启动一个页面,可以看到组件的样子,这个页面展示的就是围绕组件的所有信息。
所以在脚手架中,只要在 docs.ts
中书写需要调试组件相关的mock数据,页面就可以展示出组件的样子,同时这些mock数据可以保留作为 README
文档数据。
另外,如果保证这份demo的接口输出统一规范,还可以支持直接生成在 CodePen,Riddle 这些在线编辑的代码内容。
试想下,你的README中如果出现一段 : 点击立即体验 ,跳转过去后可以在线编辑实时看到效果,那对于任何看到你组件的同学来说都是一种享受 😉
组件参数 / Props
要收集这部分数据就比较复杂了,我们需要深入分析 TypeScript AST 语法树,提取出其中组件 props 的类型以及对于Interface的注释内容。
经过一番github,终于找到可以实现一个可以处理这件事情的小众库 react-docgen-typescript
在开发过程中,因为对一些注释及类型输出与我预期的不太一样,所以我fork后做了一些修改,已经可以完成对一个完整组件的 Props 做分析后输出一份 typefile.json 。
同样的,通过基于该能力,可以扩展为webpack插件react-docgen-typescript-loader,为组件的静态属性中添加__docInfo
属性,来声明其属性内容,于是组件开发过程变可以实现以下效果:
截图 / Preview
有了组件,有了demo,还愁没有截图吗?
直接在构建过程中用 puppeteer ,读取运行docs.ts
渲染出组件,进行截图,然后随着云构建CD过程发到CDN,就完事了!
最后,README中加入一些特殊标记,在云构建过程中进行README替换生成就可以啦!并不会影响README本身要叮嘱的内容。
最后,Duang !一份完整,漂亮,详细的文档就生成好了,整个过程我们并没有特意写过什么README方面的内容,一切都是非常轻松标准的进行输出。
结语
在上面的一整套复杂的过程中,看上去最后好像我只得到了一个自动生成README的功能。但实际上呢,其实README只是一个顺带的产物。
整个过程中,我已经拿到了这个组件的所有我想要拿到的数据,它的Props,Usage,Preview,版本信息,包名,甚至构建过程会同步发布该组件的UMD CDN包及NPM包。
接下来,就可以围绕这些数据和工具,建立和扩展很多功能和平台。
举几个栗子:
- 建立一个bit 一样的,组件平台,把团队内的组件收集起来,统一在平台展示及索引
- 根据拿到Props类型信息做可视化的搭建平台,把Props的传参直接交给用户设置,根据不同数据类型提供不同的Form Setter
- 看似组件都分布在不同的库中,却可以通过组件cli做统一的构建处理
- 非常轻松接入 微前端 框架,因为所有组件的发布构建都是标准的构建协议
- 通过统计组件发布次数,下载次数,关联bug数评估代码质量
目前在我们团队,已经使用该工具产出 30+ 的可用组件,并且发布组件已经成功接入到我们已有的可视化编辑器中。
看一眼结合可视化设置面板后的效果吧:
我发现只要实现过程中,没有给开发者带来太多的工作量,又能带来实时可以看到的效果,开发者会很乐意为那些Props做一番解释和修饰😊。
我们团队目前产出的组件看起来一片通透,整齐明了。
另外,因为脚手架出世时间还短,需要完善的地方还很多,还没有符合公司规定的开源标准,就不拿出来献丑啦😊,不过我觉得整体思路更有参考价值!
我是一个热爱生活的前端工程师! Yooh!🤠