日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 前端技术 > HTML >内容正文

HTML

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

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

webpack5推出一個非常令人驚艷的功能叫module federation,中文叫模塊聯邦,它提供了一套在不同項目構建之間的調度、運行機制。它很像微前端,但又不限于此。本文結合案例介紹一下該特性的基本應用和原理。

類似微前端

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

不過,webpack模塊聯邦有更多的優點:

  • 基于webpack生態,學習成本、實施成本低。畢竟大多數項目都在webpack
  • 天生的工程化,npm各種包任你發揮
  • 相關概念脈絡清晰易懂
  • 配置簡單易上手,官方也提供了基于各種框架的版本

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

三個概念

首先,要理解三個重要的概念:

  • webpack構建。一個獨立項目通過webpack打包編譯而產生資源包。
  • remote。一個暴露模塊供其他webpakc構建消費的webpack構建。
  • host。一個消費其他remote模塊的webpack構建。

一言以蔽之,一個webpack構建可以是remote–即服務的提供方,也可以是host–即服務的消費方,也可以同時扮演服務提供者和服務消費者,完全看項目的架構。

host與remote兩個角色的依賴關系可用下圖表示:

需要指出的是,任何一個webpack構建既可以作為host消費方,也可以作為remote提供方,區別在于職責和webpack配置的不同。

案例實操

項目依賴關系介紹

一共有三個微應用:lib-app、component-app、main-app,角色分別是:

  • lib-appas remote,暴露了兩個模塊react和react-dom
  • component-app as remote and host,依賴lib-app,暴露了一些組件供main-app消費
  • 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"}})],//...省略 }

編譯后的結果如下:


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

  • 第一個是本項目的入口文件(該項目只是暴露接口,所以該文件為空)
  • 第二個是遠程入口文件,其他webpack構建使用、訪問本項目暴露的模塊時,須通過它來加載
  • 第三個和第四個是暴露的模塊,供其他項目消費

component-app的配置

依賴lib-app,暴露三個模塊組件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"}}),] }

三個暴露的組件:

//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"}}/> }

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


并且打開控制臺網絡,react、react-dom模塊已經從本項目中分離:

main-app的配置

main-app依賴兩個項目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",})]//省略... };

由于需要等待基礎模塊加載完畢,所以需要配置懶加載入口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>)} }

運行并打開瀏覽器http://localhost:3002:

查看控制臺,資源進行了很好的分離:

基本原理

這一節,我們從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的所有依賴,返回一個promise.等一切依賴就緒,再獲取./bootstrap.js模塊并執行

這里是__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對象并依次執行對象里的成員函數,此時該對象有兩個成員:

{remotes:(chunkId, promises) => {//查找chunkId bootstrap_js對應的所有遠程模塊并加載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)=>{//負責加載chunkId對應的本地模塊} }

綜上,bootstrap_js對應了兩個promises:

  • 一個負責遠程依賴加載
  • 另一個負責本地加載

等到所有依賴模塊加載完準備就緒,才會require模塊并執行。

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

最后

本文所涉及的案例已經托管到Github。

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

總結

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

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。