博客 / 詳情

返回

Elux-從"微前端"到“微模塊”

前言:作為“前端微模塊”這個概念有點新,之前雖然也有人提過這個詞(可百度),但都只是簡單的將其等同於動態加載模塊,並沒有賦予其更大的意義,好像也沒有看到具體的落地方案。小弟也是突發奇想,摸着石頭過河,想和大家討論一下“前端微模塊”會不會成為一片廣闊的天空?

微前端夠用嗎?

從產品的角度

某個大型應用包含A,B,C,D,E,F,G等若干功能,原來一直是整體打包出售...

隨着用户需求的多樣化,有的用户僅需要部分功能,於是聰明的前端架構師“小李”利用時下流行的微前端技術,將應用拆分成了 3 個子應用:

  • 【基礎應用】包含功能:A
  • 【子應用A】包含功能:B,C,D
  • 【子應用B】包含功能:E,F,G

這樣等於有 3 個套餐可以供客户選擇:

  • 套餐A:基礎應用 + 子應用A
  • 套餐B:基礎應用 + 子應用B
  • 套餐C:基礎應用 + 子應用A + 子應用B

然而用户的需求越來越精細化,有的需要ABCD,有的需要ACEG,有的需要ABDF,而且同一個功能可能還存在需求版本的不同,這讓“小李”無可適從。

“微前端”還不足夠靈活、粒度不足夠細。

從開發的角度

對於“發送短信驗證碼”、“忘記密碼”等某些通用的業務流程和功能,如果多個工程都需要,你是如何跨工程共享和維護的呢?是簡單的複製粘貼?還是一股腦全放基座裏面?

“微前端”並沒有解決工程之間代碼的複用和維護的問題。

將業務功能放進模塊

對於後端開發來説,按業務功能來劃分模塊幾乎是業界共識,而在前端開發中往往是按UI界面來切割模塊,這樣的前端模塊實際上只是Component組件,不具備獨立性與完整性。

如果我們將完整的業務功能(包括UI組件、樣式、圖片、交互流程、業務邏輯、API請求、數據管理等)都打包到一個NPM包中,並利用NPM的版本和依賴管理機制來維護客户需求,豈不美哉?

試想一下,某客户需要 A,C1(C功能的某個版本),E2(E功能的某個版本),G 功能,我們只需要安裝相應版本的NPM包:

npm install A C@1 E@2 G

業務模塊變成了NPM包,版本號被關聯至需求。

Great!我們稱這些包含完整業務功能的模塊為前端微模塊,可見所謂的微模塊其實就是包含業務功能的NPM模塊。

微模塊的劃分

微模塊是實現特定業務功能所需資源的集合:

  • 劃分視角: 業務功能(非UI界面)
  • 劃分原則: 高內聚、低耦合(有清晰的邊界)

請注意"高內聚、低耦合"是唯一的劃分標準,並不要求單一職責,所以一個微模塊中可能包含多個功能點、多個UI組件,一組相關視圖。

如果二個微模塊之間緊密依賴,交互密切,請不要分割它們,這樣會使問題複雜化。一種常用思路是藉助於後端Restful理念,將每種資源的維護(增刪改查封)裝成一個獨立的微模塊。

微模塊與UI組件的區別

微模塊和UI組件都是一個NPM包,似乎有點相似,但其實它們有本質的區別:

  • UI組件是一種單體的封裝;而微模塊是一種資源的集合。
  • UI組件為複用而生,可能在多處被實例化,通常不包含具體的業務邏輯;而微模塊並不追求通用性,它包含具體的業務邏輯,通常只需要初始化一次。
  • 微模塊可能包含多個UI組件、視圖、Model等,也可能只是邏輯,不包含任何UI。

微模塊的開發和維護

微模塊的開發和維護就是對NPM包的開發和維護,並不附加任何新的學習成本,你需要做的只是維護它的依賴關係,並對外封裝API,以保證獨立性與易用性。

微模塊的部署

通常有2種方式使用和部署微模塊:

  • 靜態編譯:微模塊作為一個NPM包被安裝到工程中,通過打包工具(如webpack)正常編譯打包即可。這種方式的優點是代碼產物得到打包工具的各種去重和優化;缺點是當某個模塊更新時,需要整體重新打包。
  • 動態注入:利用打包工具的動態加載功能(如webpack5 的 Module Federation)將微模塊作為子應用部署(與時下流行的微前端類似)。這種方式的優點是各子應用獨立部署運行,當某子應用中的微模塊更新時,其它應用無需重新編譯,刷新瀏覽器即可動態獲取最新模塊;缺點是沒有打包工具的整體編譯與優化,代碼和資源容易重複加載或衝突。
Elux對以上二種部署方式都有支持和示例。

Elux中的微模塊

我們先看一下時下流行的前端工程目錄,假設有獨立的功能ModuleAModuleB

src
├── assets
├── consts
│      ├── ModuleA
│      │      ├── Const1.ts //A中使用的一些常量
│      ├── ModuleB
│             ├── Const2.ts //B中使用的一些常量
├── utils
├── components
│      ├── ModuleA
│      │      ├── Component1.ts //A中使用的一些UI組件
│      ├── ModuleB
│             ├── Component2.ts //B中使用的一些UI組件
├── containers
├── pages
│      ├── ModuleA
│      │      ├── Page1.ts //A中使用的一些頁面
│      ├── ModuleB
│             ├── Page2.ts //B中使用的一些頁面
├── models
│      ├── ModuleA
│      │      ├── Store1.ts //A中使用一些狀態定義
│      ├── ModuleB
│             ├── Store2.ts //B中使用一些狀態定義
│

其特點是以“文件職能”作為一級分類、“功能模塊”作為次級分類。

現在如果我需要拿掉ModuleB,或者新增ModuleC,你將不得不進行多個目錄的操作。隨着文件越來越多,相互引用越來越複雜,ModuleB的相關資源和依賴像一堆亂麻散落在各個不同文件和文件夾中,你會發現要乾淨的剝離ModuleB是一個巨大的任務...

那應當如何改進呢?
  • 將“功能模塊”作為一級分類,“文件職能”作為次級分類
  • 注意模塊的對外封裝,不要隨意繞過封裝來引用模塊內部資源

以下是Elux工程的常用結構:

src
├── modules
│      ├──  ModuleA
│      │     ├── assets
│      │     │     ├── imgs //A中使用的一些圖片等
│      │     ├── consts
│      │     │     ├── Const1.ts //A中使用的一些常量
│      │     ├── utils
│      │     ├── components
│      │     │     ├── Component1.ts //A中使用的一些UI組件
│      │     ├── views
│      │     │     ├── View1.ts //A中使用的一些業務視圖
│      │     ├── model.ts //A的數據模型
│      │     └── index.ts //A的對外封裝與導出
│      │ 
│      ├── ModuleB
│      ├── ModuleC

可以看到在Elux工程中,所有與功能模塊相關的文件都被放到了一個獨立的文件夾中,並通過index文件統一對外導出,這便是Elux中微模塊得以獨立開發、安裝和運行的基礎。

微模塊vs微前端

微前端是一個廣義上的概念,微模塊也是實現微前端的一種解決方案。與之前狹義上的微前端相比,微模塊靈活性更高,但隔離性更差(只能依靠module和約定的namespace)。如果你沒有統籌整個項目的權利,或者項目本身就是異構系統(各子應用採用不同技術棧),那微前端還是首選方案。

如果用2個字概括它們的特點:

  • 微前端更加註重:隔離
  • 微模塊更加註重:自治

廣義與狹義的微模塊

或許你會説,不否認微模塊很好,可是我們項目體量還沒那麼大,也不需要拿到市場上去給客户定製,那微模塊對我來説沒啥意義呀?

其實我們以上所説的都是狹義上的微模塊,也就是嚴格遵循應用由微模塊組合而成,不存在其它全局資源與頂級組件,其目的就是保證微模塊的完整性,讓它們可以自由組合、獨立部署。

而廣義上的微模塊或許並不以獨立開發和部署作為目標,可以存在公共資源和組件,也無需真的將業務模塊發佈成一個個可安裝的NPM包,我們只是要藉助微模塊這種解耦模式來組織我們的代碼。

不管你是不是真的需要獨立開發和部署微模塊,以微模塊的模式來架構我們的應用,讓資源高內聚、低耦合,讓工程保持清晰的脈絡結構,提高代碼的可維護性和可複用性,這才是廣義上微模塊能給我們的啓迪。

實例演示

為了證明該想法非紙上談兵,可以看看我的開源項目:Elux-基於“微模塊”和“模型驅動”的跨平台、跨框架『同構方案』,裏面的所有工程模版都是基於“微模塊”思想而架構的,其中Micro: 基於Webpack5的微前端 + 微模塊方案這個模版是以上所謂的“狹義上的微模塊”,也就是以獨立開發和部署為目標的“微模塊”,其它工程只是“廣義上的微模塊”。

安裝方法:

npx @elux/cli-init elux-init
@elux/cli-init@2.1.1
新建項目: /Users/hiisea/work/elux/aaa
totally [44P] templates are pulled from ...

? 請選擇平台架構 
  CSR: 基於瀏覽器渲染的應用 [16P] 
  SSR: 基於服務器渲染 + 瀏覽器渲染的同構應用 [8P] 
❯ Micro: 基於Webpack5的微前端 + 微模塊方案 [8P] 
  Taro: 基於Taro的跨平台應用(各類小程序) [8P] 
  RN: 基於ReactNative的原生APP(開發中...) [4P] 

拋磚引玉,你也許不會真的使用它,但它或許能給你帶來新思路...

user avatar
0 位用戶收藏了這個故事!

發佈 評論

Some HTML is okay.