【前端組件化】系列第一篇——方案探究

前端組件化系列文章第一篇:前端組件化方案探究

背景

公司目前基于多業(yè)務(wù)部門,很多業(yè)務(wù)組件和功能邏輯都具有較高的普適性,但與此同時各業(yè)務(wù)部分和開發(fā)人員缺乏一定的交流平臺,更多的是在遇到對應(yīng)需求時會簡單內(nèi)部討論一番,當(dāng)了解到其他業(yè)務(wù)部門存在落地的方案時,再進(jìn)一步進(jìn)行溝通交流。

這種方式,總體來說還是比較原始的,無論從溝通方式的效率來說,還是對于組件業(yè)務(wù)邏輯的深入理解都是非常低效的。因此,對于探索一種高效的、簡單的、現(xiàn)代化方案是非常有必要的。

我們想要的結(jié)果是(任務(wù)目標(biāo)):

  1. 不同的業(yè)務(wù)平臺開發(fā)的組件能夠最大程度復(fù)用;
  2. 新人能夠快速了解通用組件,提升開發(fā)效率

這也就是本系列文章的真實(shí)背景,也是我著手負(fù)責(zé)的項目,相關(guān)文章會按照系列形式輸出,并確保文章內(nèi)容都是在真實(shí)業(yè)務(wù)中的實(shí)踐總結(jié)。

簡要說明

作為本系列的第一篇文章,其定位和作用也是相當(dāng)清晰的:

  1. 搞清楚前端組件化是什么?
  2. 搞明白組件化要怎么做?
  3. 思考如何把組件化做的更好?

前期主要以第1、2兩點(diǎn)作為執(zhí)行方向進(jìn)行探索,在基本明白了什么是組件化以及如何實(shí)現(xiàn)自己的組件化之后,進(jìn)一步探索、對比、研究、思考如何實(shí)現(xiàn)高效能的組件化方案。

前端的發(fā)展路徑

在互聯(lián)網(wǎng)早期階段,傳統(tǒng)的開發(fā)模式中,往往是把前端的網(wǎng)頁代碼和后端的程序代碼混合在一起,借助某種模板技術(shù)(如 JSP、ASP、PHP)來在服務(wù)器端動態(tài)生成 HTML 頁面。

在這種開發(fā)模式下,網(wǎng)頁的每次改動都需要前后端人員共同參與才能完成,網(wǎng)站前后端的開發(fā)人員需要很大的溝通成本、協(xié)調(diào)成本。企業(yè)招人的時候,也不得不招一些既懂前端又懂后端程序員,來減少前后端開發(fā)人員的沖突。

可以發(fā)現(xiàn)這種模式是非常低效的。

現(xiàn)在流行的前后端分離的開發(fā)模式,就是讓后端只負(fù)責(zé)給前端提供數(shù)據(jù),由前端負(fù)責(zé)整個頁面的模板渲染、數(shù)據(jù)填充以及交互邏輯。

前后端分離之后,人們發(fā)現(xiàn)前端已經(jīng)不再是傳統(tǒng)意義上的網(wǎng)頁了,它甚至還可以做成一個手機(jī)應(yīng)用,或者做成是微信小程序那樣的小型應(yīng)用,它更接近于傳統(tǒng)的 B/S(客戶端/服務(wù)器)架構(gòu),且仍然具備網(wǎng)頁輕量級、無需下載和安裝的優(yōu)勢

什么是組件化

在前后端分離的現(xiàn)代開發(fā)模式下,以React、Vue為例,涌現(xiàn)了很多優(yōu)秀的現(xiàn)代化的前端框架,得益于新技術(shù)的發(fā)展,SPA 應(yīng)用已經(jīng)相當(dāng)成熟,該開發(fā)范式也是相當(dāng)普遍。

伴隨著這種技術(shù)行為,組件化開發(fā)也是應(yīng)運(yùn)而生,作為一個非常常規(guī)的模式,圍繞幾點(diǎn)說明:

  1. 方便復(fù)用(很多業(yè)務(wù)代碼、功能代碼都不可避免有所重復(fù),對于組件的復(fù)用使用,可謂作用很大)
  2. 方便維護(hù)(如果大量的業(yè)務(wù)代碼與功能代碼耦合一起,對于代碼的日后維護(hù)和功能拓展都有著很大的局限性和不足)
  3. 功能細(xì)分、專一、職責(zé)明確(組件的核心原則就是,一個組件只做一件事,而且其不應(yīng)該是有上下強(qiáng)關(guān)聯(lián)耦合性的,可以隨用隨取,做到職責(zé)單一,對于日后功能迭代和代碼維護(hù)好處都是顯而易見的)

就現(xiàn)代前端而言,我覺得組件化已不單單局限于 UI 組件層面,它涉及面更廣、更全、也更系統(tǒng)化,類似 hooks 的功能和業(yè)務(wù)邏輯封裝,工具類的使用封裝,構(gòu)建工具、腳本代碼等,一切符合其獨(dú)立思想的都可稱為組件化。

為什么需要組件化

組件化的目的:

  1. 為了讓各功能和業(yè)務(wù)邏輯可以被復(fù)用,以減少重復(fù)的代碼。
  2. 可以更好地使團(tuán)隊分工協(xié)作,不同的人負(fù)責(zé)編寫不同的組件,提高開發(fā)效率。
  3. 職責(zé)單一也更方便功能的迭代拓展與維護(hù),對于接手的開發(fā)人員也能降低不少上手成本

對于需要開發(fā)復(fù)雜的大型應(yīng)用的企業(yè)來說,組件化開發(fā)能極大地提高開發(fā)效率,它讓前端開發(fā)團(tuán)隊能高效地完成工作,是一個非常有用的技術(shù)。

簡單來說就是兩個關(guān)鍵詞:“復(fù)用”、“易維護(hù)

代碼拆分也好,職責(zé)單一也好,基本都離不開這兩詞,這也正式組件化的核心點(diǎn)。我們做這些事,就是為了之后遇到類似需求和功能的時候減少代碼的開發(fā),能夠快速重復(fù)使用。而對于組件在日后隨著功能和業(yè)務(wù)的發(fā)展、包括我們對于組件代碼健壯性的提升,都會進(jìn)行不斷的迭代,維護(hù)性的重要性也是不言而喻的了。

基本目標(biāo)

圍繞核心述求可以進(jìn)一步細(xì)化梳理,我們希望它能夠這樣:

  1. 可以圍繞基礎(chǔ)組件、業(yè)務(wù)組件,以及工具類的定位進(jìn)行劃分
  2. 項目方案要足夠簡單清晰,確保新人上手成本足夠低,可以快速投入開發(fā)使用
  3. 組件的可維護(hù)性需要有保障
  4. 嚴(yán)格的規(guī)范和工程化保障
  5. 支持查看API、示例的文檔網(wǎng)站
  6. 真實(shí)開發(fā)環(huán)境的模擬調(diào)試和開發(fā)
  7. 能夠以npm包的形式進(jìn)行引用使用
  8. 可靠的多包項目管理、多包版本管理
  9. 足夠優(yōu)秀的性能表現(xiàn)

技術(shù)背景

首先,以公司實(shí)際項目為背景思考,我們的技術(shù)棧目前主要圍繞 vue2 相關(guān)生態(tài)進(jìn)行前端 web 后臺類系統(tǒng)的開發(fā)。因此,主要方案設(shè)計也要以此為基礎(chǔ)導(dǎo)向進(jìn)行探索。

就目前而言,我們的組件主要包括可復(fù)性較高的業(yè)務(wù)組件以及一些通用功能組件,也包括一些工具類。組件開發(fā)主要依賴于iview基礎(chǔ)組件和lodash工具庫,部分特殊業(yè)務(wù)有使用到monaco-editor、codemirror等。

因此,現(xiàn)階段我們公司的技術(shù)棧相關(guān)生態(tài)主要為 vue2,本系列也會以公司的vue2項目經(jīng)歷為依托進(jìn)行記錄。不過結(jié)合當(dāng)下前端整體快速發(fā)展的現(xiàn)實(shí)情況下考慮,在項目實(shí)施落地之后,對相關(guān)生態(tài)具有足夠清晰地掌握之后,以vue3react為技術(shù)背景的探索也值得進(jìn)一步探索研究。

包依賴

我們公司當(dāng)前項目平臺主要依賴分析,如下:

  • 核心三大件:vue/vue-router/vuex
  • UI 類:view-designcodemirror、monaco-editor、vue-echarts、vuedraggble
  • 工具類:lodash、dayjs、uuid

圍繞以上技術(shù)相關(guān)生態(tài),做到對各部分及功能使用的二次封裝管理

主要 API 及實(shí)際項目代碼分析:

  • slot:組件拆分、UI 布局、自定義展示區(qū)域的好方法
  • props:父組件向子組件傳遞參數(shù)
  • ref:父組件獲取子組件方法、屬性
  • emit:子組件向父組件傳遞參數(shù),觸發(fā)父組件綁定事件方法
  • provide/inject:多級子父組件傳值
  • vuex:第三方狀態(tài)管理(需要考慮單一組件的可維護(hù)性)

總的來說組件封裝較頻繁使用的屬性方法為props/slot/emit/ref,也是我們項目中大量采用的方式。

vuex 的使用需要謹(jǐn)慎考慮,具有一定的耦合性,需要進(jìn)一步探索分析。

對于更優(yōu)的方式探索值得思考,核心點(diǎn)為職責(zé)單一獨(dú)立、耦合性低,方便維護(hù)。

功能/業(yè)務(wù)組件

業(yè)務(wù)組件不同于功能組件,其具有一定的使用背景和條件限制。以我們使用的 iviewantd等UI組件為例,其提供了大量的功能組件,包括但不限于表單功能組件、Table列表功能組件、多選/單選功能組件、日期功能組件等等,它只提供某一類的通用功能,并抽象封裝為一個具體的功能組件。

而相對于業(yè)務(wù)組件來說就有些許不同了,業(yè)務(wù)組件首先必定聚焦于一個明確的業(yè)務(wù)場景,其最終實(shí)現(xiàn)可能是融合了多個功能組件的組合,也可能是結(jié)合一些插件獨(dú)立實(shí)現(xiàn)的某一特殊功能。

當(dāng)前項目已存在的一些業(yè)務(wù)組件分析:

  • ProTable功能組件:由單個FilterBtn組件Table組件、Pagination組件,進(jìn)而組合成整體的一個組件(包含列表、篩選、分頁)
  • ComSqlTipTree業(yè)務(wù)組件:使用頻率相當(dāng)高的 ComSqlTipTree組件,也是集合了眾多子組件的一個組合(涉及到對Input的高級封裝、Select選擇、拼音匹配、列表展示等,該組件專門用于公司核心功能篩選類查找時的使用)

組件管理思考

  1. 基礎(chǔ)組件類:可以參照iview、antd等UI組件庫的方式進(jìn)行維護(hù)管理,聚焦于功能相關(guān),屬于較小型的組件,統(tǒng)一維護(hù)管理。
  2. 業(yè)務(wù)組件類:可以參照pro-component高級組件的管理模式進(jìn)行處理。
  3. 工具類:可以參照lodash的方式進(jìn)行維護(hù)管理

pro-component的管理模式為大量基于基礎(chǔ)組件封裝而成的高級組件,如:pro-layout、pro-tablepro-form等,每個組件可以作為獨(dú)立的npm包作為依賴使用,相互獨(dú)立、互不影響。

再思考到對于工具類的管理維護(hù),整體考慮下來,基本確定可以為多包管理的方向(Monorepo

技術(shù)調(diào)研

圍繞項目技術(shù)背景和目標(biāo)規(guī)劃,進(jìn)行相關(guān)技術(shù)調(diào)研。

相關(guān)開源項目分析

  1. 需要考慮的方向是:對于 vue2.x 版本的組件化方案,哪種更為合適(目前市面上有大量的vue3組件庫)
  2. vue2 對于 TS 的考慮 (vue2對ts的支持性一般,是否支持視情況而定)
  3. props 參數(shù) API 的文檔、demo演示,文檔網(wǎng)站建設(shè)的考慮
  4. 目錄設(shè)計、工程規(guī)范、構(gòu)建發(fā)布流程
  • element
    • monorepo,屬于比較傳統(tǒng)的單一包管理項目
    • 比價經(jīng)典的vue2組件庫項目,文檔網(wǎng)站風(fēng)格很不錯
    • 主要使用 js + vue開發(fā),構(gòu)建由webpack處理
    • 文檔網(wǎng)站由自身組件開發(fā)搭建,結(jié)合webpack loader實(shí)現(xiàn)對markdown文件的編譯及demo示例的渲染
  • vuetify
    • lernajs + yarn + workspace 的方案,標(biāo)準(zhǔn)的 lernajs + yarn 用法
    • vue2.x + ts 寫法,組件大量以 JSX 實(shí)現(xiàn),具有很好的參考學(xué)習(xí)價值(vue2 中對 TS 的使用)
    • 文檔網(wǎng)站由自身組件自行開發(fā)搭建,項目代碼較多,有一定的上手成本
  • element-plus
    • vue3 的項目,pnpm + workspace 的方案,整體思路和設(shè)計非常現(xiàn)代化
    • 組件實(shí)現(xiàn)由 vue編寫開發(fā),相關(guān)腳本代碼由 TS編寫,整個項目為 TS項目
    • 多包目錄設(shè)計、組件和文檔目錄設(shè)計合理
    • 相關(guān)構(gòu)建工具包括 rollupesbuild、vite
    • 文檔網(wǎng)站由vitepress構(gòu)建,并自行編寫了處理markdownvue demo的插件進(jìn)行處理(vitepress只支持vue3
  • idux
    • vue3 的項目,pnpm + workspace 的方案,技術(shù)都比較新
    • 版本控制由 lerna管理
    • demodocs的目錄管理很不錯,需要配合腳本實(shí)現(xiàn)最終的網(wǎng)站路由和渲染
    • 文檔網(wǎng)站由 vitepress + 自身組件構(gòu)建,并配合各種腳本實(shí)現(xiàn)對應(yīng)功能
    • 構(gòu)建工具主要為 gulp
    • 組件開發(fā)主要為 tsx形式

monorepo 是什么

  • Monorepo:所有依賴庫完全放入一個項目工程
  • Multirepo:多個依賴包獨(dú)立進(jìn)行 git 管理

monorepo 是把多個項目的所有代碼放到一個 git 倉庫中進(jìn)行管理,多個項目中會有共享的代碼則可以分包引用。整個項目就是有 root 管理的 dependencies 加上多個 packages,每個 package 也可以在自己的作用域引入自己的 dependencies

該方案可以很好的幫助我們解決不同工作區(qū)對于相同依賴的管理,以及我們在開發(fā)時,包相互間依賴的管理。

monorepo + lernajs + yarn

Lerna 是一種工具,針對使用 gitnpm 管理多軟件包代碼倉庫的工作流程進(jìn)行優(yōu)化。

Lerna 有兩種管理項目的模式:

  • Fixed/Locked 模式 (默認(rèn)): 所有的包共用一個版本號。
  • Independent mode:不同包獨(dú)立使用自己的版本,我們一般采用這種方式。在初始化的時候指定 --independent 參數(shù)

一般而言,在pnpm未出現(xiàn)前,相關(guān)workspace概念基本是配合 yarn一起使用(yarnworkspace功能),因為 npm7.x之前是沒有 workspace概念的,所以在很長的一段時間里,多包管理方案 monorepo都是與 yarn一起配合使用。

他解決了以下問題:

  • 多業(yè)務(wù)組件、互相依賴、無法復(fù)用
  • 發(fā)包流程復(fù)雜、版本管理痛苦

依賴管理

在工作區(qū) packages 下面我們有這些包:iview、pro-sqltiptree、components,其 package.json 中的 name 定義分別為@ah-ailpha/iview、@ah-ailpha/pro-sqltiptre、@ah-ailpha/components,在我們相互安裝包時,lerna 工具可以幫我們以用軟鏈接的形式直接使用。(對于軟鏈接的概念可以參考 npm link,以及pnpm的底層實(shí)現(xiàn)邏輯)

# 向 module-2 中添加 module-1 作為依賴
$ lerna add module-1 --scope=module-2

版本管理

對于monorepo的多包場景,lerna另一大核心功能就是可以很好的幫助我們管理每個包的版本,通過使用 lerna version命令即可(可結(jié)合命令式交互快速管理版本)

lerna version 在背后為我們做了這些事:

  • 識別出自上次發(fā)布以后更新過的包;
  • 提示選擇新版本;
  • 修改包的元數(shù)據(jù)來反映最新發(fā)版(修改包的版本號),在根目錄和每個包里面運(yùn)行生命周期腳本;
  • 對提交打 tag;
  • 推送到遠(yuǎn)程代碼倉庫。

monorepo + pnpm

pnpm現(xiàn)在也支持workspace的概念了工作空間(Workspace),如果是經(jīng)常關(guān)注技術(shù)社區(qū)論壇的,相信你對pnpm已經(jīng)有過了解了,pnpm因為其優(yōu)秀的性能表現(xiàn),以及其對monorepo的支持也更簡單方便,使得現(xiàn)在很多知名的開源項目都采用了該方案,如 Vue3/Vite/VueUse/Element Plus/Next.js/Astro等等。

pnpm 內(nèi)置了對單一存儲庫(也稱為多包存儲庫、多項目存儲庫或單體存儲庫)的支持, 你可以創(chuàng)建一個 workspace 以將多個項目合并到一個倉庫中。

一個 workspace 的根目錄下必須有 pnpm-workspace.yaml 文件, 也可能會有 .npmrc 文件。

如何高效的使用 pnpm,需要了解幾個常用的基本命令:

  • --filter:過濾,過濾允許您將命令限制于包的特定子集,一般用于 packages/* 下面的子項目。
  • -C:在 <path> 中啟動 pnpm ,而不是當(dāng)前的工作目錄。
  • -r:安裝在所有 packages 中(一般配合--filter指定項目目錄)
  • -w:表示把包安裝在 root 下,該包會放置在 <root>/node_modules

pnpm同樣可以實(shí)現(xiàn)對包依賴的管理,類似lerna一樣,通過軟連接的方式關(guān)聯(lián)到子項目,可以極大的方便我們對于多項目依賴的管理。

pnpm add <package-name> --filter <target-package-name>

# 比如要將lodash裝到package-a下
# --filter 后面可以為目錄名稱也可以為 package.josn 的 name 名稱
pnpm add dayjs --filter @ah-ailpha/package-a

# 向 module-2 中添加 module-1 作為依賴
pnpm add module-1 --filter module-2

lerna / changeset 版本管理分析

不管對于 yarn還是 pnpm來說,都只是對于工作空間 woekspace的多包管理,對于多依賴管理,pnpm目前可以支持,而yarn是需要lerna進(jìn)行協(xié)助的。

但是對于各包的version版本控制,兩者都不直接參與管理,只能使用第三方工具進(jìn)行處理。

lerna

目前已知的比較成熟的方案有lerna,也是使用比較頻繁的,好處是其功能比較全面,但也存在一些明顯的問題

  1. 不能和pnpm很好的適配,lerna 本身不支持 workspace 協(xié)議,導(dǎo)致基于 pnpm 開發(fā)的一些倉庫無法使用
  2. lerna version 根據(jù) commit 以及 tag 更新出來的包版本不符合預(yù)期
  3. 整個包的體積很大,依賴特別多(輕量版lerna-lite
  4. 相比較pnpm而言,lerna使用起來還是比較的笨重、繁瑣

changeset

Changesets 是一個用于 Monorepo 項目下版本以及 Changelog 文件管理的工具(目前一些比較火的 Monorepo 倉庫都在使用該工具進(jìn)行項目的發(fā)包例如 pnpm、mobx 等)

changesets 主要關(guān)心 monorepo 項目下子項目版本的更新、changelog 文件生成包的發(fā)布。

一個 changeset 是個包含了在某個分支或者 commit 上改動信息的 md 文件,它會包含這樣一些信息:

  • 需要發(fā)布的包
  • 包版本的更新層級(遵循 semver 規(guī)范)
  • CHANGELOG 信息

總的來說,changeset的工作內(nèi)容還是比較明確的,我們需要直接參與的就是包版本的管理與發(fā)布,對于changelog的文件生成會由腳本自動處理,我們無需關(guān)心(需要按照commitlint規(guī)范提交message,這里到時我們通過工程化的方式進(jìn)行控制即可)

版本控制管理小結(jié)

  1. 使用 yarn + monorepo的項目一般使用lerna配合進(jìn)行依賴和版本管理
  2. 采用 pnpm + workspace方案的 monorepo,可以選擇使用 changeset進(jìn)行版本管理控制,從而快速搭建一個完整的 monorepo項目。

尾聲

本篇文章算得上是搭建本項目的一些前期探究,在從0到1的過程還是比較迷茫的,使用什么方案,哪種方案適合我,在找到適合的方案時又發(fā)現(xiàn)并不是我喜歡的技術(shù)方向時,如何做出選擇,以及如何選擇最優(yōu)解等等,這些都是在我在實(shí)踐的過程中所經(jīng)歷的。

總的來說,我比較關(guān)注技術(shù)社區(qū)和開源項目,一般出現(xiàn)了什么新的技術(shù)框架時,我也能及時的了解和嘗試。在針對如何使用的這個問題上,通過結(jié)合官方文檔和開源社區(qū)各種demo模板,也能略知一二,再簡單上手使用對比下,大致能夠有所了解,就我個人的項目而言我還是滿喜歡嘗鮮的,覺得好用、不錯就會直接開整,遇到問題就嘗試解決,也算是在這個過程中學(xué)習(xí)了。不過,對于公司的項目來說,總體偏穩(wěn)定版、技術(shù)成熟度高、社區(qū)活躍的進(jìn)行選擇,在遇到問題時也能發(fā)現(xiàn)類似的解決方案。

monorepo算是我很早之前就打算研究和嘗試的方向了,苦于一直沒有合適的機(jī)會(??懶~),在沒有項目的推動下,自己也缺乏一定的動力,恰好現(xiàn)在公司在推進(jìn)這個事情,而且還是由我進(jìn)行負(fù)責(zé),也算得上是個不錯的機(jī)會了。

在開始之前我自己之前對于lerna是有一點(diǎn)了解的,因此,最開始在進(jìn)行技術(shù)調(diào)研的時候也是大致圍繞這個方向進(jìn)行的,期間也看了不少開源項目的設(shè)計和使用方式,基本上算是入門了,不過,在我自己進(jìn)行demo測試以及簡單使用后,發(fā)現(xiàn)lerna的確有很多不太方便、不易用的地方,尤其是對于多項目命令的支持,遠(yuǎn)不及pnpm來的方便。

pnpm對于我來說并不算陌生,我在去年就開始在用了,整體還是比較順手的,也比較喜歡,只是對于pnpm + workspace + monorepo這種方式?jīng)]有實(shí)踐過,不過在此之前倒是了解過不少相關(guān)的文章,印象較深的是介紹 vue生態(tài)的多包管理過渡到pnpm + workspace的文章,自己正好也一直想找機(jī)會嘗試來著。

因此,在使用lerna發(fā)現(xiàn)一些較大的短板之后,我也是順勢過渡為pnpm + workspace的方案來了,以及在后期嘗試了對于版本管理控制的changeset方案之后,最終確定的技術(shù)路線為pnpm + workspace + changesetmonorepo多包管理方案。

實(shí)踐篇相關(guān)文章見下一篇,歡迎關(guān)注(已經(jīng)在寫了??~)。

資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容