Webpack 5的模塊聯(lián)邦提供加載部分編譯好的代碼能力,這個(gè)似乎會(huì)成為微前端架構(gòu)的標(biāo)準(zhǔn)實(shí)現(xiàn)。
Webpack只是我分享的一小點(diǎn),我是08年出道的高級(jí)前端架構(gòu)師,有問(wèn)題或者交流經(jīng)驗(yàn)可以進(jìn)我的扣扣裙 519293536 我都會(huì)盡力幫大家哦
引言
在當(dāng)前的微前端實(shí)現(xiàn)中,我們需要通過(guò)一系列的技巧去實(shí)現(xiàn)。正如上圖所示,微前端的公共依賴(lài)加載目前并沒(méi)有非常好的實(shí)現(xiàn)方案。然后,Webpack 5中的模塊聯(lián)邦將會(huì)改變這一現(xiàn)狀。
模塊聯(lián)邦可以去依賴(lài)一個(gè)遠(yuǎn)程模塊,這個(gè)依賴(lài)會(huì)在運(yùn)行時(shí)生效,并不影響編譯時(shí)。因此,這個(gè)遠(yuǎn)程依賴(lài)的模塊就可以是一個(gè)微前端獨(dú)立模塊。同時(shí),每個(gè)獨(dú)立模塊都可以申明公共的依賴(lài)庫(kù),這樣也可以避免獨(dú)立模塊間的依賴(lài)包的冗余和沖突。
這篇文章將一步步告訴你如何通過(guò)Webpack 5的模塊聯(lián)邦特性來(lái)搭建一個(gè)微前端應(yīng)用。這里可以找到源代碼。
示例
這個(gè)例子首先包含一個(gè)空殼涵蓋兩個(gè)模塊(Home、Flights),這個(gè)空殼應(yīng)用可以按需的加載各個(gè)微前端模塊。
下面是微前端模塊的部分-Flights,這部分其實(shí)也可以獨(dú)立運(yùn)行。
通過(guò)這樣的架構(gòu)可以實(shí)現(xiàn)各個(gè)模塊的獨(dú)立開(kāi)發(fā)發(fā)布,同時(shí)有能夠按需的進(jìn)行集成整合。
模塊聯(lián)邦
在過(guò)去要實(shí)現(xiàn)微前端的架構(gòu)是非常困難的,尤其是像Webpack這類(lèi)工具是需要在編譯階段保證全部代碼的完整性。懶加載是有可能的,但需要在編譯階段排除掉才行。
在微前端架構(gòu)下,每個(gè)獨(dú)立模塊都需要獨(dú)立編譯打包,并且需要人工引入。大體的代碼如下:
import('http://other-microfrontend');
復(fù)制代碼
這樣的實(shí)現(xiàn)需要依賴(lài)external方式的JavaScript人工引入,在Webpack 5中這一實(shí)現(xiàn)方式將會(huì)得到改變。
模塊聯(lián)邦背后的原理非常簡(jiǎn)單:宿主系統(tǒng)通過(guò)配置名稱(chēng)來(lái)引用遠(yuǎn)程模塊,同時(shí)在編譯階段宿主系統(tǒng)是不需要了解遠(yuǎn)程模塊的,僅僅在運(yùn)行時(shí)通過(guò)加載遠(yuǎn)程模塊的入口文件來(lái)實(shí)現(xiàn)。
宿主系統(tǒng)實(shí)現(xiàn)
宿主系統(tǒng)用于引入遠(yuǎn)程模塊。這個(gè)例子會(huì)加載一個(gè)遠(yuǎn)程模塊mfe1/component,mfe1是配置的遠(yuǎn)程模塊名,component是其中提供的一個(gè)文件。
const rxjs = await import('rxjs');
const container = document.getElementById('container');
const flightsLink = document.getElementById('flights');
rxjs.fromEvent(flightsLink, 'click').subscribe(async _ => {
const module = await import('mfe1/component');
const elm = document.createElement(module.elementName);
[…]
container.appendChild(elm);
});
復(fù)制代碼
在Webpack配置中,采用ModuleFederationPlugin可以來(lái)申明要使用的遠(yuǎn)程模塊信息。
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
[…]
plugins: [
new ModuleFederationPlugin({
name: "shell",
library: { type: "var", name: "shell" },
remotes: {
mfe1: "mfe1"
},
shared: ["rxjs"]
})
]
復(fù)制代碼
這樣遠(yuǎn)程模塊mfe1就聲明完成了,Webpack在編譯階段就會(huì)把mfe1相關(guān)的引用都忽略,避免將其進(jìn)行打包。
在shared中可以定義依賴(lài)的公共庫(kù),這個(gè)例子就是rxjs。這樣就可以保證整個(gè)應(yīng)用僅僅會(huì)加載rxjs庫(kù)一次,否則的話(huà)公共庫(kù)會(huì)被打包進(jìn)入宿主應(yīng)用,同時(shí)也會(huì)在各個(gè)子模塊中重復(fù)出現(xiàn)。
當(dāng)然,shared的公共庫(kù)需要保證是一樣的版本。同時(shí),宿主系統(tǒng)需要通過(guò)dynamic import的方式進(jìn)行加載:
import * as rxjs from 'rxjs';
復(fù)制代碼
遠(yuǎn)程模塊的實(shí)現(xiàn)
遠(yuǎn)程模塊也是一個(gè)獨(dú)立系統(tǒng),這里采用web component方式實(shí)現(xiàn):
class Microfrontend1 extends HTMLElement {
constructor() {
super();
this.attachShadow({ mode: 'open' });
}
async connectedCallback() {
this.shadowRoot.innerHTML = `[…]`;
}
}
const elementName = 'microfrontend-one';
customElements.define(elementName, Microfrontend1);
export { elementName };
復(fù)制代碼
當(dāng)然,你可以采用任何一種前端框架來(lái)實(shí)現(xiàn),通用的框架庫(kù)可以用shared的方式在宿主和遠(yuǎn)程模塊之間實(shí)現(xiàn)公用。
在遠(yuǎn)程模塊的Webpack配置中,也需要使用ModuleFederationPlugin,將模塊暴露出去。
output: {
publicPath: "http://localhost:3000/",
[…]
},
[…]
plugins: [
new ModuleFederationPlugin({
name: "mfe1",
library: { type: "var", name: "mfe1" },
filename: "remoteEntry.js",
exposes: {
component: "./mfe1/component"
},
shared: ["rxjs"]
})
]
復(fù)制代碼
name定義了遠(yuǎn)程模塊的配置名稱(chēng)。通過(guò)遠(yuǎn)程模塊名稱(chēng)和暴露出來(lái)的組件名,宿主就可以遠(yuǎn)程進(jìn)行依賴(lài)引用:
import('mfe1/component')
復(fù)制代碼
最后,宿主還需要知道遠(yuǎn)程模塊的url來(lái)真正引入。
宿主連接遠(yuǎn)程模塊
宿主系統(tǒng)需要加載遠(yuǎn)程的入口文件,這個(gè)文件是遠(yuǎn)程模塊通過(guò)ModuleFederationPlugin打包產(chǎn)生的。
入口文件名定義在filename的配置中,這個(gè)例子定義為"remoteEntry.js"。微前端模塊的url定義在publicPath屬性上。
在宿主系統(tǒng)中引入遠(yuǎn)程模塊入口文件:
<script src="http://localhost:3000/remoteEntry.js"></script>
復(fù)制代碼
在這個(gè)例子中,我們提供了兩個(gè)系統(tǒng)
- 宿主系統(tǒng):地址是localhost:5000,會(huì)加載遠(yuǎn)程模塊入口文件
- 遠(yuǎn)程模塊:地址是localhost:3000,提供了遠(yuǎn)程模塊組件
結(jié)論
Webpack 5的模塊聯(lián)邦機(jī)制給微前端勢(shì)必會(huì)帶來(lái)革命性的變化。遠(yuǎn)程的模塊可以獨(dú)立編譯,然后在運(yùn)行時(shí)進(jìn)行加載,同時(shí)還能夠定義公共庫(kù)來(lái)避免重復(fù)加載。
現(xiàn)在Webpack 5依舊還是beta版本,但我們已經(jīng)可以預(yù)見(jiàn)在不久的將來(lái),模塊聯(lián)邦將成為微前端架構(gòu)中標(biāo)準(zhǔn)解決方案之一。
覺(jué)得我寫(xiě)的不錯(cuò)的話(huà),交個(gè)朋友,我是08年出道的高級(jí)前端架構(gòu)師,有問(wèn)題或者交流經(jīng)驗(yàn)可以進(jìn)我的扣扣裙 519293536 我都會(huì)盡力幫大家哦
本文的文字及圖片來(lái)源于網(wǎng)絡(luò)加上自己的想法,僅供學(xué)習(xí)、交流使用,不具有任何商業(yè)用途,版權(quán)歸原作者所有,如有問(wèn)題請(qǐng)及時(shí)聯(lián)系我們以作處理