日韩av黄I国产麻豆传媒I国产91av视频在线观看I日韩一区二区三区在线看I美女国产在线I麻豆视频国产在线观看I成人黄色短片

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

微前端实践--webpack5模块联邦

發(fā)布時(shí)間:2023/12/29 HTML 38 豆豆
生活随笔 收集整理的這篇文章主要介紹了 微前端实践--webpack5模块联邦 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

webpack5推出一個(gè)非常令人驚艷的功能叫module federation,中文叫模塊聯(lián)邦,它提供了一套在不同項(xiàng)目構(gòu)建之間的調(diào)度、運(yùn)行機(jī)制。它很像微前端,但又不限于此。本文結(jié)合案例介紹一下該特性的基本應(yīng)用和原理。

類似微前端

微前端的概念相信大家都不陌生,其本質(zhì)是服務(wù)的拆分與隔離,最大程度地減少服務(wù)之間的沖突與碰撞。webpack的模塊聯(lián)邦做的事情與此差不多。

不過,webpack模塊聯(lián)邦有更多的優(yōu)點(diǎn):

  • 基于webpack生態(tài),學(xué)習(xí)成本、實(shí)施成本低。畢竟大多數(shù)項(xiàng)目都在webpack
  • 天生的工程化,npm各種包任你發(fā)揮
  • 相關(guān)概念脈絡(luò)清晰易懂
  • 配置簡單易上手,官方也提供了基于各種框架的版本

那么,如果你之前有過在前端實(shí)踐微服務(wù)的念頭,又由于這樣那樣的原因沒有實(shí)施,現(xiàn)在,你的機(jī)會來了!
[外鏈圖片轉(zhuǎn)存失敗,源站可能有防盜鏈機(jī)制,建議將圖片保存下來直接上傳(img-1Ee2RO9E-1621275790600)(https://p3-juejin.byteimg.com/tos-cn-i-k3u1fbpfcp/b6d1d375b08441fa9e384d56259a4699~tplv-k3u1fbpfcp-zoom-1.image)]

三個(gè)概念

首先,要理解三個(gè)重要的概念:

  • webpack構(gòu)建。一個(gè)獨(dú)立項(xiàng)目通過webpack打包編譯而產(chǎn)生資源包。
  • remote。一個(gè)暴露模塊供其他webpakc構(gòu)建消費(fèi)的webpack構(gòu)建。
  • host。一個(gè)消費(fèi)其他remote模塊的webpack構(gòu)建。

一言以蔽之,一個(gè)webpack構(gòu)建可以是remote–即服務(wù)的提供方,也可以是host–即服務(wù)的消費(fèi)方,也可以同時(shí)扮演服務(wù)提供者和服務(wù)消費(fèi)者,完全看項(xiàng)目的架構(gòu)。

host與remote兩個(gè)角色的依賴關(guān)系可用下圖表示:

需要指出的是,任何一個(gè)webpack構(gòu)建既可以作為host消費(fèi)方,也可以作為remote提供方,區(qū)別在于職責(zé)和webpack配置的不同。

案例實(shí)操

項(xiàng)目依賴關(guān)系介紹

一共有三個(gè)微應(yīng)用:lib-app、component-app、main-app,角色分別是:

  • lib-appas remote,暴露了兩個(gè)模塊react和react-dom
  • component-app as remote and host,依賴lib-app,暴露了一些組件供main-app消費(fèi)
  • main-app as host,依賴lib-app和component-app

lib-app暴露模塊

//webpack.config.js module.exports = {//...省略plugins: [new ModuleFederationPlugin({name: "lib_app",filename: "remoteEntry.js",exposes: {"./react":"react","./react-dom":"react-dom"}})],//...省略 }

編譯后的結(jié)果如下:


除去生成的map文件,有四個(gè)文件:main.js、remoteEntry.js、...react_index.js、...react-dom_index.js;

  • 第一個(gè)是本項(xiàng)目的入口文件(該項(xiàng)目只是暴露接口,所以該文件為空)
  • 第二個(gè)是遠(yuǎn)程入口文件,其他webpack構(gòu)建使用、訪問本項(xiàng)目暴露的模塊時(shí),須通過它來加載
  • 第三個(gè)和第四個(gè)是暴露的模塊,供其他項(xiàng)目消費(fèi)

component-app的配置

依賴lib-app,暴露三個(gè)模塊組件Button、Dialog、Logo

//webpack.config.js module.exports = {//...省略plugins:[new ModuleFederationPlugin({name: "component_app",filename: "remoteEntry.js",exposes: {"./Button":"./src/Button.jsx","./Dialog":"./src/Dialog.jsx","./Logo":"./src/Logo.jsx"},remotes:{"lib-app":"lib_app@http://localhost:3000/remoteEntry.js"}}),] }

三個(gè)暴露的組件:

//Button.jsx import React from 'lib-app/react'; export default function(){return <button style={{color: "#fff",backgroundColor: "#409eff",borderColor: "#409eff"}}>按鈕組件</button> } //Dialog.jsx import React from 'lib-app/react'; export default class Dialog extends React.Component {constructor(props) {super(props);}render() {if(this.props.visible){return (<div style={{position:"fixed",left:0,right:0,top:0,bottom:0,backgroundColor:"rgba(0,0,0,.3)"}}><button onClick={()=>this.props.switchVisible(false)} style={{position:"absolute",top:"10px",right:"10px"}}>X</button><div style={{ marginTop:"20%",textAlign:"center"}}><h1>What is your name ?</h1><input style={{fontSize:"18px",lineHeight:2}} type="text" /></div></div>);}else{return null;}} } // Logo.jsx import React from 'lib-app/react'; import pictureData from './MF.jpeg' export default function(){return <img src={pictureData} style={{width:"500px",borderRadius:"10px"}}/> }

構(gòu)建結(jié)果基本跟上一個(gè)類似。
需要說明的是,為了保證暴露的組件可以正常工作,需要在本地做測試,main.js 是測試的入口函數(shù)。該子項(xiàng)目下運(yùn)行npm run start打開瀏覽器:localhost:3001可以看到組件正常工作:


并且打開控制臺網(wǎng)絡(luò),react、react-dom模塊已經(jīng)從本項(xiàng)目中分離:

main-app的配置

main-app依賴兩個(gè)項(xiàng)目lin-app、component-app。

///webpack.config.js module.exports = {//省略...plugins: [new ModuleFederationPlugin({name: "main_app",remotes:{"lib-app":"lib_app@http://localhost:3000/remoteEntry.js","component-app":"component_app@http://localhost:3001/remoteEntry.js"},}),new HtmlWebpackPlugin({template: "./public/index.html",})]//省略... };

由于需要等待基礎(chǔ)模塊加載完畢,所以需要配置懶加載入口bootstrap.js.

  • webpack打包入口文件
import("./bootstrap.js")
  • bootstrap.js
import App from './App.jsx' import ReactDOM from 'lib-app/react-dom'; import React from 'lib-app/react' ReactDOM.render(<App />, document.getElementById("app"));
  • 根組件App.jsx
import React from 'lib-app/react'; import Button from 'component-app/Button' import Dialog from 'component-app/Dialog' import Logo from 'component-app/Logo' export default class App extends React.Component{constructor(props) {super(props)//省略...}//省略...render(){return (<div>//省略...</div>)} }

運(yùn)行并打開瀏覽器http://localhost:3002:

查看控制臺,資源進(jìn)行了很好的分離:

基本原理

這一節(jié),我們從host的代碼著手,簡單分析這一切是如何交互、工作的。

程序從main.js里的一段代碼開始:

__webpack_require__.e("bootstrap_js").then(__webpack_require__.bind(__webpack_require__,"./bootstrap.js"))

__webpack_require__.e("bootstrap_js")是加載id為bootstrap_js的chunk的所有依賴,返回一個(gè)promise.等一切依賴就緒,再獲取./bootstrap.js模塊并執(zhí)行

這里是__webpack_require__.e的代碼:

__webpack_require__.e = (chunkId) => {return Promise.all(Object.keys(__webpack_require__.f).reduce((promises, key) => {__webpack_require__.f[key](chunkId, promises);return promises;}, [])); };

上面一段代碼做了一件事,遍歷__webpack_require__.f對象并依次執(zhí)行對象里的成員函數(shù),此時(shí)該對象有兩個(gè)成員:

{remotes:(chunkId, promises) => {//查找chunkId bootstrap_js對應(yīng)的所有遠(yuǎn)程模塊并加載var chunkMapping = {"bootstrap_js": ["webpack/container/remote/lib-app/react","webpack/container/remote/component-app/Button",//省略...]};var idToExternalAndNameMapping = {"webpack/container/remote/lib-app/react": ["default","./react","webpack/container/reference/lib-app"],"webpack/container/remote/component-app/Button": ["default","./Button","webpack/container/reference/component-app"],//...省略};},j:(chunkId,promises)=>{//負(fù)責(zé)加載chunkId對應(yīng)的本地模塊} }

綜上,bootstrap_js對應(yīng)了兩個(gè)promises:

  • 一個(gè)負(fù)責(zé)遠(yuǎn)程依賴加載
  • 另一個(gè)負(fù)責(zé)本地加載

等到所有依賴模塊加載完準(zhǔn)備就緒,才會require模塊并執(zhí)行。

當(dāng)然,細(xì)節(jié)遠(yuǎn)不止此。源碼里還有一些比較有趣的模塊,如__webpack_require__.l負(fù)責(zé)以script標(biāo)簽的方式加載腳本、webpackJsonpCallback負(fù)責(zé)更新本地模塊的promsie狀態(tài)、__webpack_require__.f.j里遠(yuǎn)程模塊的層級調(diào)用等,
囿于篇幅有限,無法作做過多深入介紹,有興趣的朋友,歡迎留言討論!

最后

本文所涉及的案例已經(jīng)托管到Github。

如有任何疑惑,歡迎留言討論,如果本文對你有所幫助,可以點(diǎn)贊轉(zhuǎn)發(fā)給更多的人哦。

總結(jié)

以上是生活随笔為你收集整理的微前端实践--webpack5模块联邦的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。