1、模块联邦是什么
mf是webpack5的新插件,它的主要功能是我们可以将项目中的部分组件或全部组件暴露给外侧使用。我们也可以引用其他项目中暴露的组件,从而实现模块的复用。听起来mf好像与npm安装包的形式非常类似,都可以暴露组件给外部使用,我自己本身也可以使用其他安装包的组件。那他们的具体区别有哪些呢?
我们用个实例解释:
例如我们有一个项目a,要使用项目b中的某些功能。对于npm的形式,我们可以通过将b的项目打包之后,让项目a引用就行。假设这个时候突然项目b发现自己的写的某些功能有bug,那么也要项目a更新依赖包重新发布。如果是mf的形式,我们就只需要更新项目b即可。这是最大的区别
2、Module federation该如何使用
2.1 、前置准备
mf是基于webpack5的,如果是项目中使用的构建是基于webpack4或其他版本的话,那么就需要对webpack进行升级改造。
2.2、Module federation插件配置项
name: 应用的名称。在其他应用查找的时候,会在这个name的作用域下去查找对应的组件。
remotes: 一个映射管理,将其他远程的名称映射成本地的别名。例如上面的我们将其他远程项目app_2映射成了本地的app_two。
filename: 这些对外暴露的模块存放在哪个文件中。
exposes: 对外暴露的模块。只有对外暴露的相应的模块功能才能被使用。
share d: 制定了这个参数,可以让远程加载的模块对应依赖改为使用本地项目的 vue 或 vue-router
2.3 示例
- 创建两个 vue+ webpack项目 host , remote ;
- host项目创建一个buttonCom组件;
- host项目配置webpack.dev.js
const { ModuleFederationPlugin } = require("webpack").container;
new ModuleFederationPlugin({
name: "host_app",
filename: "hostEntry.js",
exposes: {
"./Button": "./src/components/ButtonCom.vue",
},
}),
4. 重新运行host 项目 npm run dev, 会看到页面请求了 hostEntry.js 这个文件 5. 里面声明了一个 aaa_app 的变量。这就是说 webpack 把这个组件的代码分离到了这个文件里。这样别的 webpack 应用就可以直接用这个组件了。
- remote项目 在webpack.dev.js的plugins中引入host导出的组件
const { ModuleFederationPlugin } = require("webpack").container;
new ModuleFederationPlugin({
remotes: {
host_app: "host_app@http://localhost:8080/hostEntry.js",
},
}),
7. 在remote页面中就可以直接使用host导出的组件buttonCom
3、Module federation原理分析
以remote使用host导出的ButtonCom组件为例,来说明模块联邦内部的实现原理,究竟是怎样将两个不同应用之间的模块关联起来的。
(1)host在配置提供ButtonCom组件时,需要在expose中指明组件名称和组件在文件中路径的对应关系,将打包后的文件命名为hostEntry,最后打包生成的文件导出的是host_app的全局变量,这个全局变量上挂载了一个MoudleMap对象,它维护了组件名和组件的地址关系,另外也挂载了一个get方法,这个方法通过传入的模块名,先去moduelMap中找到模块打包后真正的所在地址,然后进行资源的加载。
(2)remote首先会通过模块联邦的配置,将host打包后生成的hostEntry.js文件加载进来,这样其实在remote中就已经拿到了app_host这个全局变量,以及挂载的ModuleMap对象和get方法。
(3)host在使用remote提供的Button组件时,实际是通过webpack_require方法调用Button组件的Id, 在该方法中会先判断缓存中是否存在,不存在的话,会调用_webpack.require.f.remote方法,该方法接收chunckId参数,然后在chunckMapping中查找该文件下,都使用了app2的那些组件,chunckMapping维护的是chunckId和模块ID的映射关系,找到模块ID之后,在IdNameMapping中获取到该模块所在的应用名,以及模块名,_webpack.require.f.remote底层实际调用的事app2.get(Button)的方法,通过全局变量的关联,获取到app2提供的组件
4、总结
Module Federation 是 webpack5 提供的用于应用之间共享模块的机制,只要用 ModuleFederationPlugin 声明 exposes 的模块,另一个应用里用 ModuleFederationPlugin 声明 remotes 导入的模块,就可以直接用别的应用的模块了。
这就是它为什么会叫模块联邦。
除了业务模块外,库模块也可以共享。只不过要注意这些模块都是异步加载的,所以要用 import()来异步引入。
单独引入异步组件需要用import的形式,或者把整个应用用 import() 来异步加载。