淺入深出的微前端MicroApp

ITPUB社群發表於2024-02-01


來源:京東技術

導讀

本文將深入淺出地探討微前端架構模式——MicroApp,從微前端的基本概念、核心優勢以及如何在現代web開發中實現它,詳解微前端如何使得大型應用能夠分解為小型、簡單、可獨立開發和部署的子應用,同時還能保持各個子應用間的完整性和協調性。此外,本文還將探討實施微前端時可能遇到的挑戰和最佳實踐,為開發者提供一條清晰的實施路徑,幫助其構建更加靈活和可維護的前端生態系統。




01 
前言


在今年的敏捷團隊建設中,我透過Suite執行器實現了一鍵自動化單元測試。Juint除了Suite執行器還有哪些執行器呢?由此我的Runner探索之旅開始了!
本文是由作者最近做的一個專案有感而發,因為之前做了一些技術棧的統一,為了用ant Design的pro-table,PC統一使用react,但是有一些老的專案是vue的,本次新頁面較多,老頁面的改動較少,除此之外老專案想換選單,因此想借助本次機會用react開發,經過了幾番思考,發現本次很適合用微前端來完成本次需求,最終決定用react搭建一個基座(主應用),將原來的vue專案接入到基座,這樣不僅實現了新頁面react開發,而且老專案也能和新專案融合一起。


02 
  

微前端的概念

  


理解,首先 MCube 會依據模板快取狀態判斷是否需要網路獲取最新模板,當獲取到模板後進行模板載入,載入階段會將產物轉換為檢視樹的結構,轉換完成後將透過表示式引擎解析表示式並取得正確的值,透過事件解析引擎解析使用者自定義事件並完成事件的繫結,完成解析賦值以及事件繫結後進行檢視的渲染,最終將目標頁面展示到螢幕。
什麼是微前端?微前端是借鑑了微服務的架構理念,它既可以將多個專案融合為一,又可以減少專案之間的耦合,提升專案擴充套件性,相比一整塊的前端倉庫,微前端架構下的前端倉庫傾向於更小更靈活,有一個基座應用(主應用),來管理各個子應用的載入和解除安裝,所以微前端不是指具體的庫,不是指具體的框架,不是指具體的工具,而是一種理想與架構模式,微前端的核心三大原則:獨立執行、獨立部署、獨立開發
淺入深出的微前端MicroApp圖 1.


03 
 何時使用微前端?

 



理解,首先 MCube 會依據模板快取狀態判斷是否需要網路獲取最新模板,當獲取到模板後進行模板載入,載入階段會將產物轉換為檢視樹的結構,轉換完成後將透過表示式引擎解析表示式並取得正確的值,透過事件解析引擎解析使用者自定義事件並完成事件的繫結,完成解析賦值以及事件繫結後進行檢視的渲染,最終將目標頁面展示到螢幕。
(1)一個非常龐大的專案,越來越大,後續難以維護。
(2)在一些大廠,經常會有跨部門和跨團隊協作開發專案,這樣會導致團隊效率降低和溝通成本加大,這時我們可以使用微前端,每個團隊或者每個部門單獨維護自己的專案,我們只需要一個主專案來把分散的子專案彙集到一起即可。
(3)一個非常老舊的專案,開發效率低,但是一時半會又不能全部重構,這時我們就可以新建立一個新技術新專案的基座,把老專案的頁面接入到新專案裡面,後面新需求都在新專案裡面開發就好,不用再動老專案。
(4)想獨立部署每一個單頁面應用。
(5)改善初始化載入時間,延遲載入程式碼。

(6)基於多頁的子應用缺乏管理,規範/標準不統一,無法統一控制視覺呈現、共享功能和依賴,造成重複工作。



04 
 如何建立微前端基座?

 



理解,首先 MCube 會依據模板快取狀態判斷是否需要網路獲取最新模板,當獲取到模板後進行模板載入,載入階段會將產物轉換為檢視樹的結構,轉換完成後將透過表示式引擎解析表示式並取得正確的值,透過事件解析引擎解析使用者自定義事件並完成事件的繫結,完成解析賦值以及事件繫結後進行檢視的渲染,最終將目標頁面展示到螢幕。

4.1  微前端框架選型


    
4.1.1 現有框架

1. single-spa是一個將多個單頁面應用聚合為一個整體應用的 JavaScript 微前端框架。

2. qiankun 基於 single-spa 封裝的微前端框架。

3. MicroApp 京東出品,一款基於WebComponent的思想,輕量、高效、功能強大的微前端框架。

本次專案使用的是umi+react+ts的技術棧,其實比較適合用qiankun,qiankun繼承了umi框架,但是這個框架配置起來比較麻煩。

4.1.2 MicroApp優勢

1、使用起來成本最低,將所有的頁面封裝到一個類WebComponent元件中,從而實現在主應用基座中嵌入一行程式碼即可渲染一個微前端應用。
2、不需要像 single-spa 和 qiankun 一樣要求子應用修改渲染邏輯並暴露出方法,也不需要修改webpack配置,是目前市面上接入微前端成本最低的方案。
3、提供了 js沙箱、樣式隔離、元素隔離、預載入、資料通訊、靜態資源補全等一系列完善的功能。
4、沒有任何依賴,這賦予它小巧的體積和更高的擴充套件性。
5、為了保證各個業務之間獨立開發、獨立部署的能力,micro-app做了諸多相容,在任何技術框架中都可以正常執行。
MicroApp的概念圖如下圖所示:

淺入深出的微前端MicroApp圖 2.

4.2  場景演示


    
以後臺管理系統為例

最外層是基座,基座是微前端應用整合的一個重要平臺,同時也肩負著管理公共資源、依賴、規範的責任,主要有以下職責:

(1)子應用整合,給子應用提供渲染容器
(2)許可權管理
(3)會話管理
(4)路由、選單管理
(5)主題管理
(6)共享依賴

(7)多語言管理(最重要的一點)

content裡面可以任意放不同技術的子應用,只需要開發一個主應用(主應用也可以自由選擇語言,目前支援react、vue、vite、angular、next.js、nuxt.js),將一些分散的應用接進來,主應用還可以透過控制許可權,讓不同的賬號看到的選單不一樣,即看到不同系統的頁面,透過同一個地址訪問到不同的子應用。

淺入深出的微前端MicroApp圖 3.

4.3  搭建微前端基座


    

以react基座為例

1、建立專案

(1)首先確保本地node版本>= 14(推薦用nvm來管理 node 版本,windows 下推薦用nvm-windows)
(2)透過官網提供命令可以快速建立一個基於 UMI 的專案作為主應用也就是所謂的基座
(3)安裝依賴

npm i @micro-zoe/micro-app --save

package.json檔案裡面dependencies裡面會多一行程式碼,看到下面程式碼則表示專案已經具備micro-app接入能力了。


"@micro-zoe/micro-app": "^1.0.0-alpha.7"

(4)在入口引入micro-app

首先在根目錄下建立一個global.tsx檔案



import microApp from '@micro-zoe/micro-app'
microApp.start()
(5)在主應用引入子應用
a. 分配一個子應用路由









 {    path: '/yp',    name: 'yp',    linkHidden: true,    linkDisable: true,    breadcrumbClose: true,    component: '@/pages/yp-app',  }

b. 子應用的檔案

在pages檔案下建立一個yp-app(子應用的檔案)

// name(必傳):應用名稱 // url(必傳):應用地址,會被自動補全為





















import React from 'react';import config from '@/config';
// /** @jsxRuntime classic */// /** @jsx jsxCustomEvent */// import jsxCustomEvent from '@micro-zoe/micro-app/polyfill/jsx-custom-event';
export default (): React.ReactElement => {
 // 子應用點選了麵包屑的回到首頁  const onDispathChild = (e: any) => {    const { isBackHome } = e.detail.data;    if (isBackHome) window.location.href = '/';  };
 return (    <>      <micro-app name="yp" url={config?.yp} onDataChange={onDispathChild} />    </>  );};

說明:onDataChange方法是子應用和主應用的資訊通訊方法,micro-app 在 window 下面掛載了一個全域性的物件,只需要去觸發它提供的方法,完成主子之間的通訊即可,不管是互動邏輯還是資料傳遞邏輯,就都通了。

c.主應用成功引入子應用(子應用是VUE專案)

到目前為止如果專案不存在跨域問題,子應用就已成功接入了主應用,專案左側是主應用,中間模組是子應用,裡面包含子應用的整個模組選單和列表,考慮到選單統一放到主應用(基座)方便管理,需要把子應用的頁面的選單以及一些不必要的東西刪除,然後把子專案一些公共樣式公共佈局等都統一調整下即可,最終可以得到一個主應用+子應用頁面最終頁面,到這裡你就成功接入了第一個子應用,後續應用按照同樣步驟。

淺入深出的微前端MicroApp圖 4.

接入完成不代表子應用裡面所有的模組都能用了,此時還需要檢查匯出和匯入的介面是獲取域名裡面的還是單獨定義的,如果獲取域名裡面的字首,此時匯入匯出不能正常使用,需要重新給匯入匯出單獨定義,比如在子應用建立一個單獨的host.js檔案,引用根據環境區分到處的域名字首。
2、路由跳轉
透過主應用的選單跳轉到對應子應用的路由



























//config.tslet config = {  yp: '本地環境子應用的路由字首};
const isEnvPro = process.env.NODE_ENV === 'production';
if (isEnvPro) {  config = {    yp: '預發環境環境子應用的路由字首  };}
export default config;//以上是config.ts檔案的全部-----end

//選單點選事件裡面的內容
history.push('/yp'); //切換到子應用
setTimeout(() => {    microApp.router.push({      name: 'yp',//和子應用的name要保持一致,為了匹配到對應子應用的路由      path: `${config.yp}${item.url}`,    }); //跳轉子應用的路由,其中config是上面的配置檔案,根據不同的環境取對應環境的子應用,item是當前點選的選單路徑資訊}, 500);

這裡解釋下為什麼要用setTimeout,首先透過history.push('/yp')切換到子應用,防止切換過去之後短時間內找不到子應用的路由,所以加個延遲能夠準確的跳轉到子應用對應的路由。

3、設定跨域
(1)如果僅僅本地跨域的話可以給子應用設定,在webpack-dev-server的headers中設定跨域支援:





devServer: {  headers: {    'Access-Control-Allow-Origin': '*',  }},

這個有相對應的文件,根據子應用的語言設定不同的跨域資訊。

(2)如果是介面跨域。

那麼就需要找後端設定允許前端跨域的程式碼了,以Java為例:








@Override    public void init(FilterConfig filterConfig) {        this.origins = Lists.newArrayList(");    }
這個是基礎配置,還可以改成同域名下的所有都允許跨域,最好不要設定成'*',這樣很不安全。
4、代理配置
如果遇見主應用本地訪問不到子應用本地,訪問的一直是預發或者線上,這時候需要首先考慮代理是否配對,比如作者之前的一個子專案,如下所示:














proxy: (() => {  return {    //  本地訪問預發    '/avoid': {      target: '(req) => {        if(req.headers.accept.indexOf('html') !== -1 ) {          return '/index'        }      },    }  }})()

最初本地代理是路由裡面包含'/'就代理到預發上,正常單獨訪問子應用的連結,可以正常訪問本地代理預發的介面,但是放到主應用裡面就不可以了,最後給代理改成了整個專案公共部分/avoid,解決了此問題,不一定專案是因為這個,但是可以從代理入手查詢問題。

5、資料通訊
micro-app提供了一套靈活的資料通訊機制,方便基座應用和子應用之間的資料傳輸。
正常情況下,基座應用和子應用之間的通訊是繫結的,基座應用只能向指定的子應用傳送資料,子應用只能向基座傳送資料,這種方式可以有效的避免資料汙染,防止多個子應用之間相互影響。
同時也提供了全域性通訊,方便跨應用之間的資料通訊。

子應用獲取來自基座應用的資料,以及基座應用向子應用傳送資料,基座應用獲取來自子應用的資料,全域性資料通訊詳細參考



05 
 總結

 



理解,首先 MCube 會依據模板快取狀態判斷是否需要網路獲取最新模板,當獲取到模板後進行模板載入,載入階段會將產物轉換為檢視樹的結構,轉換完成後將透過表示式引擎解析表示式並取得正確的值,透過事件解析引擎解析使用者自定義事件並完成事件的繫結,完成解析賦值以及事件繫結後進行檢視的渲染,最終將目標頁面展示到螢幕。
透過上述介紹可以知道,採用微前端架構的好處就是,將原本執行已久、沒有任何關聯的幾個應用融合為一個應用,或者將很多個小型單個應用融合為一個完整的應用,可以減少專案之間的耦合,提升專案擴充套件性,micro-app借鑑了WebComponent的思想,透過CustomElement結合自定義的ShadowDom,將微前端封裝成一個類WebComponent元件,從而實現微前端的元件化渲染。並且由於自定義ShadowDom的隔離特性,也不需要修改webpack配置,是目前市面上接入微前端成本最低的方案,因此也得到廣大程式設計師的青睞。

雖說微前端已經是一個非常成熟的領域了,使用微前端目的就是為了降本提效,但是在現在的這個開源大環境,使用哪種框架,或者自己實現微前端都可以,個人覺得應該考慮如果當前的專案接入微服務之後,變得維護成本更高,那就要考慮是否適合微前端了,並不能為了用而用,微前端並不是適合所有的場景,遇到問題嘗試著去考慮多種方案方案解決。

來自 “ ITPUB部落格 ” ,連結:https://blog.itpub.net/70024420/viewspace-3006007/,如需轉載,請註明出處,否則將追究法律責任。