这一年我的对组件的思考

4,301 阅读18分钟

这一年,对于我来说真是压力空前,之前公司接需求的时候大部分情况是看排期,如果排期紧张再协调安排处理。

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个小时的宝贵时间,介绍下我今天写的巨牛组件。🤕

反过来想,如果我在写组件的时候,反正我这个组件也没啥亮点,别人应该也不会用到,就不用补充文档了吧,应该也没人会知道。哦豁,丸蛋🙃

索引组件,来给大家分享一张图:

e55931b4-2cf6-02ed-4835-7b5af004d502.png

如果有一天你团队的组件库也能像这样,一板一眼有图有真相,那该是多么幸福和享受的一件事情!

我也知道这样好啊!谁不知道!如果我有时间,我肯定会....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 单元测试

那么等组件初始化以后,目录结构就长这样:

export default function(Component: typeof IComponent, mountNode) {
  /** DOCS_START 请将Demo生成方法都写在以下区块内,用于生成README及Riddle **/

  ReactDOM.render(
    <Component
      navigation={true}
      pagination={true}
      autoplay={true}
      dataSource={[
        {
          href: 'http://xxxxxxxx',
          image: 'https://xxxxxxx.cdn.com/tfs/TB1jHkBmNv1gK0jSZFFXXb0sXXa-1440-343.png',
        },
        {
          image: 'https://xxxxxxx.cdn.com/tfs/TB1Y_XacrY1gK0jSZTEXXXDQVXa-1416-813.png',
        },
      ]}
    />,
    mountNode,
  );

  /** DOCS_END **/
}

项目结构中没有任何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 文档数据。

330179f6-8e5a-5c05-21e5-f4faceafec33.png

另外,如果保证这份demo的接口输出统一规范,还可以支持直接生成在 CodePen,Riddle 这些在线编辑的代码内容。

试想下,你的README中如果出现一段 : 点击立即体验 ,跳转过去后可以在线编辑实时看到效果,那对于任何看到你组件的同学来说都是一种享受 😉

f1d639c6-c60e-7302-d863-1ad30f322375.png

组件参数 / Props

要收集这部分数据就比较复杂了,我们需要深入分析 TypeScript AST 语法树,提取出其中组件 props 的类型以及对于Interface的注释内容。

经过一番github,终于找到可以实现一个可以处理这件事情的小众库 react-docgen-typescript

在开发过程中,因为对一些注释及类型输出与我预期的不太一样,所以我fork后做了一些修改,已经可以完成对一个完整组件的 Props 做分析后输出一份 typefile.json 。

b4cfd20d-5723-ac5d-c7e1-e5f21ddc76ce.png

同样的,通过基于该能力,可以扩展为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!🤠

写到这里,按照正常流程,我应该放点 招聘信息?

阿里国际化中台 招聘啦!前端、Java要求 P6 及以上!有兴趣的同学可以发简历到

yee.wang@alibaba-inc.com

期待您的加入~😻😻