module federation

概述

前端的工程化已经持续了很长时间,从最开始的手动更新和维护,之后以文件为单位的自动化工具的产生,在开发和部署的过程中进行一系列的操作,最终组成一个较大的 SPA 或者 MPA。随着业务的发展,网页应用越来越多,以文件为单位进行构建则难以维护与复用。webpack5 引入了一个重要的特性 module federation,目的是解决多业务线,多工程下的模块复用问题。

使用方法

关于module federation的用法,官方给出了很详细的示例,我们以automatic-vendor-sharing为例简单来看一下是如何使用的:

线上 demo

app1

先看一下 app1 的 webpack 关键配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
new ModuleFederationPlugin({
name: 'app1',
filename: 'remoteEntry.js',
remotes: {
app2: 'app2@http://localhost:3002/remoteEntry.js',
},
exposes: {
'./Button': './src/Button',
},
shared: {
...deps,
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
}),

这里的关键信息是ModuleFederationPlugin中声明了remotes,然后我们就可以使用了,如下所示:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import LocalButton from './Button';
import React from 'react';

const RemoteButton = React.lazy(() => import('app2/Button'));

const App = () => (
<div>
<h1>Bi-Directional</h1>
<h2>App 1</h2>
<LocalButton />
<React.Suspense fallback="Loading Button">
<RemoteButton />
</React.Suspense>
</div>
);

export default App;

app2

我们回到 app1 再看一下 app1 的 webpack 配置,注意到 app1 配置了namefilename,以及exposes等信息,在开发和部署时会生成对应的文件,供其它 app 使用,我们来看一下 app2 的 webpack 关键配置:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
new ModuleFederationPlugin({
name: 'app2',
filename: 'remoteEntry.js',
remotes: {
app1: 'app1@http://localhost:3001/remoteEntry.js',
},
exposes: {
'./Button': './src/Button',
},
shared: {
...deps,
react: {
singleton: true,
},
'react-dom': {
singleton: true,
},
},
}),

app2 中也调用了 app1 的组件:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
import LocalButton from './Button';
import React from 'react';

const RemoteButton = React.lazy(() => import('app1/Button'));

const App = () => (
<div>
<h1>Bi-Directional</h1>
<h2>App 2</h2>
<LocalButton />
<React.Suspense fallback="Loading Button">
<RemoteButton />
</React.Suspense>
</div>
);

export default App;

如上示例所示,两个应用相互调用对方暴露出来的模块,那么扩展到多个应用也同样合适,这样就可以较好的解决模块复用问题

Read more