丰富的线上&线下活动,深入探索云世界
做任务,得社区积分和周边
最真实的开发者用云体验
让每位学生受益于普惠算力
让创作激发创新
资深技术专家手把手带教
遇见技术追梦人
技术交流,直击现场
海量开发者使用工具、手册,免费下载
极速、全面、稳定、安全的开源镜像
开发手册、白皮书、案例集等实战精华
为开发者定制的Chrome浏览器插件
作者:云谦
ModuleFederation[fedren]使JavaScript应用得以在客户端或服务器上动态运行另一个bundle的代码。
这其中的关键点是:
一个应用可以是Host,也可以是Remote,也可以同时是Host和Remote。
通过回答ModuleFederation如何运转?Host如何消费Remote?以及Remote如何优先使用Hostshared的依赖?这三个问题,我们分析一下ModuleFederation的原理。
配置示例:
newModuleFederationPlugin({name:"app-1",library:{type:"var",name:"app_1"},filename:"remoteEntry.js",remotes:{app_02:'app_02',app_03:'app_03',},exposes:{antd:'./src/antd',button:'./src/button',},shared:['react','react-dom'],}),配置属性:
产物:
所以比如下面如图示例的应用集群:
加载方式应该这样:
可以通过代码示例来进行理解。 B源码: //src/react.jsexport*from'react';//webpack.config.js...exposes:{react:'./src/react',},A源码: //异步加载B的react模块constReact=awaitimport('B/react');B构建产物: //windows变量letB;constmoduleMap={'react':()=>{returnPromise.all([e('a'),e('b'),e('c')]),},};B={get(moduleId){returnmoduleMap(moduleId);}}A构建产物: constmodules={'B':()=>{returnB;}};//异步获取模块export内容functione(moduleId){//1.取shared的模块//2.取remote的模块constidToExternalAndNameMapping={'B/react':['B','react'],};//从moduleB里取reactconstdata=idToExternalAndNameMapping[moduleId];__webpack_require__(data[0]).get(data[1]);//3.取当前项目的异步模块}//初始化e('B/react');这其中的原理: 再看如下两个代码示例。 B构建产物: letB;__webpack_require__.Overrides={};functione(moduleId){//1.取shared的模块//当前项目的shared模块列表constfallbackMapping={};//先从Overrides里取,再从当前项目里取push_require_try(__webpack_require__.Overrides[moduleId]||fallbackMapping[moduleId]);//2.取remote的模块//3.取当前项目的异步模块}B={override(override){Object.assign(__webpack_require__.Overrides,override);}}A构建产物: B.override(Object.assign({'react':()=>{//A的react内容},},__webpack_require__.Overrides));原理分析: 这样,B里面在requirereact时,就会用A的react模块。 ModuleFederation可以用在哪里? 如上图,这是去年画的一张微前端的图,其中最下面的“公共依赖加载”一直是没有非常优雅的方案。 方法一:让每个子应用都分开打包,主应用不管,这样不会有问题,但问题就是尺寸大,而且大了不是一点点。 方法二:主应用包含antd和react,子应用如果版本一致不打包react和antd,版本不一致就自己打一份,但有几个问题: 方法三:利用ModuleFederation的shared能力,子应用的依赖如果和主应用匹配,那么,能解决方法二里的第一个问题,但第二个问题依旧解不了。 方法四:利用ModuleFederation的remotes能力,再提一个应用专门提供库被消费,看起来前面的问题都能解。 有没有感觉技术又轮回到了seajs+spmjs的时代。 现状是,通过npm共享组件。 基于ModuleFederation,除通过npm共享依赖,还可以有运行时的依赖、组件、页面甚至应用的直接共享。 这样一来,灵活性就非常大了,可以在应用的各个层面做共享。A应用引用B整个应用,也可以应用B的的页面和组件,还可以提一个库应用,做npm依赖的运行时共享。 现在项目组织和文件依赖通常是这样: 现状是: 期望的是: 为什么不是其他的编译速度优化方案? 举一个对比的例子,比如external,我们之前还有做过自动的external方案,虽然他也可能显著提速,但有以下问题: