写点什么

爱奇艺知识 WEB 前端组件化实践

  • 2021-02-03
  • 本文字数:4531 字

    阅读完需:约 15 分钟

爱奇艺知识WEB前端组件化实践

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


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


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

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


组件化的意义在于提效,交付的产物是可用的、直观的、可组合的业务形态。


目前行业内前端组件化按面向使用人群大致可分为 3 类:


面向运营人员:运营人员主要进行页面的创建、设计,组件类似乐高积木一样,拼凑起来,针对特殊的组件,可交给开发人员定制实现,实现一些偏静态或者偏固定功能(如抽奖、问答、支付等)的页面,各个大厂一般都有自己 Low Code 平台下类似的产品。

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

面向开发人员:这也是最传统的开发模式,主要针对的是动态的页面,需要后端接口配合的场景,各个页面的组件通用,所以抽离出来公共组件供各个页面调用。

爱奇艺知识的组件化设计属于第三种,也即是面向开发人员而设计的。在开发层面,通过组件的复用,能够减少冗余代码、实现功能和业务逻辑的解耦,并且通过组件的拓展提高可拓展性、可维护性


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

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



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

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


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


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


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

1. 代码复用,提升开发效率

根据业务特点,横向和纵向划分组件,以组件为单位承接业务需求。虽然以 UI 组件为主,但对于相对独立的功能,也进行了纵向的组件抽取。

2. 组件独立开发维护,与各项目解耦

组件单独开发、调试、发布,供业务方调用,业务方只需专注业务本身。

3. 更方便的组件调用,更合理的路由跳转

组件调用需明确输入、输出参数,并对参数进行校验并给出合理错误提示;当各项目引用业务组件 涉及到跳转时,组件库自动决定是项目内(前端路由)跳转还是项目外(location.href)跳转。

4. 组件文档化,支持在线调试,降低组件使用门槛

组件库需要有完善的使用说明文档,支持在线调试,使业务方更加容易、便捷的使用。


整体设计

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


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



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



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



card 组件

基于以上设计,我们简单总结一下,组件按类别可分为:基础组件、业务组件。

其中基础组件可分为:基础 UI 组件、基础工具组件;业务组件可分为:item 组件、Card 组件、区块组件、功能组件、页面组件。

基础组件

  • 基础工具库:这是一组 JS 库,无 UI 界面,包含项目所使用的基础功能,如:网络请求、页面埋点、异常上报、与 Native 交互的 CallNative,以及一些常用 utility 工具等等。

  • 基础 UI 组件:包含了:文本、图片、按钮、布局、loading 加载、toast 提示等常用的 UI 组件。

业务组件

  • Item 组件:业务组件的最小单元,比如:列表中的一项,宫格中的一项,金刚位中的一项、轮播图中的某张图片等等。业务方可引入所需的 item 组件或组合 item 组件来完成页面的展示。

  • Card 组件:这是一套服务于 Card 化所对应的一套组件,这里简单介绍一下 Card 化:后端返回的是一套基于 Card 的数据结构,每个 card 数据与前端某一个 UI 组件一一对应,通过对数据的配置来实现对前端展现的控制。Item 组件也可以属于 Card 的一部分,由 Card 组件组合多个 Item 组件来进行界面的展示。

  • 区块组件:是为了完成某一个区块的 UI 展示,而抽离出来的组件,供业务方使用,比如:评论组件、评价组件等。

  • 功能组件:是为了完成某一项具体的业务功能而抽离出的组件,比如:播放器组件、发布器组件、分享组件等。

  • 页面组件:也叫路由组件,这是基于微前端所抽离的组件,我们的某个页面也可以当做组件,从而被其他项目所使用。

技术实现

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

设计原则

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

  • 需要统一技术栈,保证组件在同一技术生态。

  • 单一职责,一个组件只专注做一件事,且把这件事做好。

  • 追求无副作用,输入一但确定,输出就是固定的。

  • 可配置,一个组件要明确它的输入和输出分别是什么,同时入口处检查参数的有效性。

  • 粒度适中,划分粒度的大小需要根据实际情况权衡,太小会提升维护成本,太大又不够灵活和高复用性。每一个组件都应该有其独特的划分目的的,有的是为了实现复用,有的是为了封装复杂度 实现业务清晰的目的。

  • 适当的包体大小,便于页面快速加载。

  • 完善的使用说明文档。

数据协议

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


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


UI 实现

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


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

  • 图片组件,是在保留原生`img`的特性前提下,支持懒加载,自定义占位、加载失败占位、图片获取策略(webp or jpg);


  • 文本组件,支持 单行、多行截断。

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


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

构建工具

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

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

import { item40000, item40001, item40010, item40011} from '@iqiyi-kpp/ui-biz-vue'
复制代码

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

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


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


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

技术文档

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



总结

前端组件库一般是放到公司的私有仓库上,通过 npm 进行维护的,使用方需要 引用并打包到自己的项目内才能使用。随着 webpack5 module federation 的流行,也可以将组件当作微模块单独发布,各使用方可通过动态 load module 的方式进行引用


由此也可以看到前端组件化的优势:可以很大程度上降低系统各个功能的耦合性,这对前端工程化及降低代码的维护成本来说,是有很大的好处的。


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


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


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


本文转载自:爱奇艺技术产品团队(ID:iQIYI-TP)

原文链接:爱奇艺知识WEB前端组件化实践

2021-02-03 07:004960

评论

发布
暂无评论
发现更多内容

奥运背后的5G赛场,竟然也这么激烈?

脑极体

写作 7 堂课——【4. 联机式写作】

LeifChen

素材 写作技巧 8月日更 联机 写作网感

架构训练营模块四作业

Lemon

未来的价值互联网主要建立在NFT上

CECBC

极光开发者周刊【No.0806】

极光JIGUANG

你知道Kafka创建Topic这个过程做了哪些事情吗?(附视频)

石臻臻的杂货铺

大数据 kafka 源码 运维

php 精度问题

一个大红包

8月日更

jackson解析泛型的正确写法

4ye

Java Jackson 8月日更

有什么理由将代码保存为 GBK 编码

HoneyMoose

阿里P8教你Java注解与反射

陈皮的JavaLib

Java 面试 8月日更 java注解 反射机制

负载均衡的原理与设计

海明菌

负载均衡 负载均衡算法 负载均衡架构

碳中和将为中国带来什么? 绿色转型如何驱动经济跃升?

CECBC

关于区块链的学习笔记(三)

姬翔

【设计模式】外观模式

Andy阿辉

C# 后端 设计模式 8月日更

“善于治”和“以善治”:华为云Stack在智慧城市的十年踪迹十年心

脑极体

绝绝子!腾讯大牛1909页的leetcode刷题笔记,细节满满

Java 编程 架构 面试 程序人生

Java 面试都只是背答案不

HoneyMoose

不装了、摊牌了,我们要搞事情

不脱发的程序猿

程序员 技术 程序人生

全国有待形成数据资产市场 区块链、人工智能或成重要支撑技术

CECBC

关于区块链的学习笔记(二)

姬翔

网络攻防学习笔记 Day100

穿过生命散发芬芳

态势感知 网络攻防 8月日更

【前端 · 面试 】HTTP 总结(九)—— HTTP 协商缓存

编程三昧

面试 8月日更 HTTP缓存

到底该怎么定义 To B SaaS 产品

姜雨生

SaaS 标准化 To B业务 行业深度

【LeetCode】超级丑数Java题解

Albert

算法 LeetCode 8月日更

Grafana 配置 Thanos 查询历史数据

耳东@Erdong

Grafana Prometheus Thanos 8月日更

趁着课余时间学点Python(八)函数的简单理解

ベ布小禅

8月日更

JavaScript中的 async 和 await

devpoint

Promise Async await 8月日更

【架构实战营】毕业总结

Geek_2e7dd7

python-抽象

加里都好

番外4. Python OpenCV 中鼠标事件相关处理与常见问题解决方案

梦想橡皮擦

8月日更

关于区块链技术的学习笔记(一)

姬翔

爱奇艺知识WEB前端组件化实践_大前端_爱奇艺技术产品团队_InfoQ精选文章