對微前端方向有了解的同窗可能都看過 qiankun 的文檔,深刻的同窗估計也去翻過其代碼和 single-spa 的源碼。一年前我也是受微前端思想的影響,當時恰好面臨的業務是變化頻繁,須要支持線上功能的熱插拔和獨立部署。充分調研了微前端和 qiankun 以後,發現很適合當前業務,纔開始開始實踐微前端的。因爲 single-spa 太過於簡陋,就採用 qiankun@1.x 做爲微前端驅動,今天想把這段時間以來遇到的問題和解決之道跟你們分享一下。css
假設你如今維護或新開發這樣一個項目,業務變化頻繁,頁面功能有重複,但風格是一致的,暫時只有 pc 端。你拿到設計稿後發現,能夠把業務分拆成多套 layout,由基座(主應用)提供。功能獨立的模塊集成在子應用,每一個子應用有特殊的 routerBase。html
咔咔咔,兩三下你作完了全部任務,子應用也能在線配置,支持熱插拔和獨立部署。爽歪歪~前端
幾天後忽然有了如下幾個新業務場景,你陷入了沉思。。。vue
你新建了個子應用,routerBase 設置爲 h5。當判斷是移動端時自動跳轉 /h5/xxx。若是 pc 端訪問 /h5/xxx 時,自動重定向到 /xxx,能勉強應付該場景,不過由於基座過重致使移動端渲染很慢,在移動端使用「前進/後退」按鈕也會由於重定向太多致使混亂,有時候頁面渲染成 pc 頁面或沒法渲染。react
響應式頁面是活動頁,有活動報名,就要求登陸態共享。當用戶在移動端點擊登陸時,理應跳轉到移動端的登陸頁面,登陸完重定向到活動頁面 須要是登陸成功的狀態。若是是每一個子應用都有 routerBase,來回跳轉好幾回,並且還要想辦法共享登陸。git
routerBase 自然斷絕了這種可能性,根本沒法作到!github
該項目的不少依賴特別是腳手架都已經嚴重過期,鎖定一級依賴的版本但鎖不了二級以上的版本,致使構建發佈失敗。根本沒法往項目代碼中加入 bootstrap/mount/unmount...!chrome
qiankun 的定位多是中後臺項目的聚合。這類項目彼此間不多依賴,登陸態的控制能夠在基座中完成,屬於一個基座下的多個串聯。但面臨上述場景時,就顯得力不從心。npm
另外上述場景也暴露了 qiankun 的諸多問題:json
@icatjs/micro 是我這四個月來實現並在實際項目中實踐的新一代微前端框架,不但能輕鬆應付上述「困境」,還具有其餘良好的特性。目前僅有兩個方法 registerSubapps
和 start
,其餘須要注意的就是子應用的配置了。TA 是如何應對上述困境的呢?聽我一一分享下:
你們看到這個新名詞,不要覺得對子應用作了強制的分類。只要某個子應用 a 提供了 layout 或一些路徑被用做了 layout,又被其餘子應用 b 依賴了,那麼該應用 a 就能夠看作是「端應用」。a 是否是端應用,本身根本不知道,它會按子應用正常的加載。而 b 會在 a 提供了掛載點後再渲染到頁面上。看個例子吧~
這是端應用的配置
{ "name": "a", "entry": "aaa", "history": "browser", "props": {}, "rules": [ { "rule": "/", "container": "#mountNode", "endType": "pc" } ] }
解析下:a 做爲 pc 端的應用,路徑規則配置的是通配符 /
,這樣全部的路由都會被這個應用匹配到。固然會經過 endType
優先判斷是哪一個端,而後再去處理應用的「依賴鏈」。目前因爲場景比較簡單,每一個路由下只支持一條依賴鏈。理論上講可支持多條依賴鏈,也就是 多鏈多實例同時並存。
這是子應用的配置
{ "name": "b", "entry": "bbb", "history": "browser", "props": {}, "rootVars": { "externals": { "@react": "React", "@react-dom": "ReactDOM", "userInfo": "userInfo" } }, "rules": [ { "rule": "/b/activities/1520", "layout": "a > /layout/headless", "endType": "none" }, { "rule": "/b/tec-support", "container": "#mountNode", "endType": "none" }, { "rule": "/development", "layout": "a > /layout/basic", "endType": "pc" } ] }
也解析下:能夠看 rules 中配置了三個典型的規則,第一條依賴了端應用 a 的 /layout/headless,第二條不依賴任何端應用,第三條依賴了 a 的 /layout/basic。
不配置 container 的路徑,若是是子應用默認是 #subappMountNodeWrapper
,若是是端應用不依賴任何 layout 則默認是 #appMountNodeAndDoNotCover
。這樣若是頁面中有這些節點出現時,子應用就會渲染到該節點上。
你們也能夠看到,一個子應用的激活與否只和路徑規則有關,這些規則遵照 single-spa 的 activeWhen 規則,能夠是字符串、函數或數組。而每條路徑規則都有本身的 container,也有屬於本身的端 endType 和 layout。這樣一個子應用既能夠做爲依賴鏈上的一個端應用,又能夠做爲獨立的子應用。按路徑規則靈活組合,適應多種場景須要。
注意!端應用也能夠依賴其餘端應用,只須要在其路徑規則上配置須要依賴的路徑便可。
能夠是一個 html 文件路徑,也能夠是一個數組,包含多個 js、css 和 html。初始化掛載點時,以最後一個 html 的內容填充進去。
內置處理了 react/vue 多個子應用同時被激活,多個路由系統衝突的問題。無需再像使用 qiankun 那樣,還要把子應用的路由配置到主應用中,以防衝突。全局路由會攔截路由變化,把真實路徑和 layout 路徑分發到各個子應用,使其能正常渲染。
而且,全部子應用均可以有本身獨立的 404 頁面。能夠把子應用徹底當作是獨立的應用,無需顧慮路由的默認匹配,無需擔憂路由不匹配時直接進入應用的 404 頁面。
內置了 iframe 沙箱,子應用的代碼運行是在 iframe 中。這樣代碼的狀態都會保存在 iframe 中,不用麻煩提供快照,自然具有快照能力。也內置了垃圾回收隊列,當一個子應用 5 分鐘內不被激活,會被釋放掉 iframe。
注意!這些 iframe 都是空白 iframe,耗費的渲染資源不多。但框架在 iframe 中提供了虛擬 BOM,使這些字應用運行完的結果可以正確渲染到 iframe 外的真實渲染層中。
注意2!子應用的全部對 dom 的操做都被限制在掛載點中,換言之,document.body 指向的是掛載點而不是渲染層的真實 body。這種嚴密的控制也體如今 getElementById 等方法中。
固然還有其餘一些特性如第三方庫共享、全局數據共享、組件&方法&狀態流共享和緩存機制等,初次介紹就先不深刻了。後續會籌備官網,全面介紹這些特性的。
到此,咱們梳理一下困境的解決之道:
/
,這樣很容易保證 URL 一致。這是集成的 2018 年的 seeconf 官網:
這是集成的口碑官網:
因爲通用邏輯和 layout 被分攤到一層層的「端應用」中,基座只須要作好對框架的引用和對規則的獲取與解析,就能驅動起總體的站點運行起來。子應用的路由也不用顧慮衝突,而考慮在主應用中 copy 一份。
基座能夠作到很薄,每一個端只需加載其須要的 UI 庫或組件。好比 pc 端使用了 antd,移動端可使用 antd-mobile,框架不會把 antd 加載到移動端去。
主流瀏覽器 chrome, safari, edge, firefox 等都兼容,國內小衆瀏覽器 360、qq 瀏覽器等也兼容。優先使用 Proxy,不支持則退化爲 Object.defineProperty。
目前平頭哥 IoT 團隊在作芯片開放社區(OCC),這個框架的誕生也是爲了知足其不斷變化的業務需求。你們能夠看下 pc 端和移動端的 URL 是相同的,但激活的子應用是不一樣的。
也但願看到本文的同窗,在將來某個時刻使用 @icatjs/micro 框架,作出精彩紛呈的做品來!
應一些同窗的反饋,隨手搞了個示例 https//github.com/icatjs/icatjs-micro-demo, 請你們初步瞭解下該框架的使用。