先說結論:Webpack5 模塊聯邦讓 Webpack 達到了線上 Runtime 的效果,讓代碼直接在項目間利用 CDN 直接共享,再也不須要本地安裝 Npm 包、構建再發布了!javascript
咱們知道 Webpack 能夠經過 DLL 或者 Externals 作代碼共享時 Common Chunk,但不一樣應用和項目間這個任務就變得困難了,咱們幾乎沒法在項目之間作到按需熱插拔。html
模塊聯邦是 Webpack5 新內置的一個重要功能,可讓跨應用間真正作到模塊共享,因此這周讓咱們經過 webpack-5-module-federation-a-game-changer-in-javascript-architecture 這篇文章瞭解什麼是 「模塊聯邦」 功能。前端
想象一下正常的共享模塊方式,對,就是 NPM。java
以下圖所示,正常的代碼共享須要將依賴做爲 Lib 安裝到項目,進行 Webpack 打包構建再上線,以下圖:react
對於項目 Home 與 Search,須要共享一個模塊時,最多見的辦法就是將其抽成通用依賴並分別安裝在各自項目中。webpack
雖然 Monorepo 能夠必定程度解決重複安裝和修改困難的問題,但依然須要走本地編譯。git
真正 Runtime 的方式多是 UMD 方式共享代碼模塊,即將模塊用 Webpack UMD 模式打包,並輸出到其餘項目中。這是很是廣泛的模塊共享方式:github
對於項目 Home 與 Search,直接利用 UMD 包複用一個模塊。但這種技術方案問題也很明顯,就是包體積沒法達到本地編譯時的優化效果,且庫之間容易衝突。web
微前端:micro-frontends (MFE) 也是最近比較火的模塊共享管理方式,微前端就是要解決多項目並存問題,多項目並存的最大問題就是模塊共享,不能有衝突。前端工程化
因爲微前端還要考慮樣式衝突、生命週期管理,因此本文只聚焦在資源加載方式上。微前端通常有兩種打包方式:
終於提到本文的主角了,做爲 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
,插件有幾個重要參數:
name
當前應用名稱,須要全局惟一。remotes
能夠將其餘項目的 name
映射到當前項目中。exposes
表示導出的模塊,只有在此申明的模塊才能夠做爲遠程依賴被使用。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"]
})
]
};
複製代碼
正是由於 Search
在 exposes
被導出,咱們所以可使用 [name]/[exposes_name]
這個模塊,這個模塊對於被引用應用來講是一個本地模塊。
模塊聯邦爲更大型的前端應用提供了開箱解決方案,並已經做爲 Webpack5 官方模塊內置,能夠說是繼 Externals 後最終的運行時代碼複用解決方案。
另外 Webpack5 還內置了大量編譯時緩存功能,能夠看到,不管是性能仍是多項目組織,Webpack5 都在嘗試給出本身的最佳思路,期待 Webpack5 正式發佈,前端工程化會邁向一個新的階段。
若是你想參與討論,請 點擊這裏,每週都有新的主題,週末或週一發佈。前端精讀 - 幫你篩選靠譜的內容。
關注 前端精讀微信公衆號
版權聲明:自由轉載-非商用-非衍生-保持署名(創意共享 3.0 許可證)