動態

詳情 返回 返回

你想要的【微前端】都在這裏了! | 京東雲技術團隊 - 動態 詳情

作者:京東零售 鄭炳懿

開篇:

如果你不知道微前端是什麼,或者不知道微前端能解決什麼問題,那麼你可能不需要微前端。

在我看來,對於每一個沒有使用過的新技術,都應該有以下幾個過程:

1、調研該技術,產出相應的調研文檔。

2、輸出技術Demo,基本的框架結構。

3、試着在項目中使用它,這一步坑會很多。

4、把它推動到線上完成真正的技術升級。

一、調研微前端

1.1 業務背景

某次遇到一個從0到1的大型項目,該項目涉及兩個端,除了鑑權和部分業務邏輯不同外,頁面UI和其餘邏輯幾乎一致,遇到這種項目,該如何架構?既能保證項目順利開發完成,又能保證後期的迭代、維護、可擴展?

1.2 初步方案

首先,想到的技術方案有這麼兩種:

1、複用同一套代碼,通過判斷不同的權限,服務端下發標識,處理異同的業務邏輯。

2、開發兩套代碼,兩套鑑權各走各的,頁面相同部分從左邊Copy到右邊。

其次,回過頭來想了想,這兩種方案都有缺陷:

1、複用同一套代碼,後期迭代的過程中,業務差異越來越大的時候,就會形成“屎山”。

2、開發兩套代碼,後期迭代的過程中,如果業務依然高度相似,那麼每次都要把A項目中的代碼Copy到B項目中;如果業務逐漸有了各自的風格,那麼兩套代碼的方案顯然是更佳的。

最後,除此之外,還有別的更好的方案嗎?

1.3 什麼是微前端?

微前端的概念是由 ThoughtWorks 在2016年提出的,它是一種前端架構風格,將一個龐大的前端應用拆分成多個獨立靈活的小型應用,每個應用都可以獨立開發、獨立運行、獨立部署,再將這些小型應用融合為一個完整的應用,或者將原本運行已久、沒有關聯的幾個應用融合為一個應用。微前端既可以將多個項目融合為一,又可以減少項目之間的耦合,提高開發效率和可維護性。微前端的核心在於解耦,通過拆分和集成來實現前端應用的可擴展性和靈活性。

圖片來源於micro-app官網

二、初識微前端

2.1 微前端能力

1、獨立開發:微前端可以將一個龐大的前端應用拆分成多個小型應用,每個應用都可以獨立開發,不會影響其他應用的開發進度。

2、獨立部署:每個小型應用都可以獨立部署,不會影響其他應用的部署進度。這也意味着可以使用不同的技術棧、不同的部署方式、不同的版本控制工具等。

3、獨立運行:每個小型應用都可以獨立運行,不會影響其他應用的運行狀態。這也意味着可以使用不同的框架、不同的庫、不同的語言等。

4、集成靈活:微前端框架可以將多個小型應用集成為一個完整的前端應用,或者將原本運行已久、沒有關聯的幾個應用融合為一個應用。這也意味着可以根據需要動態地增加或刪除應用。

5、解耦:微前端可以將前端應用拆分成多個小型應用,每個應用都有自己的職責和業務邏輯,可以減少應用之間的耦合,提高可維護性和可擴展性。

6、增量升級:微前端可以實現增量升級,只需要升級需要更新的小型應用,而不需要升級整個前端應用。這可以減少升級帶來的風險和成本。

2.2 微前端核心

1、拆分:將前端應用拆分成多個小型應用,每個應用都有自己的職責和業務邏輯。這樣可以減少應用之間的耦合,使得每個應用都可以獨立開發、獨立部署和獨立運行。

2、集成:通過微前端框架將多個小型應用集成為一個完整的前端應用。這樣可以根據需要動態地增加或刪除應用,實現靈活的集成。

3、通信:通過定義接口和事件等方式,實現小型應用之間的通信。這樣可以保證各個應用之間的協作和交互,同時又不會影響應用之間的耦合。

4、樣式隔離:通過使用樣式隔離技術,使得每個小型應用都可以使用自己的樣式,不會影響其他應用的樣式。這樣可以保證各個應用之間的樣式不會互相干擾,同時又不會影響應用之間的耦合。

總之,微前端的核心是解耦,通過拆分、集成、通信和樣式隔離等方式,實現前端應用的解耦,提高可維護性和可擴展性。

2.3 微前端平台

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

2、qiankun 螞蟻金服出品,基於 single-spa 封裝的微前端框架。

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

由於項目使用的 umi + react +ts 的技術棧,而 qiankun 天生就集成在 umi 框架中了,只需要一些配置就可以使用微前端技術,注意,我這裏説的是一些配置,就是這一些配置,讓我放棄了 qiankun 微前端框架,因為 single-spa 要求子應用修改渲染邏輯並暴露出三個方法:bootstrap、mount、unmount,分別對應初始化、渲染和卸載,這也導致子應用需要對入口文件進行修改。而 qiankun 是基於single-spa進行封裝,所以這些特點也被 qiankun 繼承下來,並且需要對 webpack 配置進行一些修改,成本相對較高。

再來看 micro-app 老東家出品的微前端框架,借鑑了 WebComponent 的思想,通過 CustomElement 結合自定義的 ShadowDom,將微前端封裝成一個類WebComponent 組件,從而實現微前端的組件化渲染。並且由於自定義ShadowDom的隔離特性,micro-app不需要像single-spa和qiankun一樣要求子應用修改渲染邏輯並暴露出方法,也不需要修改 webpack 配置,是目前市面上接入微前端成本最低的方案。

圖片來源於micro-app官網

三、應用微前端

3.1 選擇 mirco-app

結合上述的調研結果,決定使用 micro-app 框架來架構我的這個大型項目。第一,micro-app 使用簡單,學習成本低,小巧的體積和更高的擴展性;第二,老東家的技術,必須全力支持。

確定最終技術方案:

1、項目涉及到兩個端,準備啓用兩個基座,這兩個基座內管理鑑權和統一調用的公共邏輯,基座獨立部署,屬主應用。

2、項目中相同的UI部分,獨立到業務組件庫,可複用,業務邏輯部分,各自在項目中處理,相互獨立。

3.2 啓動 mirco-app

這裏有詳細的使用文檔,就不再贅述,從引入依賴到項目完全渲染出來,只需要四步即可, micro-app 直通車。

值得一提的是第二步,有個小坑,入口處引入包,然後調用方法。

如果你的項目是 Vue的話,這裏説的入口文件應該是 main.js;如果你的項目是 umi 框架的話,入口文件指的的是 src/pages/.umi/umi.js 文件,這個文件是 umi 自動生成的,無法讓你在這裏面編碼,所以你需要在 src 目錄下面新建一個 index 或者 global 的文件,把下面的代碼複製進去。

// 項目入口處引入
import microApp from '@micro-zoe/micro-app'

microApp.start()

按照文檔的指引,你應該看到這個界面,如果沒有看到這個界面,那説明你的姿勢有問題,可能是跨域導致,關於跨越問題,Q&A裏面有解決方案,用《程序員的修煉之路》中的一句話來説:“讀一下那些該死的報錯信息”,沒準你就能啓動成功了。

頂部導航和左側菜單是基座,也就是主應用,右側的內容區域,是子應用。

3.3 踩坑 micro-app

3.3.1 路由問題

項目啓動起來要面對的第一個問題就是路由問題。案例裏面給的菜單是一級菜單,但是實際項目應用中可能有二級、甚至三級菜單,那怎麼匹配路由跳轉到對應的子應用呢?

核心代碼:

  microApp.router.push({ 
    name: 'pop',  // 子應用名稱
    path: `${config.pop}${item.url}`  // config是配置文件 item是當前點擊的菜單路徑信息
  });

處理邏輯:

1、優先處理樹形菜單,樹形菜單使用遞歸調用,後期不管是幾級菜單都不用管它了。

2、與服務端約定好樹形菜單的字段,出必要字段外,應該包含對應的子應用名稱,路徑,icon圖標等信息,這些信息是你提前給服務端,配置到表結構中的。如果項目足夠大的話,可以啓一個SaaS系統,更加靈活和可靠。

3、當點擊菜單中對應的某個菜單時,取到當前路徑拼接域名即可完成跳轉。

 <micro-app
   name="pop"
   url={config?.pop}
 />

3.3.2 麪包屑問題

強烈建議把麪包屑放到子應用中,麪包屑在子應用中的好處是自由完成跳轉,不用主應用做特別的處理,唯一需要處理的是麪包屑裏面的首頁,因為麪包屑放到子應用中,點擊回首頁時,回到的其實是子應用的首頁,並非是主應用的首頁。

主應用處理邏輯:

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="pop"
        url={config?.pop}
        default-page={`${config?.pop}${config.defaultUrl}`}
        onDataChange={onDispathChild}
      />
    </>
  );
};

子應用邏輯:

  // 點擊回到首頁的時候,需要告訴父應用,讓父應用去重置路由
  const onBackHome = () => {
    window.microApp?.dispatch({ isBackHome: true });
  };

micro-app 在 window 下面掛載了一個全局的對象,我們只需要去觸發它提供的方法,完成主子之間的通信即可,這個邏輯想明白之後,不管是交互邏輯還是數據傳遞邏輯,一通都通。

3.3.3 打包問題

主子應用兩個項目,在進行打包的過程,做了分包的處理,micro-app 中的js沙箱隔離技術有點小缺陷,由於主子應用使用的都是 umi 的框架,打包之後會錯誤的把子應用的包插入主應用中,導致應用報錯,加載不出來。

處理邏輯:

// 不分割組件

dynamicImport: false,

由於在實際項目操作中遇到的問題可能會比以上列舉的比較多,上面舉了幾個典型的例子,後續大家如果使用中遇到什麼問題,也可以私信我進行解決,或者留言評論。

四、總結微前端

最終我們的這個大型項目採用微前端實現了業務解耦,維護性高,擴展性高的期望,後期迭代so easy。

用起來其實還是蠻簡單的,但是用好了不容易,目前我們正在規劃把一整個業務線集成到微前端中,因為有些項目太老了,無法維護了,把這些老項目直接一個鏈接成子應用,新的迭代的都獨立成一個單獨的子應用,可以使用新框架,新技術去實現,技能提高開發效率,又能很好的擴展和迭代,個人覺得微前端技術很優秀,很受用。

以下是一些拆分邏輯,希望給使用微前端技術的同學一些參考:

使用微前端拆分一個大型項目需要注意以下幾點:

1、拆分粒度:應該根據業務功能、團隊職責、技術棧等因素來確定拆分粒度。拆分粒度太小會增加應用之間的通信成本,拆分粒度太大會影響獨立開發和部署的能力。

2、拆分邊界:應該確定每個小型應用的邊界,使得每個應用都有自己的職責和業務邏輯。拆分邊界應該儘可能地減少應用之間的耦合,同時又保證各個應用之間的協作和交互。

3、通信方式:應該確定小型應用之間的通信方式,包括接口、事件等。通信方式應該儘可能地簡單和高效,同時又能夠滿足各個應用之間的協作和交互需求。

4、數據管理:應該確定小型應用之間的數據管理方式,包括數據共享、數據隔離等。數據管理方式應該儘可能地簡單和高效,同時又能夠滿足各個應用之間的數據共享和隔離需求。

5、樣式隔離:應該使用樣式隔離技術,使得每個小型應用都可以使用自己的樣式,不會影響其他應用的樣式。這樣可以保證各個應用之間的樣式不會互相干擾,同時又不會影響應用之間的耦合。

6、集成方式:應該確定集成方式,包括微前端框架的選擇、部署方式等。集成方式應該儘可能地簡單和高效,同時又能夠滿足各個應用之間的集成需求。

總之,使用微前端拆分一個大型項目需要注意拆分粒度、拆分邊界、通信方式、數據管理、樣式隔離和集成方式等方面,以實現前端應用的解耦,提高可維護性和可擴展性。

user avatar mannayang 頭像 ljc1212 頭像 smalike 頭像 definecloud 頭像 sunplay 頭像 huikaichedemianbao 頭像 zhengzhouaiwenkeji 頭像 kohler21 頭像 kongxudexiaoxiongmao 頭像 yangshengyuan 頭像 crmeb 頭像 huamingshixunkeji 頭像
點贊 23 用戶, 點贊了這篇動態!
點贊

Add a new 評論

Some HTML is okay.