@hhfenpm/micro-app 1.0.7 → 1.0.8
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 +40 -25
- package/dist/index.esm.js +152 -99
- package/dist/index.js +152 -99
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -14,12 +14,12 @@ yarn add @hhfenpm/micro-app
|
|
|
14
14
|
|
|
15
15
|
## 能力概览
|
|
16
16
|
|
|
17
|
-
| 能力
|
|
18
|
-
|
|
19
|
-
| **通信桥接** | 子应用通过 `vm.$base.命名空间.方法(params)` 调用父应用方法,支持 Promise
|
|
20
|
-
| **状态同步** | 父子应用 Vuex `base` 模块双向同步
|
|
17
|
+
| 能力 | 说明 |
|
|
18
|
+
| ------------ | ----------------------------------------------------------------------------------- |
|
|
19
|
+
| **通信桥接** | 子应用通过 `vm.$base.命名空间.方法(params)` 调用父应用方法,支持 Promise |
|
|
20
|
+
| **状态同步** | 父子应用 Vuex `base` 模块双向同步 |
|
|
21
21
|
| **生命周期** | 父应用调用 `mount/update/unmount`,子应用通过 `window.__MICRO_APP_LIFECYCLE__` 响应 |
|
|
22
|
-
| **路由同步** | 子应用路由变化同步到父应用 URL(需子应用调用 `store.attachRouterSync(router)`)
|
|
22
|
+
| **路由同步** | 子应用路由变化同步到父应用 URL(需子应用调用 `store.attachRouterSync(router)`) |
|
|
23
23
|
|
|
24
24
|
---
|
|
25
25
|
|
|
@@ -32,14 +32,16 @@ yarn add @hhfenpm/micro-app
|
|
|
32
32
|
```javascript
|
|
33
33
|
import { initBridge, createRegisterHandlers } from '@hhfenpm/micro-app'
|
|
34
34
|
|
|
35
|
-
const vm = new Vue({
|
|
35
|
+
const vm = new Vue({
|
|
36
|
+
/* ... */
|
|
37
|
+
})
|
|
36
38
|
|
|
37
39
|
// getElectron:返回 electron 模块,无则 () => ({}) 或 () => require('@/utils/electron')
|
|
38
40
|
const getElectron = () => ({}) // 或 () => require('@/utils/electron')
|
|
39
41
|
const toHandlers = createRegisterHandlers(getElectron)
|
|
40
42
|
|
|
41
43
|
initBridge({
|
|
42
|
-
|
|
44
|
+
isBase: true,
|
|
43
45
|
vm,
|
|
44
46
|
handlers: toHandlers(vm),
|
|
45
47
|
iframeSelector: '#microApp', // 可选,默认 '#microApp'
|
|
@@ -56,13 +58,17 @@ initBridge({
|
|
|
56
58
|
```javascript
|
|
57
59
|
import { initBridge } from '@hhfenpm/micro-app'
|
|
58
60
|
|
|
59
|
-
const vm = new Vue({
|
|
61
|
+
const vm = new Vue({
|
|
62
|
+
/* ... */
|
|
63
|
+
})
|
|
60
64
|
|
|
61
|
-
initBridge({
|
|
65
|
+
initBridge({ isBase: false, vm })
|
|
62
66
|
|
|
63
67
|
// 调用父应用:vm.$base.命名空间.方法(params),返回 Promise
|
|
64
68
|
vm.$base.ui.$message('来自子应用')
|
|
65
|
-
vm.$base.ui.$confirm('确认?').then(ok => {
|
|
69
|
+
vm.$base.ui.$confirm('确认?').then(ok => {
|
|
70
|
+
/* ... */
|
|
71
|
+
})
|
|
66
72
|
vm.$base.cs.show()
|
|
67
73
|
```
|
|
68
74
|
|
|
@@ -77,7 +83,7 @@ import { createMicroAppCore } from '@hhfenpm/micro-app'
|
|
|
77
83
|
|
|
78
84
|
const modelMap = () => ({
|
|
79
85
|
'disease-analysis': ['/disease-analysis', '/ds-consult'],
|
|
80
|
-
|
|
86
|
+
health: ['/health-manage'],
|
|
81
87
|
})
|
|
82
88
|
|
|
83
89
|
const core = createMicroAppCore({
|
|
@@ -86,7 +92,7 @@ const core = createMicroAppCore({
|
|
|
86
92
|
})
|
|
87
93
|
|
|
88
94
|
// 根据路径得到模块名,未命中或未启用则为 null
|
|
89
|
-
const module = core.microAppModule('/disease-analysis')
|
|
95
|
+
const module = core.microAppModule('/disease-analysis') // 'disease-analysis'
|
|
90
96
|
|
|
91
97
|
// 子应用完整 URL(含 hash)
|
|
92
98
|
const src = core.microAppSrc('/disease-analysis')
|
|
@@ -110,7 +116,7 @@ import base from './store/modules/base' // 需含 base/SYNC_STATE
|
|
|
110
116
|
|
|
111
117
|
const store = new Vuex.Store({
|
|
112
118
|
modules: { base },
|
|
113
|
-
plugins: [baseSyncPlugin({
|
|
119
|
+
plugins: [baseSyncPlugin({ isBase: true, iframeSelector: '#microApp' })],
|
|
114
120
|
})
|
|
115
121
|
```
|
|
116
122
|
|
|
@@ -122,7 +128,7 @@ import base from './store/modules/base'
|
|
|
122
128
|
|
|
123
129
|
const store = new Vuex.Store({
|
|
124
130
|
modules: { base },
|
|
125
|
-
plugins: [baseSyncPlugin({
|
|
131
|
+
plugins: [baseSyncPlugin({ isBase: false, iframeSelector: '#microApp' })],
|
|
126
132
|
})
|
|
127
133
|
|
|
128
134
|
import router from './router'
|
|
@@ -141,9 +147,15 @@ store.attachRouterSync(router) // 必调,用于把子应用路由同步到父
|
|
|
141
147
|
|
|
142
148
|
```javascript
|
|
143
149
|
window.__MICRO_APP_LIFECYCLE__ = {
|
|
144
|
-
mount(payload) {
|
|
145
|
-
|
|
146
|
-
|
|
150
|
+
mount(payload) {
|
|
151
|
+
/* 挂载后 */
|
|
152
|
+
},
|
|
153
|
+
update(payload) {
|
|
154
|
+
/* 更新时,如路由变化 */
|
|
155
|
+
},
|
|
156
|
+
unmount(payload) {
|
|
157
|
+
/* 卸载前 */
|
|
158
|
+
},
|
|
147
159
|
}
|
|
148
160
|
```
|
|
149
161
|
|
|
@@ -161,30 +173,33 @@ store.callMicroAppLifeCycle('unmount')
|
|
|
161
173
|
|
|
162
174
|
## API 一览
|
|
163
175
|
|
|
164
|
-
| 接口
|
|
165
|
-
|
|
166
|
-
| `initBridge({
|
|
167
|
-
| `createRegisterHandlers(getElectron?)`
|
|
168
|
-
| `createMicroAppCore({ modelMap, enabledModules? })`
|
|
169
|
-
| `baseSyncPlugin({
|
|
176
|
+
| 接口 | 说明 |
|
|
177
|
+
| -------------------------------------------------------- | ------------------------------------------------------------------------- |
|
|
178
|
+
| `initBridge({ isBase, vm, iframeSelector?, handlers? })` | 初始化桥接;父应用传 `handlers`,子应用可访问 `vm.$base` |
|
|
179
|
+
| `createRegisterHandlers(getElectron?)` | 返回 `(vm) => ({ ui, cs })`,用作 `handlers` |
|
|
180
|
+
| `createMicroAppCore({ modelMap, enabledModules? })` | 返回 `{ microAppModule, microAppSrc, microAppDeployed }` |
|
|
181
|
+
| `baseSyncPlugin({ isBase, iframeSelector? })` | Vuex 插件,并挂载 `store.attachRouterSync`、`store.callMicroAppLifeCycle` |
|
|
170
182
|
|
|
171
183
|
### 参数说明
|
|
172
184
|
|
|
173
185
|
- **initBridge**
|
|
174
|
-
|
|
186
|
+
|
|
187
|
+
- `isBase`: 是否父应用
|
|
175
188
|
- `vm`: Vue 实例(子应用会在其上挂 `vm.$base`、`vm.$baseReady`)
|
|
176
189
|
- `iframeSelector`: 父应用 iframe 选择器,默认 `'#microApp'`
|
|
177
190
|
- `handlers`: 仅父应用需要,`{ [namespace]: { [method]: (params)=>any } }`
|
|
178
191
|
|
|
179
192
|
- **createRegisterHandlers**
|
|
193
|
+
|
|
180
194
|
- `getElectron`: `() => electronModule`,可选;异常或未传时 `cs` 使用 noop
|
|
181
195
|
|
|
182
196
|
- **createMicroAppCore**
|
|
197
|
+
|
|
183
198
|
- `modelMap`: `() => ({ [moduleName]: path[] })`,必填
|
|
184
199
|
- `enabledModules`: `() => string[]` 或 `string[]`,可选;缺省时从 `window.GLOBAL_CONFIG.microApp` 读取
|
|
185
200
|
|
|
186
201
|
- **baseSyncPlugin**
|
|
187
|
-
- `
|
|
202
|
+
- `isBase`: 是否父应用
|
|
188
203
|
- `iframeSelector`: 默认 `'#microApp'`
|
|
189
204
|
|
|
190
205
|
---
|
package/dist/index.esm.js
CHANGED
|
@@ -89,7 +89,7 @@ const safeClone = value => {
|
|
|
89
89
|
const createBaseObject = pending => {
|
|
90
90
|
const namespaces = {};
|
|
91
91
|
const hasProxy = typeof Proxy !== 'undefined';
|
|
92
|
-
|
|
92
|
+
|
|
93
93
|
const createMethod = (namespace, method) => {
|
|
94
94
|
return params =>
|
|
95
95
|
new Promise(resolve => {
|
|
@@ -104,7 +104,7 @@ const createBaseObject = pending => {
|
|
|
104
104
|
});
|
|
105
105
|
})
|
|
106
106
|
};
|
|
107
|
-
|
|
107
|
+
|
|
108
108
|
if (hasProxy) {
|
|
109
109
|
const base = {};
|
|
110
110
|
return new Proxy(base, {
|
|
@@ -117,33 +117,36 @@ const createBaseObject = pending => {
|
|
|
117
117
|
get(target2, method) {
|
|
118
118
|
if (typeof method === 'string') {
|
|
119
119
|
if (!namespaces[namespace][method]) {
|
|
120
|
-
namespaces[namespace][method] = createMethod(
|
|
120
|
+
namespaces[namespace][method] = createMethod(
|
|
121
|
+
namespace,
|
|
122
|
+
method
|
|
123
|
+
);
|
|
121
124
|
}
|
|
122
125
|
return namespaces[namespace][method]
|
|
123
126
|
}
|
|
124
127
|
return undefined
|
|
125
|
-
}
|
|
128
|
+
},
|
|
126
129
|
})
|
|
127
130
|
}
|
|
128
131
|
return undefined
|
|
129
|
-
}
|
|
132
|
+
},
|
|
130
133
|
})
|
|
131
134
|
} else {
|
|
132
135
|
const base = {};
|
|
133
136
|
const commonNamespaces = ['ui', 'cs'];
|
|
134
|
-
|
|
137
|
+
|
|
135
138
|
commonNamespaces.forEach(ns => {
|
|
136
139
|
namespaces[ns] = {};
|
|
137
140
|
const nsObj = {};
|
|
138
|
-
|
|
141
|
+
|
|
139
142
|
Object.defineProperty(base, ns, {
|
|
140
143
|
get() {
|
|
141
144
|
return nsObj
|
|
142
145
|
},
|
|
143
|
-
configurable: true
|
|
146
|
+
configurable: true,
|
|
144
147
|
});
|
|
145
148
|
});
|
|
146
|
-
|
|
149
|
+
|
|
147
150
|
return base
|
|
148
151
|
}
|
|
149
152
|
};
|
|
@@ -160,15 +163,15 @@ function createRegisterHandlers(getElectron) {
|
|
|
160
163
|
}
|
|
161
164
|
|
|
162
165
|
const initBridge = ({
|
|
163
|
-
|
|
166
|
+
isBase = false,
|
|
164
167
|
vm,
|
|
165
168
|
iframeSelector = '#microApp',
|
|
166
169
|
handlers = {},
|
|
167
170
|
} = {}) => {
|
|
168
|
-
const finalHandlers =
|
|
171
|
+
const finalHandlers = isBase ? handlers : Object.create(null);
|
|
169
172
|
const pending = Object.create(null);
|
|
170
173
|
|
|
171
|
-
if (!
|
|
174
|
+
if (!isBase && vm) {
|
|
172
175
|
const baseObj = createBaseObject(pending);
|
|
173
176
|
vm.$base = baseObj;
|
|
174
177
|
vm.$baseReady = true;
|
|
@@ -216,8 +219,8 @@ const initBridge = ({
|
|
|
216
219
|
if (e.origin !== window.location.origin) return
|
|
217
220
|
|
|
218
221
|
const { type } = e.data || {};
|
|
219
|
-
if (
|
|
220
|
-
if (!
|
|
222
|
+
if (isBase && type === BRIDGE$1.INVOKE) handleInvoke(e);
|
|
223
|
+
if (!isBase && type === BRIDGE$1.CALLBACK) handleCallback(e);
|
|
221
224
|
});
|
|
222
225
|
};
|
|
223
226
|
|
|
@@ -288,141 +291,191 @@ const LIFE_CYCLE = {
|
|
|
288
291
|
|
|
289
292
|
const BRIDGE = { INVOKE: 'bridge-invoke', CALLBACK: 'bridge-callback' };
|
|
290
293
|
|
|
291
|
-
const
|
|
292
|
-
const
|
|
294
|
+
const LIFE_CYCLE_SET = new Set(Object.values(LIFE_CYCLE));
|
|
295
|
+
const BRIDGE_SET = new Set(Object.values(BRIDGE));
|
|
296
|
+
const INTERNAL_SET = new Set([
|
|
297
|
+
MESSAGE.SYNC_FROM_CHILD,
|
|
298
|
+
MESSAGE.REQUEST_FROM_CHILD,
|
|
299
|
+
MESSAGE.CHILD_ROUTE_CHANGE,
|
|
300
|
+
]);
|
|
293
301
|
|
|
294
302
|
const postToChild = (iframeSelector, message) => {
|
|
295
|
-
document.querySelector(iframeSelector)
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
);
|
|
303
|
+
const iframe = document.querySelector(iframeSelector);
|
|
304
|
+
if (!iframe) return
|
|
305
|
+
iframe.contentWindow?.postMessage(message, window.location.origin);
|
|
299
306
|
};
|
|
300
307
|
|
|
301
308
|
const postToParent = message => {
|
|
302
309
|
window.parent?.postMessage(message, window.location.origin);
|
|
303
310
|
};
|
|
304
311
|
|
|
305
|
-
const isLifeCycleMessage = type => LIFE_CYCLE_TYPES.includes(type);
|
|
306
|
-
|
|
307
|
-
const isBridgeMessage = type => BRIDGE_TYPES.includes(type);
|
|
308
|
-
|
|
309
|
-
const isInternalMessage = type =>
|
|
310
|
-
[
|
|
311
|
-
MESSAGE.SYNC_FROM_CHILD,
|
|
312
|
-
MESSAGE.REQUEST_FROM_CHILD,
|
|
313
|
-
MESSAGE.CHILD_ROUTE_CHANGE,
|
|
314
|
-
].includes(type);
|
|
315
|
-
|
|
316
312
|
const syncRouteFromChild = fullPath => {
|
|
317
313
|
if (typeof fullPath !== 'string') return
|
|
314
|
+
|
|
318
315
|
const { origin, pathname } = window.location;
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
316
|
+
let base = origin;
|
|
317
|
+
|
|
318
|
+
if (pathname && pathname !== '/') {
|
|
319
|
+
base = (origin + pathname).replace(/\/$/, '');
|
|
320
|
+
}
|
|
321
|
+
|
|
323
322
|
const target = `${base}/#${fullPath}`;
|
|
324
323
|
if (window.location.href !== target) {
|
|
325
324
|
window.location.href = target;
|
|
326
325
|
}
|
|
327
326
|
};
|
|
328
327
|
|
|
328
|
+
const createMessageHandlers = (
|
|
329
|
+
store,
|
|
330
|
+
isBase,
|
|
331
|
+
iframeSelector,
|
|
332
|
+
getLatestBaseState
|
|
333
|
+
) => {
|
|
334
|
+
const handlers = [];
|
|
335
|
+
|
|
336
|
+
if (!isBase) {
|
|
337
|
+
handlers.push((type, payload) => {
|
|
338
|
+
if (LIFE_CYCLE_SET.has(type)) {
|
|
339
|
+
window.__MICRO_APP_LIFECYCLE__?.[type]?.(payload);
|
|
340
|
+
return true
|
|
341
|
+
}
|
|
342
|
+
return false
|
|
343
|
+
});
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
handlers.push((type, payload, fullPath) => {
|
|
347
|
+
if (type === MESSAGE.SYNC_FROM_CHILD && isBase) {
|
|
348
|
+
store.commit('base/SYNC_STATE', payload);
|
|
349
|
+
return true
|
|
350
|
+
}
|
|
351
|
+
|
|
352
|
+
if (type === MESSAGE.SYNC_FROM_PARENT && !isBase) {
|
|
353
|
+
store.commit('base/SYNC_STATE', payload);
|
|
354
|
+
return true
|
|
355
|
+
}
|
|
356
|
+
|
|
357
|
+
if (type === MESSAGE.REQUEST_FROM_CHILD && isBase) {
|
|
358
|
+
postToChild(iframeSelector, {
|
|
359
|
+
type: MESSAGE.SYNC_FROM_PARENT,
|
|
360
|
+
payload: getLatestBaseState(),
|
|
361
|
+
});
|
|
362
|
+
return true
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
if (type === MESSAGE.CHILD_ROUTE_CHANGE && isBase) {
|
|
366
|
+
syncRouteFromChild(fullPath);
|
|
367
|
+
return true
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
return false
|
|
371
|
+
});
|
|
372
|
+
|
|
373
|
+
handlers.push((type, data) => {
|
|
374
|
+
if (isBase && !INTERNAL_SET.has(type) && !BRIDGE_SET.has(type)) {
|
|
375
|
+
window.parent?.postMessage(data, '*');
|
|
376
|
+
return true
|
|
377
|
+
}
|
|
378
|
+
return false
|
|
379
|
+
});
|
|
380
|
+
|
|
381
|
+
return handlers
|
|
382
|
+
};
|
|
383
|
+
|
|
329
384
|
function baseSyncPlugin({
|
|
330
|
-
|
|
385
|
+
isBase = false,
|
|
331
386
|
iframeSelector = '#microApp',
|
|
332
387
|
} = {}) {
|
|
333
388
|
return store => {
|
|
334
389
|
let latestBaseState = store.state.base;
|
|
390
|
+
let isMounted = false;
|
|
391
|
+
|
|
392
|
+
const handleStateChange = () => {
|
|
393
|
+
if (!isMounted) return
|
|
394
|
+
|
|
395
|
+
const message = isBase
|
|
396
|
+
? { type: MESSAGE.SYNC_FROM_PARENT, payload: latestBaseState }
|
|
397
|
+
: { type: MESSAGE.SYNC_FROM_CHILD, payload: latestBaseState };
|
|
335
398
|
|
|
336
|
-
|
|
337
|
-
|
|
399
|
+
isBase ? postToChild(iframeSelector, message) : postToParent(message);
|
|
400
|
+
};
|
|
401
|
+
|
|
402
|
+
const unwatch = store.watch(
|
|
403
|
+
() => store.state.base,
|
|
338
404
|
newBase => {
|
|
339
405
|
latestBaseState = newBase;
|
|
340
|
-
|
|
341
|
-
postToChild(iframeSelector, {
|
|
342
|
-
type: MESSAGE.SYNC_FROM_PARENT,
|
|
343
|
-
payload: latestBaseState,
|
|
344
|
-
});
|
|
345
|
-
} else {
|
|
346
|
-
postToParent({
|
|
347
|
-
type: MESSAGE.SYNC_FROM_CHILD,
|
|
348
|
-
payload: latestBaseState,
|
|
349
|
-
});
|
|
350
|
-
}
|
|
406
|
+
handleStateChange();
|
|
351
407
|
},
|
|
352
408
|
{ deep: true }
|
|
353
409
|
);
|
|
354
410
|
|
|
411
|
+
const messageHandlers = createMessageHandlers(
|
|
412
|
+
store,
|
|
413
|
+
isBase,
|
|
414
|
+
iframeSelector,
|
|
415
|
+
() => latestBaseState
|
|
416
|
+
);
|
|
417
|
+
|
|
418
|
+
const messageListener = event => {
|
|
419
|
+
if (event.origin !== window.location.origin) return
|
|
420
|
+
|
|
421
|
+
const { type, payload, fullPath } = event.data || {};
|
|
422
|
+
if (!type) return
|
|
423
|
+
|
|
424
|
+
for (const handler of messageHandlers) {
|
|
425
|
+
if (handler(type, payload, fullPath, event.data)) {
|
|
426
|
+
break
|
|
427
|
+
}
|
|
428
|
+
}
|
|
429
|
+
};
|
|
430
|
+
|
|
355
431
|
store.attachRouterSync = router => {
|
|
356
|
-
if (!router ||
|
|
357
|
-
|
|
432
|
+
if (!router || isBase) return
|
|
433
|
+
|
|
434
|
+
const routeHandler = to => {
|
|
358
435
|
const parentHref = window.parent?.location?.href || '';
|
|
359
|
-
const
|
|
360
|
-
|
|
361
|
-
: '';
|
|
436
|
+
const hashIndex = parentHref.indexOf('#');
|
|
437
|
+
const parentFullPath =
|
|
438
|
+
hashIndex > -1 ? parentHref.slice(hashIndex + 1) : '';
|
|
362
439
|
const childFullPath = to.fullPath.startsWith('/')
|
|
363
440
|
? to.fullPath
|
|
364
441
|
: '/' + to.fullPath;
|
|
442
|
+
|
|
365
443
|
if (parentFullPath !== childFullPath) {
|
|
366
444
|
postToParent({
|
|
367
445
|
type: MESSAGE.CHILD_ROUTE_CHANGE,
|
|
368
446
|
fullPath: to.fullPath,
|
|
369
447
|
});
|
|
370
448
|
}
|
|
371
|
-
}
|
|
449
|
+
};
|
|
450
|
+
|
|
451
|
+
router.afterEach(routeHandler);
|
|
372
452
|
};
|
|
373
453
|
|
|
374
454
|
store.callMicroAppLifeCycle = (type, payload) => {
|
|
375
|
-
if (!
|
|
376
|
-
if (!isLifeCycleMessage(type)) return
|
|
455
|
+
if (!isBase || !LIFE_CYCLE_SET.has(type)) return
|
|
377
456
|
|
|
378
|
-
postToChild(iframeSelector, {
|
|
379
|
-
type,
|
|
380
|
-
payload,
|
|
381
|
-
});
|
|
457
|
+
postToChild(iframeSelector, { type, payload });
|
|
382
458
|
};
|
|
383
459
|
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
if (!isParent && isLifeCycleMessage(type)) {
|
|
389
|
-
window.__MICRO_APP_LIFECYCLE__?.[type]?.(payload);
|
|
390
|
-
return
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
if (isParent && type === MESSAGE.SYNC_FROM_CHILD) {
|
|
394
|
-
store.commit('base/SYNC_STATE', payload);
|
|
395
|
-
return
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
if (!isParent && type === MESSAGE.SYNC_FROM_PARENT) {
|
|
399
|
-
store.commit('base/SYNC_STATE', payload);
|
|
400
|
-
return
|
|
401
|
-
}
|
|
402
|
-
|
|
403
|
-
if (isParent && type === MESSAGE.REQUEST_FROM_CHILD) {
|
|
404
|
-
postToChild(iframeSelector, {
|
|
405
|
-
type: MESSAGE.SYNC_FROM_PARENT,
|
|
406
|
-
payload: latestBaseState,
|
|
407
|
-
});
|
|
408
|
-
return
|
|
409
|
-
}
|
|
410
|
-
|
|
411
|
-
if (isParent && type === MESSAGE.CHILD_ROUTE_CHANGE) {
|
|
412
|
-
syncRouteFromChild(fullPath);
|
|
413
|
-
return
|
|
414
|
-
}
|
|
415
|
-
|
|
416
|
-
if (isParent && !isInternalMessage(type) && !isBridgeMessage(type)) {
|
|
417
|
-
window.parent?.postMessage(event.data || {}, '*');
|
|
418
|
-
}
|
|
460
|
+
store.destroy = () => {
|
|
461
|
+
window.removeEventListener('message', messageListener);
|
|
462
|
+
unwatch?.();
|
|
463
|
+
isMounted = false;
|
|
419
464
|
};
|
|
420
465
|
|
|
421
|
-
window.addEventListener('message',
|
|
466
|
+
window.addEventListener('message', messageListener);
|
|
422
467
|
|
|
423
|
-
if (!
|
|
424
|
-
|
|
468
|
+
if (!isBase && window.parent) {
|
|
469
|
+
const requestTimer = setTimeout(() => {
|
|
470
|
+
postToParent({ type: MESSAGE.REQUEST_FROM_CHILD });
|
|
471
|
+
isMounted = true;
|
|
472
|
+
clearTimeout(requestTimer);
|
|
473
|
+
}, 0);
|
|
474
|
+
} else {
|
|
475
|
+
isMounted = true;
|
|
425
476
|
}
|
|
477
|
+
|
|
478
|
+
return store
|
|
426
479
|
}
|
|
427
480
|
}
|
|
428
481
|
|
package/dist/index.js
CHANGED
|
@@ -91,7 +91,7 @@ const safeClone = value => {
|
|
|
91
91
|
const createBaseObject = pending => {
|
|
92
92
|
const namespaces = {};
|
|
93
93
|
const hasProxy = typeof Proxy !== 'undefined';
|
|
94
|
-
|
|
94
|
+
|
|
95
95
|
const createMethod = (namespace, method) => {
|
|
96
96
|
return params =>
|
|
97
97
|
new Promise(resolve => {
|
|
@@ -106,7 +106,7 @@ const createBaseObject = pending => {
|
|
|
106
106
|
});
|
|
107
107
|
})
|
|
108
108
|
};
|
|
109
|
-
|
|
109
|
+
|
|
110
110
|
if (hasProxy) {
|
|
111
111
|
const base = {};
|
|
112
112
|
return new Proxy(base, {
|
|
@@ -119,33 +119,36 @@ const createBaseObject = pending => {
|
|
|
119
119
|
get(target2, method) {
|
|
120
120
|
if (typeof method === 'string') {
|
|
121
121
|
if (!namespaces[namespace][method]) {
|
|
122
|
-
namespaces[namespace][method] = createMethod(
|
|
122
|
+
namespaces[namespace][method] = createMethod(
|
|
123
|
+
namespace,
|
|
124
|
+
method
|
|
125
|
+
);
|
|
123
126
|
}
|
|
124
127
|
return namespaces[namespace][method]
|
|
125
128
|
}
|
|
126
129
|
return undefined
|
|
127
|
-
}
|
|
130
|
+
},
|
|
128
131
|
})
|
|
129
132
|
}
|
|
130
133
|
return undefined
|
|
131
|
-
}
|
|
134
|
+
},
|
|
132
135
|
})
|
|
133
136
|
} else {
|
|
134
137
|
const base = {};
|
|
135
138
|
const commonNamespaces = ['ui', 'cs'];
|
|
136
|
-
|
|
139
|
+
|
|
137
140
|
commonNamespaces.forEach(ns => {
|
|
138
141
|
namespaces[ns] = {};
|
|
139
142
|
const nsObj = {};
|
|
140
|
-
|
|
143
|
+
|
|
141
144
|
Object.defineProperty(base, ns, {
|
|
142
145
|
get() {
|
|
143
146
|
return nsObj
|
|
144
147
|
},
|
|
145
|
-
configurable: true
|
|
148
|
+
configurable: true,
|
|
146
149
|
});
|
|
147
150
|
});
|
|
148
|
-
|
|
151
|
+
|
|
149
152
|
return base
|
|
150
153
|
}
|
|
151
154
|
};
|
|
@@ -162,15 +165,15 @@ function createRegisterHandlers(getElectron) {
|
|
|
162
165
|
}
|
|
163
166
|
|
|
164
167
|
const initBridge = ({
|
|
165
|
-
|
|
168
|
+
isBase = false,
|
|
166
169
|
vm,
|
|
167
170
|
iframeSelector = '#microApp',
|
|
168
171
|
handlers = {},
|
|
169
172
|
} = {}) => {
|
|
170
|
-
const finalHandlers =
|
|
173
|
+
const finalHandlers = isBase ? handlers : Object.create(null);
|
|
171
174
|
const pending = Object.create(null);
|
|
172
175
|
|
|
173
|
-
if (!
|
|
176
|
+
if (!isBase && vm) {
|
|
174
177
|
const baseObj = createBaseObject(pending);
|
|
175
178
|
vm.$base = baseObj;
|
|
176
179
|
vm.$baseReady = true;
|
|
@@ -218,8 +221,8 @@ const initBridge = ({
|
|
|
218
221
|
if (e.origin !== window.location.origin) return
|
|
219
222
|
|
|
220
223
|
const { type } = e.data || {};
|
|
221
|
-
if (
|
|
222
|
-
if (!
|
|
224
|
+
if (isBase && type === BRIDGE$1.INVOKE) handleInvoke(e);
|
|
225
|
+
if (!isBase && type === BRIDGE$1.CALLBACK) handleCallback(e);
|
|
223
226
|
});
|
|
224
227
|
};
|
|
225
228
|
|
|
@@ -290,141 +293,191 @@ const LIFE_CYCLE = {
|
|
|
290
293
|
|
|
291
294
|
const BRIDGE = { INVOKE: 'bridge-invoke', CALLBACK: 'bridge-callback' };
|
|
292
295
|
|
|
293
|
-
const
|
|
294
|
-
const
|
|
296
|
+
const LIFE_CYCLE_SET = new Set(Object.values(LIFE_CYCLE));
|
|
297
|
+
const BRIDGE_SET = new Set(Object.values(BRIDGE));
|
|
298
|
+
const INTERNAL_SET = new Set([
|
|
299
|
+
MESSAGE.SYNC_FROM_CHILD,
|
|
300
|
+
MESSAGE.REQUEST_FROM_CHILD,
|
|
301
|
+
MESSAGE.CHILD_ROUTE_CHANGE,
|
|
302
|
+
]);
|
|
295
303
|
|
|
296
304
|
const postToChild = (iframeSelector, message) => {
|
|
297
|
-
document.querySelector(iframeSelector)
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
);
|
|
305
|
+
const iframe = document.querySelector(iframeSelector);
|
|
306
|
+
if (!iframe) return
|
|
307
|
+
iframe.contentWindow?.postMessage(message, window.location.origin);
|
|
301
308
|
};
|
|
302
309
|
|
|
303
310
|
const postToParent = message => {
|
|
304
311
|
window.parent?.postMessage(message, window.location.origin);
|
|
305
312
|
};
|
|
306
313
|
|
|
307
|
-
const isLifeCycleMessage = type => LIFE_CYCLE_TYPES.includes(type);
|
|
308
|
-
|
|
309
|
-
const isBridgeMessage = type => BRIDGE_TYPES.includes(type);
|
|
310
|
-
|
|
311
|
-
const isInternalMessage = type =>
|
|
312
|
-
[
|
|
313
|
-
MESSAGE.SYNC_FROM_CHILD,
|
|
314
|
-
MESSAGE.REQUEST_FROM_CHILD,
|
|
315
|
-
MESSAGE.CHILD_ROUTE_CHANGE,
|
|
316
|
-
].includes(type);
|
|
317
|
-
|
|
318
314
|
const syncRouteFromChild = fullPath => {
|
|
319
315
|
if (typeof fullPath !== 'string') return
|
|
316
|
+
|
|
320
317
|
const { origin, pathname } = window.location;
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
318
|
+
let base = origin;
|
|
319
|
+
|
|
320
|
+
if (pathname && pathname !== '/') {
|
|
321
|
+
base = (origin + pathname).replace(/\/$/, '');
|
|
322
|
+
}
|
|
323
|
+
|
|
325
324
|
const target = `${base}/#${fullPath}`;
|
|
326
325
|
if (window.location.href !== target) {
|
|
327
326
|
window.location.href = target;
|
|
328
327
|
}
|
|
329
328
|
};
|
|
330
329
|
|
|
330
|
+
const createMessageHandlers = (
|
|
331
|
+
store,
|
|
332
|
+
isBase,
|
|
333
|
+
iframeSelector,
|
|
334
|
+
getLatestBaseState
|
|
335
|
+
) => {
|
|
336
|
+
const handlers = [];
|
|
337
|
+
|
|
338
|
+
if (!isBase) {
|
|
339
|
+
handlers.push((type, payload) => {
|
|
340
|
+
if (LIFE_CYCLE_SET.has(type)) {
|
|
341
|
+
window.__MICRO_APP_LIFECYCLE__?.[type]?.(payload);
|
|
342
|
+
return true
|
|
343
|
+
}
|
|
344
|
+
return false
|
|
345
|
+
});
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
handlers.push((type, payload, fullPath) => {
|
|
349
|
+
if (type === MESSAGE.SYNC_FROM_CHILD && isBase) {
|
|
350
|
+
store.commit('base/SYNC_STATE', payload);
|
|
351
|
+
return true
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
if (type === MESSAGE.SYNC_FROM_PARENT && !isBase) {
|
|
355
|
+
store.commit('base/SYNC_STATE', payload);
|
|
356
|
+
return true
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (type === MESSAGE.REQUEST_FROM_CHILD && isBase) {
|
|
360
|
+
postToChild(iframeSelector, {
|
|
361
|
+
type: MESSAGE.SYNC_FROM_PARENT,
|
|
362
|
+
payload: getLatestBaseState(),
|
|
363
|
+
});
|
|
364
|
+
return true
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
if (type === MESSAGE.CHILD_ROUTE_CHANGE && isBase) {
|
|
368
|
+
syncRouteFromChild(fullPath);
|
|
369
|
+
return true
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
return false
|
|
373
|
+
});
|
|
374
|
+
|
|
375
|
+
handlers.push((type, data) => {
|
|
376
|
+
if (isBase && !INTERNAL_SET.has(type) && !BRIDGE_SET.has(type)) {
|
|
377
|
+
window.parent?.postMessage(data, '*');
|
|
378
|
+
return true
|
|
379
|
+
}
|
|
380
|
+
return false
|
|
381
|
+
});
|
|
382
|
+
|
|
383
|
+
return handlers
|
|
384
|
+
};
|
|
385
|
+
|
|
331
386
|
function baseSyncPlugin({
|
|
332
|
-
|
|
387
|
+
isBase = false,
|
|
333
388
|
iframeSelector = '#microApp',
|
|
334
389
|
} = {}) {
|
|
335
390
|
return store => {
|
|
336
391
|
let latestBaseState = store.state.base;
|
|
392
|
+
let isMounted = false;
|
|
393
|
+
|
|
394
|
+
const handleStateChange = () => {
|
|
395
|
+
if (!isMounted) return
|
|
396
|
+
|
|
397
|
+
const message = isBase
|
|
398
|
+
? { type: MESSAGE.SYNC_FROM_PARENT, payload: latestBaseState }
|
|
399
|
+
: { type: MESSAGE.SYNC_FROM_CHILD, payload: latestBaseState };
|
|
337
400
|
|
|
338
|
-
|
|
339
|
-
|
|
401
|
+
isBase ? postToChild(iframeSelector, message) : postToParent(message);
|
|
402
|
+
};
|
|
403
|
+
|
|
404
|
+
const unwatch = store.watch(
|
|
405
|
+
() => store.state.base,
|
|
340
406
|
newBase => {
|
|
341
407
|
latestBaseState = newBase;
|
|
342
|
-
|
|
343
|
-
postToChild(iframeSelector, {
|
|
344
|
-
type: MESSAGE.SYNC_FROM_PARENT,
|
|
345
|
-
payload: latestBaseState,
|
|
346
|
-
});
|
|
347
|
-
} else {
|
|
348
|
-
postToParent({
|
|
349
|
-
type: MESSAGE.SYNC_FROM_CHILD,
|
|
350
|
-
payload: latestBaseState,
|
|
351
|
-
});
|
|
352
|
-
}
|
|
408
|
+
handleStateChange();
|
|
353
409
|
},
|
|
354
410
|
{ deep: true }
|
|
355
411
|
);
|
|
356
412
|
|
|
413
|
+
const messageHandlers = createMessageHandlers(
|
|
414
|
+
store,
|
|
415
|
+
isBase,
|
|
416
|
+
iframeSelector,
|
|
417
|
+
() => latestBaseState
|
|
418
|
+
);
|
|
419
|
+
|
|
420
|
+
const messageListener = event => {
|
|
421
|
+
if (event.origin !== window.location.origin) return
|
|
422
|
+
|
|
423
|
+
const { type, payload, fullPath } = event.data || {};
|
|
424
|
+
if (!type) return
|
|
425
|
+
|
|
426
|
+
for (const handler of messageHandlers) {
|
|
427
|
+
if (handler(type, payload, fullPath, event.data)) {
|
|
428
|
+
break
|
|
429
|
+
}
|
|
430
|
+
}
|
|
431
|
+
};
|
|
432
|
+
|
|
357
433
|
store.attachRouterSync = router => {
|
|
358
|
-
if (!router ||
|
|
359
|
-
|
|
434
|
+
if (!router || isBase) return
|
|
435
|
+
|
|
436
|
+
const routeHandler = to => {
|
|
360
437
|
const parentHref = window.parent?.location?.href || '';
|
|
361
|
-
const
|
|
362
|
-
|
|
363
|
-
: '';
|
|
438
|
+
const hashIndex = parentHref.indexOf('#');
|
|
439
|
+
const parentFullPath =
|
|
440
|
+
hashIndex > -1 ? parentHref.slice(hashIndex + 1) : '';
|
|
364
441
|
const childFullPath = to.fullPath.startsWith('/')
|
|
365
442
|
? to.fullPath
|
|
366
443
|
: '/' + to.fullPath;
|
|
444
|
+
|
|
367
445
|
if (parentFullPath !== childFullPath) {
|
|
368
446
|
postToParent({
|
|
369
447
|
type: MESSAGE.CHILD_ROUTE_CHANGE,
|
|
370
448
|
fullPath: to.fullPath,
|
|
371
449
|
});
|
|
372
450
|
}
|
|
373
|
-
}
|
|
451
|
+
};
|
|
452
|
+
|
|
453
|
+
router.afterEach(routeHandler);
|
|
374
454
|
};
|
|
375
455
|
|
|
376
456
|
store.callMicroAppLifeCycle = (type, payload) => {
|
|
377
|
-
if (!
|
|
378
|
-
if (!isLifeCycleMessage(type)) return
|
|
457
|
+
if (!isBase || !LIFE_CYCLE_SET.has(type)) return
|
|
379
458
|
|
|
380
|
-
postToChild(iframeSelector, {
|
|
381
|
-
type,
|
|
382
|
-
payload,
|
|
383
|
-
});
|
|
459
|
+
postToChild(iframeSelector, { type, payload });
|
|
384
460
|
};
|
|
385
461
|
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
if (!isParent && isLifeCycleMessage(type)) {
|
|
391
|
-
window.__MICRO_APP_LIFECYCLE__?.[type]?.(payload);
|
|
392
|
-
return
|
|
393
|
-
}
|
|
394
|
-
|
|
395
|
-
if (isParent && type === MESSAGE.SYNC_FROM_CHILD) {
|
|
396
|
-
store.commit('base/SYNC_STATE', payload);
|
|
397
|
-
return
|
|
398
|
-
}
|
|
399
|
-
|
|
400
|
-
if (!isParent && type === MESSAGE.SYNC_FROM_PARENT) {
|
|
401
|
-
store.commit('base/SYNC_STATE', payload);
|
|
402
|
-
return
|
|
403
|
-
}
|
|
404
|
-
|
|
405
|
-
if (isParent && type === MESSAGE.REQUEST_FROM_CHILD) {
|
|
406
|
-
postToChild(iframeSelector, {
|
|
407
|
-
type: MESSAGE.SYNC_FROM_PARENT,
|
|
408
|
-
payload: latestBaseState,
|
|
409
|
-
});
|
|
410
|
-
return
|
|
411
|
-
}
|
|
412
|
-
|
|
413
|
-
if (isParent && type === MESSAGE.CHILD_ROUTE_CHANGE) {
|
|
414
|
-
syncRouteFromChild(fullPath);
|
|
415
|
-
return
|
|
416
|
-
}
|
|
417
|
-
|
|
418
|
-
if (isParent && !isInternalMessage(type) && !isBridgeMessage(type)) {
|
|
419
|
-
window.parent?.postMessage(event.data || {}, '*');
|
|
420
|
-
}
|
|
462
|
+
store.destroy = () => {
|
|
463
|
+
window.removeEventListener('message', messageListener);
|
|
464
|
+
unwatch?.();
|
|
465
|
+
isMounted = false;
|
|
421
466
|
};
|
|
422
467
|
|
|
423
|
-
window.addEventListener('message',
|
|
468
|
+
window.addEventListener('message', messageListener);
|
|
424
469
|
|
|
425
|
-
if (!
|
|
426
|
-
|
|
470
|
+
if (!isBase && window.parent) {
|
|
471
|
+
const requestTimer = setTimeout(() => {
|
|
472
|
+
postToParent({ type: MESSAGE.REQUEST_FROM_CHILD });
|
|
473
|
+
isMounted = true;
|
|
474
|
+
clearTimeout(requestTimer);
|
|
475
|
+
}, 0);
|
|
476
|
+
} else {
|
|
477
|
+
isMounted = true;
|
|
427
478
|
}
|
|
479
|
+
|
|
480
|
+
return store
|
|
428
481
|
}
|
|
429
482
|
}
|
|
430
483
|
|