將來魔法校的微前端實踐

1、 背景javascript

魔法校是tob起家,衆所周知tob業務很容易作成巨石應用,近兩年來魔法校飛速發展,咱們的某個主要的前端項目遇到了瓶頸,那就是項目太大了。css

爲了減小耦合度加快打包速度,咱們選擇將一些功能提出來新建項目,而後經過iframe的方式引入到主項目中去。雖然項目體積大的問題獲得瞭解決,但用戶體驗卻隨之降低。html

由於每次用戶切換到iframe的tab時無論優化的再好總要有一瞬間的白屏,整個系統使用起來沒有連貫性,並且在iframe裏切換頁面瀏覽器的地址欄url並不會變化,給人的感受就是兩個系統。前端

業務的快速發展迫使咱們去尋找一種新的方式-微前端。vue

2、微前端的基本概念java

一、什麼是微前端node

微前端是近兩年比較火的一個概念,這個術語最初來自 2016 年的 ThoughtWorks 技術雷達,它將微服務的概念擴展到了前端領域。目前的趨勢是構建一個功能豐富且強大的前端應用,即單頁面應用(SPA)。前端層一般由一個單獨的團隊開發,隨着時間的推移,會變得愈來愈龐大而難以維護。這就是傳說中的前端巨無霸Frontend Monolith。react

微前端背後的理念是將一個網站或者 Web App 當成特性的組合體,每一個特性都由一個獨立的團隊負責。每一個團隊都有擅長的特定業務領域或是它關心的任務。這裏,一個團隊是跨職能的,它能夠端到端,從數據庫到用戶界面完整的開發它所負責的功能。webpack

然而,這個概念並不新鮮,過去它叫針對垂直系統的前端一體化或獨立系統。只不過微前端顯然是一個更加友好而且不那麼笨重的術語。git

二、微前端的優點

◾複雜度可控:每個UI業務模塊由獨立的前端團隊開發,避免代碼巨無霸,保持開發時的高速編譯,保持較低的複雜度,便於維護與開發效率。

◾獨立部署:每個模塊可單獨存放,單獨部署,不對其餘模塊有任何影響。

◾技術選型靈活:也是最具吸引力的,在同一項目下可使用現在市面上全部前端技術棧,也包括將來的前端技術棧。

◾容錯:單個模塊發生錯誤,不影響全局。

◾擴展:每個服務能夠獨立橫向擴展以知足業務伸縮性,與資源的沒必要要消耗。

三、咱們什麼時候須要前端微服務化

◾項目技術棧過於老舊,相關技能的開發人員少,功能擴展吃力,重構成本高,維護成本高。

◾項目過於龐大,代碼編譯慢,開發體差,須要一種更高維度的解耦方案。

◾單一技術棧沒法知足你的業務需求。

◾須要將其它現有項目整合到主項目中。

四、實現微前端的幾種方式

◾iframe:iframe是最簡單也是最直接的辦法,iframe自帶沙箱隔離,可以使多個應用同時運行在一個用戶界面上。

◾路由分發式微前端:即經過路由將不一樣的業務分發到不一樣、獨立前端應用上,典型表明阿里雲。

◾結合Web Components 技術構建:使用 Web Components 構建獨立於框架的組件,隨後在對應的框架中引入這些組件,適合較小的模塊。

◾自制框架兼容應用:表明框架有 single-spa、阿里的 qiankun 在頁面合適的地方引入或者建立 DOM,用戶操做時,加載對應的應用(觸發應用的啓動),並能卸載應用。

5.單體應用與微前端架構對比

◾單體應用

1.jfif

微前端

2.jfif

3、如何實現微前端應用

一、基本概念

實現一套微前端架構,能夠把其分紅四部分參考:https://alili.tech/archive/11...

◾加載器:也就是微前端架構的核心,主要用來調度子應用,決定什麼時候展現哪一個子應用, 能夠把它理解成電源。

◾包裝器:有了加載器,能夠把現有的應用包裝,使得加載器可使用它們,它至關於電源適配器。

◾主應用:通常是包含全部子應用公共部分的項目—— 它至關於電器底座。

◾子應用:衆多展現在主應用內容區的應用—— 它至關於你要使用的電器。

因此是這麼個概念:電源(加載器)→電源適配器(包裝器)→️電器底座(主應用)→️電器(子應用)️。

總的來講是這樣一個流程:用戶訪問index.html後,瀏覽器運行加載器的js文件,加載器去配置文件,而後註冊配置文件中配置的各個子應用後,首先加載主應用(菜單等),再經過路由斷定,動態遠程加載子應用。

2.預備知識

✅SystemJs

SystemJS提供通用的模塊導入途徑,支持傳統模塊和ES6的模塊。SystemJS有兩個版本,6.x版本是在瀏覽器中使用的,0.21版本的是在瀏覽器和node環境中使用的,二者的使用方式不一樣。

參考:https://github.com/systemjs/s...

在微服務中主要充當加載器的角色。

值得注意的是咱們暫時沒有選擇用system.js,由於通過調研,目前須要加載的資源不多,有點殺雞焉用宰牛刀的感受,目前咱們的作法是動態建立script去引用資源,固然正統的作法仍是使用system.js。

✅singleSpa

single-spa是一個在前端應用程序中將多個javascript應用集合在一塊兒的框架。主要充當包裝器的角色。

參考:https://single-spa.js.org/doc...

4、具體實現步驟

首先須要兩個前端項目,一個主項目,一個子項目,主項目有基本的登陸、導航模塊,剩下的主要業務邏輯在子項目中。

由於咱們好將來主要的前端技術棧是vue,咱們就用vue來舉例說明,固然react和angular也都適用。

1.子項目

首先咱們來看下vue.config.js裏的修改

3.png

publicPath這個選項通常咱們作項目的時候寫’/'就好了,這個選項表示資源文件從哪一個地址進行加載,通常都是從網站的根目錄加載,可是如今要寫成子項目的存儲地址,能夠是阿里雲oss,也能夠是cdn上。

4.png

devServer須要新增header頭用來跨域,主要是咱們在本地開發的時候從主項目的端口號里加載子項目端口號的資源也會跨域。

5.jfif

output選項要指明資源包的名稱以及運行環境,這裏咱們選擇了window,注意若是使用system.js的話這裏要指明是umd模式。

stats-webpack-plugin這個插件本來是用來描述各個依賴之間的相互引用關係,如今咱們用它生成manifest.json文件,這個manifest.json文件裏有什麼東西呢?咱們來看一下。

6.jfif

這裏面咱們主要用到entrypoints,能夠看到這就是啓動子項目所須要加載的入口文件,也就是說咱們在主項目裏請求這個manifest.json文件就知道都須要加載哪些js。

7.jfif
這邊咱們還給css加了個做用域single-spa-vue,子項目的因此css只有在這個樣式前綴下才能生效,保證子項目的樣式不會影響到主項目。

◾而後是main.js的修改

8.jfif

這邊咱們用了一個小插件single-spa-vue,這個插件的主要做用就是導出single-spa框架所須要的三個生命週期bootstrap、mount、unmount,對應的還有single-spa-react、single-spa-angular。
能夠看到咱們這樣的寫法能夠確保子項目做爲一個模塊在主項目裏運行,也能夠單獨拿出來打包部署,甚至能夠二者並行存在。

◾router.js修改

9.jfif

router要加一個baseUrl,咱們的項目叫’learnSystem’,先後都要加’/'這個url前綴是咱們在主項目的模塊路由前綴,若是不加在主項目刷新頁面的時候會匹配不到子項目。

2.主項目

◾新增single-spa-config.js文件

10.jfif

主要步驟就是動態建立script標籤,遠程加載子項目所需js文件,而後註冊微服務模塊’learnSystem’。

一開始這個文件是放在main.js中加載的,後來發現若是子項目又能夠比主項目加載的還快,這樣就會出問題,而後咱們把它放在裏App.vue的created鉤子函數裏,用require引入,確保主項目加載完畢以後再加載子項目。

上圖中LEARN_URL能夠根據環境配置不一樣的值,如開發環境能夠配置localhost+子項目的端口號,生產環境能夠配置線上的連接。

◾router.js

11.png

router須要加模糊匹配*,不然在子模塊當前頁面直接刷新會先進入到主項目的404頁面

◾App.vue

12.jfif
一開始咱們的App.vue只有一個router-view,如今咱們要提供一個容器供子項目渲染,還記得single-spa-vue這個做用域嗎?確保子項目的樣式只會在這個div裏生效

3.主項目與子項目通訊

一般,咱們建議嘗試避免這種狀況-將這些應用程序耦合在一塊兒。若是您發現本身常常在應用程序之間執行此操做,則可能要考慮那些單獨的應用程序實際上應該只是一個應用程序。可是有一些場景是須要用到通訊的,好比子項目請求接口發現token過時,須要通知主項目退出登陸並跳轉到登陸界面。

咱們用了一種簡單的方法,既然這兩個項目同屬一個窗口,那他們也共有一個window對象,在主項目裏註冊一個方法並掛載到window對象上,在子項目裏調用此方法就能達到目的。

4.優化打包配置

由於主項目與子項目都用到了相同的一部分依賴,能夠考慮將公用的依賴不打包進去,改成在主項目引入來提升打包效率
修改vue.config.js

13.png

請注意,可共用的資源要保證主項目和子項目所用的依賴版本號一致,或者能夠兼容到同一版本,假如某個依賴兩個項目之間版本相差過大,那麼這就不是一個能夠共用的資源。

5、結語

此套方案只能說是一套可行性方案,其實還有不少能夠優化的地方,咱們能夠一塊兒來探討。

好比:

上述咱們解決了子應用與主應用之間css相互之間影響,可是別忘了還有js呢,如何創造像iframe那樣的沙箱,使得應用之間互不影響包括全局變量事件等處理,是一個比較重要的點。

咱們用vue避免不了使用vuex,那麼不一樣的應用之間可否共享vuex的數據?由於有一些權限之類的數據多是通用的。或者更深一步,應用可否自身來控制某個state是應用的私有變量或者是其它應用能夠訪問的公共變量。

咱們如今子項目的資源是懶加載,也就是當路由匹配到’learnSystem’時纔去加載子項目的資源。其實預加載可能會更好一點,也就是應用空閒時去加載子應用資源。

子應用嵌套,微前端如何嵌套微前端。

主應用如何下發狀態給子應用。

雖然它並不完美,可是並不妨礙咱們去體驗微前端帶來的好處,咱們將以上這些東西分享給你們,也請你們關注到將來魔法校近年來的成長。

14.gif

相關文章
相關標籤/搜索