微前端microApp

西安小哥發表於2022-05-11

微前端microApp實踐

微前端的概念是由ThoughtWorks在2016年提出的,它借鑑了微服務的架構理念,核心在於將一個龐大的前端應用拆分成多個獨立靈活的小型應用,每個應用都可以獨立開發、獨立執行、獨立部署,再將這些小型應用融合為一個完整的應用,或者將原本執行已久、沒有關聯的幾個應用融合為一個應用。微前端既可以將多個專案融合為一,又可以減少專案之間的耦合,提升專案擴充套件性,相比一整塊的前端倉庫,微前端架構下的前端倉庫傾向於更小更靈活。

專案改造背景

因專案需要要做一個大資料融合平臺,主要功能模組包括使用者管理、流程管理、大資料治理運算元應用,基礎元件等混合構成的融合平臺;公司目前已經存在使用者管理、流程管理等成品;基本主內容也是和這些產品的功能一致,主框架只是控制著導航和頭部資訊;因此希望能夠抱著複用的方式,更快的進行融合接入。

前端流行的微服務框架比對

引數singlespaqiankumicroapp
開發成本開發成本高開發成本中開發成本高
維護成本
技術棧不限技術棧不限技術棧不限技術棧
實現難易實現難實現中實現簡單
原理監聽 url change 事件監聽 url change 事件WebComponent

經過對比,目前覺得micro-app使用簡單,將所有功能都封裝到一個類WebComponent元件中,從而實現在基座應用中嵌入一行程式碼即可渲染一個微前端應用。同時micro-app還提供了js沙箱、樣式隔離、元素隔離、預載入、資料通訊、靜態資源補全等一系列完善的功能。子應用基本不需要過多的進行專案改造,相對使用成本更低

對接說明

  • 主框架依賴包引入
import microApp from '@micro-zoe/micro-app'
  • 主應用啟動(並可以進行全域性配置)
microApp.start({
  plugins: {
    global: [{
      loader(code, url, options) { // 必填
        console.log('全域性外掛')
        return code
      }
    }],
    }
  }
})

//相關引數
microApp.start({
inline: true, // 預設值false
destroy: true, // 預設值false
disableScopecss: true, // 預設值false
disableSandbox: true, // 預設值false
shadowDOM: true, // 預設值false
ssr: true, // 預設值false
})

  • 配置元件節點
      <micro-app
      style="height: 100%;"
        name='appnameUserCenter'
        :url='url'
        :data='microAppData'
        @created='handleCreate'
        @beforemount='handleBeforeMount'
        @mounted='handleMount'
        @unmount='handleUnmount'
        @error='handleError'
        @datachange='handleDataChange'
      ></micro-app>

生命週期列表

  1. created
    <micro-app>標籤初始化後,載入資源前觸發。
  2. beforemount
    載入資源完成後,開始渲染之前觸發。
  3. mounted
    子應用渲染結束後觸發。
  4. unmount
    子應用解除安裝時觸發。
  5. error
    子應用渲染出錯時觸發,只有會導致渲染終止的錯誤才會觸發此生命週期。
  • 路由匹配設定(模糊匹配,建議主應用history,微應用hash模式,)
  {
    path: '/mainPanel',
    name: 'mainPanel',
    component: mainPanel,
    children:[
      {
        path: '/mainPanel/dataCenter*',
        name: 'dataCenter',
        component:()=>dataCenter
      },
      {
        path: '/mainPanel/userCenter*',
        name: 'userCenter',
        component:()=>userCenter
      },
    ]
  }
  • 主微框架通訊
 microMenu(appName, path, hash) {

            if (!getActiveApps().includes(appName)) {
   
                path = '/mainPanel' + path+'/'
                    // child-vite 和 child-react17子應用為hash路由,這裡拼接一下hash值
                    hash && (path += `/#${hash}`)
                    // 主應用跳轉
                    this.$router.push(path)
                } else {
           
                    let childPath = null
                    // child-vite 和 child-react17子應用是hash路由,hash值就是它的頁面地址,這裡單獨處理
                    if (hash) {
                    childPath = hash
                    } else {
                    // path的值形式如:/app-vue2/page2,這裡/app-vue2是子應用的基礎路由,/page2才是頁面地址,所以我們需要將/app-vue2部分刪除
                    childPath = path.replace(/^\/app-[^/]+/, '')
                    !childPath && (childPath = '/') // 防止地址為空
                    }
                    // 主應用通過下發data資料控制子應用跳轉
                    microApp.setData(appName, { path: childPath })
                }
        }
  • 微框架及其路由跳轉

(function () {
  let app = null;
  //建立vue例項
  const createVue = function () {
    app = new Vue({
      el: "#app",
      router,
      store,
      render: (h) => h(App),
    });
  };
  // 與基座進行資料互動
  const handleMicroData = function (callBack) {
    window.microApp.addDataListener((data) => {
      callBack(data);
    });
  };

  // 微前端環境下,註冊mount和unmount方法
  if (window.__MICRO_APP_ENVIRONMENT__) {
    let {token} = window.microApp.getData();
    token && setToken(token);
    console.log("data-center token:", token);
    window[`micro-app-${window.__MICRO_APP_NAME__}`] = {
      //微前端掛載
      mount: () => {
        createVue();
        handleMicroData((data) => {
          //互動操作
          store.dispatch("settings/changeSetting", {
            key: "microFlag",
            value: true,
          });
          console.log("data-center addDataListener:", data);
          router.push(data.path);
        });
      },
      //微前端解除安裝
      unmount: () => {
        app.$destroy();
        app.$el.innerHTML = "";
        app = null;
        console.log("微應用child-vue2解除安裝了");
      },
    };
  } else {
    // 非微前端環境直接渲染
    createVue();
  }
})();

相關文章