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

微信扫一扫,分享到朋友圈

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

过去我们在讨论前端组件化架构的时候,通常是指某个框架限制下的组件化架构,主流组件化框架有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等其他技术栈,必然又需要经历同样的阵痛,如此往复,耗费大量人力,组件库的稳定性较差,后续升级难度重重。

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

一、技术选型

跨框架组件(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,都取得了不错的效果。

1.3 优缺点分析

1)优点

  • 框架0耦合

  • 浏览器原生支持

  • 主流框架支持

  • 未来组件化趋势

2)缺点

  • 兼容性

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

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

  • 数据绑定

  • 状态管理

  • 开发成本

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

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

2 方案对比

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

二、跨框架组件开发方案

1 架构设计

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

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

  • 基础库

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

  • 组件层

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

  • 桥梁层

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

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

  • 封装层

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

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

  • 基础包

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

  • 包服务管理

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

2 技术细节

2.1 Direflow

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

2.2 封装层

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

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

2)参数传递

  • 参数初始化

  • 参数变更检测

3)通信

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

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

4)base包输出

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

三、落地问题

1 转换能力

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

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

2 基础包复用

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

然而,要做的事情远不止这些,我们通过管理命名空间、收敛基础库版本、管理包依赖以及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步,轻松完成一个业务组件的 开发。

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

五、价值分析

  1. 效率提升

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

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

  2. 环境隔离

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

  3. 交互视觉统一

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

六、写在最后

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

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

:heart: 交流讨论

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

微信扫一扫,分享到朋友圈

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

当前AI的特点及工业影响

上一篇

约翰尼·德普辞演《神奇动物》第三部影片 格林德沃将换脸

下一篇

你也可能喜欢

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

长按储存图像,分享给朋友