模块联邦
webpack
作为前端工程师广泛使用的打包工具,在整个前端生态中具有不可撼动的地位。目前,在最新的webpack5
版本中带来了许多新特性,其中模块联邦
倍受关注。
什么是模块联邦
module federation
模块联邦,它可以让多个独立构建的应用之间,动态的调用彼此的模块。这种运行机制,可以让我们轻松的拆分应用,真正做到跨应用的模块共享。
重要概念
host
: webpack构建可以是remote远程服务的提供方。
remote
:也可以作为host主机的服务消费方。
bidirectional-hosts
: 亦可作为双向主机,同时兼顾remote和host。
container
:每个构建都充当一个容器,能够通过从对应的容器中加载模块来访问其它容器暴露出来的模块。
简单示例
app1 配置:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { ModuleFederationPlugin } = require("webpack").container; // 通过使用webpack内置插件构建模块
module.exports = (env = {}) => ({
// 其它 webpack 配置...
plugins: [
new ModuleFederationPlugin({
name: "app1", // 当前应用的名称,需要全局维一
filename: "remoteEntry.js", // 共享模块的入口文件
library: { type: 'var', name: 'app1' }, // 共享模块的全局引用
exposes: { // 导出的模块,只有在此申明的模块才可以作为远程依赖被使用
"./Button": "./src/components/Button",
},
shared: ['vue', 'element-ui'] // 远程加载的模块对应的依赖使用本地项目的依赖
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "./public/index.html"),
})
],
devServer: {
port: 3001,
}
});
app2 配置:
const HtmlWebpackPlugin = require("html-webpack-plugin");
const { ModuleFederationPlugin } = require("webpack").container; // 通过使用webpack内置插件构建模块
module.exports = (env = {}) => ({
// 其它 webpack 配置...
plugins: [
new ModuleFederationPlugin({
name: 'app2',
filename: "remoteEntry.js",
remotes: { // 引入远程应用的导出的模块, name@host address/filename.
app1: 'app1@http://localhost:3001/remoteEntry.js'
},
shared: ['vue', 'element-ui'] // 抽离的依赖与其它应用保持一致
}),
new HtmlWebpackPlugin({
template: path.resolve(__dirname, "./public/index.html"),
})
],
});
更多的使用案例请参考此仓库: module-federation-examplesh
微前端架构存在的问题
在当前的微前端架构中,通过了许多技术手段如应用分离、JS沙箱、CSS隔离、预加载等实现了整个架构的使用。但对于公共依赖加载目前并没有非常好的解决方案。
通常处理公共依赖的方式是使用npm,将依赖抽离作为lib公共库进行管理。应用之中使用到lib,将其安装到项目中,再通过webpack打包上线。
这种方式虽然解决了公共依赖问题,但还是需要走本地编译,无法做到项目运行时(runtime)调用。
使用webpack5模块联邦就可以解决这一问题。
将公共依赖配置成一个远程模块,子应用只需要根据需求动态加载。这种方式可以做到运行时调用,不用考虑本地编译问题。
这就衍生出一种新的应用形态——中心应用
,这个应用具备模块化输出的能力,可以在线动态的分发运行时的子模块。
结语
模块联邦在一定程度上弥补了微前端架构中的不足,让微前端架构日益趋向成熟。在可以预见的未来,前端工程化将进入一个新的阶段,下一波技术浪潮将会来临。