作者|APoorGuide本文介绍了ModuleFederation的概念和应用场景,并结合具体的代码示例,帮助您初步了解ModuleFederation的模块共享和公共依赖加载。方便后续更深入的学习相关内容,同时也为微前端的探索提供了一种新的思路,一定会给大家一些提升和启发。全文5405字,预计阅读时间14分钟。01什么是模块联盟(MF)?一般直译为“模块联合会”,看看官网是怎么说的?动机多个单独的构建应该形成一个应用程序。这些单独的构建之间不应该有依赖关系,因此它们可以单独开发和部署。这通常被称为微前端,但不限于此。多个独立构建一个应用程序即可形成。这些独立构建互不依赖,可以独立开发和部署。这通常被称为微前端,但不限于此。通俗地说,MF提供了在当前应用程序中远程加载其他服务器上的应用程序的能力。对此,可以推导出以下两个概念:host:引用其他应用程序的应用程序remote:被其他应用程序使用的应用程序△图片来自网络。不同于我们一般讨论的基础应用和微应用。它是去中心化的,彼此平等,每个应用单独部署在自己的服务器上,每个应用都可以引用其他应用,也可以被其他应用引用,即每个应用都可以充当宿主,也可以出现作为遥控器。△图片来自网络02应用场景微前端:通过共享和暴露,可以将多个应用引入到同一个应用中进行管理。资源复用,减少编译量:多个应用使用的公共组件可以单独部署,在运行时通过MF的功能引入到其他项目中,这样组件代码就不会被编译到项目中,也可以满足需求多个项目同时使用的需求,一箭双雕。03使用方法项目结构如下:module-home:首页,在布局中显示一个字符串。module-layout:布局,只包含一个html模板。module-lib:暴露工具方法,共享lodash库。3.1相关配置参数列表3.2各个应用的配置//apps/module-lib/webpack.config.jsplugins:[newModuleFederationPlugin({name:'lib',filename:'remoteLib.js',library:{type:'var',name:'lib'},exposes:{//提供工具方法'./utils':'./index.js',},shared:["lodash"]})]//apps/module-home/webpack.config.jsplugins:[newModuleFederationPlugin({name:'home',filename:'remoteHome.js',library:{type:'var',name:'home'},exposes:{//提供挂载方法'./mount':'./index.js',},shared:["lodash"]})]//apps/module-layout/webpack.config.jsplugins:[newModuleFederationPlugin({name:'main',文件名:'remoteMain.js',遥控器:{'lib':'lib@http://localhost:3001/remoteLib.js','home':'home@http://localhost:3003/remoteHome.js',},共享:['lodash']}),newHtmlWebpackPlugin({template:path.resolve(__dirname,'./public/index.html'),inject:'body'})]//apps/module-layout/boot.jsimport{getUid,setUid}来自'lib/utils'//使用module-lib中公开的方法import{mount}from'home/mount'//使用module-home中公开的挂载方法import_from'lodash';setUid();setUid();console.log(getUid())console.log(_.get)mount()如下图:布局中显示了home挂载的节点,控制台也打印了调用lib中方法的log,和lib共享lodash也生效了(整个过程只加载了一个lodash)3.3以remoteLib为例子简要分析//确定全局变量varlib;/******/(()=>{//webpackBootstrap/******/"usestrict";/******/var__webpack_modules__=({/***/"webpack/container/entry/lib":/*!***************************!*\!***容器条目***!\***********************//***/((__unused_webpack_module,exports,__webpack_require__)=>{eval("varmoduleMap={\n\t\"./utils\":()=>{\n\t\treturn__webpack_require__.e(\"index_js\").then(()=>(()=>((__webpack_require__(/*!./index.js*/\"./index.js\")))));\n\t}\n};\nvarget=(module,getScope)=>{\n\t__webpack_require__.R=getScope;\n\tgetScope=(\n\t\t__webpack_require__.o(moduleMap,module)\n\t\t\t?moduleMap[模块]()\n\t\t\t:Promise.resolve().then(()=>{\n\t\t\t\tthrownewError('Module\"'+module+'\"在容器中不存在。');\n\t\t\t})\n\t);\n\t__webpack_require__.R=undefined;\n\treturngetScope;\n};\nvarinit=(shareScope,initScope)=>{\n\tif(!__webpack_require__.S)return;\n\tvarname=\"default\"\n\tvaroldScope=__webpack_require__.S[name];\n\tif(oldScope&&oldScope!==shareScope)thrownewError(\"容器初始化失败,因为它已经用不同的共享范围初始化\");\n\t__webpack_require__.S[name]=shareScope;\n\treturn__webpack_require__.I(name,initScope);\n};\n\n//这会导出getter以禁止修改\n__webpack_require__.d(exports,{\n\tget:()=>(get),\n\tinit:()=>(init)\n});\n\n//#sourceURL=webpack://module-lib/container_entry?");/***/})1.moduleMap:用于映射暴露2.get方法:导出到宿主应用,用于获取远程expose模块3.init方法:导出到宿主应用,用于将远程模块注入get方法调用__webpack_require__.e加载chunk/******///这个文件只包含入口块。/******///附加块的块加载函数/******/__webpack_require__.e=(chunkId)=>{/******/returnPromise.all(Object.keys(__webpack_require__.f).reduce((promises,key)=>{/******/__webpack_require__.f[key](chunkId,promises);/******/返回承诺;/******/},[]));/******/};__webpack_require__.e调用__webpack_require__.f/******/__webpack_require__.f.consumes=(chunkId,promises)=>{/******/if(__webpack_require__.o(chunkMapping,chunkId)){/******/chunkMapping[chunkId].forEach((id)=>{//如果主机已经有那么直接使用,否则就去远程安装/******/if(__webpack_require__.o(installedModules,id))returnpromises.push(installedModules[id]);/******/varonFactory=(factory)=>{/******/installedModules[id]=0;/******/__webpack_require__.m[id]=(module)=>{/******/delete__webpack_require__.c[id];/******/module.exports=factory();/******/}/******/};/******/varonError=(error)=>{/******/deleteinstalledModules[id];/******/__webpack_require__.m[id]=(module)=>{/*******/delete__webpack_require__.c[id];/******/throwerror;/******/}/******/};/******/try{/******/varpromise=moduleToHandlerMapping[id]();/******/if(promise.then){/******/promises.push(installedModules[id]=promise.then(onFactory)['catch'](onError));/******/}elseonFactory(promise);/******/}catch(e){onError(e);}/******/});/******/}/******/}/******/})();主机加载自己的包main。js,使用jsonp加载对应remote提供的remoteLib.js;全局变量暴露在远程中,宿主注入远程后可以获得相应的模块。共享模块在使用前会检查是否有自身,如果没有则加载远程04扩展学习的内容可以学习开源项目:基于Webpack5ModuleFederation,优雅实用的微前端解决方案https://github.com/yuzhanglon….——END——参考资料:[1]如何用Webpack的ModuleFederationPlugin搭建微前端[2]Webpack新功能ModuleFederation深入解析[3]基于WebpackModuleFederation,这可能是一个更优雅的方案微前端方案解决方案【4】腾讯文档探索webpack5新特性Modulefederation的应用【5】ModuleFederation原理解析推荐阅读:熟练使用Golang泛型简化代码编写Go语言DDD实践初级文章Diffie-Hellman密钥协商算法研究贴吧低代码高性能规则引擎设计在权限系统上多利熊业务应用分布式系统关键路径延迟分析实践
