组件化作为一种开发模式,其在代码复用,提高开发效率上的效果被广泛认可。组件化思想适用于移动端、Web前端、PC端、TV端等多种类型的客户端和前端开发

本文主要讲述爱奇艺知识 WEB 前端团队如何结合自身的业务特点,探索和实践了一套高效的前端组件化方案。

组件化:前端解耦和提效利器

前端业务发展过程中,代码体积会越来越大,业务的逻辑复杂程度也会随着迭代越来越高。

组件化的意义在于提效,交付的产物是可用的、直观的、可组合的业务形态。目前行业内前端组件化按面向使用人群大致可分为3类:面向运营人员:运营人员主要进行页面的创建、设计,组件类似乐高积木一样,拼凑起来,针对特殊的组件,可交给开发人员定制实现,实现一些偏静态或者偏固定功能(如抽奖、问答、支付等)的页面,各个大厂一般都有自己 Low Code 平台下类似的产品。

面向设计人员:设计人员主要参与页面设计,并直接将设计稿转换成前端代码,省去前端的开发过程,比如阿里的 imgcook,也可针对一些复杂逻辑,可交给开发人员进行二次开发。

面向开发人员:这也是最传统的开发模式,主要针对的是动态的页面,需要后端接口配合的场景,各个页面的组件通用,所以抽离出来公共组件供各个页面调用。爱奇艺知识的组件化设计属于第三种,也即是面向开发人员而设计的。在开发层面,通过组件的复用,能够减少冗余代码、实现功能和业务逻辑的解耦,并且通过组件的拓展提高可拓展性、可维护性

业务场景:项目多且独立、又要保持产品一致性

具体到组件的拆分,目前在业内并没有统一的标准,需要结合具体的业务场景,因为不同场景下组件拆分的力度、程度可能都有所不同。

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(1)

爱奇艺知识 WEB 前端项目构成

从爱奇艺知识WEB前端项目构成可以看到,知识Web前端的项目很多,我们把项目按类型分开,每个分类下的项目都是独立的项目,完成其相关的业务功能,各项目是独立开发、独立部署的,并且项目间没有直接的业务关联。项目虽然多,但项目中都有业务相关的课程、讲师、店铺等实体,而这些实体的UI样式在各个项目中要基本保持一致,另外一些通用的UI元素,比如弹框、loading等也要保证风格一致,因此为了产品体验一致性,同时提升开发效率,提高代码复用性,Web前端需要进行组件抽离

在这里需要简单说明一下,我们Web端组件化思路和知识移动端团队在组件化的思路是不太一样的,移动端更多的是从业务和功能的纵向进行组件划分,也可以称之为模块化,每一个组件或模块既包括UI又包括业务逻辑,比如播放器组件播控播放控制和UI样式,分享组件包括分享功能和弹窗,支付组件包括支付流程和收银台支付结果页;而Web前端的组件化更偏重UI层面,逻辑更多的是放在页面中,这也符合Web开发的特点,UI元素复用性更高

感兴趣的同学可以了解一下移动端组件化的设计思路,传送门在这里:爱奇艺知识移动端组件化探索和实践。

根据上述背景,知识Web前端进行了相应的组件化建设,目标如下:

1. 代码复用,提升开发效率根据业务特点,横向和纵向划分组件,以组件为单位承接业务需求。虽然以UI组件为主,但对于相对独立的功能,也进行了纵向的组件抽取。2. 组件独立开发维护,与各项目解耦组件单独开发、调试、发布,供业务方调用,业务方只需专注业务本身。3. 更方便的组件调用,更合理的路由跳转组件调用需明确输入、输出参数,并对参数进行校验并给出合理错误提示;当各项目引用业务组件 涉及到跳转时,组件库自动决定是项目内(前端路由)跳转还是项目外(location.href)跳转。4. 组件文档化,支持在线调试,降低组件使用门槛组件库需要有完善的使用说明文档,支持在线调试,使业务方更加容易、便捷的使用。

整体设计

任何工具的设计都需要从实际的业务场景出发,回到我们的场景下,需要考虑如何管理项目间所依赖的公共组件资源变得非常重要,组件的设计既要符合业务方使用的便利性,同时也要满足组件自身开发的可维护性、可扩展性

我们认为,组件化的关键在于组件的分层以及拆分,明确组件的层级以及对层级的定义对于组件化系统至关重要。下面是基于我们自身的业务,我们将组件进行如下分层(图示):

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(2)

为了更好的理解,我们将层级之间的关系进行如下展示(图示):

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(3)

由于 Card 组件由多个 Item 组件组成,所以 Card 组件与 Item 组件的关系如下:

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(4)

card组件

基于以上设计,我们简单总结一下,组件按类别可分为:基础组件、业务组件。其中基础组件可分为:基础 UI 组件、基础工具组件;业务组件可分为:item 组件、Card 组件、区块组件、功能组件、页面组件。

基础组件

业务组件

技术实现

由于基础组件、区块组件、功能组件已经是非常通用的设计,这里我们重点介绍一下业务组件中的Card 组件、Item 组件。需要注意的是,不管是基础组件还是业务组件,我们在设计之初都需要让其符合以下设计原则。

设计原则

我们的组件设计原则需满足如下要求:

数据协议

在项目初期,我们的 H5 移动端首页:https://zhishi.m.iqiyi.com 是基于后端的 Card 化数据,由后端数据选择前端的 Card 组件、Item 组件来进行页面的展示,在这种场景下,我们的 Card 组件、Item 组件首先被设计出来,与此同时我们设计了一套前端数据协议(可以理解为数据格式定义),后端 Card 数据经过前端协议后,转换成前端的 Card 数据结构,在此数据结构的基础上进而抽离出 Card 组件、Item 组件。

后来发现我们大量的页面并非基于 Card 化数据,而是基于不同的 API 、不同的数据结构,如何让这些页面也复用我们的 Card 组件、Item 组件呢?为此我们需要不同的转换器,将后端的接口数据根据前端数据协议转换为 前端的数据格式(如下图),这样无论后端接口数据如何改变,我们只需更改转换器的逻辑,而无需更改前端组件代码,进而复用我们的 Card 组件、Item 组件。

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(5)

UI 实现

在具体的 UI 实现方面,我们拿下图中我们的业务 UI 组件库内常用的两个Item举例:课程列表 Item、课程宫格 Item

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(6)

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(7)

不难发现Item 组件主要是由 图片、文本组成的,而图片、文本恰好又属于我们的基础 UI 组件库范畴。

所以我们在编写 Item 组件的时候只需组合图片、文本组件即可,这样后期随着我们组件数量增长,当我们开发其他 Item 组件的时候会变得非常轻松,效率也得到极大提升。

还有一点需要注意的是:可能我们的组件需要同时满足在移动端手机、平板、 PC端的正常展现,这样就会涉及到布局以及屏幕适配的问题,同时也涉及到设备旋转带来的屏幕尺寸动态变化的问题。所以在组件在设计的时候 宽、高不能定死,而是引用方设定的,同时我们需要在组件内兼容不同屏幕的适配样式,也可以分别导出不同屏幕的适配样式文件供引用方使用。

构建工具

由于基础工具库是一组 JS 库,所以我们使用 rollup 构建,它是一个高效的 library 模块打包器,可以使我们的组件更加轻量、简洁,同时生成 es, umd 格式文件供前端调用。

UI 组件库,我们使用 VUE 作为前端技术栈,使用 Webpack 进行构建,业务组件项目支持导出多个组件入口,支持业务组件按需加载(如下所示)

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(8)

组件支持按需加载就意味着,各组件入口需要单独打包,这会涉及到各入口的公共资源重复引用的问题。

我们可以使用@babel/runtime,@babel/plugin-transform-runtime,设置 core-js false,做大限度减小 babel 转换的包体。

使用 babel 命令打包 JS 文件(不使用 webpack),减小 JS 包体。

使用 webpack externals 将第三方依赖,以及每个组件的公共引用提出来,通过 require 的方式去引用,而不是重复打包到每个组件内。

技术文档

我们的组件库开发完成,并不意味着组件化这件事就算做完了,一个良好的组件库往往需要有一个良好的文档说明,这样会降低团队成员的沟通成本,所以基于 storybook 我们搭建了 UI 组件的文档站点,比如下图的基础 UI 组件库文档,可动态展示最新的组件版本,同时支持 UI 组件在线调试,更能直观的表达组件样式与交互,增强了组件的易用性。

网站建设分析爱奇艺(爱奇艺知识WEB前端组件化实践)(9)

总结

前端组件库一般是放到公司的私有仓库上,通过 npm 进行维护的,使用方需要 引用并打包到自己的项目内才能使用。随着 webpack5 module federation 的流行,也可以将组件当作微模块单独发布,各使用方可通过动态 load module 的方式进行引用。由此也可以看到前端组件化的优势:可以很大程度上降低系统各个功能的耦合性,这对前端工程化及降低代码的维护成本来说,是有很大的好处的。

爱奇艺知识 WEB 前端组件库经过不断的完善和迭代,基本实现了组件化的全部目标,组件通过独立开发、测试、发布,使得各业务项目只需关注本身业务,组件得到充分复用,目前组件化已成功运用到各个业务项目中。

组件化并非一蹴而就,而是一个持续的过程,比如:随着业务组件会变得很多,业务组件需要支持业务方按需加载,同时需要考虑组件的包体大小,不能因组件包体过大导致页面加载过慢;业务组件应该通过类似 Jenkins 工具统一发布,发布前应进行自动化测试,以完成很好的测试覆盖等等。

当然在实际开发工作中会有许多不理想的情况,比如一个小项目没有那么多重复的代码,比如设计团队不认可组件化等等,所以组件化需要考虑具体的业务场景,在这个前提下设计出符合我们自身的组件化系统才有必要。

,