愛奇藝知識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 工具統一發布,發佈前應進行自動化測試,以完成很好的測試覆蓋等等。

當然在實際開發工作中會有許多不理想的情況,比如一個小項目沒有那麼多重複的代碼,比如設計團隊不認可組件化等等,所以組件化需要考慮具體的業務場景,在這個前提下設計出符合我們自身的組件化系統纔有必要。

也許你還想看
優化無止境,愛奇藝中後臺 Web 應用性能優化實踐
一切數據皆可配置:愛奇藝海外站的運營後臺設計實踐

 掃一掃下方二維碼,更多精彩內容陪伴你!

本文分享自微信公衆號 - 愛奇藝技術產品團隊(iQIYI-TP)。
如有侵權,請聯繫 [email protected] 刪除。
本文參與“OSC源創計劃”,歡迎正在閱讀的你也加入,一起分享。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章