基于微前端的業務邏輯拆分
一、什么是微前端?
微前端是一種多個團隊通過獨立發布功能的方式來共同構建現代化 web 應用的技術手段及方法策略。
微前端在2016年ThoughtWorks Technology Radar正式被提出。借鑒了微服務的架構理念,將一個龐大的前端應用拆分為多個獨立靈活的小型應用,每個應用都可以獨立開發、獨立運行、獨立部署,再將這些小型應用聯合為一個完整的應用。微前端既可以將多個項目融合為一,又可以減少項目之間的耦合,提升項目擴展性,相比一整塊的前端倉庫,微前端架構下的前端倉庫傾向于更小更靈活。
架構特點
- 技術棧無關:主框架不限制接入應用的技術棧,子應用可自主選擇技術棧;
- 獨立開發/部署:各個團隊之間倉庫獨立,單獨部署,互不依賴;
- 增量升級:當一個應用龐大之后,技術升級或重構相當麻煩,而微應用具備漸進式升級的特性;
- 獨立運行時:微應用之間運行時互不依賴,有獨立的狀態管理;
- 提升效率:應用越龐大,越難以維護,協作效率越低下。微應用可以很好拆分,提升效率。
二、目前可用的微前端方案
2.1 基于iframe完全隔離
作為前端開發,我們對iframe已經非常熟悉了,在一個應用中可以獨立運行另一個應用。
優點:
- 非常簡單,無需任何改造;
- 完美隔離,JS、CSS都是獨立的運行環境;
- 不限制使用,頁面上可以放多個iframe來組合業務。
缺點:
- 無法保持路由狀態,刷新后路由狀態就丟失;
- 完全的隔離導致與子應用的交互變得極其困難,只能采用postMessage方式;
- iframe中的彈窗無法突破其本身;
- 整個應用全量資源加載,加載太慢。
2.2 基于single-spa路由劫持
single-spa (opens new window)是一個目前主流的微前端采用基座技術方案,其主要實現思路:預先注冊子應用,監聽路由的變化,匹配到激活的路由則加載子應用資源,順序調用生命周期函數(初始化,掛載,卸載)并最終渲染到容器。
優點:
- 有開箱即用的API;
- 技術棧無關,任意技術棧均可接入;
- HTML Entry接入方式,將整個微應用打包成一個JS文件,發布靜態資源服務器,然后在主應用中配置該JS文件的地址告訴single-spa去這個地址加載微應用。
缺點:
- 對微應用侵入性強,會將應用打包為一個JS文件,常用的優化措施,如按需加載,css獨立打包等都沒有了;
- 沒有做樣式隔離,樣式容易混淆覆蓋;
- 沒有做JS隔離,JS全局對象污染;
- 無預加載機制,加載資源太慢;
- 微應用之間沒有任何通信手段,只能用戶自己實現。
2.3 基于web components封裝組件
官方提出的組件化方案,它通過對組件進行更高程度的封裝,以組件加載的方式將微應用整合在一起實現應用之間的解耦。
優點:
- 加載子應用比single-spa注冊監聽方式更加優雅;
- 技術棧無關,是瀏覽器原生組件,在任何框架中都可以使用;
- 無需與其他應用之間產生任何關聯;
- 應用間采用shadow dom,隔離樣式。
缺點:
- 瀏覽器兼容性不好。
2.4 quankun
Quankun是對single-spa做了一層封裝,主要解決了single-spa的痛點和不足,通過import-html-entry包解析HTML獲取資源路徑,然后對資源進行解析,加載。
優點:
- 阿里團隊開發維護,文檔多,有開箱即用的API;
- JS沙箱機制,確保應用直接變量事件不沖突;
- 資源預加載,在瀏覽器空閑時間預加載未打開的微應用資源,加速了微應用的打開速度;
- 可用于任意JS框架,像嵌入一個iframe,且兼容IE11。
缺點:
- 上線部署文檔少;
- 只能解決子項目之間的樣式相互污染,不能解決子項目的樣式污染主項目的樣式。
2.5 EMP
主要基于Webpack5 Module Federation,是一種去中心化的微前端實現方案,不僅能很好的隔離應用,還可以輕松實現應用之間的資源共享和通信。
優點:
- 快速封裝可復用模塊,無需單獨拆包發布到NPM,可直接暴露需要共享的模塊;
- 實時動態更新,只需要發布基站應用,只需要訪問時刷新,即可使用最新業務模塊;
- 引入端無需手動更新,遠端模塊靈活維護和引入端可以自由組合,甚至可以運行是引入使用遠端模塊;
- 做到第三方依賴共享,使代碼盡可能地重復利用,減少加載內容。
缺點:
- 對webpack強依賴,老舊項目不友好;
- 沒有做CSS隔離和JS隔離,需要靠用戶自覺;
- 子應用保活、多應用激活無法實現;
- 主、子應用的路由可能發生沖突。
三、我們要解決的問題
拆分巨型應用,使應用方便迭代更新,提高開發部署效率
單體應用在一個相對長的時間跨度下,由于參與的人員、團隊的增多、變遷,從一個普通應用演變成一個巨石應用(Frontend Monolith)后,隨之而來的應用不可維護的問題。這類問題在企業級 Web 應用中尤其常見。而微前端思想可以將一個龐大的前端應用拆分為多個獨立靈活的小應用,每個應用可以獨立開發,獨立更新,獨立部署,減少模塊之間的耦合性,提高項目擴展性,有利于各子應用漸進式優化,不影響新增功能以及其他子應用的運行。
跨團隊協作,實現需求分工,爭取資源最優化,提高工作效率
大需求需要拆分,不同的部分需要不同的業務能力,需要涉及多個團隊甚至多個部門協同開發,所謂專業的團隊做專業的事情,細化能力,實現能力效用最大化,提高團隊整體工作效率,實現1+1>2的效果。
兼容歷史應用,實現增量開發
舊項目技術棧不統一,微前端主框架可以不限制接入應用的技術棧,可以隨時加載不同技術棧模塊,不需要為了兼容現有項目做大規模改造重構,提升開發,測試與維護效率。
四、我們的方案
1??采用基于web component的micro-app框架為基礎,拆分出可獨立運行的子應用;
2??進一步封裝業務邏輯層,實現基于js沙箱與shadow dom的代碼隔離;
3??抽離子應用的公用模塊,進一步縮減巨石項目代碼規模,提高迭代維護效率。
4.1 技術特點
高擴展性、獨立性、開放性:基于micro-app實現微前端主框架,將主應用拆分為主平臺系統和各子系統等可以獨立交付運行的前端子應用,再進一步將業務模塊抽象,公用模塊從子應用中抽離,模塊化開發部署,提高了各個子應用/業務模塊的可拓展性,減少耦合性,提高開發效率,降低交付成本。
統一功能模塊獨立性,提高安全性:用戶信息,角色權限等通用業務功可以抽象出來單獨開發部署,降低重復開發,減少項目整理代碼量,但因為需要集成到不同的子應用,為避免和宿主頁面樣式沖突,采用基于shadow dom+JS沙箱機制,建立獨立作用域,實現custom element,將JS和CSS都被隔絕在dom作用域中,實現代碼隔離,使代碼更干凈,整潔,降低耦合性。
抽離通用功能模塊,進一步縮減項目冗余:菜單,頭部,腳部,登錄,注冊等使用vite工具將其打包微ESM模塊,對于當前單一技術棧實現的業務項目,不需要每個子應該都重新開發公用模塊,讓代碼包總體積更小,提高開發效率,并實現模塊的按需異步加載,提升頁面整體加載速度。
4.2 什么是JS沙箱
JS沙箱主要是用于隔離掛載在window上的變量,保證應用之間js環境得獨立。在子應用運行時訪問的window其實是一個Proxy代理對象。所有子應用的全局變量變更都是在閉包中產生的,不會真正回寫到window上,這樣就能避免多實例之間的污染。
4.3 什么是shadow dom
Shadow-dom是游離在DOM樹之外的節點樹,他的創建基于自定義DOM元素(非document),并且創建后的shadow-dom節點可以從界面上直觀的看到。更重要的是,shadow-dom具有良好的密封性,可以隔離css樣式,避免css全局樣式污染。
4.4 模塊之間如何通信
該方案涉及按照業務拆分的子應用,按照功能拆分的子模塊,他們的通信方式是不通的。
1.按照業務拆分的子應用并不是一個模塊,而是一個可以獨立運行的應用,然而應用之間的頻繁的通信會增加應用的復雜度和耦合度,因此要盡量減少子應用之間的通信,非必要不交互。這里我們使用micro-app官方提供的API即可實現。
2.按照功能模塊拆分的子模塊,既是基于web component實現的子模塊,之間的通信可遵循父組件加載子組件,父子組件之間的通信。