百度關於EMP的探索:落地生產可用的微前端架構

圖片

導讀:隨着 Web 前端工程‬日趨複雜,也‬帶來了更大的工程理治‬挑戰,微前端在‬大型前端工架程‬構解決方案中成已‬爲重要思路之一。本文詳細描述 EMP 的誕生背景、使用場景、生態以及如何使用,能夠幫助你們能更簡單、更高效的構建生產可用微前端架構。html

全文3740字,預計閱讀時間9分鐘。前端

1、EMP是什麼


EMP 是一個微前端架構解決方案集合,旨在幫助你們能更簡單、更高效的構建生產可用微前端架構。https://github.com/efoxTeam/empvue

2020年5月開始,咱們團隊開始探索微前端架構。調研從主流的 iframe、Single SPA 到那時剛剛問世的 module federation,最後選擇性能和比較有前景的 module federation 做爲基礎技術進行架構 EMP 微前端解決方案。至今有一年多,已經 releases 53 個版本,解決 108 個 issues,同時具備必定程度生態,有 43 種使用場景的 Demo,支持 7 種 EMP UI 插件支持(包括但不限於 React、Vue、Angular、Preact),4 個編譯器支持(babel、esbuild、swc、esm),1 個 Webpack Plugin,目前 EMP 已在服務的線上應用具備必定的穩定性和擴展性。node

2、EMP 出現的背景


隨着 Web 應用的日漸強大,隨之而來的是前端項目不斷膨脹。業務需求不斷疊加的狀況下,巨石項目愈來愈難維護,編譯時間愈來愈難等。具體來講是,可能會出現 幾 MB 的 Bundle Size、十幾甚至幾十號前端開發人員、一個前端代碼庫(含 node_modules)會有幾 GB。因此須要思考如何把龐大的 Web 項目分解成若干個項目,以便於團隊分工協做。react

業務開發中,不一樣項目之間會存在不少可複用的模塊。通用的用戶數據、UI架構風格、類似的業務邏輯均可以複用,例如一個時間戳轉時間的函數就能夠處處複用而無需重寫甚至引庫。因此須要思考如何可讓多個應用項目直接共享這些可複用的模塊。固然拆成 NPM 包是一個不錯的想法,也是最經常使用的。webpack

3、EMP 的優點


  • 巨型項目解耦。把巨型項目分解成多個小型項目,分團隊開發維護。git

  • 快速封裝可複用模塊。無需單獨拆包發佈到 NPM,可直接暴露須要共享的模塊。引入端僅須要簡單配置輸出端的地址便可在代碼上使用該共享模塊。github

  • 動態更新。把複用的業務模塊放在同一個基站應用之中進行管理和維護,而且暴露出去能夠給多個應用使用。若是業務模塊須要更新邏輯的話,只須要發佈部署基站應用,其餘應用並不須要任何操做,只須要訪問時刷新,便可使用最新業務模塊。web

圖片

- 遠端模塊,因爲引入端無需手動更新,遠端模塊的靈活維護和引入端能夠自由組合,甚至能夠運行時引入使用遠端模塊。npm

圖片

- 加速構建。由於引入其餘項目暴露的模塊,不須要本地構建這些子模塊的代碼,減少了構建體積,提高整個應用的構建速度。- 減小單個項目 Bundle Size。由於引入其餘項目暴露的模塊,減小各個項目 Bundle Size。

圖片

- 下圖時對舊項目改造使用了 EMP 微前端方案後帶來的速度提高的實際數據

圖片

4、EMP 架構設計


圖片

5、EMP 生態


EMP 針對不一樣的UI框架和使用場景都有進行適配和優化。

圖片

6、EMP 開箱即用

1.初始化

npx @efox/emp-cli init
  • 能夠選擇如下模板項目進行初始化,推薦試用 React Typescript 模板

    圖片

  • 按提示執行 cd my-emp && yarn && yarn dev 以後,項目將會自動打開在瀏覽器。

  • React 基站:

    圖片

+ React 項目:

圖片

  • 若是你想預先安裝 @efox/emp-cli,能夠經過全局安裝 npm install -g @efox/emp-cliyarn global add @efox/emp-cli

  • 建議你卸載該包使用 npm uninstall -g @efox/emp-cli or yarn global remove @efox/emp-cli 確保 npx 使用的 @efox/emp-cli 是最新版本。

2. EMP 惟一的配置文件 emp-config.js ,

以 React 爲例,解釋配置核心:
/**
 * @type {import('@efox/emp-cli').EMPConfig}
 */
module.exports = {
  webpack() {
    return {
      devServer: {
        /**
         * 設置 devServer
         */
        port: 8002,
      },
    }
  },
  async moduleFederation() {
    return {
      /**
      * name: 對外暴露項目名,
      */
      name: 'demo',
      /**
      * filename: 對外暴露引用文件名,
      */
      filename: 'emp.js',
      /**
      * remotes 遠程模塊
      * remotes: {
      * '引用別名': '遠程模塊項目名@遠程模塊的emp.js文件地址',
      * },
      */
      remotes: {
        '@emp/demo1': 'demo1@http://localhost:8001/emp.js',
      },
      /**
      * exposes 暴露模塊
      * exposes: {
      * '對外暴露的相對路徑': '當前項目相對路徑',
      * },
      */
      exposes: {
        './components/Hello': 'src/components/Hello',
        './helper': 'src/helper',
      },
      /**
      * shared 共享的第三方依賴
      * shared: ['依賴名'],
      */
      shared: ['react', 'react-dom'],
    }
  },
}
以 Vue2 爲例,解釋配置核心:
const withVue2 = require('@efox/emp-vue2')
module.exports = withVue2(({config}) => {
  const projectName = 'vue2Project'
  const port = 8008
  config.output.publicPath(`http://localhost:${port}/`)
  config.devServer.port(port)
  config.plugin('mf').tap(args => {
    args[0] = {
      ...args[0],
      ...{
        /**
         * name: 對外暴露項目名,
         */
        name: projectName,
        /**
        * filename: 對外暴露引用文件名,
        */
        filename: 'emp.js',
        /**
         * remotes 遠程模塊
         * remotes: {
         * '引用別名': '遠程模塊項目名@遠程模塊的emp.js文件地址',
         * },
         */
        remotes: {
          '@v2b': 'vue2Base@http://localhost:8009/emp.js',
        },
        /**
        * exposes 暴露模塊
        * exposes: {
        * '對外暴露的相對路徑': '當前項目相對路徑',
        * },
        */
        exposes: {
          './Content': './src/components/Content',
        },
        /**
        * shared 共享的第三方依賴
        * shared: ['依賴名'],
        */
        shared: ['vue/dist/vue.esm.js'],
      },
    }
    return args
  })

  config.plugin('html').tap(args => {
    args[0] = {
      ...args[0],
      ...{
        title: 'EMP Vue2 Project',
      },
    }
    return args
  })
})

7、已有項目無痛升級到 EMP 微前端架構


  • @vue/cli Vue2 模版升級到微前端 EMP

  • React CRA 項目升級到微前端 EMP

8、跨框架調用實現


EMP 不推薦你們跨框架調用,由於這樣會增長維護成本和風險。可是咱們仍是支持:

  • Vue3 調用 Vue2 組件

  • Vue&React 互相調用

9、對比 NPM 拆包


  • 可是 npm 拆包有必定工做量:
  1. 須要把可複用模塊從業務項目抽離到一個新的 package

  2. 搭建新的構建配置

  3. 單獨建 repo

  4. 在原有業務項目從新引用

  5. 可能會由於封裝,須要從新設計 API

  • 可是業務模塊抽離成 npm 包後,使用 npm 包的更新流程繁瑣複雜:
  1. 更新 npm 包版本

  2. 更新 A 應用的npm包版本

  3. 重啓 A 應用進行驗證

  4. 發佈部署 A 管理系統應用

  5. 對 B 和C 應用循環2和三、4步驟

圖片

  • 可是 npm 包會拖慢構建速度:經過 npm 引入 n 個的業務模塊後,在構建時至關於將n個業務模塊的代碼「複製」到了項目中,構建時須要同步去構建這些業務子模塊,致使 bundle size 變大,構建時長會增長,開發體驗變差,發佈效率也會隨之下降。

圖片

10、總結

  • 本文用較短的篇幅介紹了 EMP 的誕生背景、使用場景、生態以及如何無痛使用。

  • EMP 在不斷迭代升級,同時生態日漸完善,歡迎各位來了解、使用 EMP 微前端解決方案。

  • 期待你們一塊兒探討,歡迎來提issue或者新功能:

    https://github.com/efoxTeam/emp

11、QA


招聘信息:

百度直播研發部招聘研發崗位,包括客戶端-Android/iOS方向,服務端-Go/PHP方向。咱們負責百度直播業務,對直播業務感興趣歡迎加入咱們。

關注同名公衆號百度Geek說,輸入內推便可,咱們期待你的加入!

推薦閱讀:

百度C++工程師的那些極限優化(併發篇)

百度C++工程師的那些極限優化(內存篇)

|百度大規模Service Mesh落地實踐

一種基於實時分位數計算的系統及方法

---------- END ----------

百度Geek說

百度官方技術公衆號上線啦!

技術乾貨 · 行業資訊 · 線上沙龍 · 行業大會

招聘信息 · 內推信息 · 技術書籍 · 百度周邊

歡迎各位同窗關注

相關文章
相關標籤/搜索