Module Federation在客服工單業務中的最佳實踐

得物技術發表於2022-04-09

Module Federation: 是模組聯邦的意思,在webpack 5中流行起來的,也屬於一種微前端方案。

一、背景

1、客服高頻工作場景

一線客服: 基於一站式工作臺中的線上工作臺及電話工作臺,根據使用者進線反饋的問題,檢視當前使用者相關的工單詳情或訂單詳情,並根據實際情況決定是否建立新的工單。

二線客服: 根據各種渠道反饋的工單(其中一個主要來源是一線客服的反饋),根據工單內容,聯絡使用者或其他相關方溝通處理並完結工單。

2、使用iframe的背景

在上述場景中我們可以知道:

  • 一線客服和二線客服不是同一批同學,分屬不同的部門;
  • 由於業務上的一些區別,所以IM與工單是兩個不同的前端專案,也由不同的前端同學開發和維護;
  • 即使使用微前端拆分後,IM、電話和工單也屬於不同的微應用,工單頁面在IM和電話子應用中沒法直接引入工單詳情頁面

改造之前 IM 和電話工作臺中使用到的工單 詳情 頁面都是使用iframe巢狀的,這在前期是最簡便,相容性最好的方案。

二、存在的問題

1、iframe問題的擴大化

我們知道,單個iframe是比較佔 記憶體 的,開啟比較慢,只是偶爾使用的時候,這些可能並不是什麼大問題,但在一線客服中有這麼些場景會急劇擴大這些問題,具體如下:

  • 一線客服與單個使用者對話過程中,開啟多個該使用者的工單詳情或訂單詳情
  • 一線客服對接多個使用者諮詢
  • 一線客服頻繁且快速的切換不同的使用者及不同的工單/訂單詳情
  • 由於客服對切換不同會話的響應有要求,IM側對不同的會話頁面做了快取(如keep-alive)

這會導致 記憶體 消耗急劇升高,切換響應速度慢,甚至會導致瀏覽器崩潰,客服使用 體驗 差,最終導致客服效能的降低

2、記憶體不斷升高

模擬使用者在IM中開啟一個新客戶的訊息,點選建立工單,點選工單詳情,再開啟一個新的客戶訊息重複上述動作的頁面文件數,記憶體佔用及頁面節點數的趨勢圖,如下:

由於頁面快取的存在,可見 記憶體 佔用是越來越高的,在一分多鐘的時間內從100多MB到500多MB,而且可以判斷的是當使用者的這類操作,其記憶體佔有率將持續走高,雖然在大多數情況下瀏覽器的垃圾回收機制會啟動,但由於:

  • 頁面級的快取使垃圾回收不那麼有效
  • 在客服的長時的工作下,記憶體還是會持續走高

最終應用會越來越慢,甚至導致崩潰,並已經有一些客服在反饋崩潰的問題了:

3、響應速度慢

先看段工單詳情開啟的視訊,如下:

視訊中開啟工單詳情並非首屏開啟,也需要2.8秒,當首屏開啟的時候甚至需要7s!

注意: 此處及後續的資料都是在測試環境採集的,由於是內部實現的新開標籤頁,對LCP( Largest Contentful Paint, 最大內容渲染 ), TTI( Time to Interactive, 可互動時間)等不能很好採集,主要是根據谷歌效能工具中截圖中的時間資料來獲取的,該值更接近於TTI。

三、選型及對應策略

根據當下的情況,已經不能再繼續使用iframe了,那有什麼方案可以滿足我們目前的情形呢,首先梳理我們目前的訴求,這個訴求主要有兩方面:

  • 一方面當然是解決上述問題,提升效能,提升客服使用體驗
  • 另一方面它需要對前端來說要足夠友好,能實現,有良好相容性,也要保持前端的目前低成本維護

擺在我們面前的常用的方案大概有這麼兩個,npm包和以qiankun為代表的微前端

方案效能維護
npm好,與本地元件無異,效能是最好的差,一旦工單有釋出,IM也得跟隨發版,不可接受
微前端較好好,專案解耦,IM側無需關心工單側的迭代及具體技術

1、npm包適合麼

先看下我們需要引用的頁面本身,如下圖所示:

它是一個複雜度高的,業務關聯性高,更新頻次高的三高頁面級元件,完全不適合做成低頻的npm包了

2、微前端合適麼

大家可能以為我要選qiankun為主的微前端方案了,但並不是,因為qiankun或其他類似的微前端方案在我們這樣的具體場景下也有一些問題:

2.1、對巢狀場景的支援度不高

在我們一站式工作臺的整體方案中,已經使用qiankun將工單、IM、電話拆成了三個子應用,如果IM再引用工單子應用就會形成應用之間的巢狀,如下圖所示:

搜尋微前端巢狀方案:

結論 無論是webpack還是vite,以沙箱隔離為主要解決方案的微前端在巢狀場景上支援度不高 並且如果以後出現更多,更深,甚至迴圈巢狀的情況的話,那就更棘手了。

2.2、場景不適合

以沙箱隔離的微前端方案,還是會在每次引用時將專案本身初始化所需的檔案都引用並且解析載入,即使你引用一個小元件他也會這麼做,還是會影響元件載入的速度。所以它主要是解決以專案維度的引用,隔離及效能問題。在以模組或元件為維度的情形不適合,它還是有點重了。

那麼是否存在這樣一個方案,可以像npm包這樣靈巧,只載入對應的元件程式碼,又可以像微前端這樣直接引用,與專案無關呢,答案是有的,那就是這次的主角——Module Federation(模組聯邦)。

四、Module Federation模組聯邦

模組聯邦,它首先是在webpack 5中流行開來的,可見文件:Module Federation | webpack 中文文件,而且它也屬於一種微前端方案。

1、我們關注下它能幹什麼

我感覺一句話概括就是:它能允許一個線上部署的專案在執行時載入其他線上部署專案中的元件

其中關鍵幾點如下:

  • 它沒有沙箱隔離方案,與宿主環境共用一個window環境
  • 載入時只載入目標元件及其相關的內容
  • 無需改變元件或頁面在之前的專案目錄位置或結構,直接根據對應目錄層級引用即可
  • 使用時與本專案元件使用方式一致,因為它就是一個元件,只是遠端載入而已

2、基本原理

設想一下,在webpack中可以將一些後續載入的模組打成chunk包,然後在使用到這個模組的時候再懶載入,這種情形一般是在同一個專案中進行。

那麼我們是否也可以在A專案中把一個元件及其的依賴打包成chunk包,而在B專案中按約定的地址非同步import剛才那個A專案的chunk包,並執行使用呢?答案就是Module Federation。

2.1、一些概念

  • 遠端元件提供方稱為remote端,遠端元件使用方稱為host端。
  • 一個專案既可以為remote端,也可以為host端,可以使用數個不同其他專案的元件,也可以為數個其他專案提供不同的元件。

據此,我們甚至可以打造一個去中心化的應用叢集,大概這樣:

2.2、社群應用

而且此項技術已在多個知名廠商中應用:

2.3、vite中的Module Federation方案

vite外掛vite-plugin-federation提供了對標webpack的能力,只是載入的方式改成了ESM,其外掛介面設計與webpack的引數設計幾乎是一樣的。vite-plugin-federation也是vite官方推薦和收錄的外掛,已收錄在社群外掛列表GitHub - vitejs/awesome-vite: ⚡️ A curated list of awesome things related to Vite.js

2.4、具體到我們的場景中

工單工作臺應用,作為remote端,它可以提供工單詳情,訂單詳情和建立工單,賠付模組等多個頁面級元件。

IM 或電話工作臺應用,作為host端,可以使用上述元件。

3、具體實踐

由於我們兩個專案都使用的是vue3 + vite方案,所以使用vite-plugin-federation外掛是我們最佳的選擇。首先需要在host端和remote端安裝外掛,如下命令:

yarn add @originjs/vite-plugin-federation -D

注意: 此處為了展示方便使用了官方外掛,實際由於專案相關的原因,我們對官方外掛進行了一些改動。

3.1、工單工作臺作為remote端的配置

(1) 在外掛內註冊需要提供的元件

並且提供需要共享的三方依賴

(2) 配置完成後打包

在remote端打包後會生成對應的入口檔案,chunk檔案及依賴包檔案:

3.2、IM和電話工作臺作為host端的配置

(1) 外掛配置,設定遠端包地址

(2) 引用及註冊元件 main.ts檔案 如下

這時需要注意,ticket-share為host側在vite外掛中註冊的包名,Detail為remote端暴露(exposes欄位)宣告的元件名。 除了在全域性註冊,還可以在任意需要引用的地方引用。

(3) 元件的使用

在需要的地方引入使用,並根據業務情況傳遞props,props的使用方式與普通元件無異。

此時我們已經完成了全部配置,此後我們只要打包上線執行即可。

五、重構之後的效果

1、載入速度

再來看一段視訊

大家可以與最開始的視訊對比一下,可以看出非常直觀的差異。

首屏二次(非首屏)
iframe7076ms2594ms
模組聯邦1279ms428ms

注意:上述資料由測試環境進行十次平均得到,測試值更接近TTI。

從資料中可以看到,在首屏環境(即無任何快取)下模組聯邦載入速度提高了5.5倍。而在二次載入場景中(此場景是客服使用頻率最高的場景),速度提高了6倍!

2、記憶體

我們依舊根據開始的場景,模擬客服開啟多個使用者多個工單/訂單詳情的情形,如上圖,首先可以發現:

  • 沒有記憶體洩漏!
  • 記憶體佔用在相同的時間內,最高只達到了55MB,並回落。
  • 單個工單詳情開啟記憶體增幅從10MB降低到不足1MB。

因為除了模組聯邦帶來的直接收益,我們還享受到了它的附加收益,由於模組聯邦本身引用的是一個元件,所以利用vue元件本身的特性,多個工單詳情我們可以複用同一個例項!

3、客服反饋

上線之後,我們再也沒有收到相關的任何負面反饋,例如開啟工單詳情慢,或者說瀏覽器崩潰的反饋沒有了!

六、後續規劃

1、模組聯邦的缺點:維護共享庫

它並不是沒有任何缺點,在配置過程中我們可以看到需要配置share欄位,即不同專案需要共享的三方庫,例如A專案使用vue,B專案也使用vue,那麼就需要將vue宣告出來,外掛會將vue自動分割出來,這樣A,B專案可以共享使用了,在remote端和host端都需要宣告,宣告如下:

shared: { 
  vue: { 
    // remote端該欄位為requiredVersion 
    version: '3.1.5' 
  }, 
  axios: { 
    version: '0.21.1' 
  }, 
  vuex: { 
    version: '4.0.0' 
  }, 
  'vue-router': { 
    version: '4.0.8' 
  } 
 } 

但是,這裡對開發同學有非常不友好的點:

  • 需要將元件共享的包都手動找出來
  • 共享有時是強制的,如果漏了某些包,可能會導致頁面報錯或崩潰,想象一下頁面同時有兩個vue
  • 同一個庫,有時需要維護在約定的版本範圍內,有時一個包太老或太新也會在載入時報錯

簡而言之,就是對共享包的維護成本很大!

2、解決思路

  • 需要建立日常及生產構建時hook
  • 然後自建服務監聽這些hook,對比三方庫的包差異及其版本差異, 並丟擲相應警告
  • 引入巡檢,構建完成後對遠端模組部分進行檢查,因為不是每個改動都會使測試迴歸,但每個改動都可能引起頁面崩潰。
  • 對外掛進一步封裝,使開發者無需關心三方依賴的管理。

3、與去應用化assets釋出的衝突

  • 由於assets釋出天然需要引入版本號,因此每個迭代所有的資源的地址都會帶入版本號
  • 遠端元件引用需要按約定確定一個remote端的入口檔案地址,該地址基本是固定的

所以,目前remote端專案還不能使用assets釋出,接下來一是可以用介面的方式代替,二是需要團隊之間協商處理這個問題。

4、更大方向的暢想

還記得“可以打造一個去中心化的應用叢集”那張圖嗎?元件的引用不僅僅出現在團隊內部,也可能出現在團隊間共享,例如建立工單這個模組就會被情報系統這樣的團隊引用。

即各個團隊間,或團隊內部的元件或模組互相引用的,目前主要依靠iframe解決的,都可以使用模組聯邦解決。

而公司內部也可以有這麼個平臺,集合模組聯邦的團隊,業務模組展示管理,共享依賴包的校驗,警告或自動修補等等功能,來實現業務級別的團隊內外高效協作。

擴充套件閱讀:

【1】https://juejin.cn/post/685656...

【2】https://github.com/umijs/qian...\

【3】https://webpack.docschina.org...

【4】https://juejin.cn/post/684490...

【5】https://juejin.cn/post/691149...

【6】https://github.com/vitejs/awe...

【7】https://github.com/vitejs/awe...

文/LIUZHOUCHANG

關注得物技術,做最潮技術人!

相關文章