组件化高级开发:干货笔记指南

发表时间: 2017-07-10 08:36

各位网友大家晚上好,今天很高兴能参加IT168的直播,一开始的时候以为直播是有摄像头的主播,飞机火箭满屏飞,但是我一想如果大家但是我这长相肯定马上就走了,还好今天看不见,可能大家会多听一会儿,大家有看到我的长相吗,希望大家多听一会儿。

我先简单的自我介绍一下,我叫林溪,是百度外卖这边新业务部门的前端负责人,主要经历是一三年加入百度地图,一五年来到百度外卖这边。

我今天分享的主要内容是这三大块。

  1. 我们简单回顾一下组件发展的历程,

  2. 组件发展的新趋势,组件化和可视化的结合。

  3. 介绍一下可视化的相关的东西。

我们首先介绍一下组件化的发展历程

第一代的组件化,PPT上比较清楚,YUI、EXT、Jquery Plugin,他们多半是基于原形链的寄成或者是Jquery做一些组件,如果非要有一个特点我觉得是集成是这个组件化可能是共有的特性。

第二代组件化更多的是现代的组件化,基于VUE,React,这种类型的组件,这个比较优秀的是大家可能是比较了解,淘宝的ANTD,谷歌的Material UI,我用的比较好的我觉得是iView UI,这样的一些组件库,功能是非常强大也是非常好用的类型。

第二代组件化的特征是第一个他是有比较完善的生命周期,有很hook,大家可以在每个生命周期里干一些事情,第二个状态管理机制是基于这个模型,第三个是他的操作是隔离开的,这些特性是依赖于我们底层专业的组件库提供的,还有一个特点是他是生命式编程,是跟我们的这个命令式编程是相对的,我们是弄一个出来,传入一些什么东西。在第二代组件库的时候我们基本上都是直接写他的标签,生命式的,这个其实是一个能提高我们开发效率的地方。这个不一定是因为这个生命式,整体来说第二代组件库他是功能很丰富。

我们接着来谈一下组件化发展的新趋势

大家用这个antd开发运营后端这个东西效率是非常高的,第二个我认为组件化发展的新趋势,刚才说到我们在使用第二代组件库的时候,大家都会做同样一个事情,先基于这个库去完善一个组件库,比如说做一个antd的库,业界可能是有很多这样的库,我们现在的库已经是非常完善,开发效率我们有很大的提高,大家在思考一个问题,我们现在的开发效率已经足够高吗。我们在使用第二代组件库开发一些业务中的时候,遇到这样的问题,比如说运营后端的系统,信息管理系统,MIS的系统,他们有很多的逻辑是重复的,比如说一个页面有一些条件搜索,过滤的区,下面显示的表格进行分页之类的,这种逻辑是非常多的,我们每次这么写的话是重复开发,复制粘贴改写组件的属性。然后还有一个类型是像我们做运营活动的页面,他要求是这个更高可配置用的,图片什么链接什么都可配置的,对配置要求是比较高的。

基于像这种的重复性的开发,我们的开发效率能不能再提升,组件的特性能不能更大的复用他,这个页面能不能更好的配置他,这个是我们遇到的比较现实的问题。

我们在这方面做一些尝试,我们在组件化可配置化与可视化的页面编辑的具体尝试,我们有两个项目是做这个事情,第一个是我们把运行活动平台的H5做成了可视化页面编辑的平台,我们可以通过配置组件的具体属性生成页面,实现这个组件的可复用,另外一个是针对运营后端的系统,多半是一些逻辑是相通的,我们可以做一些事情的,也是通过配置生成运营后端的页面。

另外是在业界我参与过一些会议,也听到一些公司的分享,比如说淘宝他们有一个Nrails的系统,也是用来可视化配置运行后端的系统,还有是像美团他们也做运营后端的自动化配置的系统。

大家业界很多人在去做可视化与组件化的配置的尝试,这个我们做这个之前也是没有跟业界进行一个约定,大家是不约而同的朝一个方向走,所以我觉得这个是一个能提高我们组件更高效率的一种手段和途径,大家都是朝这个方向走的,我觉得这个是我们今后的一种趋势。

刚才说我参加一些会议,其中有淘宝的分享,他们有这个系统,就是Nrails他们也是基于对运营后端这一块,对可视化进行配置,美团也有这样的尝试,大家可能都之前是没有约定这样做的,大家最终是达到惊人的一致,这个应该说是能提高组件化的功效的一种很好的方法,我觉得这个也是未来的用趋势。

所以是组件化与可视化的编辑结合是组件化未来发展的趋势,我们可以通过组件化的配置让你用组件化开发页面效率更高,我们现在做的一些系统,从经验来看确实是可以达到效果,所以我觉得高级阶段是可视化的东西。

可视化编辑技术方面的东西

第三部分是跟大家详细介绍一下可视化编辑技术的一些方面的东西。

首先我们说的是可视化编辑他是这样的一个概念,我们有这样一个平台能对组件各种拖拽,配置,最终我们保存是一个阶层,然后在另外一个页面把这个拿到以后对这个进行还原,基本上很多系统都是这样的思路。

比如说我们现在的运营的工具,他们都是这样的概念。我会介绍其中三个我觉得是这种可视化编辑不可避免的三个基本技术,组件的复用,组件的扩展以及发布流程相关的东西,由于今天时间的关系,基础的平台的相关东西就不做详细的介绍了。

第一个是组件复用,我们刚才说可视化编辑是提高我们开发效率的一个工具,如果我们组件不能进行复用,一个组件进来只能当一个使用,这种不能体现出我们能提高开发效率,所以我们就必须是组件是可以进行嵌套的,比如说这个PPT列表的,如果我们不能嵌套的话,一个组件加一个组件是两个效果,如果我们可以的话就有无穷多种组合,我们通过组件嵌套解决组件复用的问题,可以把一个组件拖到另外一个组件上面去,整个页面可以有多层去组成。

大家看这个图片的PPT上面,左边这一块是我们的一个JSON的基本结构,他是有root,root下面是有children,children里面是组件的一个完整的配置,有title,就是中文名称可以起一个,name是组件的名称,比如说你用VUE实现的话,他就是vue的一个name,name就是组件的name,他的cid是他的唯一标识,大家可以注意到里面有一个animation的一个东西,你可以组件设置动画。这些是一个基本的json的配置,我们对组件进行各种拖拽,最终对应的是添加组件,插入或者是删除,对应的是这个结构。我们怎么实现这个东西的。这个是你可以在系统的渲染每个组件的时候,在外面有一层容器,他就处理这个,处理这个事件,在他上面时候他就更新他的children的数据,更新JSON。

插入组件有一个地方就是如果我想把一个组件拖到两个组件中间,原身是不支持这个操作的,我们在中间的时候显示一条线的时候,你需要除了刚才说的在组件外面包括容器之外你还需要在容器里面插入站位的容器,就处理插入的操作,你有这个到英文drop的上面的时候,对于children的进行改变,这样就是可以实现比较好的体验。

我们刚才说的是我们在外面包括容器,不让自建具体的接触处理这种事件,他的优点是组件你不需要关,你开发一个组件不需要关心这些编辑平台的一些细节的问题。只是要专注做好你组件的业务就可以了。但是因为我们是一个嵌套的东西,你的children里的子节点是怎么显示的,这个是你需要开发的,如果你英文是没有显示的。我们现在介绍一下嵌套组件的渲染,上一章是树形的结构,我们要有一个组件数,反序列化,他是一个树,我们人从最叶子节点开始,把他这一层的都渲染出来,就得到这个一层的树组,这个树组作为他的parent的children参与到他的parent的渲染,一层层的渲染,最终渲染到root上面。这个树的层级的便利是相当于我们在大学学的,我们也是基于这样的模型实现的。

刚才说的我们是从这个开始渲染,具体渲染的是这样的流程,看这个图,JSON描述的是组件的路径组件的名称的东西,我们是先加载这个路径,然后是在VUE里面我们需要把这个组件进行注册,我们对把各种首先是进行拼装,我们去创建他的实例,像jsx的这种文件,他是有一个方法,这里面可以把他渲染出来。这个方法是渲染组件的名称,组件的属性还有他的props,大家会看这个PPT上面的有一个attrs的属性,我们可以绑定到组件的属性,然后我们可以给组件绑定原生的事件,这个可以用在编辑平台上,我想点击这个组件,让他进行他的属性的配置,你可以让这个通过绑定这个事件一点他就出现他的属性,这个不需要组件开发者如何定义他的属性是怎么显示的,由系统实现,还有一个是我们是嵌套的,我们会涉及到副子键相关的渲染或者是相通的东西,有两个方法,第一个我们可以通过系统自带一些方法,比如说是像$parent, $children,这个是可以访问他的实力,拿到实力可以改变他的值,可以调他的各种方法,可以具体的操作这些东西,另外一个方法是修改JSON,另外一个是你可以重新渲染,是进行通讯的,你设置这个里面组件的某个值改变了,他就是也是一种通讯,这部分简单总结一下是你在做这样的可视化平台的时候,我们刚刚上面说的方法是可以对组件进行嵌套实现复用,比你单个一个组件当一个组件使用肯定是好处是很多的。

他的配置性是不能复用的N倍,刚才也介绍了组件嵌套如何渲染,比如说是关连或者是通讯的东西,大家如果做这样的平台,实现可复用组件嵌套的方式有一些参考,另外这部分介绍组件扩展相关的东西。组件扩展是我们目前想到的方式有三个,第一个是大家都非常熟悉的模式,这个平台的代码,大家把代码都改完以后,在check out,然后再check in,不同的人只要有权限都可以进行改,这个是一种在本地编译好上传的模式,这个也是比较简单,他也是有一些问题。如果你这个平台是要给多个团队多人使用的话你可能就会遇到一些问题,比如说像平台的可维护性,因为多人编辑可能是会有一些隐患,这是很明显的,尽管你有代码规范也有编码规范相关的各种东西都有,很多人改一个代码的时候你的可控性就会变差,如果你不存在这个问题的话这个方案没有什么问题,他本身是非常简单的方案,是非常简单的实现。

第二类和第三类的方案是我们把这个组件上传到我们的平台上去,他们的区别是说我把这个组件在本地编译好了上传上去还是把原代码上传上去,是这样的区别,一开始我们对这个事情第二种和第三种方案的认识也不足,他们两种是互斥的,我们做这个是第三种方案,因为前端的跟以前是大不一样了,我们直接写代码,我们写模块化这个东西,这个是运行不起来的,我们需要直接进行编译,打包,才可以短期进行,我们直接上传原代码的方式,肯定是对代码进行编译,然后是会发现,如果上传原代码的话,我对第三方的库有依赖的话其实这种方式去实现是非常困难的,但是反过来如果使用第二种方案,我有一个工具,你在这里面进行开发,开发完以后依赖第三方的你最终打包上传这个是很简单很容易的事情,第二种方案的缺点是需要设置好通用库的依赖,比如说你这个组件直接编译后,你里面包含vue的通用的库,你的组件会变大,可能是会有性能的问题。

所以也是因为这个原因,我们做这样的系统没有使用第二种方案,当时我们没有工具,如果第二种方案你有了工具,你设置好了正确的对通用库的依赖,确保了打包后的最终文件里是不包括这个通用库的时候,依赖第三方库也是很简单的事情,这两种方案是结合起来一起使用,才是比较完美的方案,后面会介绍刚才我们说到的时时编译,这样的东西的一些技术。这个介绍一下组件库的规范。我们的系统是这样设计的,你扩展一个组件需要写两个组件,第一他是在页面上长什么样就写什么样,第二个是属性组件,我需要给主组件配置什么样的数据,你的属性组件就写成什么样了,这两个组件肯定是可以进行通信的,我们点这个主组件,他主组件会把属性传递给属性组件进行显示,用户编辑完他的属性以后,他会把信息通过调用这个方法,规定好的方法,传给主组件,所以这里面的约束是说你两个组件命名有约束,主组件和属性组件,属性组件的名称是主组件加一个property,我们会在编辑的时候惦记这个组件以后,我们刚才说的绑定事件,会主动加载属性组件,然后会调用dispatchPropertyChange的方法,把属性给传递过来。

这种是为了你是扩展组件的时候你不用关心平台相关的事情,这都是系统给你实现好的,对你的依赖是非常好的,也是比较少的,这个是我们设计的一个原则。刚才说到的上传原代码,我往可视化编辑系统上传一个原代码,对他进行编译,不编译这个组件用不了,这个之前的探索是很坎坷的,最终得出这样的一个结论,首先我们组件上传到服务器完以后,在node这一层调用webpack的API,webpack动态的编译后的文件途径,就把最终编译后的文件输出到前台。

这个编译的时候需要注意的是我们输出的编译的模块方式是UMD,在服务器端输出的,这个模块是编译完以后需要在浏览器当中用,他必须支持浏览器模块的规范,他是amd + commonJS的规范,这样是在浏览器端也可以进行使用,我们就使用这个requeirJS。requireJS把反回的路径加载进来,就可以连接到上一个流程,加载的组件以后用VUE进行注册,这个里面也有一个小注意的地方,requirJS这个不能直接写成这种形式,requrie这个也可以被webpack编译,会认为webpack他自己的require,所以你小注意一下,比如说你用window重命名,这个就不会有问题。

线下的脚手架的编译流程差不多,我们线下有一个工具,你可以初始化环境。然后你可以在环境里面编辑组件进行各种调试,然后你可以进行编译,然后是可以进行上传,也是一个规范,相当于我们是实施线上编译的步骤,这个工具必须设置好对通用库的依赖,比如说vue这种库,可能是用external当时外部的一个饮用,保证他最终编译后的组件是不包含通用库的,不会存在重复的部分。

接下来说一下发布。是有两种模式,第一种是发布的时候只把页面配置各种信息进行保存,第二种是除了把配置信息进行保存之外还把页面所用的各种资源进行一个编译。产生配置信息和资源,这两种的比较是如果我只保存信息,我最终的页面就是需要有大量的代码逻辑,把配置信息进行还原,各种渲染的代码都在最终页面里面。

我说的第二种方案就是我在发布的时候产生的信息,我又产生资源,我把这个上面所用的各种GS,CSS或者是图片什么的进行编译,我最终页面的逻辑就非常简单,只需要加载资源和配置信息,这个页面就完成了。

因为我们做的系统是第二种方案,最终页面肯定是承担巨大的访问量的。他肯定是放在集群上面的,你去修改集群上的一个东西,肯定是每个公司都有每个公司的方法,比如说持续集成,持续交付的流程,我觉得一点,你公司越大,持续交付的流程越复杂就越大,如果是用第二种方案的话,你的最终页面他的逻辑是非常简单的,是固定的,你不用对他进行维护,这个是你提高工作效率的一个方法,还有一点是使用第二种方案的时候因为一旦你发布完以后你的页面的配置信息和所用的资源他都进行打包以后放到了某个地方,这个页面是稳定的,不管你这个平台怎么改或者是挂了,或者是其它的东西怎么改,组件怎么改都是不影响他的,如果你是在最终页面有大量的逻辑去还原JSON的话,有可能你改所有的页面都受影响,稳定性方面说第二个方案是更优的。

如果是用第二种发布的流程方案的话有这样的步骤,因为刚才说的对各种资源进行编译,你需要在后端准备编译的环境,他肯定是有限的,如果是请求很多的话肯定是要有排队的机制,然后到你了以后你去准备编译环境,也就是你写代码的环境,把用到的各种东西都拷进去,进行编译,这样的命令,npm run build去执行编译,最终得到编译的文件,要么是保存当前的或者是做集群,上传操作,对列你可以用这个redis的队列,有一个库是bull,这个队列是比较好用,英文的话用这个可以复合一个,这个日志回传我们系统是有这样的一个特性,后面的进行编译的时候,回传到前端页面做显示,如果出错可以知道是什么原因,这个相当于是从服务器端语音端的通讯可以用SSE或者websocket,SSE服务器编程是非常简单的,不需要那么复杂写很多东西。

最后总结一下整体的结合方案的流程,第一种方案可能是一个前端把代码进行修改完以后本地进行编译完以后系统进行重新上线,进行各种配置以后点发布,信息到数据库里,最终页面去数据库里读配置信息,他里面有一个渲染的过程,页面逻辑是必须把所有的渲染的逻辑包含在里面,这种方案是最简单的,不需要很多的技术流程在里面的。

比如说后面的方案是通过上传的,是一个前端他把这个,通过脚手架对组件进行开发上传到平台上面,对页面进行各种配置以后发布,会看这个JSON的文件,所有的组件都拷贝到这个环境里面,对这个编译环境进行编译,最终得到的文件,你可以设置最终输出的是一个文件,包括图片,这个文件是上传到静态集群,把信息放到数据库里面,或者是没有静态集群也是把路径直接放到数据库里面,页面直接读取,他是不包含渲染的,已经编译好的,这个方案三是跟二是很类似的,不一样的地方是你直接通过平台上传组件,你没有脚手架,平台帮你实施编译,后面流程是一样的,不在详细赘述了。

我们简单的总结一下,我们刚才在这说的是我们的组件的层级嵌套的渲染实现的方式方法,以及组件扩展的方式,以及发布流程相关的东西。大家是可以对这些方案进行自由组合的,就是你的业务,如果你是只有一个业务团队的产品,你可能是不需要后面那么复杂,组件上传实施编译的流程。直接代码可以改下来就可以,相当于是更适合你的业务的,这些都是我们的可视化编辑的基础。不管是实现什么的功能这些都是很基础的东西,你都绕不过去的。

比如说是我们要完全实现一个可视化编辑的运营后台这样的一个功能的时候,我通过这个平台去满足所有运营平台的功能的时候,光这点还不够,还需要服务的配置或者是组件有什么事件这些配置,或者是多路由,各种的相关的东西,这个也有一些尝试。

今天的时间关系可能是来不及跟大家介绍,以后如果有机会的话可以来继续分享这一部分。我对组件化可视化的平台这部分的介绍结束了。