去中心化组件共享方案 —— Webpack Module Federation(模块联邦)

发布时间 2023-03-26 20:24:03作者: 一颗冰淇淋

在大型应用中, 我们可能会对其进行拆分,分成容器、主应用和多个子应用,使拆分后的应用独立开发与部署,更加容易维护。但无论是微应用、公共模块应用,都需要放到容器中才能使用。

如果多个应用之间希望资源共享,除了使用 npm 包的形式,基于Webpack 5 Module Federation(模块联邦)实现的EMP微前端方案也可以一试,它不限制技术栈,但依赖于 Webpack5。

使用场景

如果应用B需要使用应用A中的User模块,那么应用B就相当于容器,同时应用A也可以使用来自应用C的Menu模块,此时应用A变成了容器。

如何使用

要想使用 Module Federation,肯定是需要搭建 webpack 环境,配置方式也比较简单,使用 ModuleFederationPlugin 分别导出/导出即可。

A应用导出文件

webpack配置需要导出的文件路径和名称

 // 其余配置省略
const Mfp = require('webpack').container.ModuleFederationPlugin;

module.exports = {  
  plugins: [
     new Mfp({
        // 对外提供打包后的文件名
        filename: 'user.js',    
        // 导出的应用/组织什么名字
        name: 'userComponent',
        // 要导出哪一个文件,key值为引入时的名字,value为当前文件路径
        exposes: {
            './username': './src/username.js',
            './userHobby': './src/userHobby.js',
        }
    })
  ]
}

B应用导入文件

webpack设置需要导入的资源地址和名称

const Mfp = require('webpack').container.ModuleFederationPlugin

plugins: [
    new Mfp({
        name: 'root',
        // key值为导入后使用的名字,value为导出的 filename@文件地址/name,设置本地服务地址方便调试
        remotes: {
            userComponent: 'userComponent@http://localhost:3001/user.js'
        }
    })
]

在需要使用的js文件中异步导入,userComponent 是定义的导入后的名字,斜杠(/)加上导出文件webpack配置exposes属性的文件名

const Username = React.lazy(()=>import('userComponent/username'))
const UserHobby = React.lazy(()=>import('userComponent/userHobby'))

return (
<React.Suspense fallback="loading"> 
    <Username/>
    <UserHobby/>
</React.Suspense>)

引入后,http://localhost:3001/user.js 将会被加载,并且资源内容挂载到 window 对象中。

这样,便可以达到应用之间共享组件的目的。

以上就是 Webpack Module Federation(模块联邦) 的介绍, 更多有关 前端工程化 的内容可以参考我其它的博文,持续更新中~