维护成本高首先,在技术栈发生变更时,需要花大量精力迁移新技术栈的组件库。其次,在快节奏的互联网环境下,业务调整非常快,业务组件的需求变更非常频繁,意味着后续需要不断地在新旧技术栈下开发和维护多个“外壳不同,逻辑相同”的组件,维护成本非常高。
视觉交互不一致新旧技术栈下的技术策略不同,导致采用的基础UI库可能也不同。以网易严选为例,年以前,技术栈是Angular,所维护的基础UI库是自研的Shark,而技术栈转换成React后,采用Antd作为基础UI库。由于Shark和Antd在设计上不完全一致,导致新旧系统整体的视觉和交互会有轻微的差异。
升级困难由于环境强耦合性,后续如果要进行React升级或者使用Vue等其他技术栈,必然又需要经历同样的阵痛,如此往复,耗费大量人力,组件库的稳定性较差,后续升级难度重重。
基于以上痛点,我们希望能探索一套环境无关、便于接入、完全自治的跨框架组件开发模式。
一、技术选型跨框架组件(CrossFrameworkComponent(CFC))是一种支持各种框架的基于单个通用模块的有效结构。我们前面说到,不同框架、同一框架不同版本无法共存,导致组件无法跨框架复用,甚至只能固定在框架的某个版本,这与前端未来的模块化发展是相违背的。庆幸的是,W3C于年提出WebComponents的概念,并与年产出v1草案,使浏览器原生支持模块化。Google也一直致力于WebComponents的发展,率先在Chrome完成了浏览器的底层支持。
1WebComponents1.1概念WebComponents的三驾马车,即Customelements、ShadowDOM和HTMLtemplates。
1)Customelements????允许用户自定义一组JSAPI,完成UI和逻辑行为,这与主流框架中的组件自定义元素的概念是一致的。
2)ShadowDOM????自定义元素将生成一棵与主文档隔离的“影子”DOM树,而ShadowDOM的作用就是将这棵树附加到宿主元素中,保证了元素功能的私有和独立性。
3)HTMLtemplates????提供了template和slot功能,用于自定义元素结构和模板复用。
1.2生态7年以前,WebComponents的发展是较为缓慢的,毕竟标准的推进需要各大浏览器厂商的支持,过程漫长,各大公司都在观望。到了7年,陆续有公司开始使用WebComponents构建UI库。但是原生的开发方式非常繁琐,有不少团队开始研究WebComponents的开发框架和编译工具?,通过更灵活、便捷的方式开发编译出WebComponents。其中,Svelte团队的Svelte框架,Polymer团队的Lit-html、腾讯的Omi,都取得了不错的效果。
1.3优缺点分析1)优点
框架0耦合
浏览器原生支持
主流框架支持
未来组件化趋势
2)缺点
兼容性目前原生浏览器中只有Chrome和Firfox提供了全面的支持,IE和Edge等并不友好。庆幸的是,官方polyfill可以提供IE11以及Edge和其他大部分浏览器的支持,这对B端产品来说,已经够了。
数据绑定
状态管理
开发成本 WebComponents目前并没有数据绑定和状态管理,导致我们无法像其他主流框架那样方便地更新视图、使用redux等进行数据状态管理。
至此,我们萌生了一个大胆的想法,是不是可以使用某个主流框架进行组件核心逻辑的开发,以WebComponents作为桥梁,进行其他框架的复用手段?2方案对比网易严选从年开始了对跨框架组件开发方案的调研,通过对比开发效率、基础UI库复用、性能、学习成本等角度对比了以下几种方案,最终结合网易严选现状,以React技术栈为基础开发,转换成WebComponents,最后再封装层进行技术栈耦合,达到“底层一套核心代码,上层支持多套框架”的目的。二、跨框架组件开发方案1架构设计在CFC架构设计中,网易严选借鉴了许多外部的优秀方案与设计,经过长时间的探索、开发和实践,形成了有严选特色的跨框架组件开发架构体系。
????
整体架构如图,分成5层,从下到上依次是基础库、组件层、桥梁层、封装层、应用层。基础库底层基础库包括了技术栈、基础UI库以及其他工具库,是上层建设的基石。
组件层组件层,采用React进行组件核心逻辑开发,这里需要可以复用底层基础UI库和其他业务组件库。
桥梁层通过第三方工具Direflow完成React组件到WebComponents的转换,从而实现内部完全自治,统一对外输出形态,上层可以接入任意支持WebComponents的框架中。为了资源复用,我们将源码以UMD的方式打包并上传至CDN,通过懒加载的方式与封装层进行联通。
封装层至此,应用层已经可以直接使用组件了,但是由于在React/Angular/Vue中使用WebComponents时需要处理事件、参数变更等,使用方式较为繁琐。为了减轻组件使用者的负担,我们在封装层进行了统一的源码加载、参数传递、事件处理等中间转换。最终,对外发布的npm包和现有多套组件的使用方式是一致的。
基础包收纳与框架无关,又需要在WebComponents和不同框架之间复用或者对外暴露的文件。
包服务管理用于管理包依赖和加载顺序。
2技术细节2.1DireflowDireflow是一个将React框架转成WebComponents的第三方工具,目前github的star数在50左右。其背后的技术很简单,利用了WebComponents的生命钩子完成组件的挂载、更新和卸载。
2.2封装层封装层起到了胶水作用,主要完成以下功能:
1)加载WebComponents及其依赖的源码
2)参数传递
参数初始化
参数变更检测
3)通信
回调函数,在封装层转化成框架的事件传递方式
全局通信,使用Event完成全局事件通知
)base包输出
由于封装层的代码比较固定,我们提供了脚本化配置,通过几行简单的配置,实现一键生成封装层。最后,尽管需要保持封装层和技术栈的统一,在该方案下的升级和重构成本是非常低的。
三、落地问题1转换能力通过大量落地实践,我们对该方案在React和Angular框架封装后的能力进行分析,最后得出如下结果。可以看到,在参数变更、事件、路由等常规组件能力上,React和Angular都是无损的,而在slot模板能力上,无法在React组件中自定义Angular组件。
目前对于这种场景还无法解决,但是在大部分业务场景里,是可以通过合理的组件设计去规避使用slot,尽可能地用数据驱动视图。2基础包复用我们在前面提到,Direflow只是一个转换工具,对外输出WebComponents,其底层本质上还是React。因此,在运行时会加载React库和UI库。在落地的时候发现,单个业务包的大小达到1.2M,无法忍受。所以我们加入了资源复用,将React相关套件、UI库以及Direflow剥离出去,通过包加载管理和浏览器缓存以达到复用目的。最后核心业务包部分控制在几十K。
然而,要做的事情远不止这些,我们通过管理命名空间、收敛基础库版本、管理包依赖以及CDN服务的方式缓解了包大小和包冲突的问题。
包冲突管理包命名空间,以隔离影响
版本收敛试想一下,如果我们的一个应用场景里用到的多个组件包底层的React都是来自于不同的版本,虽然不冲突了,但是复用率将大打折扣。另外,多个框架在一个环境会占用大量内存,影响页面性能。所以我们通过管理包服务以及代码检测的方式进行版本收敛,在底层React版本始终加载大版本下的最新小版本,相同环境内的React版本不应该超过2个。
包依赖通过包管理服务管理业务包依赖,在懒加载的时候进行按序加载,保证执行顺序,避免重复加载和冲突。
加快加载速度将所有资源上传到cdn,以加快加载速度。
3样式处理ShadowDOM天然的隔离性,让css的处理变得稍微复杂。
ShadowDOM内通过style-it插入根节点前。
ShadowDOM外在ShadowDOM外进行DOM操作,eg,全局的toast、modal,已经脱离了ShadowDOM,就需要在全局额外动态加载对应的css,并且要保证对应命名空间的唯一性。
第三方UI样式对于第三方UI样式,比如我们现在用的antd,同样需要进行资源复用,动态加载。
四、开发姿势和使用姿势目前,网易严选已将开发模板集成到cli,通过以下5步,轻松完成一个业务组件的开发。而对于组件使用者的而言,由于封装层已经隔离了内部的复用,并没有额外增加使用者的成本,使用的时候直接以技术栈对应的开发方式即可。五、价值分析效率提升互联网寒冬时代,各大公司都在强调降本增效,提高生产力才是硬道理。从网易严选目前落地的组件包的代码量上看,人力投入可缩小至60%。
环境隔离由于将框架和版本解耦,真正做到组件自治,未来升级技术栈的时候,也只需要新增对应的封装层即可,做到平滑升级。
交互视觉统一因为只维护了一份代码,组件在不同技术栈下的表现可以保证一致。
六、写在最后最后需要强调的是,跨框架组件开发模式终究是未来组件库的趋势,真正的组件库应该是完全自治、环境隔离、不受框架和版本限制的,网易严选的跨框架组件方案是结合严选场景的具有严选特色的方案。而WebComponents在未来会提供越来越多的特性,值得一试。至于底层是选择React-WebComponents、Angular-WebComponents,还是直接使用Svelte、Omi这样的框架,都需要各团队结合实际情况去调整方案。综上,本文通过介绍网易严选跨框架组件开发模式的方案设计和落地细节,力求保证组件库的隔离性、一致性和稳定性,希望给大家提供一个新的思路。
??交流讨论欢迎