@jiayouzuo/vite-module-federation-core 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +416 -0
- package/dist/dev/expose.d.ts +3 -0
- package/dist/dev/expose.d.ts.map +1 -0
- package/dist/dev/expose.js +17 -0
- package/dist/dev/remote.d.ts +3 -0
- package/dist/dev/remote.d.ts.map +1 -0
- package/dist/dev/remote.js +274 -0
- package/dist/dev/shared.d.ts +3 -0
- package/dist/dev/shared.d.ts.map +1 -0
- package/dist/dev/shared.js +22 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +181 -0
- package/dist/prod/expose.d.ts +3 -0
- package/dist/prod/expose.d.ts.map +1 -0
- package/dist/prod/expose.js +231 -0
- package/dist/prod/remote.d.ts +3 -0
- package/dist/prod/remote.d.ts.map +1 -0
- package/dist/prod/remote.js +392 -0
- package/dist/prod/shared.d.ts +4 -0
- package/dist/prod/shared.d.ts.map +1 -0
- package/dist/prod/shared.js +247 -0
- package/dist/types.d.ts +160 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +1 -0
- package/dist/utils.d.ts +51 -0
- package/dist/utils.d.ts.map +1 -0
- package/dist/utils.js +327 -0
- package/dist/virtual.d.ts +6 -0
- package/dist/virtual.d.ts.map +1 -0
- package/dist/virtual.js +34 -0
- package/dist/walker.d.ts +16 -0
- package/dist/walker.d.ts.map +1 -0
- package/dist/walker.js +110 -0
- package/package.json +48 -0
package/README.md
ADDED
|
@@ -0,0 +1,416 @@
|
|
|
1
|
+
# @jiayouzuo/vite-module-federation-core
|
|
2
|
+
|
|
3
|
+
Vite 模块联邦插件,支持微前端架构中的模块共享与远程加载。
|
|
4
|
+
|
|
5
|
+
## 安装
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
pnpm add @jiayouzuo/vite-module-federation-core
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## 功能特性
|
|
12
|
+
|
|
13
|
+
- 支持 `exposes` 暴露模块
|
|
14
|
+
- 支持 `remotes` 消费远程模块
|
|
15
|
+
- 支持 `shared` 共享依赖
|
|
16
|
+
- 支持 `exposes` 和 `remotes` 同时使用
|
|
17
|
+
- 支持 `singleton` 单例模式
|
|
18
|
+
- 支持 `strictVersion` 严格版本校验
|
|
19
|
+
- 支持开发环境和生产环境
|
|
20
|
+
- 支持 Vue 和 React 项目
|
|
21
|
+
|
|
22
|
+
---
|
|
23
|
+
|
|
24
|
+
## Vue 示例
|
|
25
|
+
|
|
26
|
+
### 远程应用(暴露模块)
|
|
27
|
+
|
|
28
|
+
```ts
|
|
29
|
+
// remote-vue-app/vite.config.ts
|
|
30
|
+
import { defineConfig } from 'vite'
|
|
31
|
+
import vue from '@vitejs/plugin-vue'
|
|
32
|
+
import federation from '@jiayouzuo/vite-module-federation-core'
|
|
33
|
+
|
|
34
|
+
export default defineConfig({
|
|
35
|
+
plugins: [
|
|
36
|
+
vue(),
|
|
37
|
+
federation({
|
|
38
|
+
// 模块名称,主应用通过此名称引用
|
|
39
|
+
name: 'remoteVueApp',
|
|
40
|
+
// 远程入口文件名
|
|
41
|
+
filename: 'remoteEntry.js',
|
|
42
|
+
// 暴露的模块,key 为导出名,value 为文件路径
|
|
43
|
+
exposes: {
|
|
44
|
+
'./Button': './src/components/Button.vue',
|
|
45
|
+
'./Card': './src/components/Card.vue',
|
|
46
|
+
'./utils': './src/utils/index.ts'
|
|
47
|
+
},
|
|
48
|
+
// 共享依赖,避免重复加载
|
|
49
|
+
shared: {
|
|
50
|
+
vue: {
|
|
51
|
+
singleton: true, // 单例模式,确保只有一个 Vue 实例
|
|
52
|
+
requiredVersion: '^3.0.0'
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
})
|
|
56
|
+
],
|
|
57
|
+
// 需要 es2022 或更高
|
|
58
|
+
build: {
|
|
59
|
+
target: 'es2022',
|
|
60
|
+
minify: false
|
|
61
|
+
}
|
|
62
|
+
})
|
|
63
|
+
```
|
|
64
|
+
|
|
65
|
+
### 主应用(消费远程模块)
|
|
66
|
+
|
|
67
|
+
```ts
|
|
68
|
+
// host-vue-app/vite.config.ts
|
|
69
|
+
import { defineConfig } from 'vite'
|
|
70
|
+
import vue from '@vitejs/plugin-vue'
|
|
71
|
+
import federation from '@jiayouzuo/vite-module-federation-core'
|
|
72
|
+
|
|
73
|
+
export default defineConfig({
|
|
74
|
+
plugins: [
|
|
75
|
+
vue(),
|
|
76
|
+
federation({
|
|
77
|
+
name: 'hostVueApp',
|
|
78
|
+
// 远程模块配置
|
|
79
|
+
remotes: {
|
|
80
|
+
// key: 引用名称,value: 远程入口地址
|
|
81
|
+
remoteVueApp: 'http://localhost:5001/assets/remoteEntry.js'
|
|
82
|
+
},
|
|
83
|
+
// 共享依赖配置需与远程应用一致
|
|
84
|
+
shared: {
|
|
85
|
+
vue: {
|
|
86
|
+
singleton: true,
|
|
87
|
+
requiredVersion: '^3.0.0'
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
})
|
|
91
|
+
],
|
|
92
|
+
build: {
|
|
93
|
+
target: 'es2022',
|
|
94
|
+
minify: false
|
|
95
|
+
}
|
|
96
|
+
})
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
### 使用远程 Vue 组件
|
|
100
|
+
|
|
101
|
+
```vue
|
|
102
|
+
<!-- host-vue-app/src/App.vue -->
|
|
103
|
+
<script setup lang="ts">
|
|
104
|
+
import { defineAsyncComponent } from 'vue'
|
|
105
|
+
|
|
106
|
+
// 方式1: 动态导入(推荐,支持懒加载)
|
|
107
|
+
const RemoteButton = defineAsyncComponent(() => import('remoteVueApp/Button'))
|
|
108
|
+
const RemoteCard = defineAsyncComponent(() => import('remoteVueApp/Card'))
|
|
109
|
+
|
|
110
|
+
// 方式2: 导入工具函数
|
|
111
|
+
import { formatDate } from 'remoteVueApp/utils'
|
|
112
|
+
</script>
|
|
113
|
+
|
|
114
|
+
<template>
|
|
115
|
+
<div>
|
|
116
|
+
<h1>主应用</h1>
|
|
117
|
+
<!-- 使用远程组件 -->
|
|
118
|
+
<RemoteButton @click="handleClick">远程按钮</RemoteButton>
|
|
119
|
+
<RemoteCard title="远程卡片" />
|
|
120
|
+
</div>
|
|
121
|
+
</template>
|
|
122
|
+
```
|
|
123
|
+
|
|
124
|
+
---
|
|
125
|
+
|
|
126
|
+
## React 示例
|
|
127
|
+
|
|
128
|
+
### 远程应用(暴露模块)
|
|
129
|
+
|
|
130
|
+
```ts
|
|
131
|
+
// remote-react-app/vite.config.ts
|
|
132
|
+
import { defineConfig } from 'vite'
|
|
133
|
+
import react from '@vitejs/plugin-react'
|
|
134
|
+
import federation from '@jiayouzuo/vite-module-federation-core'
|
|
135
|
+
|
|
136
|
+
export default defineConfig({
|
|
137
|
+
plugins: [
|
|
138
|
+
react(),
|
|
139
|
+
federation({
|
|
140
|
+
name: 'remoteReactApp',
|
|
141
|
+
filename: 'remoteEntry.js',
|
|
142
|
+
// 暴露 React 组件
|
|
143
|
+
exposes: {
|
|
144
|
+
'./Button': './src/components/Button.tsx',
|
|
145
|
+
'./Modal': './src/components/Modal.tsx',
|
|
146
|
+
'./hooks': './src/hooks/index.ts'
|
|
147
|
+
},
|
|
148
|
+
shared: {
|
|
149
|
+
// React 必须使用单例模式,否则会报 hooks 错误
|
|
150
|
+
react: {
|
|
151
|
+
singleton: true,
|
|
152
|
+
requiredVersion: '^18.0.0'
|
|
153
|
+
},
|
|
154
|
+
'react-dom': {
|
|
155
|
+
singleton: true,
|
|
156
|
+
requiredVersion: '^18.0.0'
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
})
|
|
160
|
+
],
|
|
161
|
+
build: {
|
|
162
|
+
target: 'es2022',
|
|
163
|
+
minify: false
|
|
164
|
+
}
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 主应用(消费远程模块)
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
// host-react-app/vite.config.ts
|
|
172
|
+
import { defineConfig } from 'vite'
|
|
173
|
+
import react from '@vitejs/plugin-react'
|
|
174
|
+
import federation from '@jiayouzuo/vite-module-federation-core'
|
|
175
|
+
|
|
176
|
+
export default defineConfig({
|
|
177
|
+
plugins: [
|
|
178
|
+
react(),
|
|
179
|
+
federation({
|
|
180
|
+
name: 'hostReactApp',
|
|
181
|
+
remotes: {
|
|
182
|
+
remoteReactApp: 'http://localhost:5002/assets/remoteEntry.js'
|
|
183
|
+
},
|
|
184
|
+
shared: {
|
|
185
|
+
react: {
|
|
186
|
+
singleton: true,
|
|
187
|
+
requiredVersion: '^18.0.0'
|
|
188
|
+
},
|
|
189
|
+
'react-dom': {
|
|
190
|
+
singleton: true,
|
|
191
|
+
requiredVersion: '^18.0.0'
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
})
|
|
195
|
+
],
|
|
196
|
+
build: {
|
|
197
|
+
target: 'es2022',
|
|
198
|
+
minify: false
|
|
199
|
+
}
|
|
200
|
+
})
|
|
201
|
+
```
|
|
202
|
+
|
|
203
|
+
### 使用远程 React 组件
|
|
204
|
+
|
|
205
|
+
```tsx
|
|
206
|
+
// host-react-app/src/App.tsx
|
|
207
|
+
import React, { lazy, Suspense } from 'react'
|
|
208
|
+
|
|
209
|
+
// 动态导入远程组件
|
|
210
|
+
const RemoteButton = lazy(() => import('remoteReactApp/Button'))
|
|
211
|
+
const RemoteModal = lazy(() => import('remoteReactApp/Modal'))
|
|
212
|
+
|
|
213
|
+
// 导入远程 hooks
|
|
214
|
+
import { useCounter } from 'remoteReactApp/hooks'
|
|
215
|
+
|
|
216
|
+
function App() {
|
|
217
|
+
const { count, increment } = useCounter()
|
|
218
|
+
|
|
219
|
+
return (
|
|
220
|
+
<div>
|
|
221
|
+
<h1>主应用</h1>
|
|
222
|
+
{/* 使用 Suspense 包裹远程组件 */}
|
|
223
|
+
<Suspense fallback={<div>加载中...</div>}>
|
|
224
|
+
<RemoteButton onClick={increment}>
|
|
225
|
+
点击次数: {count}
|
|
226
|
+
</RemoteButton>
|
|
227
|
+
<RemoteModal title="远程弹窗" />
|
|
228
|
+
</Suspense>
|
|
229
|
+
</div>
|
|
230
|
+
)
|
|
231
|
+
}
|
|
232
|
+
|
|
233
|
+
export default App
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
---
|
|
237
|
+
|
|
238
|
+
## 混合使用(同时作为主应用和远程应用)
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
// middle-app/vite.config.ts
|
|
242
|
+
import { defineConfig } from 'vite'
|
|
243
|
+
import vue from '@vitejs/plugin-vue'
|
|
244
|
+
import federation from '@jiayouzuo/vite-module-federation-core'
|
|
245
|
+
|
|
246
|
+
export default defineConfig({
|
|
247
|
+
plugins: [
|
|
248
|
+
vue(),
|
|
249
|
+
federation({
|
|
250
|
+
name: 'middleApp',
|
|
251
|
+
filename: 'remoteEntry.js',
|
|
252
|
+
// 暴露自己的模块给其他应用
|
|
253
|
+
exposes: {
|
|
254
|
+
'./Header': './src/components/Header.vue',
|
|
255
|
+
'./Footer': './src/components/Footer.vue'
|
|
256
|
+
},
|
|
257
|
+
// 同时消费其他远程模块
|
|
258
|
+
remotes: {
|
|
259
|
+
remoteVueApp: 'http://localhost:5001/assets/remoteEntry.js',
|
|
260
|
+
remoteReactApp: 'http://localhost:5002/assets/remoteEntry.js'
|
|
261
|
+
},
|
|
262
|
+
shared: {
|
|
263
|
+
vue: { singleton: true }
|
|
264
|
+
}
|
|
265
|
+
})
|
|
266
|
+
],
|
|
267
|
+
build: {
|
|
268
|
+
target: 'es2022'
|
|
269
|
+
}
|
|
270
|
+
})
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
---
|
|
274
|
+
|
|
275
|
+
## 配置项
|
|
276
|
+
|
|
277
|
+
### 基础配置
|
|
278
|
+
|
|
279
|
+
| 参数 | 类型 | 必填 | 说明 |
|
|
280
|
+
|------|------|------|------|
|
|
281
|
+
| name | string | 是 | 模块名称,其他应用通过此名称引用 |
|
|
282
|
+
| filename | string | 否 | 远程入口文件名,默认 `remoteEntry.js` |
|
|
283
|
+
| exposes | object | 否 | 暴露的模块,key 为导出路径,value 为文件路径 |
|
|
284
|
+
| remotes | object | 否 | 远程模块,key 为引用名称,value 为入口地址 |
|
|
285
|
+
| shared | array/object | 否 | 共享依赖配置 |
|
|
286
|
+
| shareScope | string | 否 | 共享作用域,默认 `default` |
|
|
287
|
+
|
|
288
|
+
### shared 配置
|
|
289
|
+
|
|
290
|
+
```ts
|
|
291
|
+
shared: {
|
|
292
|
+
// 简单写法:直接写包名
|
|
293
|
+
lodash: {},
|
|
294
|
+
|
|
295
|
+
// 完整配置
|
|
296
|
+
vue: {
|
|
297
|
+
// 单例模式:强制使用同一版本
|
|
298
|
+
// Vue/React 必须开启,否则会出现多实例问题
|
|
299
|
+
singleton: true,
|
|
300
|
+
|
|
301
|
+
// 严格版本:版本不匹配时抛出错误而不是回退到本地
|
|
302
|
+
strictVersion: false,
|
|
303
|
+
|
|
304
|
+
// 要求的版本范围
|
|
305
|
+
requiredVersion: '^3.0.0',
|
|
306
|
+
|
|
307
|
+
// 当前提供的版本(通常自动从 package.json 读取)
|
|
308
|
+
version: '3.4.0',
|
|
309
|
+
|
|
310
|
+
// 是否生成共享 chunk,默认 true
|
|
311
|
+
generate: true,
|
|
312
|
+
|
|
313
|
+
// 是否预加载到 HTML head
|
|
314
|
+
modulePreload: false
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
|
|
318
|
+
// 数组简写
|
|
319
|
+
shared: ['vue', 'pinia', 'lodash']
|
|
320
|
+
```
|
|
321
|
+
|
|
322
|
+
### remotes 配置
|
|
323
|
+
|
|
324
|
+
```ts
|
|
325
|
+
remotes: {
|
|
326
|
+
// 简单写法:直接写入口地址
|
|
327
|
+
remoteApp: 'http://localhost:5001/assets/remoteEntry.js',
|
|
328
|
+
|
|
329
|
+
// 完整配置
|
|
330
|
+
remoteApp2: {
|
|
331
|
+
// 远程入口地址
|
|
332
|
+
external: 'http://localhost:5002/assets/remoteEntry.js',
|
|
333
|
+
// 模块格式:esm | systemjs | var
|
|
334
|
+
format: 'esm',
|
|
335
|
+
// 来源框架:vite | webpack
|
|
336
|
+
from: 'vite'
|
|
337
|
+
},
|
|
338
|
+
|
|
339
|
+
// 动态地址(运行时决定)
|
|
340
|
+
dynamicApp: {
|
|
341
|
+
external: `Promise.resolve(window.REMOTE_URL || 'http://localhost:5003/assets/remoteEntry.js')`,
|
|
342
|
+
externalType: 'promise',
|
|
343
|
+
format: 'esm',
|
|
344
|
+
from: 'vite'
|
|
345
|
+
}
|
|
346
|
+
}
|
|
347
|
+
```
|
|
348
|
+
|
|
349
|
+
### exposes 配置
|
|
350
|
+
|
|
351
|
+
```ts
|
|
352
|
+
exposes: {
|
|
353
|
+
// 简单写法
|
|
354
|
+
'./Button': './src/components/Button.vue',
|
|
355
|
+
|
|
356
|
+
// 完整配置
|
|
357
|
+
'./Card': {
|
|
358
|
+
import: './src/components/Card.vue',
|
|
359
|
+
// 是否阻止样式自动注入到 head
|
|
360
|
+
dontAppendStylesToHead: false
|
|
361
|
+
}
|
|
362
|
+
}
|
|
363
|
+
```
|
|
364
|
+
|
|
365
|
+
---
|
|
366
|
+
|
|
367
|
+
## 类型声明
|
|
368
|
+
|
|
369
|
+
为远程模块添加类型声明:
|
|
370
|
+
|
|
371
|
+
```ts
|
|
372
|
+
// src/types/remote.d.ts
|
|
373
|
+
|
|
374
|
+
// Vue 远程模块
|
|
375
|
+
declare module 'remoteVueApp/Button' {
|
|
376
|
+
import { DefineComponent } from 'vue'
|
|
377
|
+
const component: DefineComponent<{}, {}, any>
|
|
378
|
+
export default component
|
|
379
|
+
}
|
|
380
|
+
|
|
381
|
+
declare module 'remoteVueApp/utils' {
|
|
382
|
+
export function formatDate(date: Date): string
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
// React 远程模块
|
|
386
|
+
declare module 'remoteReactApp/Button' {
|
|
387
|
+
import { FC } from 'react'
|
|
388
|
+
interface ButtonProps {
|
|
389
|
+
onClick?: () => void
|
|
390
|
+
children?: React.ReactNode
|
|
391
|
+
}
|
|
392
|
+
const Button: FC<ButtonProps>
|
|
393
|
+
export default Button
|
|
394
|
+
}
|
|
395
|
+
|
|
396
|
+
declare module 'remoteReactApp/hooks' {
|
|
397
|
+
export function useCounter(): {
|
|
398
|
+
count: number
|
|
399
|
+
increment: () => void
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
```
|
|
403
|
+
|
|
404
|
+
---
|
|
405
|
+
|
|
406
|
+
## 注意事项
|
|
407
|
+
|
|
408
|
+
1. **build.target 需要设置为 `es2022` 或更高**(因为使用了顶层 await、`??=` 等语法)
|
|
409
|
+
2. **React 项目必须对 react 和 react-dom 开启 singleton**,否则会报 hooks 相关错误
|
|
410
|
+
3. **Vue 项目建议对 vue 开启 singleton**,避免多实例问题
|
|
411
|
+
4. **共享依赖版本需要兼容**,主应用和远程应用的依赖版本差异过大可能导致问题
|
|
412
|
+
5. **开发环境和生产环境地址不同**,可通过环境变量区分配置
|
|
413
|
+
|
|
414
|
+
## License
|
|
415
|
+
|
|
416
|
+
MIT
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"expose.d.ts","sourceRoot":"","sources":["../../src/dev/expose.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAUnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,2BAA2B,GAAG,mBAAmB,CAgBzF"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* 开发环境 - 模块暴露插件
|
|
3
|
+
*/
|
|
4
|
+
import { resolve } from 'path';
|
|
5
|
+
import { parsedOptions, parseExposeOptions, EXPOSES_MAP, EXPOSES_KEY_MAP, normalizePath, removeNonRegLetter } from '../utils.js';
|
|
6
|
+
export function devExposePlugin(options) {
|
|
7
|
+
parsedOptions.devExpose = parseExposeOptions(options);
|
|
8
|
+
for (const item of parsedOptions.devExpose) {
|
|
9
|
+
const exposeFilepath = normalizePath(resolve(item[1].import));
|
|
10
|
+
EXPOSES_MAP.set(item[0], exposeFilepath);
|
|
11
|
+
EXPOSES_KEY_MAP.set(item[0], `__federation_expose_${removeNonRegLetter(item[0])}`);
|
|
12
|
+
}
|
|
13
|
+
return {
|
|
14
|
+
name: 'federation:expose-development',
|
|
15
|
+
virtualFile: {}
|
|
16
|
+
};
|
|
17
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"remote.d.ts","sourceRoot":"","sources":["../../src/dev/remote.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,mBAAmB,EAAE,2BAA2B,EAAE,MAAM,aAAa,CAAA;AAiBnF,wBAAgB,eAAe,CAAC,OAAO,EAAE,2BAA2B,GAAG,mBAAmB,CA4QzF"}
|