最新公告
  • 欢迎您光临起源地模板网,本站秉承服务宗旨 履行“站长”责任,销售只是起点 服务永无止境!立即加入钻石VIP
  • 带你解析微前端新方案-Module Federation

    正文概述 掘金(是萱酱啊)   2021-04-12   1589

    这是个撒

    webpack5模块联邦为我们提供了一种在应用程序之间共享代码的新方法。用白话来说,模块联邦提供了一种模块间共享代码的能力,为前端代码组织结构提供新的思路。

    用它能干哈

    那么谈谈能用他做啥

    1. 模块拆解。庞大的应用会面临代码编译速度慢,各个模块迭代快速上线排队等,拆解模块解决问题
    2. 能力共享 。a应用写了某种能力,b应用也需要,常规做法再贴一份做迁移,有了模块联邦直接共享。
    3. 资源共享。传统的npm共享面临资源同步问题,使用模块联邦一键更新。
    4. ...more

    咋用捏

    引入ModuleFederationPlugin,w5自带,无需安装 带你解析微前端新方案-Module Federation

    宿主配置也类似,就不贴了。

    如何引用暴露出的Search呢,import('search/Search')

    原理

    基础概念

    常见的import

    先从前置基础开始聊聊,我们的import变成了啥,大概手撸一段伪代码就是酱紫,通过webpack_require来取我们的import的东西,其实是被存进了一个缓存对象,用到时先检查模块是否已经加载过了,如果加载过了直接返回,没有加载过就调加载的方法的加载。

    import React from 'react';
    
    export default function MyCom () {
      return <div> hello world </div>;
    }
    
    (() => {
    function webpack_require(dep) {
      return webpack_module[dep]
    }
    function define(key, obj) {
     	webpack_module[key] = obj;
    }
      
      ((webpack_require, define) => {
        const namespace = 'src_myCom_index_jsx';
        const myDep = {
          React: 'node_modules_react_index_js'
        };
        function MyCom() {
        	return webpack_require(myDep.React).creatElement(div, 'hello,world')
      	}
        define(namespace, {
          default: MyCom,
          xx: xxx
        });
      })(webpack_require)
    })()
    

    moduleMap从何而来

    能够根据我们传入的模块id返回模块的内容,那么必然有映射的对象,那么这个nb的moudleMap是从何而来,在我们打出来的bundle.js,大概有酱婶儿的东东~

    (function (modules) {})({
        "./src/main.js": (function (module, __webpack_exports__, __webpack_require__) {}),
    })();
    

    动态的import被解析成啥样呢

    大概解析成酱紫

    __webpack_require__.e( /*! import() */ 0).then(__webpack_require__.bind(null, /*! ./chunka*/ "./src/chunka.js")).then(module => {});
    

    大概就是用__webpack_require__.e,用类似于jsonp的方法去加载chunk,等加载完了再把这堆塞到自己的map里面。

    ///////

    开始我们的正题,神奇的MF

    MF的文件结构

    简单写一下,大致拥有这点东西,表达的意思就是app1可以引入app2的Button,app2可以引入app1的AppOneCom,他们共享依赖react、react-dom,如果不使用devserver,还需要在app1的html里加 ,app2的同理。

    app1
    ---index.js 入口文件
    ---bootstrap.js 启动文件
    ---App.js react组件
    ---AppOneCom.jsx 用于暴露的组件
     
    app2
    ---index.js 入口文件
    ---bootstrap.js 启动文件
    ---App.js react组件
    ---Button.jsx 用于暴露的组件
    

    MF都打出来了啥

    和以前不一样的大致就是这些,其他chunk和bundle我就不列举了。

    带你解析微前端新方案-Module Federation

    考究的加载顺序

    带你解析微前端新方案-Module Federation

    依次在加载远程模块时,它知道自己依赖的共享模块,然后去检测是否存在,不存在依次去加载,所以依赖就位后才开始执行自己。

    加载顺序先加载main.js是因为是要知晓我们的远程主机,然后拉取远程主机的入口文件remoteEntry,拉取共享的依赖,加载远程主机的chunk。

    流程分析、梳理源码

    大致瞅一眼打出来的东西,webpack那些工具方法.s .l .e等等之类的都有两套在main和RemoteEntry里,好家伙,啥都有两套呢,各处理各的。

    带你解析微前端新方案-Module Federation

    异步加载文件的__webpack_require__.e,和以前不太一样,调用了__webpack_require__.f,把f上的方法挨个执行了遍,f上的remote,cosumes,j这仨。remote是处理远程需要引入的文件的,cosumes处理共享文件的,j是jsonp是真正执行拉取的地方。这块代码比较多也比较易懂,就不贴了。

    remoteEntry第一行

    带你解析微前端新方案-Module Federation

    带你解析微前端新方案-Module Federation

    这也解释了window上为啥有app_two,这些初始化加载的,后面也会通过window在调。

    crucial point!

    既然上面的分析都看到了,main.js和remoteEntry里的啥啥都不是一套,对于共享的文件咋整呢,我总不能拉取两遍吧,分别给modulemap赋值吧,那还叫啥子共享,必须保持单例在store里面。关键点来咯,我简写下就是酱紫

    在main.js里面,被共享的react...

    register('react', '17.0.0', () => __webpack_require__.e('node_modules_react_index_js').then(() => () => __webpack_require__('./node_modules/react/index.js')));
    // ....这堆register执行完了 执行了initExternal
    initExternal("webpack/container/reference/app_two");
    
    // initExternal方法大概就是酱紫
    function initExternal() {
      var module = __webpack_require__(id);
    	if (!module) return;
    	var initFn = module => module && module.init && module.init(__webpack_require__.S[name], initScope);
      if (module.then) return promises.push(module.then(initFn, handleError));
    }
    

    initExternal方法看清没看清没,__webpack_require__虽然这家伙是自己的,但是返回的是module,这家伙可是个对象上面还挂着方法,假想如果这家伙是app2的,那就是他们通讯的方式了,他把自己的webpack_require.s 传过去了。那么就去康康module是个啥。

    function __webpack_require__(moduleId) {
      ...omit
      // 其他的先不看,这段话是执行我们__webpack_modules__['webpack/container/reference/app_two'],沿着寻找我们穿进去的"webpack/container/reference/app_two"对应的是啥
    __webpack_modules__[moduleId](module, module.exports, __webpack_require__); // Return the exports of the module
    }
    // 找到这段
    'webpack/container/reference/app_two': /***/ (module, __unused_webpack_exports, __webpack_require__) => {
                module.exports = new Promise((resolve, reject) => {
                    __webpack_require__.l(
                        'http://localhost:3002/remoteEntry.js',
                        event => {
                           // 异常处理,omit
                        },
                        'app_two'
                    );
                }).then(() => app_two);
    }
      // 这段执行完了取module.exports就是Promise,PromiseValue是app_two,我在这里打log
    

    带你解析微前端新方案-Module Federation

    实锤了这个module的promiseValue就是window.app_two,印证了上面的猜测,调了2的init,init里将传进来的赋值给自己,2的init如下。

    var init = (shareScope, initScope) => {
    	if (!__webpack_require__.S) return;
    	var oldScope = __webpack_require__.S["default"];
    	var name = "default"
      // crucial point
    	__webpack_require__.S[name] = shareScope;
    	return __webpack_require__.I(name, initScope);
    };
    
    

    大概上面的问题也解释通了,如何实现的共享,main拉完了资源通知了remoteEntry的去赋值,至于版本不一致问题啥的不再细说,有兴趣可以深入探讨。

    总结

    优势还是很明显的,几乎无需二次开发成本的代码模块拆分,丝滑的共享,开箱即用...(我在吹啥)

    模块联邦为微前端提供的新思路还是很惊艳的,期待更多发现~


    起源地下载网 » 带你解析微前端新方案-Module Federation

    常见问题FAQ

    免费下载或者VIP会员专享资源能否直接商用?
    本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
    提示下载完但解压或打开不了?
    最常见的情况是下载不完整: 可对比下载完压缩包的与网盘上的容量,若小于网盘提示的容量则是这个原因。这是浏览器下载的bug,建议用百度网盘软件或迅雷下载。若排除这种情况,可在对应资源底部留言,或 联络我们.。
    找不到素材资源介绍文章里的示例图片?
    对于PPT,KEY,Mockups,APP,网页模版等类型的素材,文章内用于介绍的图片通常并不包含在对应可供下载素材包内。这些相关商业图片需另外购买,且本站不负责(也没有办法)找到出处。 同样地一些字体文件也是这种情况,但部分素材会在素材包内有一份字体下载链接清单。
    模板不会安装或需要功能定制以及二次开发?
    请QQ联系我们

    发表评论

    还没有评论,快来抢沙发吧!

    如需帝国cms功能定制以及二次开发请联系我们

    联系作者

    请选择支付方式

    ×
    迅虎支付宝
    迅虎微信
    支付宝当面付
    余额支付
    ×
    微信扫码支付 0 元