精讀《Webpack5 新特性 - 模塊聯邦》

1 引言

先說結論:Webpack5 模塊聯邦讓 Webpack 達到了線上 Runtime 的效果,讓代碼直接在項目間利用 CDN 直接共享,再也不須要本地安裝 Npm 包、構建再發布了!javascript

咱們知道 Webpack 能夠經過 DLL 或者 Externals 作代碼共享時 Common Chunk,但不一樣應用和項目間這個任務就變得困難了,咱們幾乎沒法在項目之間作到按需熱插拔。html

模塊聯邦是 Webpack5 新內置的一個重要功能,可讓跨應用間真正作到模塊共享,因此這周讓咱們經過 webpack-5-module-federation-a-game-changer-in-javascript-architecture 這篇文章瞭解什麼是 「模塊聯邦」 功能。前端

2 概述 & 精讀

NPM 方式共享模塊

想象一下正常的共享模塊方式,對,就是 NPM。java

以下圖所示,正常的代碼共享須要將依賴做爲 Lib 安裝到項目,進行 Webpack 打包構建再上線,以下圖:react

對於項目 Home 與 Search,須要共享一個模塊時,最多見的辦法就是將其抽成通用依賴並分別安裝在各自項目中。webpack

雖然 Monorepo 能夠必定程度解決重複安裝和修改困難的問題,但依然須要走本地編譯。git

UMD 方式共享模塊

真正 Runtime 的方式多是 UMD 方式共享代碼模塊,即將模塊用 Webpack UMD 模式打包,並輸出到其餘項目中。這是很是廣泛的模塊共享方式:github

對於項目 Home 與 Search,直接利用 UMD 包複用一個模塊。但這種技術方案問題也很明顯,就是包體積沒法達到本地編譯時的優化效果,且庫之間容易衝突。web

微前端方式共享模塊

微前端:micro-frontends (MFE) 也是最近比較火的模塊共享管理方式,微前端就是要解決多項目並存問題,多項目並存的最大問題就是模塊共享,不能有衝突。前端工程化

因爲微前端還要考慮樣式衝突、生命週期管理,因此本文只聚焦在資源加載方式上。微前端通常有兩種打包方式:

  1. 子應用獨立打包,模塊更解耦,但沒法抽取公共依賴等。
  2. 總體應用一塊兒打包,很好解決上面的問題,但打包速度實在是太慢了,不具有水平擴展能力。

模塊聯邦方式

終於提到本文的主角了,做爲 Webpack5 內置核心特性之一的 Federated Module:

從圖中能夠看到,這個方案是直接將一個應用的包應用於另外一個應用,同時具有總體應用一塊兒打包的公共依賴抽取能力。

讓應用具有模塊化輸出能力,其實開闢了一種新的應用形態,即 「中心應用」,這個中心應用用於在線動態分發 Runtime 子模塊,並不直接提供給用戶使用:

對微前端而言,這張圖就是一個完美的主應用,由於全部子應用均可以利用 Runtime 方式複用主應用的 Npm 包和模塊,更好的集成到主應用中。

模塊聯邦的使用方式以下:

const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");

module.exports = {
  // other webpack configs...
  plugins: [
    new ModuleFederationPlugin({
      name: "app_one_remote",
      remotes: {
        app_two: "app_two_remote",
        app_three: "app_three_remote"
      },
      exposes: {
        AppContainer: "./src/App"
      },
      shared: ["react", "react-dom", "react-router-dom"]
    }),
    new HtmlWebpackPlugin({
      template: "./public/index.html",
      chunks: ["main"]
    })
  ]
};
複製代碼

模塊聯邦自己是一個普通的 Webpack 插件 ModuleFederationPlugin,插件有幾個重要參數:

  1. name 當前應用名稱,須要全局惟一。
  2. remotes 能夠將其餘項目的 name 映射到當前項目中。
  3. exposes 表示導出的模塊,只有在此申明的模塊才能夠做爲遠程依賴被使用。
  4. shared 是很是重要的參數,制定了這個參數,可讓遠程加載的模塊對應依賴改成使用本地項目的 React 或 ReactDOM。

好比設置了 remotes: { app_twp: "app_two_remote" },在代碼中就能夠直接利用如下方式直接從對方應用調用模塊:

import { Search } from "app_two/Search";
複製代碼

這個 app_two/Search 來自於 app_two 的配置:

// app_two 的 webpack 配置
export default {
  plugins: [
    new ModuleFederationPlugin({
      name: "app_two",
      library: { type: "var", name: "app_two" },
      filename: "remoteEntry.js",
      exposes: {
        Search: "./src/Search"
      },
      shared: ["react", "react-dom"]
    })
  ]
};
複製代碼

正是由於 Searchexposes 被導出,咱們所以可使用 [name]/[exposes_name] 這個模塊,這個模塊對於被引用應用來講是一個本地模塊。

3 總結

模塊聯邦爲更大型的前端應用提供了開箱解決方案,並已經做爲 Webpack5 官方模塊內置,能夠說是繼 Externals 後最終的運行時代碼複用解決方案。

另外 Webpack5 還內置了大量編譯時緩存功能,能夠看到,不管是性能仍是多項目組織,Webpack5 都在嘗試給出本身的最佳思路,期待 Webpack5 正式發佈,前端工程化會邁向一個新的階段。

討論地址是:精讀《Webpack5 新特性 - 模塊聯邦》 · Issue #239 · dt-fe/weekly

若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。

關注 前端精讀微信公衆號

版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證

相關文章
相關標籤/搜索