21

基于 Web Components 跨框架组件开发实践,告别重复轮子

 3 years ago
source link: https://mp.weixin.qq.com/s?__biz=Mzg5NDAyNjc2MQ%3D%3D&%3Bmid=2247485339&%3Bidx=1&%3Bsn=351c68c2205c5062249941b08366e98d
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
NzeqaeJ.gif!mobile

过去我们在讨论前端组件化架构的时候,通常是指某个框架限制下的组件化架构,主流组件化框架有React、Angular和Vue。理想的组件库可以自然地用于所有的前端框架,而传统的组件库是技术栈强耦合的,在面临技术栈升级或变更的时候,往往需要进行大面积的代码调整和重构,同时需要维护多套组件库。这种环境强耦合的方式会带来重复开发、交互不一致、升级困难等问题。网易严选前端团队从2019年开始了对跨框架组件开发的实践,以未来组件化趋势Web Components为桥梁,将组件核心代码与技术栈隔离,支持React和Angular的封装,力求“write once,run any where ”。

背景

网易严选发展至今,前端技术栈经历了Jquery、NEJ、Angular以及目前的React,每一次的版本升级和技术栈变更都需要持续完善组件库。 理想状况下,技术栈升级的过程应该是【组件升级】-> 【项目升级】,但是由于组件库数量庞大、逻辑复杂,应用项目众多,很难在短时间内完成系统升级。 网易严选目前有100+B端业务系统,每个系统少则几十个页面,多则数百个页面,且需求量日益增多,实际落地过程中很难挤出足够的排期来完成升级,这就意味着升级是逐步进行地、漫长地。 而在这个漫长的过程中,我们需要同时维护多套技术栈下的组件库,必然会带来一些问题:

  1. 护成本高

    首先,在技术栈发生变更时,需要花大量精力迁移新技术栈的组件库。 其次,在快节奏的互联网环境下,业务调整非常快,业务组件的需求变更非常频繁,意味着后续需要不断地在新 旧技术栈下开发和维护

    多个“外壳不同,逻辑相同”的组件,维护成本非常高。

  2. 视觉交互不一致

    新旧技术栈下的技术策略不同,导致采用的基础UI库可能也不同。 以网易严选为例,2019年以前,技术栈是Angular,所维护的基础UI库是自研的Shark,而技术栈转换成React后,采用Antd作为基础UI库。

    由于Shark和Antd在设计上不完全一致,导致新旧系统整体的视觉和交互会有轻微的差异。

  3. 升级困难
    由于环境强耦合性,后续如果要进行React升级或者使用Vue等其他技术栈,必然又需要经历同样的阵痛,如此往复,耗费大量人力,组件库的稳定性较差,后续升级难度重重。

基于以上痛点,我们希望能探索一套环境无关、便于接入、完全自治的跨框架组件开发模式。

umUNRfB.jpg!mobile

一、技术选型

跨框架组件(Cross Framework Component (CFC)) 是一种支持 各种框架 的基于单个 通用模块 的有效结构。

我们前面说到,不同框架、同一框架不同版本无法共存,导致组件无法跨框架复用,甚至只能固定在框架的某个版本,这与前端未来的模块化发展是相违背的。 庆幸的是,W3C于2011年提出Web Components的概念,并与2014年产出 v1草案,使浏览器原生支持模块化。 Google也一直致力于Web Components的发展,率先在Chrome完成了浏览器的底层支持。

1 Web Components

1.1 概念

Web Components的三驾马车,即Custom elements、Shadow DOM和HTML templates。

1)Custom elements

允许用户自定义一组JS API,完成UI和逻辑行为,这与主流框架中的组件自定义元素的概念是一致的。

2)Shadow DOM

自定义元素将生成一棵与主文档隔离的“影子”DOM树,而Shadow DOM

的作用就是将这棵树附加到宿主元素中,保证了元素功能的私有和独立性。

3)HTML templates

提供了 template 和 slot 功能,用于自定义元素结构和模板复用。

1.2 生态

2017年以前,Web Components的发展是较为缓慢的,毕竟标准的推进需要各大浏览器厂商的支持,过程漫长,各大公司都在观望。 到了2017年,陆续有公司开始使用Web Components构建UI库。 但是原生的开发方式非常繁琐,有不少团队开始研究Web Components的开发框架和编译工具Ï,通过更灵活、便捷的方式开发编译出Web Components。 其中,Svelte团队的Svelte框架,Polymer团队的Lit-html、腾讯的Omi,都取得了不错的效果。

Ab2ABjE.jpg!mobile

1.3 优缺点分析

1)优点

  • 框架0耦合

  • 浏览器原生支持

  • 主流框架支持

  • 未来组件化趋势

2)缺点

  • 兼容性

    目前原生浏览器中只有Chrome和Firfox提供了全面的支持,IE和Edge等并不友好。

    庆幸的是,官方polyfill可以提供IE11以及Edge和其他大部分浏览器的支持,这对B端产品来说,已经够了。

  • 数据绑定

  • 状态管理

  • 开发成本

    Web Components目前并没有数据绑定和状态管理,导致我们无法像其他主流框架那样方便地更新视图、使用redux等进行数据状态管理。

至此,我们萌生了一个大胆的想法,是不是可以使用某个主流框架进行组件核心逻辑的开发,以Web Components作为桥梁,进行其他框架的复用手段?

2 方案对比

网易严选从2019年开始了对跨框架组件开发方案的调研,通过对比开发效率、基础UI库复用、性能、学习成本等角度对比了以下几种方案,最终结合网易严选现状,以React技术栈为基础开发,转换成Web Components,最后再封装层进行技术栈耦合,达到“底层一套核心代码,上层支持多套框架”的目的。

3eMNrqz.jpg!mobile

二、跨框架组件开发方案

1 架构设计

在CFC架构设计中,网易严选借鉴了许多外部的优秀方案与设计,经过长时间的探索、开发和实践,形成了有严选特色的跨框架组件开发架构体系。

zaie6rr.jpg!mobile

整体架构如图,分成5层,从下到上依次是基础库、组件层、桥梁层、封装层、应用层。

  • 基础库

    底层基础库包括了技术栈、基础UI库以及其他工具库,是上层建设的基石。

  • 组件层

    组件层,采用React进行组件核心逻辑开发,这里需要可以复用底层基础UI库和其他业务组件库。

  • 桥梁层

    通过第三方工具Direflow完成React组件到Web Components的转换,从而实现内部完全自治,统一对外输出形态,上层可以接入任意支持Web Components的框架中。

    为了资源复用,我们将源码以UMD的方式打包并上传至CDN,通过懒加载的方式与封装层进行联通。

  • 封装层

    至此,应用层已经可以直接使用组件了,但是由于在React/Angular/Vue中使用Web Components时需要处理事件、参数变更等,使用方式较为繁琐。 为了减轻组件使用者的负担,我们在封装层进行了统一的源码加载、参数传递、事件处理等中间转换。

    最终,对外发布的npm包和现有多套组件的使用方式是一致的。

  • 基础包

    收纳与框架无关,又需要在 Web  Components 和不同框架之间复用或者对外暴露的文件。

  • 包服务管理

    用于管理包依赖和加载顺序。

2 技术细节

2.1 Direflow

IR7fYfq.jpg!mobile

Direflow是一个将React框架转成Web Components的第三方工具,目前github的star数在50左右。 其背后的技术很简单,利用了Web Components的生命钩子完成组件的挂载、更新和卸载。

6r2iIzN.jpg!mobile

2.2 封装层

封装层起到了胶水作用,主要完成以下功能:

1)加载Web Components及其依赖的源码

2)参数传递

  • 参数初始化

  • 参数变更检测

3)通信

  • 回调函数,在封装层转化成框架的事件传递方式

  • 全局通信,使用Event完成全局事件通知

4)base包输出

由于封装层的代码比较固定,我们提供了脚本化配置,通过几行简单的配置,实现一键生成封装层。 最后,尽管需要保持封装层和技术栈的统一,在该方案下的升级和重构成本是非常低的。

三、落地问题

1 转换能力

通过大量落地实践,我们对该方案在React和Angular框架封装后的能力进行分析,最后得出如下结果。 可以看到,在参数变更、事件、路由等常规组件能力上,React和Angular都是无损的,而在slot模板能力上,无法在React组件中自定义Angular组件。

qaeyY36.jpg!mobile

目前对于这种场景还无法解决,但是在大部分业务场景里,是可以通过合理的组件设计去规避使用slot,尽可能地用数据驱动视图。

2 基础包复用

我们在前面提到,Direflow只是一个转换工具,对外输出Web Components,其底层本质上还是React。 因此,在运行时会加载React库和UI库。 在落地的时候发现,单个业务包的大小达到1.2M,无法忍受。 所以我们加入了资源复用,将React相关套件、UI库以及Direflow剥离出去,通过包加载管理和浏览器缓存以达到复用目的。 最后核心业务包部分控制在几十K。

vMraEbu.jpg!mobile

然而,要做的事情远不止这些,我们通过管理命名空间、收敛基础库版本、管理包依赖以及CDN服务的方式缓解了包大小和包冲突的问题。

  1. 包冲突

    管理包命名空间,以隔离影响

  2. 版本收敛

    试想一下,如果我们的一个应用场景里用到的多个组件包底层的React都是来自于不同的版本,虽然不冲突了,但是复用率将大打折扣。 另外,多个框架在一个环境会占用大量内存,影响页面性能。

    所以我们通过管理包服务以及代码检测的方式进行版本收敛,在底层React版本始终加载大版本下的最新小版本,相同环境内的React版本不应该超过2个。

  3. 包依赖

    通过包管理服务管理业务包依赖,在懒加载的时候进行按序加载,保证执行顺序,避免重复加载和冲突。

  4. 加快加载速度

    将所有资源上传到cdn,以加快加载速度。

3 样式处理

Shadow DOM天然的隔离性,让css的处理变得稍微复杂。

  • Shadow DOM内

    通过style-it插入根节点前。

  • Shadow DOM外

    在Shadow DOM外进行DOM操作,eg,全局的toast、modal,已经脱离了Shadow DOM,就需要在全局额外动态加载对应的css,并且要保证对应命名空间的唯一性。

  • 第三方UI样式

    对于第三方UI样式,比如我们现在用的antd,同样需要进行资源复用,动态加载。

四、开发姿势和使用姿势

目前,网易严选已将开发模板集成到cli,通过以下5步,轻松完成一个业务组件的 开发。

而对于 组件使用者的而言,由于封装层已经隔离了内部的复用,并没有额外增加使用者的成本,使用的时候直接以技术栈对应的开发方式即可。

f6Jbuam.jpg!mobile

五、价值分析

  1. 效率提升

    互联网寒冬时代,各大公司都在强调降本增效,提高生产力才是硬道理。

    从网易严选目前落地的组件包的代码量上看,人力投入可缩小至60%。

  2. 环境隔离

    由于将框架和版本解耦,真正做到组件自治,未来升级技术栈的时候,也只需要新增对应的封装层即可,做到平滑升级。

  3. 交互视觉统一

    因为只维护了一份代码,组件在不同技术栈下的表现可以保证一致。

六、写在最后

最后需要强调的是,跨框架组件开发模式终究是未来组件库的趋势,真正的组件库应该是完全自治、环境隔离、不受框架和版本限制的,网易严选的跨框架组件方案是结合严选场景的具有严选特色的方案 而Web Components在未来会提供越来越多的特性,值得一试。 至于底层是选择React -> Web Components、Angular -> Web Components,还是直接使用Svelte、Omi这样的框架,都需要各团队结合实际情况去调整方案。

综上,本文通过介绍网易严选跨框架组件开发模式的方案设计和落地细节,力求保证组件库的隔离性、一致性和稳定性,希望给大家提供一个新的思路。

:heart: 交流讨论

欢迎关注公众号  秋风的笔记 ,主要记录日常中觉得有意思的工具以及分享开发实践,保持深度和专注度。回复"好友"可加微信,秋风的笔记常年陪伴你的左右。

Avi6Vj6.jpg!mobile


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK