@hhfenpm/micro-app 1.0.1 → 1.0.3
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/dist/index.esm.js +83 -203
- package/dist/index.js +82 -203
- package/package.json +1 -1
package/dist/index.esm.js
CHANGED
|
@@ -1,12 +1,62 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
1
|
+
var uiHandler = vm => ({
|
|
2
|
+
$message: vm.$message,
|
|
3
|
+
$success: msg => vm.$message.success(msg),
|
|
4
|
+
$warning: msg => vm.$message.warning(msg),
|
|
5
|
+
$error: msg => vm.$message.error(msg),
|
|
6
|
+
$notify: options => vm.$notify(options),
|
|
7
|
+
$confirm: (...args) => vm.$confirm(...args).then(() => true).catch(() => false),
|
|
8
|
+
$alert: (...args) => vm.$alert(...args).then(() => true).catch(() => false),
|
|
9
|
+
$prompt: (...args) => vm.$prompt(...args).then(res => res.value).catch(() => null),
|
|
10
|
+
$loading: options => {
|
|
11
|
+
const loading = vm.$loading(options);
|
|
12
|
+
return () => loading.close()
|
|
13
|
+
},
|
|
14
|
+
});
|
|
15
|
+
|
|
16
|
+
const noop = () => console.warn('[bridge] electron 不可用');
|
|
17
|
+
|
|
18
|
+
const KEYS = [
|
|
19
|
+
'renderer_listen',
|
|
20
|
+
'web_send',
|
|
21
|
+
'web_send_path',
|
|
22
|
+
'show',
|
|
23
|
+
'hide',
|
|
24
|
+
'quit',
|
|
25
|
+
'showAlertDialog',
|
|
26
|
+
'closeAlertDialog',
|
|
27
|
+
'closeAlertDialogAndJump',
|
|
28
|
+
'set_bounds',
|
|
29
|
+
'get_bounds',
|
|
30
|
+
'workarea',
|
|
31
|
+
'center',
|
|
32
|
+
'maximize',
|
|
33
|
+
'unmaximize',
|
|
34
|
+
'is_maximized',
|
|
35
|
+
'minimize',
|
|
36
|
+
'open_top',
|
|
37
|
+
'close_top',
|
|
38
|
+
'update',
|
|
39
|
+
'collapse',
|
|
40
|
+
'unfold',
|
|
41
|
+
'unfoldMax',
|
|
42
|
+
'get_version',
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
function createCs(electron = {}) {
|
|
46
|
+
const base = Object.fromEntries(
|
|
47
|
+
KEYS.map(k => [k, typeof electron[k] === 'function' ? electron[k] : noop])
|
|
48
|
+
);
|
|
49
|
+
return {
|
|
50
|
+
...electron,
|
|
51
|
+
...base,
|
|
52
|
+
is_app:
|
|
53
|
+
typeof electron.is_app === 'function'
|
|
54
|
+
? electron.is_app()
|
|
55
|
+
: !!electron.is_app,
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
const BRIDGE$1 = { INVOKE: 'bridge-invoke', CALLBACK: 'bridge-callback' };
|
|
10
60
|
|
|
11
61
|
const post = (target, message) =>
|
|
12
62
|
target?.postMessage(message, window.location.origin);
|
|
@@ -24,27 +74,26 @@ const safeClone = value => {
|
|
|
24
74
|
}
|
|
25
75
|
};
|
|
26
76
|
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
77
|
+
function createRegisterHandlers(getElectron) {
|
|
78
|
+
const electron = (() => {
|
|
79
|
+
try {
|
|
80
|
+
return typeof getElectron === 'function' ? getElectron() : {}
|
|
81
|
+
} catch {
|
|
82
|
+
return {}
|
|
83
|
+
}
|
|
84
|
+
})();
|
|
85
|
+
return vm => ({ ui: uiHandler(vm), cs: createCs(electron) })
|
|
86
|
+
}
|
|
87
|
+
|
|
36
88
|
const initBridge = ({
|
|
37
89
|
isParent = false,
|
|
38
90
|
vm,
|
|
39
91
|
iframeSelector = '#microApp',
|
|
40
92
|
handlers = {},
|
|
41
93
|
} = {}) => {
|
|
42
|
-
// 父应用使用传入的 handlers,子应用为空对象
|
|
43
94
|
const finalHandlers = isParent ? handlers : Object.create(null);
|
|
44
|
-
|
|
45
95
|
const pending = Object.create(null);
|
|
46
96
|
|
|
47
|
-
// 子应用:创建 $base 代理对象,用于调用父应用方法
|
|
48
97
|
if (!isParent && vm) {
|
|
49
98
|
vm.$base = new Proxy(
|
|
50
99
|
{},
|
|
@@ -76,7 +125,6 @@ const initBridge = ({
|
|
|
76
125
|
vm.$baseReady = true;
|
|
77
126
|
}
|
|
78
127
|
|
|
79
|
-
// 处理来自子应用的调用请求(父应用)
|
|
80
128
|
const handleInvoke = e => {
|
|
81
129
|
const { action, params, callbackId } = e.data || {};
|
|
82
130
|
if (!action || !callbackId) return
|
|
@@ -97,7 +145,7 @@ const initBridge = ({
|
|
|
97
145
|
result: safeClone(payload),
|
|
98
146
|
});
|
|
99
147
|
|
|
100
|
-
result
|
|
148
|
+
Promise.resolve(result).then(done).catch(done);
|
|
101
149
|
} catch (err) {
|
|
102
150
|
post(iframeWindow, {
|
|
103
151
|
type: BRIDGE$1.CALLBACK,
|
|
@@ -107,7 +155,6 @@ const initBridge = ({
|
|
|
107
155
|
}
|
|
108
156
|
};
|
|
109
157
|
|
|
110
|
-
// 处理来自父应用的响应(子应用)
|
|
111
158
|
const handleCallback = e => {
|
|
112
159
|
const { callbackId, result } = e.data || {};
|
|
113
160
|
if (!callbackId || !pending[callbackId]) return
|
|
@@ -116,7 +163,6 @@ const initBridge = ({
|
|
|
116
163
|
delete pending[callbackId];
|
|
117
164
|
};
|
|
118
165
|
|
|
119
|
-
// 监听消息
|
|
120
166
|
window.addEventListener('message', e => {
|
|
121
167
|
if (e.origin !== window.location.origin) return
|
|
122
168
|
|
|
@@ -126,104 +172,6 @@ const initBridge = ({
|
|
|
126
172
|
});
|
|
127
173
|
};
|
|
128
174
|
|
|
129
|
-
var uiHandler = vm => ({
|
|
130
|
-
$message: (...args) => vm.$message(...args),
|
|
131
|
-
$success: msg => vm.$message.success(msg),
|
|
132
|
-
$warning: msg => vm.$message.warning(msg),
|
|
133
|
-
$error: msg => vm.$message.error(msg),
|
|
134
|
-
$notify: options => vm.$notify(options),
|
|
135
|
-
$confirm: (...args) =>
|
|
136
|
-
vm
|
|
137
|
-
.$confirm(...args)
|
|
138
|
-
.then(() => true)
|
|
139
|
-
.catch(() => false),
|
|
140
|
-
$alert: (...args) =>
|
|
141
|
-
vm
|
|
142
|
-
.$alert(...args)
|
|
143
|
-
.then(() => true)
|
|
144
|
-
.catch(() => false),
|
|
145
|
-
$prompt: (...args) =>
|
|
146
|
-
vm
|
|
147
|
-
.$prompt(...args)
|
|
148
|
-
.then(res => res.value)
|
|
149
|
-
.catch(() => null),
|
|
150
|
-
$loading: options => {
|
|
151
|
-
const loading = vm.$loading(options);
|
|
152
|
-
return () => loading.close()
|
|
153
|
-
},
|
|
154
|
-
});
|
|
155
|
-
|
|
156
|
-
const noop = () => console.warn('[bridge] electron 不可用');
|
|
157
|
-
|
|
158
|
-
const KEYS = [
|
|
159
|
-
'renderer_listen',
|
|
160
|
-
'web_send',
|
|
161
|
-
'web_send_path',
|
|
162
|
-
'show',
|
|
163
|
-
'hide',
|
|
164
|
-
'quit',
|
|
165
|
-
'showAlertDialog',
|
|
166
|
-
'closeAlertDialog',
|
|
167
|
-
'closeAlertDialogAndJump',
|
|
168
|
-
'set_bounds',
|
|
169
|
-
'get_bounds',
|
|
170
|
-
'workarea',
|
|
171
|
-
'center',
|
|
172
|
-
'maximize',
|
|
173
|
-
'unmaximize',
|
|
174
|
-
'is_maximized',
|
|
175
|
-
'minimize',
|
|
176
|
-
'open_top',
|
|
177
|
-
'close_top',
|
|
178
|
-
'update',
|
|
179
|
-
'collapse',
|
|
180
|
-
'unfold',
|
|
181
|
-
'unfoldMax',
|
|
182
|
-
'get_version',
|
|
183
|
-
];
|
|
184
|
-
|
|
185
|
-
/** @param {Object} [electron] 宿主传入的 electron 模块,无或 require 失败时传 {} */
|
|
186
|
-
function createCs(electron = {}) {
|
|
187
|
-
const base = Object.fromEntries(
|
|
188
|
-
KEYS.map(k => [k, typeof electron[k] === 'function' ? electron[k] : noop])
|
|
189
|
-
);
|
|
190
|
-
return {
|
|
191
|
-
...electron,
|
|
192
|
-
...base,
|
|
193
|
-
is_app:
|
|
194
|
-
typeof electron.is_app === 'function'
|
|
195
|
-
? electron.is_app()
|
|
196
|
-
: !!electron.is_app,
|
|
197
|
-
}
|
|
198
|
-
}
|
|
199
|
-
|
|
200
|
-
/**
|
|
201
|
-
* @param {() => Object} [getElectron] 返回 electron 模块,如 () => require('@/utils/electron')
|
|
202
|
-
*/
|
|
203
|
-
function createRegisterHandlers(getElectron) {
|
|
204
|
-
let electron = {};
|
|
205
|
-
try {
|
|
206
|
-
if (typeof getElectron === 'function') electron = getElectron();
|
|
207
|
-
} catch {}
|
|
208
|
-
|
|
209
|
-
return vm => ({
|
|
210
|
-
ui: uiHandler(vm),
|
|
211
|
-
cs: createCs(electron),
|
|
212
|
-
})
|
|
213
|
-
}
|
|
214
|
-
|
|
215
|
-
/**
|
|
216
|
-
* 微前端核心功能
|
|
217
|
-
* 提供模块路由映射、URL 生成、部署检测等功能
|
|
218
|
-
*/
|
|
219
|
-
|
|
220
|
-
/**
|
|
221
|
-
* 创建微前端核心功能
|
|
222
|
-
* @param {Object} options - 配置选项
|
|
223
|
-
* @param {Function} options.modelMap - 模块路由映射函数,返回 { [moduleName]: string[] }
|
|
224
|
-
* @param {Array<string>|Function} options.enabledModules - 启用的模块列表或获取模块列表的函数
|
|
225
|
-
* @returns {Object} 核心功能对象
|
|
226
|
-
*/
|
|
227
175
|
function createMicroAppCore({
|
|
228
176
|
modelMap,
|
|
229
177
|
enabledModules,
|
|
@@ -234,10 +182,6 @@ function createMicroAppCore({
|
|
|
234
182
|
|
|
235
183
|
const MAP = modelMap();
|
|
236
184
|
|
|
237
|
-
/**
|
|
238
|
-
* 获取启用的模块列表
|
|
239
|
-
* @returns {Array<string>|null}
|
|
240
|
-
*/
|
|
241
185
|
const getEnabledModules = () => {
|
|
242
186
|
if (Array.isArray(enabledModules)) {
|
|
243
187
|
return enabledModules
|
|
@@ -245,49 +189,30 @@ function createMicroAppCore({
|
|
|
245
189
|
if (typeof enabledModules === 'function') {
|
|
246
190
|
return enabledModules()
|
|
247
191
|
}
|
|
248
|
-
// 默认从 window.GLOBAL_CONFIG.microApp 获取
|
|
249
192
|
if (typeof window !== 'undefined' && window.GLOBAL_CONFIG) {
|
|
250
193
|
return window.GLOBAL_CONFIG.microApp || null
|
|
251
194
|
}
|
|
252
195
|
return null
|
|
253
196
|
};
|
|
254
197
|
|
|
255
|
-
/**
|
|
256
|
-
* 根据路径获取对应的微前端模块名
|
|
257
|
-
* @param {string} path - 路由路径
|
|
258
|
-
* @returns {string|null} 模块名,如果不在任何模块中则返回 null
|
|
259
|
-
*/
|
|
260
198
|
const microAppModule = path => {
|
|
261
199
|
const value = path.split('?')[0];
|
|
262
|
-
const key = Object.keys(MAP).find(
|
|
263
|
-
const
|
|
264
|
-
return
|
|
200
|
+
const key = Object.keys(MAP).find(k => MAP[k].includes(value));
|
|
201
|
+
const mods = getEnabledModules();
|
|
202
|
+
return mods?.includes(key) ? key : null
|
|
265
203
|
};
|
|
266
204
|
|
|
267
|
-
/**
|
|
268
|
-
* 生成微前端应用的完整 URL
|
|
269
|
-
* @param {string} path - 路由路径
|
|
270
|
-
* @returns {string} 完整的 URL
|
|
271
|
-
*/
|
|
272
205
|
const microAppSrc = path => {
|
|
273
206
|
const module = microAppModule(path);
|
|
274
207
|
const base = window.location.href.split('#')[0];
|
|
275
208
|
return `${base}${module ? `${module}/` : ''}#${path}`
|
|
276
209
|
};
|
|
277
210
|
|
|
278
|
-
/**
|
|
279
|
-
* 检测微前端模块是否已部署
|
|
280
|
-
* @param {string} module - 模块名
|
|
281
|
-
* @returns {Promise<boolean>} 是否已部署
|
|
282
|
-
*/
|
|
283
211
|
const microAppDeployed = async module => {
|
|
284
212
|
try {
|
|
285
|
-
const
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
});
|
|
289
|
-
return result.ok
|
|
290
|
-
} catch (error) {
|
|
213
|
+
const res = await fetch(`/${module}`, { method: 'GET', cache: 'no-store' });
|
|
214
|
+
return res.ok
|
|
215
|
+
} catch {
|
|
291
216
|
return false
|
|
292
217
|
}
|
|
293
218
|
};
|
|
@@ -299,23 +224,6 @@ function createMicroAppCore({
|
|
|
299
224
|
}
|
|
300
225
|
}
|
|
301
226
|
|
|
302
|
-
/**
|
|
303
|
-
* 创建默认的微前端核心功能实例
|
|
304
|
-
* 使用 window.GLOBAL_CONFIG.microApp 作为配置源
|
|
305
|
-
* @param {Function} modelMap - 模块路由映射函数
|
|
306
|
-
* @returns {Object} 核心功能对象
|
|
307
|
-
*/
|
|
308
|
-
function createDefaultMicroAppCore(modelMap) {
|
|
309
|
-
return createMicroAppCore({
|
|
310
|
-
modelMap,
|
|
311
|
-
})
|
|
312
|
-
}
|
|
313
|
-
|
|
314
|
-
/**
|
|
315
|
-
* Vuex 状态同步插件
|
|
316
|
-
* 用于在父子应用之间同步 Vuex store 状态
|
|
317
|
-
*/
|
|
318
|
-
|
|
319
227
|
const MESSAGE = {
|
|
320
228
|
SYNC_FROM_CHILD: 'sync-base-from-child',
|
|
321
229
|
SYNC_FROM_PARENT: 'sync-base-from-parent',
|
|
@@ -334,11 +242,11 @@ const BRIDGE = { INVOKE: 'bridge-invoke', CALLBACK: 'bridge-callback' };
|
|
|
334
242
|
const LIFE_CYCLE_TYPES = Object.values(LIFE_CYCLE);
|
|
335
243
|
const BRIDGE_TYPES = Object.values(BRIDGE);
|
|
336
244
|
|
|
337
|
-
const getIframe = selector => document.querySelector(selector);
|
|
338
|
-
|
|
339
245
|
const postToChild = (iframeSelector, message) => {
|
|
340
|
-
|
|
341
|
-
|
|
246
|
+
document.querySelector(iframeSelector)?.contentWindow?.postMessage(
|
|
247
|
+
message,
|
|
248
|
+
window.location.origin
|
|
249
|
+
);
|
|
342
250
|
};
|
|
343
251
|
|
|
344
252
|
const postToParent = message => {
|
|
@@ -369,13 +277,6 @@ const syncRouteFromChild = fullPath => {
|
|
|
369
277
|
}
|
|
370
278
|
};
|
|
371
279
|
|
|
372
|
-
/**
|
|
373
|
-
* 创建状态同步插件
|
|
374
|
-
* @param {Object} options - 配置选项
|
|
375
|
-
* @param {boolean} options.isParent - 是否为父应用,默认 false
|
|
376
|
-
* @param {string} options.iframeSelector - iframe 选择器,默认 '#microApp'
|
|
377
|
-
* @returns {Function} Vuex 插件函数
|
|
378
|
-
*/
|
|
379
280
|
function baseSyncPlugin({
|
|
380
281
|
isParent = false,
|
|
381
282
|
iframeSelector = '#microApp',
|
|
@@ -383,7 +284,6 @@ function baseSyncPlugin({
|
|
|
383
284
|
return store => {
|
|
384
285
|
let latestBaseState = store.state.base;
|
|
385
286
|
|
|
386
|
-
// 监听 base 状态变化,自动同步
|
|
387
287
|
store.watch(
|
|
388
288
|
state => state.base,
|
|
389
289
|
newBase => {
|
|
@@ -403,7 +303,6 @@ function baseSyncPlugin({
|
|
|
403
303
|
{ deep: true }
|
|
404
304
|
);
|
|
405
305
|
|
|
406
|
-
// 附加路由同步功能(子应用使用)
|
|
407
306
|
store.attachRouterSync = router => {
|
|
408
307
|
if (!router || isParent) return
|
|
409
308
|
router.afterEach(to => {
|
|
@@ -423,7 +322,6 @@ function baseSyncPlugin({
|
|
|
423
322
|
});
|
|
424
323
|
};
|
|
425
324
|
|
|
426
|
-
// 调用微前端生命周期(父应用使用)
|
|
427
325
|
store.callMicroAppLifeCycle = (type, payload) => {
|
|
428
326
|
if (!isParent) return
|
|
429
327
|
if (!isLifeCycleMessage(type)) return
|
|
@@ -434,30 +332,25 @@ function baseSyncPlugin({
|
|
|
434
332
|
});
|
|
435
333
|
};
|
|
436
334
|
|
|
437
|
-
// 处理消息
|
|
438
335
|
const handleMessage = event => {
|
|
439
336
|
if (event.origin !== window.location.origin) return
|
|
440
337
|
const { type, payload, fullPath } = event.data || {};
|
|
441
338
|
|
|
442
|
-
// 子应用处理生命周期消息
|
|
443
339
|
if (!isParent && isLifeCycleMessage(type)) {
|
|
444
340
|
window.__MICRO_APP_LIFECYCLE__?.[type]?.(payload);
|
|
445
341
|
return
|
|
446
342
|
}
|
|
447
343
|
|
|
448
|
-
// 父应用处理来自子应用的状态同步
|
|
449
344
|
if (isParent && type === MESSAGE.SYNC_FROM_CHILD) {
|
|
450
345
|
store.commit('base/SYNC_STATE', payload);
|
|
451
346
|
return
|
|
452
347
|
}
|
|
453
348
|
|
|
454
|
-
// 子应用处理来自父应用的状态同步
|
|
455
349
|
if (!isParent && type === MESSAGE.SYNC_FROM_PARENT) {
|
|
456
350
|
store.commit('base/SYNC_STATE', payload);
|
|
457
351
|
return
|
|
458
352
|
}
|
|
459
353
|
|
|
460
|
-
// 父应用响应子应用的状态请求
|
|
461
354
|
if (isParent && type === MESSAGE.REQUEST_FROM_CHILD) {
|
|
462
355
|
postToChild(iframeSelector, {
|
|
463
356
|
type: MESSAGE.SYNC_FROM_PARENT,
|
|
@@ -466,13 +359,11 @@ function baseSyncPlugin({
|
|
|
466
359
|
return
|
|
467
360
|
}
|
|
468
361
|
|
|
469
|
-
// 父应用处理子应用的路由变化
|
|
470
362
|
if (isParent && type === MESSAGE.CHILD_ROUTE_CHANGE) {
|
|
471
363
|
syncRouteFromChild(fullPath);
|
|
472
364
|
return
|
|
473
365
|
}
|
|
474
366
|
|
|
475
|
-
// 父应用转发其他消息到父窗口
|
|
476
367
|
if (isParent && !isInternalMessage(type) && !isBridgeMessage(type)) {
|
|
477
368
|
window.parent?.postMessage(event.data || {}, '*');
|
|
478
369
|
}
|
|
@@ -480,23 +371,12 @@ function baseSyncPlugin({
|
|
|
480
371
|
|
|
481
372
|
window.addEventListener('message', handleMessage);
|
|
482
373
|
|
|
483
|
-
// 子应用初始化时请求父应用状态
|
|
484
374
|
if (!isParent && window.parent) {
|
|
485
375
|
postToParent({ type: MESSAGE.REQUEST_FROM_CHILD });
|
|
486
376
|
}
|
|
487
377
|
}
|
|
488
378
|
}
|
|
489
379
|
|
|
490
|
-
|
|
491
|
-
* @hhfenpm/micro-app
|
|
492
|
-
* 微前端通信桥接和状态同步工具
|
|
493
|
-
*/
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
var index = {
|
|
497
|
-
initBridge,
|
|
498
|
-
createDefaultMicroAppCore,
|
|
499
|
-
baseSyncPlugin,
|
|
500
|
-
};
|
|
380
|
+
var index = { initBridge, baseSyncPlugin };
|
|
501
381
|
|
|
502
|
-
export { baseSyncPlugin,
|
|
382
|
+
export { baseSyncPlugin, createMicroAppCore, createRegisterHandlers, index as default, initBridge };
|
package/dist/index.js
CHANGED
|
@@ -2,15 +2,65 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
var uiHandler = vm => ({
|
|
6
|
+
$message: vm.$message,
|
|
7
|
+
$success: msg => vm.$message.success(msg),
|
|
8
|
+
$warning: msg => vm.$message.warning(msg),
|
|
9
|
+
$error: msg => vm.$message.error(msg),
|
|
10
|
+
$notify: options => vm.$notify(options),
|
|
11
|
+
$confirm: (...args) => vm.$confirm(...args).then(() => true).catch(() => false),
|
|
12
|
+
$alert: (...args) => vm.$alert(...args).then(() => true).catch(() => false),
|
|
13
|
+
$prompt: (...args) => vm.$prompt(...args).then(res => res.value).catch(() => null),
|
|
14
|
+
$loading: options => {
|
|
15
|
+
const loading = vm.$loading(options);
|
|
16
|
+
return () => loading.close()
|
|
17
|
+
},
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
const noop = () => console.warn('[bridge] electron 不可用');
|
|
21
|
+
|
|
22
|
+
const KEYS = [
|
|
23
|
+
'renderer_listen',
|
|
24
|
+
'web_send',
|
|
25
|
+
'web_send_path',
|
|
26
|
+
'show',
|
|
27
|
+
'hide',
|
|
28
|
+
'quit',
|
|
29
|
+
'showAlertDialog',
|
|
30
|
+
'closeAlertDialog',
|
|
31
|
+
'closeAlertDialogAndJump',
|
|
32
|
+
'set_bounds',
|
|
33
|
+
'get_bounds',
|
|
34
|
+
'workarea',
|
|
35
|
+
'center',
|
|
36
|
+
'maximize',
|
|
37
|
+
'unmaximize',
|
|
38
|
+
'is_maximized',
|
|
39
|
+
'minimize',
|
|
40
|
+
'open_top',
|
|
41
|
+
'close_top',
|
|
42
|
+
'update',
|
|
43
|
+
'collapse',
|
|
44
|
+
'unfold',
|
|
45
|
+
'unfoldMax',
|
|
46
|
+
'get_version',
|
|
47
|
+
];
|
|
48
|
+
|
|
49
|
+
function createCs(electron = {}) {
|
|
50
|
+
const base = Object.fromEntries(
|
|
51
|
+
KEYS.map(k => [k, typeof electron[k] === 'function' ? electron[k] : noop])
|
|
52
|
+
);
|
|
53
|
+
return {
|
|
54
|
+
...electron,
|
|
55
|
+
...base,
|
|
56
|
+
is_app:
|
|
57
|
+
typeof electron.is_app === 'function'
|
|
58
|
+
? electron.is_app()
|
|
59
|
+
: !!electron.is_app,
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
const BRIDGE$1 = { INVOKE: 'bridge-invoke', CALLBACK: 'bridge-callback' };
|
|
14
64
|
|
|
15
65
|
const post = (target, message) =>
|
|
16
66
|
target?.postMessage(message, window.location.origin);
|
|
@@ -28,27 +78,26 @@ const safeClone = value => {
|
|
|
28
78
|
}
|
|
29
79
|
};
|
|
30
80
|
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
81
|
+
function createRegisterHandlers(getElectron) {
|
|
82
|
+
const electron = (() => {
|
|
83
|
+
try {
|
|
84
|
+
return typeof getElectron === 'function' ? getElectron() : {}
|
|
85
|
+
} catch {
|
|
86
|
+
return {}
|
|
87
|
+
}
|
|
88
|
+
})();
|
|
89
|
+
return vm => ({ ui: uiHandler(vm), cs: createCs(electron) })
|
|
90
|
+
}
|
|
91
|
+
|
|
40
92
|
const initBridge = ({
|
|
41
93
|
isParent = false,
|
|
42
94
|
vm,
|
|
43
95
|
iframeSelector = '#microApp',
|
|
44
96
|
handlers = {},
|
|
45
97
|
} = {}) => {
|
|
46
|
-
// 父应用使用传入的 handlers,子应用为空对象
|
|
47
98
|
const finalHandlers = isParent ? handlers : Object.create(null);
|
|
48
|
-
|
|
49
99
|
const pending = Object.create(null);
|
|
50
100
|
|
|
51
|
-
// 子应用:创建 $base 代理对象,用于调用父应用方法
|
|
52
101
|
if (!isParent && vm) {
|
|
53
102
|
vm.$base = new Proxy(
|
|
54
103
|
{},
|
|
@@ -80,7 +129,6 @@ const initBridge = ({
|
|
|
80
129
|
vm.$baseReady = true;
|
|
81
130
|
}
|
|
82
131
|
|
|
83
|
-
// 处理来自子应用的调用请求(父应用)
|
|
84
132
|
const handleInvoke = e => {
|
|
85
133
|
const { action, params, callbackId } = e.data || {};
|
|
86
134
|
if (!action || !callbackId) return
|
|
@@ -101,7 +149,7 @@ const initBridge = ({
|
|
|
101
149
|
result: safeClone(payload),
|
|
102
150
|
});
|
|
103
151
|
|
|
104
|
-
result
|
|
152
|
+
Promise.resolve(result).then(done).catch(done);
|
|
105
153
|
} catch (err) {
|
|
106
154
|
post(iframeWindow, {
|
|
107
155
|
type: BRIDGE$1.CALLBACK,
|
|
@@ -111,7 +159,6 @@ const initBridge = ({
|
|
|
111
159
|
}
|
|
112
160
|
};
|
|
113
161
|
|
|
114
|
-
// 处理来自父应用的响应(子应用)
|
|
115
162
|
const handleCallback = e => {
|
|
116
163
|
const { callbackId, result } = e.data || {};
|
|
117
164
|
if (!callbackId || !pending[callbackId]) return
|
|
@@ -120,7 +167,6 @@ const initBridge = ({
|
|
|
120
167
|
delete pending[callbackId];
|
|
121
168
|
};
|
|
122
169
|
|
|
123
|
-
// 监听消息
|
|
124
170
|
window.addEventListener('message', e => {
|
|
125
171
|
if (e.origin !== window.location.origin) return
|
|
126
172
|
|
|
@@ -130,104 +176,6 @@ const initBridge = ({
|
|
|
130
176
|
});
|
|
131
177
|
};
|
|
132
178
|
|
|
133
|
-
var uiHandler = vm => ({
|
|
134
|
-
$message: (...args) => vm.$message(...args),
|
|
135
|
-
$success: msg => vm.$message.success(msg),
|
|
136
|
-
$warning: msg => vm.$message.warning(msg),
|
|
137
|
-
$error: msg => vm.$message.error(msg),
|
|
138
|
-
$notify: options => vm.$notify(options),
|
|
139
|
-
$confirm: (...args) =>
|
|
140
|
-
vm
|
|
141
|
-
.$confirm(...args)
|
|
142
|
-
.then(() => true)
|
|
143
|
-
.catch(() => false),
|
|
144
|
-
$alert: (...args) =>
|
|
145
|
-
vm
|
|
146
|
-
.$alert(...args)
|
|
147
|
-
.then(() => true)
|
|
148
|
-
.catch(() => false),
|
|
149
|
-
$prompt: (...args) =>
|
|
150
|
-
vm
|
|
151
|
-
.$prompt(...args)
|
|
152
|
-
.then(res => res.value)
|
|
153
|
-
.catch(() => null),
|
|
154
|
-
$loading: options => {
|
|
155
|
-
const loading = vm.$loading(options);
|
|
156
|
-
return () => loading.close()
|
|
157
|
-
},
|
|
158
|
-
});
|
|
159
|
-
|
|
160
|
-
const noop = () => console.warn('[bridge] electron 不可用');
|
|
161
|
-
|
|
162
|
-
const KEYS = [
|
|
163
|
-
'renderer_listen',
|
|
164
|
-
'web_send',
|
|
165
|
-
'web_send_path',
|
|
166
|
-
'show',
|
|
167
|
-
'hide',
|
|
168
|
-
'quit',
|
|
169
|
-
'showAlertDialog',
|
|
170
|
-
'closeAlertDialog',
|
|
171
|
-
'closeAlertDialogAndJump',
|
|
172
|
-
'set_bounds',
|
|
173
|
-
'get_bounds',
|
|
174
|
-
'workarea',
|
|
175
|
-
'center',
|
|
176
|
-
'maximize',
|
|
177
|
-
'unmaximize',
|
|
178
|
-
'is_maximized',
|
|
179
|
-
'minimize',
|
|
180
|
-
'open_top',
|
|
181
|
-
'close_top',
|
|
182
|
-
'update',
|
|
183
|
-
'collapse',
|
|
184
|
-
'unfold',
|
|
185
|
-
'unfoldMax',
|
|
186
|
-
'get_version',
|
|
187
|
-
];
|
|
188
|
-
|
|
189
|
-
/** @param {Object} [electron] 宿主传入的 electron 模块,无或 require 失败时传 {} */
|
|
190
|
-
function createCs(electron = {}) {
|
|
191
|
-
const base = Object.fromEntries(
|
|
192
|
-
KEYS.map(k => [k, typeof electron[k] === 'function' ? electron[k] : noop])
|
|
193
|
-
);
|
|
194
|
-
return {
|
|
195
|
-
...electron,
|
|
196
|
-
...base,
|
|
197
|
-
is_app:
|
|
198
|
-
typeof electron.is_app === 'function'
|
|
199
|
-
? electron.is_app()
|
|
200
|
-
: !!electron.is_app,
|
|
201
|
-
}
|
|
202
|
-
}
|
|
203
|
-
|
|
204
|
-
/**
|
|
205
|
-
* @param {() => Object} [getElectron] 返回 electron 模块,如 () => require('@/utils/electron')
|
|
206
|
-
*/
|
|
207
|
-
function createRegisterHandlers(getElectron) {
|
|
208
|
-
let electron = {};
|
|
209
|
-
try {
|
|
210
|
-
if (typeof getElectron === 'function') electron = getElectron();
|
|
211
|
-
} catch {}
|
|
212
|
-
|
|
213
|
-
return vm => ({
|
|
214
|
-
ui: uiHandler(vm),
|
|
215
|
-
cs: createCs(electron),
|
|
216
|
-
})
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/**
|
|
220
|
-
* 微前端核心功能
|
|
221
|
-
* 提供模块路由映射、URL 生成、部署检测等功能
|
|
222
|
-
*/
|
|
223
|
-
|
|
224
|
-
/**
|
|
225
|
-
* 创建微前端核心功能
|
|
226
|
-
* @param {Object} options - 配置选项
|
|
227
|
-
* @param {Function} options.modelMap - 模块路由映射函数,返回 { [moduleName]: string[] }
|
|
228
|
-
* @param {Array<string>|Function} options.enabledModules - 启用的模块列表或获取模块列表的函数
|
|
229
|
-
* @returns {Object} 核心功能对象
|
|
230
|
-
*/
|
|
231
179
|
function createMicroAppCore({
|
|
232
180
|
modelMap,
|
|
233
181
|
enabledModules,
|
|
@@ -238,10 +186,6 @@ function createMicroAppCore({
|
|
|
238
186
|
|
|
239
187
|
const MAP = modelMap();
|
|
240
188
|
|
|
241
|
-
/**
|
|
242
|
-
* 获取启用的模块列表
|
|
243
|
-
* @returns {Array<string>|null}
|
|
244
|
-
*/
|
|
245
189
|
const getEnabledModules = () => {
|
|
246
190
|
if (Array.isArray(enabledModules)) {
|
|
247
191
|
return enabledModules
|
|
@@ -249,49 +193,30 @@ function createMicroAppCore({
|
|
|
249
193
|
if (typeof enabledModules === 'function') {
|
|
250
194
|
return enabledModules()
|
|
251
195
|
}
|
|
252
|
-
// 默认从 window.GLOBAL_CONFIG.microApp 获取
|
|
253
196
|
if (typeof window !== 'undefined' && window.GLOBAL_CONFIG) {
|
|
254
197
|
return window.GLOBAL_CONFIG.microApp || null
|
|
255
198
|
}
|
|
256
199
|
return null
|
|
257
200
|
};
|
|
258
201
|
|
|
259
|
-
/**
|
|
260
|
-
* 根据路径获取对应的微前端模块名
|
|
261
|
-
* @param {string} path - 路由路径
|
|
262
|
-
* @returns {string|null} 模块名,如果不在任何模块中则返回 null
|
|
263
|
-
*/
|
|
264
202
|
const microAppModule = path => {
|
|
265
203
|
const value = path.split('?')[0];
|
|
266
|
-
const key = Object.keys(MAP).find(
|
|
267
|
-
const
|
|
268
|
-
return
|
|
204
|
+
const key = Object.keys(MAP).find(k => MAP[k].includes(value));
|
|
205
|
+
const mods = getEnabledModules();
|
|
206
|
+
return mods?.includes(key) ? key : null
|
|
269
207
|
};
|
|
270
208
|
|
|
271
|
-
/**
|
|
272
|
-
* 生成微前端应用的完整 URL
|
|
273
|
-
* @param {string} path - 路由路径
|
|
274
|
-
* @returns {string} 完整的 URL
|
|
275
|
-
*/
|
|
276
209
|
const microAppSrc = path => {
|
|
277
210
|
const module = microAppModule(path);
|
|
278
211
|
const base = window.location.href.split('#')[0];
|
|
279
212
|
return `${base}${module ? `${module}/` : ''}#${path}`
|
|
280
213
|
};
|
|
281
214
|
|
|
282
|
-
/**
|
|
283
|
-
* 检测微前端模块是否已部署
|
|
284
|
-
* @param {string} module - 模块名
|
|
285
|
-
* @returns {Promise<boolean>} 是否已部署
|
|
286
|
-
*/
|
|
287
215
|
const microAppDeployed = async module => {
|
|
288
216
|
try {
|
|
289
|
-
const
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
});
|
|
293
|
-
return result.ok
|
|
294
|
-
} catch (error) {
|
|
217
|
+
const res = await fetch(`/${module}`, { method: 'GET', cache: 'no-store' });
|
|
218
|
+
return res.ok
|
|
219
|
+
} catch {
|
|
295
220
|
return false
|
|
296
221
|
}
|
|
297
222
|
};
|
|
@@ -303,23 +228,6 @@ function createMicroAppCore({
|
|
|
303
228
|
}
|
|
304
229
|
}
|
|
305
230
|
|
|
306
|
-
/**
|
|
307
|
-
* 创建默认的微前端核心功能实例
|
|
308
|
-
* 使用 window.GLOBAL_CONFIG.microApp 作为配置源
|
|
309
|
-
* @param {Function} modelMap - 模块路由映射函数
|
|
310
|
-
* @returns {Object} 核心功能对象
|
|
311
|
-
*/
|
|
312
|
-
function createDefaultMicroAppCore(modelMap) {
|
|
313
|
-
return createMicroAppCore({
|
|
314
|
-
modelMap,
|
|
315
|
-
})
|
|
316
|
-
}
|
|
317
|
-
|
|
318
|
-
/**
|
|
319
|
-
* Vuex 状态同步插件
|
|
320
|
-
* 用于在父子应用之间同步 Vuex store 状态
|
|
321
|
-
*/
|
|
322
|
-
|
|
323
231
|
const MESSAGE = {
|
|
324
232
|
SYNC_FROM_CHILD: 'sync-base-from-child',
|
|
325
233
|
SYNC_FROM_PARENT: 'sync-base-from-parent',
|
|
@@ -338,11 +246,11 @@ const BRIDGE = { INVOKE: 'bridge-invoke', CALLBACK: 'bridge-callback' };
|
|
|
338
246
|
const LIFE_CYCLE_TYPES = Object.values(LIFE_CYCLE);
|
|
339
247
|
const BRIDGE_TYPES = Object.values(BRIDGE);
|
|
340
248
|
|
|
341
|
-
const getIframe = selector => document.querySelector(selector);
|
|
342
|
-
|
|
343
249
|
const postToChild = (iframeSelector, message) => {
|
|
344
|
-
|
|
345
|
-
|
|
250
|
+
document.querySelector(iframeSelector)?.contentWindow?.postMessage(
|
|
251
|
+
message,
|
|
252
|
+
window.location.origin
|
|
253
|
+
);
|
|
346
254
|
};
|
|
347
255
|
|
|
348
256
|
const postToParent = message => {
|
|
@@ -373,13 +281,6 @@ const syncRouteFromChild = fullPath => {
|
|
|
373
281
|
}
|
|
374
282
|
};
|
|
375
283
|
|
|
376
|
-
/**
|
|
377
|
-
* 创建状态同步插件
|
|
378
|
-
* @param {Object} options - 配置选项
|
|
379
|
-
* @param {boolean} options.isParent - 是否为父应用,默认 false
|
|
380
|
-
* @param {string} options.iframeSelector - iframe 选择器,默认 '#microApp'
|
|
381
|
-
* @returns {Function} Vuex 插件函数
|
|
382
|
-
*/
|
|
383
284
|
function baseSyncPlugin({
|
|
384
285
|
isParent = false,
|
|
385
286
|
iframeSelector = '#microApp',
|
|
@@ -387,7 +288,6 @@ function baseSyncPlugin({
|
|
|
387
288
|
return store => {
|
|
388
289
|
let latestBaseState = store.state.base;
|
|
389
290
|
|
|
390
|
-
// 监听 base 状态变化,自动同步
|
|
391
291
|
store.watch(
|
|
392
292
|
state => state.base,
|
|
393
293
|
newBase => {
|
|
@@ -407,7 +307,6 @@ function baseSyncPlugin({
|
|
|
407
307
|
{ deep: true }
|
|
408
308
|
);
|
|
409
309
|
|
|
410
|
-
// 附加路由同步功能(子应用使用)
|
|
411
310
|
store.attachRouterSync = router => {
|
|
412
311
|
if (!router || isParent) return
|
|
413
312
|
router.afterEach(to => {
|
|
@@ -427,7 +326,6 @@ function baseSyncPlugin({
|
|
|
427
326
|
});
|
|
428
327
|
};
|
|
429
328
|
|
|
430
|
-
// 调用微前端生命周期(父应用使用)
|
|
431
329
|
store.callMicroAppLifeCycle = (type, payload) => {
|
|
432
330
|
if (!isParent) return
|
|
433
331
|
if (!isLifeCycleMessage(type)) return
|
|
@@ -438,30 +336,25 @@ function baseSyncPlugin({
|
|
|
438
336
|
});
|
|
439
337
|
};
|
|
440
338
|
|
|
441
|
-
// 处理消息
|
|
442
339
|
const handleMessage = event => {
|
|
443
340
|
if (event.origin !== window.location.origin) return
|
|
444
341
|
const { type, payload, fullPath } = event.data || {};
|
|
445
342
|
|
|
446
|
-
// 子应用处理生命周期消息
|
|
447
343
|
if (!isParent && isLifeCycleMessage(type)) {
|
|
448
344
|
window.__MICRO_APP_LIFECYCLE__?.[type]?.(payload);
|
|
449
345
|
return
|
|
450
346
|
}
|
|
451
347
|
|
|
452
|
-
// 父应用处理来自子应用的状态同步
|
|
453
348
|
if (isParent && type === MESSAGE.SYNC_FROM_CHILD) {
|
|
454
349
|
store.commit('base/SYNC_STATE', payload);
|
|
455
350
|
return
|
|
456
351
|
}
|
|
457
352
|
|
|
458
|
-
// 子应用处理来自父应用的状态同步
|
|
459
353
|
if (!isParent && type === MESSAGE.SYNC_FROM_PARENT) {
|
|
460
354
|
store.commit('base/SYNC_STATE', payload);
|
|
461
355
|
return
|
|
462
356
|
}
|
|
463
357
|
|
|
464
|
-
// 父应用响应子应用的状态请求
|
|
465
358
|
if (isParent && type === MESSAGE.REQUEST_FROM_CHILD) {
|
|
466
359
|
postToChild(iframeSelector, {
|
|
467
360
|
type: MESSAGE.SYNC_FROM_PARENT,
|
|
@@ -470,13 +363,11 @@ function baseSyncPlugin({
|
|
|
470
363
|
return
|
|
471
364
|
}
|
|
472
365
|
|
|
473
|
-
// 父应用处理子应用的路由变化
|
|
474
366
|
if (isParent && type === MESSAGE.CHILD_ROUTE_CHANGE) {
|
|
475
367
|
syncRouteFromChild(fullPath);
|
|
476
368
|
return
|
|
477
369
|
}
|
|
478
370
|
|
|
479
|
-
// 父应用转发其他消息到父窗口
|
|
480
371
|
if (isParent && !isInternalMessage(type) && !isBridgeMessage(type)) {
|
|
481
372
|
window.parent?.postMessage(event.data || {}, '*');
|
|
482
373
|
}
|
|
@@ -484,27 +375,15 @@ function baseSyncPlugin({
|
|
|
484
375
|
|
|
485
376
|
window.addEventListener('message', handleMessage);
|
|
486
377
|
|
|
487
|
-
// 子应用初始化时请求父应用状态
|
|
488
378
|
if (!isParent && window.parent) {
|
|
489
379
|
postToParent({ type: MESSAGE.REQUEST_FROM_CHILD });
|
|
490
380
|
}
|
|
491
381
|
}
|
|
492
382
|
}
|
|
493
383
|
|
|
494
|
-
|
|
495
|
-
* @hhfenpm/micro-app
|
|
496
|
-
* 微前端通信桥接和状态同步工具
|
|
497
|
-
*/
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
var index = {
|
|
501
|
-
initBridge,
|
|
502
|
-
createDefaultMicroAppCore,
|
|
503
|
-
baseSyncPlugin,
|
|
504
|
-
};
|
|
384
|
+
var index = { initBridge, baseSyncPlugin };
|
|
505
385
|
|
|
506
386
|
exports.baseSyncPlugin = baseSyncPlugin;
|
|
507
|
-
exports.createDefaultMicroAppCore = createDefaultMicroAppCore;
|
|
508
387
|
exports.createMicroAppCore = createMicroAppCore;
|
|
509
388
|
exports.createRegisterHandlers = createRegisterHandlers;
|
|
510
389
|
exports.default = index;
|