模块联邦(Vite)
模块联邦
什么是模块联邦?模块联邦是
Webpack 5
的新特性,它允许不同的应用或组件之间进行动态的模块共享。为什么要使用模块联邦?模块联邦可以解决多个应用或组件之间的依赖问题,避免重复安装依赖,提高开发效率。
项目地址
项目目录
1 | |-- packages |
项目搭建
使用 lerna 创建一个 monorepo
项目。(也可以直接创建两个项目)
- 命令行执行
npx lerna init
, 初始化项目
开启 pnpm workspaces
lerna.json
中添加下面配置1
2
3
4
5{
"npmClient": "pnpm",
"packages": ["packages/*"],
... // 其他配置
}在根目录下创建
pnpm-workspace.yaml
并添加下面配置1
2packages:
- 'packages/*'然后在根目录下创建
packages
目录 (注意:名称要与上面配置的packages/*
目录名称一致)
进入 packages
创建项目 host
依次执行下面命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 进入 packages 目录
cd ./packages
# 创建项目 host
pnpm create vite
# Project name
host
# Select a framework
React
# Select a variant
TypeScript + SWC在
packages/host/vite.config.ts
中配置启动端口1
2
3
4
5
6export default defineConfig({
server: {
port: 8000,
},
... // 其他配置
});
进入 packages
创建项目 remote
依次执行下面命令
1
2
3
4
5
6
7
8
9
10
11
12
13
14# 进入 packages 目录
cd ./packages
# 创建项目 remote
pnpm create vite
# Project name
remote
# Select a framework
React
# Select a variant
TypeScript + SWC在
packages/remote/vite.config.ts
中配置启动端口1
2
3
4
5
6export default defineConfig({
server: {
port: 8001,
},
... // 其他配置
});
为两个项目添加 @originjs/vite-plugin-federation
1 | # -r 为所有项目执行命令 |
配置 remote
项目
在
packages/remote/src/components/CustomButton/index.tsx
中添加下面代码1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18interface Props {
/** 按钮文案 */
text?: string;
/** 按钮点击事件 */
onClick?: () => void;
/** 按钮样式 */
style?: React.CSSProperties;
/** 按钮类名 */
className?: string;
}
/** 自定义按钮 */
const CustomButton = (props: Props) => {
const { text, ...rest } = props;
return <button {...rest}>{text}</button>;
};
export default CustomButton;在
packages/remote/src/components/index.ts
中添加下面代码1
export { default as CustomButton } from './CustomButton/index.tsx';
修改
packages/remote/src/App.tsx
文件内容如下1
2
3
4
5
6
7
8
9
10
11
12import './App.css';
import { CustomButton } from './components';
function App() {
return (
<>
<CustomButton text="Hello Remote" />
</>
);
}
export default App;修改
packages/remote/vite.config.ts
文件内容如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import federation from '@originjs/vite-plugin-federation';
// https://vite.dev/config/
// federation参数参考 https://github.com/originjs/vite-plugin-federation?tab=readme-ov-file#configuration
export default defineConfig({
plugins: [
react(),
federation({
// 必填, 作为远程模块的模块名称
name: 'remote',
// 非必填, 作为远程模块的入口文件, 默认为 remoteEntry.js
filename: 'remoteEntry.js',
// 向公众公开的组件列表
exposes: {
'./CustomButton': './src/components/CustomButton/index.tsx',
},
// 本地和远程模块共享的依赖项. 本地模块需要配置所有使用的远程模块的依赖; 远程模块需要配置外部提供的组件的依赖.
shared: ['react', 'react-dom'],
}),
],
server: {
port: 8001,
},
preview: {
// 生产端口
// 只有 Host 端支持 dev 模式,Remote 端要求使用 生成 RemoteEntry.js 包.
// 详见: https://github.com/originjs/vite-plugin-federation?tab=readme-ov-file#vite-dev-mode
port: 8001,
},
build: {
// 处理报错: ERROR: await is not available in the configured target environmentTop-level
// 详见: https://github.com/originjs/vite-plugin-federation?tab=readme-ov-file#error-top-level-await-is-not-available-in-the-configured-target-environment
target: 'esnext',
},
});
配置 host
项目
修改
packages/host/src/App.tsx
文件内容如下1
2
3
4
5
6
7
8
9
10
11
12
13
14import './App.css';
import React from 'react';
const CustomButton = React.lazy(() => import('remote/CustomButton'));
function App() {
return (
<>
<CustomButton text="Hello Host" />
</>
);
}
export default App;修改
packages/host/src/vite-env.d.ts
文件内容如下1
2
3
4
5
6
7/// <reference types="vite/client" />
declare module 'remote/*' {
import { ComponentType } from 'react';
const component: ComponentType<any>;
export default component;
}修改
packages\host\vite.config.ts
文件内容如下1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22import { defineConfig } from 'vite';
import react from '@vitejs/plugin-react-swc';
import federation from '@originjs/vite-plugin-federation';
// https://vite.dev/config/
export default defineConfig({
plugins: [
react(),
federation({
// 必填, 作为远程模块的模块名称
name: 'host',
remotes: {
// 作为本地模块引用的远程模块入口文件, [远程模块名称]: [远程模块入口文件地址]
remote: 'http://localhost:8001/assets/remoteEntry.js',
},
shared: ['react', 'react-dom'],
}),
],
server: {
port: 8000,
},
});
启动项目
先启动
remote
项目 (根目录下执行)1
2
3
4
5# 需要先打包项目, 生成 remoteEntry.js
pnpm -F remote build
# 启动项目
pnpm -F remote run preview再启动
host
项目 (根目录下执行)1
pnpm -F host dev
配置快捷命令
在根目录
package.json
中添加下面配置1
2
3
4
5
6
7
8"scripts": {
"preinstall": "npx only-allow pnpm",
"remote": "pnpm -F remote build && pnpm -F remote run preview",
"host": "pnpm -F host dev",
"bootstrap": "lerna bootstrap",
"clean": "lerna clean && rimraf ./node_modules"
},
... // 其他配置执行
pnpm run remote
启动remote
项目执行
pnpm run host
启动host
项目
本博客所有文章除特别声明外,均采用 CC BY-NC-SA 4.0 许可协议。转载请注明来源 小四先生的云!
评论