这是个撒
webpack5模块联邦为我们提供了一种在应用程序之间共享代码的新方法。用白话来说,模块联邦提供了一种模块间共享代码的能力,为前端代码组织结构提供新的思路。
用它能干哈
那么谈谈能用他做啥
- 模块拆解。庞大的应用会面临代码编译速度慢,各个模块迭代快速上线排队等,拆解模块解决问题
- 能力共享 。a应用写了某种能力,b应用也需要,常规做法再贴一份做迁移,有了模块联邦直接共享。
- 资源共享。传统的npm共享面临资源同步问题,使用模块联邦一键更新。
- ...more
咋用捏
引入ModuleFederationPlugin,w5自带,无需安装
宿主配置也类似,就不贴了。
如何引用暴露出的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我就不列举了。
考究的加载顺序
依次在加载远程模块时,它知道自己依赖的共享模块,然后去检测是否存在,不存在依次去加载,所以依赖就位后才开始执行自己。
加载顺序先加载main.js是因为是要知晓我们的远程主机,然后拉取远程主机的入口文件remoteEntry,拉取共享的依赖,加载远程主机的chunk。
流程分析、梳理源码
大致瞅一眼打出来的东西,webpack那些工具方法.s .l .e等等之类的都有两套在main和RemoteEntry里,好家伙,啥都有两套呢,各处理各的。
异步加载文件的__webpack_require__.e,和以前不太一样,调用了__webpack_require__.f,把f上的方法挨个执行了遍,f上的remote,cosumes,j这仨。remote是处理远程需要引入的文件的,cosumes处理共享文件的,j是jsonp是真正执行拉取的地方。这块代码比较多也比较易懂,就不贴了。
remoteEntry第一行
这也解释了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的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的去赋值,至于版本不一致问题啥的不再细说,有兴趣可以深入探讨。
总结
优势还是很明显的,几乎无需二次开发成本的代码模块拆分,丝滑的共享,开箱即用...(我在吹啥)
模块联邦为微前端提供的新思路还是很惊艳的,期待更多发现~
常见问题FAQ
- 免费下载或者VIP会员专享资源能否直接商用?
- 本站所有资源版权均属于原作者所有,这里所提供资源均只能用于参考学习用,请勿直接商用。若由于商用引起版权纠纷,一切责任均由使用者承担。更多说明请参考 VIP介绍。
- 提示下载完但解压或打开不了?
- 找不到素材资源介绍文章里的示例图片?
- 模板不会安装或需要功能定制以及二次开发?
发表评论
还没有评论,快来抢沙发吧!