webpack5推出的新特性联邦模块,允许在不同项目之间通过CDN共享模块,解决了应用间共享模块的问题,相对于npm包共享的方式更加的便利,可以直接通过CDN来共享模块;
模块共享方式对比
| 方式 | 优势 | 不足 |
|---|---|---|
| NPM | 1、共享模块 2、支持TS | 1、组件改动后,需要通知每个依赖该组件的项目去重新编译上线 2、需要将组件安装,再从node_modules引入使用 |
| UMD/CDN(大部分SDK实现方式,将变量挂载到全局上) | 1、共享模块 2、runtime(运行时)加载模块 | 1、共享的模块和项目无法通过webpack进一步编译优化 2、无法共享TS |
| 模块联邦 Module Federation | 1、共享模块 2、模块升级无需每个项目重新编译上线 3、共享模块和项目可以一起编译,方便进行公共模块提取或者压缩编译优化 | 1、不支持共享TS,需要再Host收到维护远程模块的类型 2、需要确保共享模块的健壮性,因为其本身的改动升级会直接影响所有依赖它的项目,这一点是优势也是不足 3、需确保消费和被消费的项目Webpack都升级到webpack5 |
模块共享方式图示对比
模块联邦如何使用?
Host:主模块,当消费远程模块时,其被称为Host
Remote:远程模块,当其被消费时,就是Remote远程模块;
一个模块既可以当主模块也可以当远程模块
API说明:
name: 当前应用名称,需要全局唯一
remotes: 作为host时,声明消费哪些模块
exposes: 作为remote(远程模块)时,导出的具体模块
shared:强制远程(Remotes)模块使用主模块(Host)的依赖项,当主模块没有该依赖项时,会直接使用远程模块自身的依赖;
// A项目的配置
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
// other webpack configs...
plugins: [
new ModuleFederationPlugin({
name: "app_A",
remotes: {
moduleB: "moduleB@https://localhost:3001/moduleB.js",
moduleC: "moduleC@https://localhost:3002/moduleC.js"
},
shared: ["react", "react-dom", "react-router-dom"]
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
chunks: ["main"]
})
]
};
// A项目使用远程模块 from格式'remotes的Key/远程模块exposes的key'
import ModuleB from 'moduleB/list';
// B项目的配置
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
// other webpack configs...
plugins: [
new ModuleFederationPlugin({
name: "app_B",
remotes: {
moduleC: "moduleC@https://localhost:3002/moduleC.js"
},
filename: 'moduleB.js',
exposes:{
list: './src/components/ModuleB.vue'
},
shared: ["react", "react-dom", "react-router-dom"]
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
chunks: ["main"]
})
]
};
// C项目的配置
const HtmlWebpackPlugin = require("html-webpack-plugin");
const ModuleFederationPlugin = require("webpack/lib/container/ModuleFederationPlugin");
module.exports = {
// other webpack configs...
plugins: [
new ModuleFederationPlugin({
name: "app_C",
filename: 'moduleC.js',
exposes:{
search: './src/components/ModuleC.vue'
}
}),
new HtmlWebpackPlugin({
template: "./public/index.html",
chunks: ["main"]
})
]
};