基于webpack 5 ModuleFederationPlugin 实现微前端
有这么一个需求,项目里有很多业务模块,它们都有引用一些公共组件,每个业务模块打包后都是一个独立的应用,当公共组件修改时,单独打包公共组件,其他应用能够不需要重新构建,就能直接使用最新的公共组件,要怎么实现?
一开始我想到的是使用网络资源,就是把公共组件打包后的js文件放到服务器,其他应用通过script请求使用,尝试了一下,难以实现,放弃了。
后来找到了webpack 5的ModuleFederationPlugin,看了一下官方文档,完全适合这个需求,记录一下实现过程。
主要使用webpack 5的ModuleFederationPlugin插件实现模块共享和引用。
一、先创建两个vue-cli项目,分别是app1和app2
app1作为公共应用,把组件共享给其他应用使用
app2作为业务应用,引用app1共享的组件
这里就不介绍vue-cli创建步骤了,直接跳过
二、app1新增组件button.vue和divider.vue

index.js提供按需引用
// button/index.js
import Button from './button.vue'
export default {
install(Vue) {
Vue.component('PtButton', Button)
}
}
common.js提供全量注册
// common.js
import './style.css'
import Button from './button/index'
import Divider from './divider/index'
const install = async (vue) => {
[
Button,
Divider
].forEach(component => {
vue.use(component)
})
}
export default {
install,
Button,
Divider
}
vue.config.js 配置
// vue.config.js
module.exports = {
// 共享模块必须是完整路径,不能是相对路径,否则无法请求额外的css和js资源
publicPath: process.env.NODE_ENV === 'production' ? "http://localhost:2020/peento" : "http://localhost:8095",
chainWebpack: (config) => {
/* splitChunks可能会和 ModuleFederationPlugin 造成冲突,先移除 */
config.optimization.delete("splitChunks");
config
.plugin("module-federation-plugin")
.use(require("webpack").container.ModuleFederationPlugin, [
{
name: "peento", // 模块名称
filename: "peento.js", // 输出的文件名称
exposes: {
// 对外暴露的组件
"./peento-ui": "./src/components/common.js", // 暴露所有组件,通过use方法使用
"./button": "./src/components/button/button", // 暴露单独组件,需要注册使用
},
remotes: {}
},
]);
},
devServer: {
port: 8095,
hot: true
},
};
三、app2引用app1共享出来的组件
app2的vue.config.js配置
// app2 vue.config.js
module.exports = {
chainWebpack(config) {
config.optimization.delete('splitChunks')
config
.plugin("module-federation-plugin")
.use(require("webpack").container.ModuleFederationPlugin, [
{
remotes: {
// 生产环境所有应用域名相同的情况下,可以使用相对路径,否则需要使用完整路径
peento: process.env.NODE_ENV === 'production' ? "peento@http://localhost:2020/peento/peento.js" : "peento@http://localhost:8095/peento.js"
}
}
])
},
devServer: {
port: 8085,
hot: true
},
};
app2的mian.js引用app1的组件
// app2 main.js
import Vue from 'vue'
import App from './App.vue'
import('peento/peento-ui').then(res => {
const peento = res.default
Vue.use(peento) // 全量注册,可直接在组件里使用
new Vue({
render: h => h(App),
}).$mount('#app')
})
也可以直接在组件中使用
// app2 App.vue
<template>
<div id="app">
<PtButton>895621</PtButton>
</div>
</template>
<script>
export default {
name: 'App',
components: {
PtButton: () => import('peento/button')
}
}
</script>
四、分布运行app1和app2开发环境,app2页面正常显示app1的button组件,实践成功!

下面是我根据上面的需求实现的一个多模块项目,有兴趣的可以看一下;
点击查看:vue-cli-module
项目结构和配置展示:


浙公网安备 33010602011771号