@micro-zoe/micro-app 0.5.3 → 0.7.0
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.zh-cn.md +2 -2
- package/lib/index.d.ts +39 -82
- package/lib/index.esm.js +1083 -785
- package/lib/index.esm.js.map +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.min.js.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +4 -4
- package/polyfill/jsx-custom-event.js +11 -1
- package/polyfill/jsx-custom-event.js.map +1 -1
- package/typings/global.d.ts +15 -11
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '0.
|
|
1
|
+
const version = '0.7.0';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -41,6 +41,9 @@ function isBoundFunction(target) {
|
|
|
41
41
|
function isShadowRoot(target) {
|
|
42
42
|
return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
|
|
43
43
|
}
|
|
44
|
+
const rawDefineProperty = Object.defineProperty;
|
|
45
|
+
const rawDefineProperties = Object.defineProperties;
|
|
46
|
+
const rawHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
44
47
|
/**
|
|
45
48
|
* format error log
|
|
46
49
|
* @param msg message
|
|
@@ -230,6 +233,17 @@ let currentMicroAppName = null;
|
|
|
230
233
|
function setCurrentAppName(appName) {
|
|
231
234
|
currentMicroAppName = appName;
|
|
232
235
|
}
|
|
236
|
+
let isWaitingForReset = false;
|
|
237
|
+
function throttleDeferForSetAppName(appName) {
|
|
238
|
+
if (!isWaitingForReset || currentMicroAppName !== appName) {
|
|
239
|
+
isWaitingForReset = true;
|
|
240
|
+
setCurrentAppName(appName);
|
|
241
|
+
defer(() => {
|
|
242
|
+
isWaitingForReset = false;
|
|
243
|
+
setCurrentAppName(null);
|
|
244
|
+
});
|
|
245
|
+
}
|
|
246
|
+
}
|
|
233
247
|
// get the currently running app.name
|
|
234
248
|
function getCurrentAppName() {
|
|
235
249
|
return currentMicroAppName;
|
|
@@ -297,16 +311,16 @@ var ObservedAttrName;
|
|
|
297
311
|
ObservedAttrName["URL"] = "url";
|
|
298
312
|
})(ObservedAttrName || (ObservedAttrName = {}));
|
|
299
313
|
// app status
|
|
300
|
-
var
|
|
301
|
-
(function (
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
})(
|
|
314
|
+
var appStates;
|
|
315
|
+
(function (appStates) {
|
|
316
|
+
appStates["NOT_LOADED"] = "NOT_LOADED";
|
|
317
|
+
appStates["LOADING_SOURCE_CODE"] = "LOADING_SOURCE_CODE";
|
|
318
|
+
appStates["LOAD_SOURCE_FINISHED"] = "LOAD_SOURCE_FINISHED";
|
|
319
|
+
appStates["LOAD_SOURCE_ERROR"] = "LOAD_SOURCE_ERROR";
|
|
320
|
+
appStates["MOUNTING"] = "MOUNTING";
|
|
321
|
+
appStates["MOUNTED"] = "MOUNTED";
|
|
322
|
+
appStates["UNMOUNT"] = "UNMOUNT";
|
|
323
|
+
})(appStates || (appStates = {}));
|
|
310
324
|
// lifecycles
|
|
311
325
|
var lifeCycles;
|
|
312
326
|
(function (lifeCycles) {
|
|
@@ -315,7 +329,18 @@ var lifeCycles;
|
|
|
315
329
|
lifeCycles["MOUNTED"] = "mounted";
|
|
316
330
|
lifeCycles["UNMOUNT"] = "unmount";
|
|
317
331
|
lifeCycles["ERROR"] = "error";
|
|
332
|
+
// 👇 keep-alive only
|
|
333
|
+
lifeCycles["BEFORESHOW"] = "beforeshow";
|
|
334
|
+
lifeCycles["AFTERSHOW"] = "aftershow";
|
|
335
|
+
lifeCycles["AFTERHIDDEN"] = "afterhidden";
|
|
318
336
|
})(lifeCycles || (lifeCycles = {}));
|
|
337
|
+
// keep-alive status
|
|
338
|
+
var keepAliveStates;
|
|
339
|
+
(function (keepAliveStates) {
|
|
340
|
+
keepAliveStates["KEEP_ALIVE_SHOW"] = "KEEP_ALIVE_SHOW";
|
|
341
|
+
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "KEEP_ALIVE_HIDDEN";
|
|
342
|
+
})(keepAliveStates || (keepAliveStates = {}));
|
|
343
|
+
const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Promise,Function,Proxy,WeakMap,WeakRef,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,location,navigator,undefined';
|
|
319
344
|
|
|
320
345
|
/**
|
|
321
346
|
* fetch source of html, js, css
|
|
@@ -333,6 +358,10 @@ function fetchSource(url, appName = null, options = {}) {
|
|
|
333
358
|
}
|
|
334
359
|
|
|
335
360
|
const globalEnv = {};
|
|
361
|
+
/**
|
|
362
|
+
* Note loop nesting
|
|
363
|
+
* Only prototype or unique values can be put here
|
|
364
|
+
*/
|
|
336
365
|
function initGlobalEnv() {
|
|
337
366
|
if (isBrowser) {
|
|
338
367
|
/**
|
|
@@ -340,12 +369,13 @@ function initGlobalEnv() {
|
|
|
340
369
|
* pay attention to this binding
|
|
341
370
|
*/
|
|
342
371
|
const rawSetAttribute = Element.prototype.setAttribute;
|
|
343
|
-
const rawAppendChild =
|
|
344
|
-
const rawInsertBefore =
|
|
345
|
-
const rawReplaceChild =
|
|
346
|
-
const rawRemoveChild =
|
|
372
|
+
const rawAppendChild = Element.prototype.appendChild;
|
|
373
|
+
const rawInsertBefore = Element.prototype.insertBefore;
|
|
374
|
+
const rawReplaceChild = Element.prototype.replaceChild;
|
|
375
|
+
const rawRemoveChild = Element.prototype.removeChild;
|
|
347
376
|
const rawAppend = Element.prototype.append;
|
|
348
377
|
const rawPrepend = Element.prototype.prepend;
|
|
378
|
+
const rawCloneNode = Element.prototype.cloneNode;
|
|
349
379
|
const rawCreateElement = Document.prototype.createElement;
|
|
350
380
|
const rawCreateElementNS = Document.prototype.createElementNS;
|
|
351
381
|
const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
|
|
@@ -355,6 +385,13 @@ function initGlobalEnv() {
|
|
|
355
385
|
const rawGetElementsByClassName = Document.prototype.getElementsByClassName;
|
|
356
386
|
const rawGetElementsByTagName = Document.prototype.getElementsByTagName;
|
|
357
387
|
const rawGetElementsByName = Document.prototype.getElementsByName;
|
|
388
|
+
const ImageProxy = new Proxy(Image, {
|
|
389
|
+
construct(Target, args) {
|
|
390
|
+
const elementImage = new Target(...args);
|
|
391
|
+
elementImage.__MICRO_APP_NAME__ = getCurrentAppName();
|
|
392
|
+
return elementImage;
|
|
393
|
+
},
|
|
394
|
+
});
|
|
358
395
|
const rawWindow = Function('return window')();
|
|
359
396
|
const rawDocument = Function('return document')();
|
|
360
397
|
const supportModuleScript = isSupportModuleScript();
|
|
@@ -382,6 +419,7 @@ function initGlobalEnv() {
|
|
|
382
419
|
rawRemoveChild,
|
|
383
420
|
rawAppend,
|
|
384
421
|
rawPrepend,
|
|
422
|
+
rawCloneNode,
|
|
385
423
|
rawCreateElement,
|
|
386
424
|
rawCreateElementNS,
|
|
387
425
|
rawCreateDocumentFragment,
|
|
@@ -391,6 +429,7 @@ function initGlobalEnv() {
|
|
|
391
429
|
rawGetElementsByClassName,
|
|
392
430
|
rawGetElementsByTagName,
|
|
393
431
|
rawGetElementsByName,
|
|
432
|
+
ImageProxy,
|
|
394
433
|
// common global vars
|
|
395
434
|
rawWindow,
|
|
396
435
|
rawDocument,
|
|
@@ -409,13 +448,6 @@ function initGlobalEnv() {
|
|
|
409
448
|
}
|
|
410
449
|
}
|
|
411
450
|
|
|
412
|
-
// https://developer.mozilla.org/zh-CN/docs/Web/API/CSSRule
|
|
413
|
-
var CSSRuleType;
|
|
414
|
-
(function (CSSRuleType) {
|
|
415
|
-
CSSRuleType[CSSRuleType["STYLE_RULE"] = 1] = "STYLE_RULE";
|
|
416
|
-
CSSRuleType[CSSRuleType["MEDIA_RULE"] = 4] = "MEDIA_RULE";
|
|
417
|
-
CSSRuleType[CSSRuleType["SUPPORTS_RULE"] = 12] = "SUPPORTS_RULE";
|
|
418
|
-
})(CSSRuleType || (CSSRuleType = {}));
|
|
419
451
|
/**
|
|
420
452
|
* Bind css scope
|
|
421
453
|
* Special case:
|
|
@@ -496,14 +528,15 @@ function scopedPackRule(rule, prefix, packName) {
|
|
|
496
528
|
function scopedRule(rules, prefix) {
|
|
497
529
|
let result = '';
|
|
498
530
|
for (const rule of rules) {
|
|
499
|
-
|
|
500
|
-
|
|
531
|
+
// https://developer.mozilla.org/zh-CN/docs/Web/API/CSSRule
|
|
532
|
+
switch (rule.constructor.name) {
|
|
533
|
+
case 'CSSStyleRule':
|
|
501
534
|
result += scopedStyleRule(rule, prefix);
|
|
502
535
|
break;
|
|
503
|
-
case
|
|
536
|
+
case 'CSSMediaRule':
|
|
504
537
|
result += scopedPackRule(rule, prefix, 'media');
|
|
505
538
|
break;
|
|
506
|
-
case
|
|
539
|
+
case 'CSSSupportsRule':
|
|
507
540
|
result += scopedPackRule(rule, prefix, 'supports');
|
|
508
541
|
break;
|
|
509
542
|
default:
|
|
@@ -897,17 +930,21 @@ function execScripts(scriptList, app, initedHook) {
|
|
|
897
930
|
}
|
|
898
931
|
}
|
|
899
932
|
if (deferScriptPromise.length) {
|
|
900
|
-
|
|
901
|
-
res.
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
!info.module && initedHook(false);
|
|
906
|
-
});
|
|
907
|
-
initedHook(isUndefined(initedHook.moduleCount));
|
|
908
|
-
}).catch((err) => {
|
|
933
|
+
promiseStream(deferScriptPromise, (res) => {
|
|
934
|
+
const info = deferScriptInfo[res.index][1];
|
|
935
|
+
info.code = info.code || res.data;
|
|
936
|
+
}, (err) => {
|
|
937
|
+
initedHook.errorCount = initedHook.errorCount ? ++initedHook.errorCount : 1;
|
|
909
938
|
logError(err, app.name);
|
|
910
|
-
|
|
939
|
+
}, () => {
|
|
940
|
+
deferScriptInfo.forEach(([url, info]) => {
|
|
941
|
+
if (info.code) {
|
|
942
|
+
runScript(url, app, info, false, initedHook);
|
|
943
|
+
!info.module && initedHook(false);
|
|
944
|
+
}
|
|
945
|
+
});
|
|
946
|
+
initedHook(isUndefined(initedHook.moduleCount) ||
|
|
947
|
+
initedHook.errorCount === deferScriptPromise.length);
|
|
911
948
|
});
|
|
912
949
|
}
|
|
913
950
|
else {
|
|
@@ -1042,7 +1079,7 @@ function bindScope(url, app, code, module) {
|
|
|
1042
1079
|
}
|
|
1043
1080
|
if (app.sandBox && !module) {
|
|
1044
1081
|
globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
|
|
1045
|
-
return `;(function(
|
|
1082
|
+
return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
1046
1083
|
}
|
|
1047
1084
|
return code;
|
|
1048
1085
|
}
|
|
@@ -1180,498 +1217,199 @@ function extractHtml(app) {
|
|
|
1180
1217
|
});
|
|
1181
1218
|
}
|
|
1182
1219
|
|
|
1183
|
-
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
return boundedMap.get(value);
|
|
1187
|
-
}
|
|
1188
|
-
// bind function
|
|
1189
|
-
const boundFunction = isBoundFunction(value);
|
|
1190
|
-
boundedMap.set(value, boundFunction);
|
|
1191
|
-
return boundFunction;
|
|
1192
|
-
}
|
|
1193
|
-
const constructorMap = new WeakMap();
|
|
1194
|
-
function isConstructor(value) {
|
|
1195
|
-
if (constructorMap.has(value)) {
|
|
1196
|
-
return constructorMap.get(value);
|
|
1197
|
-
}
|
|
1198
|
-
const valueStr = value.toString();
|
|
1199
|
-
const result = (value.prototype &&
|
|
1200
|
-
value.prototype.constructor === value &&
|
|
1201
|
-
Object.getOwnPropertyNames(value.prototype).length > 1) ||
|
|
1202
|
-
/^function\s+[A-Z]/.test(valueStr) ||
|
|
1203
|
-
/^class\s+/.test(valueStr);
|
|
1204
|
-
constructorMap.set(value, result);
|
|
1205
|
-
return result;
|
|
1206
|
-
}
|
|
1207
|
-
const rawWindowMethodMap = new WeakMap();
|
|
1208
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
1209
|
-
function bindFunctionToRawWidow(rawWindow, value) {
|
|
1210
|
-
if (rawWindowMethodMap.has(value)) {
|
|
1211
|
-
return rawWindowMethodMap.get(value);
|
|
1220
|
+
class EventCenter {
|
|
1221
|
+
constructor() {
|
|
1222
|
+
this.eventList = new Map();
|
|
1212
1223
|
}
|
|
1213
|
-
|
|
1214
|
-
|
|
1215
|
-
|
|
1216
|
-
|
|
1217
|
-
|
|
1218
|
-
if (value.hasOwnProperty('prototype') && !bindRawWindowValue.hasOwnProperty('prototype')) {
|
|
1219
|
-
bindRawWindowValue.prototype = value.prototype;
|
|
1224
|
+
// whether the name is legal
|
|
1225
|
+
isLegalName(name) {
|
|
1226
|
+
if (!name) {
|
|
1227
|
+
logError('event-center: Invalid name');
|
|
1228
|
+
return false;
|
|
1220
1229
|
}
|
|
1221
|
-
|
|
1222
|
-
return bindRawWindowValue;
|
|
1223
|
-
}
|
|
1224
|
-
return value;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
// document.onclick binding list, the binding function of each application is unique
|
|
1228
|
-
const documentClickListMap = new Map();
|
|
1229
|
-
let hasRewriteDocumentOnClick = false;
|
|
1230
|
-
/**
|
|
1231
|
-
* Rewrite document.onclick and execute it only once
|
|
1232
|
-
*/
|
|
1233
|
-
function overwriteDocumentOnClick() {
|
|
1234
|
-
hasRewriteDocumentOnClick = true;
|
|
1235
|
-
if (Object.getOwnPropertyDescriptor(document, 'onclick')) {
|
|
1236
|
-
return logWarn('Cannot redefine document property onclick');
|
|
1237
|
-
}
|
|
1238
|
-
const rawOnClick = document.onclick;
|
|
1239
|
-
document.onclick = null;
|
|
1240
|
-
let hasDocumentClickInited = false;
|
|
1241
|
-
function onClickHandler(e) {
|
|
1242
|
-
documentClickListMap.forEach((f) => {
|
|
1243
|
-
isFunction(f) && f.call(document, e);
|
|
1244
|
-
});
|
|
1230
|
+
return true;
|
|
1245
1231
|
}
|
|
1246
|
-
|
|
1247
|
-
|
|
1248
|
-
|
|
1249
|
-
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
|
|
1256
|
-
documentClickListMap.set(appName, f);
|
|
1232
|
+
/**
|
|
1233
|
+
* add listener
|
|
1234
|
+
* @param name event name
|
|
1235
|
+
* @param f listener
|
|
1236
|
+
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
1237
|
+
*/
|
|
1238
|
+
on(name, f, autoTrigger = false) {
|
|
1239
|
+
if (this.isLegalName(name)) {
|
|
1240
|
+
if (!isFunction(f)) {
|
|
1241
|
+
return logError('event-center: Invalid callback function');
|
|
1257
1242
|
}
|
|
1258
|
-
|
|
1259
|
-
|
|
1243
|
+
let eventInfo = this.eventList.get(name);
|
|
1244
|
+
if (!eventInfo) {
|
|
1245
|
+
eventInfo = {
|
|
1246
|
+
data: {},
|
|
1247
|
+
callbacks: new Set(),
|
|
1248
|
+
};
|
|
1249
|
+
this.eventList.set(name, eventInfo);
|
|
1260
1250
|
}
|
|
1261
|
-
if (
|
|
1262
|
-
|
|
1263
|
-
|
|
1251
|
+
else if (autoTrigger && Object.getOwnPropertyNames(eventInfo.data).length) {
|
|
1252
|
+
// auto trigger when data not null
|
|
1253
|
+
f(eventInfo.data);
|
|
1264
1254
|
}
|
|
1255
|
+
eventInfo.callbacks.add(f);
|
|
1265
1256
|
}
|
|
1266
|
-
}
|
|
1267
|
-
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1275
|
-
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
1276
|
-
document.addEventListener = function (type, listener, options) {
|
|
1277
|
-
var _a;
|
|
1278
|
-
const appName = getCurrentAppName();
|
|
1279
|
-
/**
|
|
1280
|
-
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
1281
|
-
*/
|
|
1282
|
-
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1283
|
-
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1284
|
-
if (appListenersMap) {
|
|
1285
|
-
const appListenerList = appListenersMap.get(type);
|
|
1286
|
-
if (appListenerList) {
|
|
1287
|
-
appListenerList.add(listener);
|
|
1257
|
+
}
|
|
1258
|
+
// remove listener, but the data is not cleared
|
|
1259
|
+
off(name, f) {
|
|
1260
|
+
if (this.isLegalName(name)) {
|
|
1261
|
+
const eventInfo = this.eventList.get(name);
|
|
1262
|
+
if (eventInfo) {
|
|
1263
|
+
if (isFunction(f)) {
|
|
1264
|
+
eventInfo.callbacks.delete(f);
|
|
1288
1265
|
}
|
|
1289
1266
|
else {
|
|
1290
|
-
|
|
1267
|
+
eventInfo.callbacks.clear();
|
|
1291
1268
|
}
|
|
1292
1269
|
}
|
|
1293
|
-
else {
|
|
1294
|
-
documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
|
|
1295
|
-
}
|
|
1296
|
-
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1297
1270
|
}
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1271
|
+
}
|
|
1272
|
+
// dispatch data
|
|
1273
|
+
dispatch(name, data) {
|
|
1274
|
+
if (this.isLegalName(name)) {
|
|
1275
|
+
if (!isPlainObject(data)) {
|
|
1276
|
+
return logError('event-center: data must be object');
|
|
1277
|
+
}
|
|
1278
|
+
let eventInfo = this.eventList.get(name);
|
|
1279
|
+
if (eventInfo) {
|
|
1280
|
+
// Update when the data is not equal
|
|
1281
|
+
if (eventInfo.data !== data) {
|
|
1282
|
+
eventInfo.data = data;
|
|
1283
|
+
for (const f of eventInfo.callbacks) {
|
|
1284
|
+
f(data);
|
|
1285
|
+
}
|
|
1309
1286
|
}
|
|
1310
1287
|
}
|
|
1288
|
+
else {
|
|
1289
|
+
eventInfo = {
|
|
1290
|
+
data: data,
|
|
1291
|
+
callbacks: new Set(),
|
|
1292
|
+
};
|
|
1293
|
+
this.eventList.set(name, eventInfo);
|
|
1294
|
+
}
|
|
1311
1295
|
}
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
|
|
1296
|
+
}
|
|
1297
|
+
// get data
|
|
1298
|
+
getData(name) {
|
|
1299
|
+
var _a;
|
|
1300
|
+
const eventInfo = this.eventList.get(name);
|
|
1301
|
+
return (_a = eventInfo === null || eventInfo === void 0 ? void 0 : eventInfo.data) !== null && _a !== void 0 ? _a : null;
|
|
1302
|
+
}
|
|
1319
1303
|
}
|
|
1304
|
+
|
|
1305
|
+
const eventCenter = new EventCenter();
|
|
1320
1306
|
/**
|
|
1321
1307
|
* Format event name
|
|
1322
|
-
* @param
|
|
1323
|
-
* @param
|
|
1308
|
+
* @param appName app.name
|
|
1309
|
+
* @param fromBaseApp is from base app
|
|
1324
1310
|
*/
|
|
1325
|
-
function
|
|
1326
|
-
if (
|
|
1327
|
-
return
|
|
1328
|
-
}
|
|
1329
|
-
return type;
|
|
1311
|
+
function formatEventName(appName, fromBaseApp) {
|
|
1312
|
+
if (!isString(appName) || !appName)
|
|
1313
|
+
return '';
|
|
1314
|
+
return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`;
|
|
1330
1315
|
}
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1338
|
-
|
|
1339
|
-
|
|
1340
|
-
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
const listenerList = eventListenerMap.get(type);
|
|
1345
|
-
if (listenerList) {
|
|
1346
|
-
listenerList.add(listener);
|
|
1316
|
+
// Global data
|
|
1317
|
+
class EventCenterForGlobal {
|
|
1318
|
+
/**
|
|
1319
|
+
* add listener of global data
|
|
1320
|
+
* @param cb listener
|
|
1321
|
+
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
1322
|
+
*/
|
|
1323
|
+
addGlobalDataListener(cb, autoTrigger) {
|
|
1324
|
+
const appName = this.appName;
|
|
1325
|
+
// if appName exists, this is in sub app
|
|
1326
|
+
if (appName) {
|
|
1327
|
+
cb.__APP_NAME__ = appName;
|
|
1328
|
+
cb.__AUTO_TRIGGER__ = autoTrigger;
|
|
1347
1329
|
}
|
|
1348
|
-
|
|
1349
|
-
|
|
1330
|
+
eventCenter.on('global', cb, autoTrigger);
|
|
1331
|
+
}
|
|
1332
|
+
/**
|
|
1333
|
+
* remove listener of global data
|
|
1334
|
+
* @param cb listener
|
|
1335
|
+
*/
|
|
1336
|
+
removeGlobalDataListener(cb) {
|
|
1337
|
+
isFunction(cb) && eventCenter.off('global', cb);
|
|
1338
|
+
}
|
|
1339
|
+
/**
|
|
1340
|
+
* dispatch global data
|
|
1341
|
+
* @param data data
|
|
1342
|
+
*/
|
|
1343
|
+
setGlobalData(data) {
|
|
1344
|
+
// clear dom scope before dispatch global data, apply to micro app
|
|
1345
|
+
removeDomScope();
|
|
1346
|
+
eventCenter.dispatch('global', data);
|
|
1347
|
+
}
|
|
1348
|
+
/**
|
|
1349
|
+
* get global data
|
|
1350
|
+
*/
|
|
1351
|
+
getGlobalData() {
|
|
1352
|
+
return eventCenter.getData('global');
|
|
1353
|
+
}
|
|
1354
|
+
/**
|
|
1355
|
+
* clear all listener of global data
|
|
1356
|
+
* if appName exists, only the specified functions is cleared
|
|
1357
|
+
* if appName not exists, only clear the base app functions
|
|
1358
|
+
*/
|
|
1359
|
+
clearGlobalDataListener() {
|
|
1360
|
+
const appName = this.appName;
|
|
1361
|
+
const eventInfo = eventCenter.eventList.get('global');
|
|
1362
|
+
if (eventInfo) {
|
|
1363
|
+
for (const cb of eventInfo.callbacks) {
|
|
1364
|
+
if ((appName && appName === cb.__APP_NAME__) ||
|
|
1365
|
+
!(appName || cb.__APP_NAME__)) {
|
|
1366
|
+
eventInfo.callbacks.delete(cb);
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1350
1369
|
}
|
|
1351
|
-
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1352
|
-
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
1353
|
-
};
|
|
1354
|
-
microWindow.removeEventListener = function (type, listener, options) {
|
|
1355
|
-
type = formatEventType(type, microWindow);
|
|
1356
|
-
const listenerList = eventListenerMap.get(type);
|
|
1357
|
-
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
1358
|
-
listenerList.delete(listener);
|
|
1359
|
-
}
|
|
1360
|
-
rawWindowRemoveEventListener.call(rawWindow, type, listener, options);
|
|
1361
|
-
};
|
|
1362
|
-
microWindow.setInterval = function (handler, timeout, ...args) {
|
|
1363
|
-
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
1364
|
-
intervalIdMap.set(intervalId, { handler, timeout, args });
|
|
1365
|
-
return intervalId;
|
|
1366
|
-
};
|
|
1367
|
-
microWindow.setTimeout = function (handler, timeout, ...args) {
|
|
1368
|
-
const timeoutId = rawSetTimeout.call(rawWindow, handler, timeout, ...args);
|
|
1369
|
-
timeoutIdMap.set(timeoutId, { handler, timeout, args });
|
|
1370
|
-
return timeoutId;
|
|
1371
|
-
};
|
|
1372
|
-
microWindow.clearInterval = function (intervalId) {
|
|
1373
|
-
intervalIdMap.delete(intervalId);
|
|
1374
|
-
rawClearInterval.call(rawWindow, intervalId);
|
|
1375
|
-
};
|
|
1376
|
-
microWindow.clearTimeout = function (timeoutId) {
|
|
1377
|
-
timeoutIdMap.delete(timeoutId);
|
|
1378
|
-
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1379
|
-
};
|
|
1380
|
-
const umdWindowListenerMap = new Map();
|
|
1381
|
-
const umdDocumentListenerMap = new Map();
|
|
1382
|
-
let umdIntervalIdMap = new Map();
|
|
1383
|
-
let umdTimeoutIdMap = new Map();
|
|
1384
|
-
let umdOnClickHandler;
|
|
1385
|
-
// record event and timer before exec umdMountHook
|
|
1386
|
-
const recordUmdEffect = () => {
|
|
1387
|
-
// record window event
|
|
1388
|
-
eventListenerMap.forEach((listenerList, type) => {
|
|
1389
|
-
if (listenerList.size) {
|
|
1390
|
-
umdWindowListenerMap.set(type, new Set(listenerList));
|
|
1391
|
-
}
|
|
1392
|
-
});
|
|
1393
|
-
// record timers
|
|
1394
|
-
if (intervalIdMap.size) {
|
|
1395
|
-
umdIntervalIdMap = new Map(intervalIdMap);
|
|
1396
|
-
}
|
|
1397
|
-
if (timeoutIdMap.size) {
|
|
1398
|
-
umdTimeoutIdMap = new Map(timeoutIdMap);
|
|
1399
|
-
}
|
|
1400
|
-
// record onclick handler
|
|
1401
|
-
umdOnClickHandler = documentClickListMap.get(appName);
|
|
1402
|
-
// record document event
|
|
1403
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1404
|
-
if (documentAppListenersMap) {
|
|
1405
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1406
|
-
if (listenerList.size) {
|
|
1407
|
-
umdDocumentListenerMap.set(type, new Set(listenerList));
|
|
1408
|
-
}
|
|
1409
|
-
});
|
|
1410
|
-
}
|
|
1411
|
-
};
|
|
1412
|
-
// rebuild event and timer before remount umd app
|
|
1413
|
-
const rebuildUmdEffect = () => {
|
|
1414
|
-
// rebuild window event
|
|
1415
|
-
umdWindowListenerMap.forEach((listenerList, type) => {
|
|
1416
|
-
for (const listener of listenerList) {
|
|
1417
|
-
microWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1418
|
-
}
|
|
1419
|
-
});
|
|
1420
|
-
// rebuild timer
|
|
1421
|
-
umdIntervalIdMap.forEach((info) => {
|
|
1422
|
-
microWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
1423
|
-
});
|
|
1424
|
-
umdTimeoutIdMap.forEach((info) => {
|
|
1425
|
-
microWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
1426
|
-
});
|
|
1427
|
-
// rebuild onclick event
|
|
1428
|
-
umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
|
|
1429
|
-
// rebuild document event
|
|
1430
|
-
setCurrentAppName(appName);
|
|
1431
|
-
umdDocumentListenerMap.forEach((listenerList, type) => {
|
|
1432
|
-
for (const listener of listenerList) {
|
|
1433
|
-
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1434
|
-
}
|
|
1435
|
-
});
|
|
1436
|
-
setCurrentAppName(null);
|
|
1437
|
-
};
|
|
1438
|
-
// release all event listener & interval & timeout when unmount app
|
|
1439
|
-
const releaseEffect = () => {
|
|
1440
|
-
// Clear window binding events
|
|
1441
|
-
if (eventListenerMap.size) {
|
|
1442
|
-
eventListenerMap.forEach((listenerList, type) => {
|
|
1443
|
-
for (const listener of listenerList) {
|
|
1444
|
-
rawWindowRemoveEventListener.call(rawWindow, type, listener);
|
|
1445
|
-
}
|
|
1446
|
-
});
|
|
1447
|
-
eventListenerMap.clear();
|
|
1448
|
-
}
|
|
1449
|
-
// Clear timers
|
|
1450
|
-
if (intervalIdMap.size) {
|
|
1451
|
-
intervalIdMap.forEach((_, intervalId) => {
|
|
1452
|
-
rawClearInterval.call(rawWindow, intervalId);
|
|
1453
|
-
});
|
|
1454
|
-
intervalIdMap.clear();
|
|
1455
|
-
}
|
|
1456
|
-
if (timeoutIdMap.size) {
|
|
1457
|
-
timeoutIdMap.forEach((_, timeoutId) => {
|
|
1458
|
-
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1459
|
-
});
|
|
1460
|
-
timeoutIdMap.clear();
|
|
1461
|
-
}
|
|
1462
|
-
// Clear the function bound by micro application through document.onclick
|
|
1463
|
-
documentClickListMap.delete(appName);
|
|
1464
|
-
// Clear document binding event
|
|
1465
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1466
|
-
if (documentAppListenersMap) {
|
|
1467
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1468
|
-
for (const listener of listenerList) {
|
|
1469
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
1470
|
-
}
|
|
1471
|
-
});
|
|
1472
|
-
documentAppListenersMap.clear();
|
|
1473
|
-
}
|
|
1474
|
-
};
|
|
1475
|
-
return {
|
|
1476
|
-
recordUmdEffect,
|
|
1477
|
-
rebuildUmdEffect,
|
|
1478
|
-
releaseEffect,
|
|
1479
|
-
};
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
|
-
class EventCenter {
|
|
1483
|
-
constructor() {
|
|
1484
|
-
this.eventList = new Map();
|
|
1485
|
-
}
|
|
1486
|
-
// whether the name is legal
|
|
1487
|
-
isLegalName(name) {
|
|
1488
|
-
if (!name) {
|
|
1489
|
-
logError('event-center: Invalid name');
|
|
1490
|
-
return false;
|
|
1491
|
-
}
|
|
1492
|
-
return true;
|
|
1493
1370
|
}
|
|
1371
|
+
}
|
|
1372
|
+
// Event center for base app
|
|
1373
|
+
class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
1494
1374
|
/**
|
|
1495
1375
|
* add listener
|
|
1496
|
-
* @param
|
|
1497
|
-
* @param
|
|
1376
|
+
* @param appName app.name
|
|
1377
|
+
* @param cb listener
|
|
1498
1378
|
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
1499
1379
|
*/
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
if (!isFunction(f)) {
|
|
1503
|
-
return logError('event-center: Invalid callback function');
|
|
1504
|
-
}
|
|
1505
|
-
let eventInfo = this.eventList.get(name);
|
|
1506
|
-
if (!eventInfo) {
|
|
1507
|
-
eventInfo = {
|
|
1508
|
-
data: {},
|
|
1509
|
-
callbacks: new Set(),
|
|
1510
|
-
};
|
|
1511
|
-
this.eventList.set(name, eventInfo);
|
|
1512
|
-
}
|
|
1513
|
-
else if (autoTrigger && Object.getOwnPropertyNames(eventInfo.data).length) {
|
|
1514
|
-
// auto trigger when data not null
|
|
1515
|
-
f(eventInfo.data);
|
|
1516
|
-
}
|
|
1517
|
-
eventInfo.callbacks.add(f);
|
|
1518
|
-
}
|
|
1519
|
-
}
|
|
1520
|
-
// remove listener, but the data is not cleared
|
|
1521
|
-
off(name, f) {
|
|
1522
|
-
if (this.isLegalName(name)) {
|
|
1523
|
-
const eventInfo = this.eventList.get(name);
|
|
1524
|
-
if (eventInfo) {
|
|
1525
|
-
if (isFunction(f)) {
|
|
1526
|
-
eventInfo.callbacks.delete(f);
|
|
1527
|
-
}
|
|
1528
|
-
else {
|
|
1529
|
-
eventInfo.callbacks.clear();
|
|
1530
|
-
}
|
|
1531
|
-
}
|
|
1532
|
-
}
|
|
1533
|
-
}
|
|
1534
|
-
// dispatch data
|
|
1535
|
-
dispatch(name, data) {
|
|
1536
|
-
if (this.isLegalName(name)) {
|
|
1537
|
-
if (!isPlainObject(data)) {
|
|
1538
|
-
return logError('event-center: data must be object');
|
|
1539
|
-
}
|
|
1540
|
-
let eventInfo = this.eventList.get(name);
|
|
1541
|
-
if (eventInfo) {
|
|
1542
|
-
// Update when the data is not equal
|
|
1543
|
-
if (eventInfo.data !== data) {
|
|
1544
|
-
eventInfo.data = data;
|
|
1545
|
-
for (const f of eventInfo.callbacks) {
|
|
1546
|
-
f(data);
|
|
1547
|
-
}
|
|
1548
|
-
}
|
|
1549
|
-
}
|
|
1550
|
-
else {
|
|
1551
|
-
eventInfo = {
|
|
1552
|
-
data: data,
|
|
1553
|
-
callbacks: new Set(),
|
|
1554
|
-
};
|
|
1555
|
-
this.eventList.set(name, eventInfo);
|
|
1556
|
-
}
|
|
1557
|
-
}
|
|
1558
|
-
}
|
|
1559
|
-
// get data
|
|
1560
|
-
getData(name) {
|
|
1561
|
-
var _a;
|
|
1562
|
-
const eventInfo = this.eventList.get(name);
|
|
1563
|
-
return (_a = eventInfo === null || eventInfo === void 0 ? void 0 : eventInfo.data) !== null && _a !== void 0 ? _a : null;
|
|
1380
|
+
addDataListener(appName, cb, autoTrigger) {
|
|
1381
|
+
eventCenter.on(formatEventName(formatAppName(appName), false), cb, autoTrigger);
|
|
1564
1382
|
}
|
|
1565
|
-
}
|
|
1566
|
-
|
|
1567
|
-
const eventCenter = new EventCenter();
|
|
1568
|
-
/**
|
|
1569
|
-
* Format event name
|
|
1570
|
-
* @param appName app.name
|
|
1571
|
-
* @param fromBaseApp is from base app
|
|
1572
|
-
*/
|
|
1573
|
-
function formatEventName(appName, fromBaseApp) {
|
|
1574
|
-
if (!isString(appName) || !appName)
|
|
1575
|
-
return '';
|
|
1576
|
-
return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`;
|
|
1577
|
-
}
|
|
1578
|
-
// Global data
|
|
1579
|
-
class EventCenterForGlobal {
|
|
1580
1383
|
/**
|
|
1581
|
-
*
|
|
1384
|
+
* remove listener
|
|
1385
|
+
* @param appName app.name
|
|
1582
1386
|
* @param cb listener
|
|
1583
|
-
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
1584
1387
|
*/
|
|
1585
|
-
|
|
1586
|
-
|
|
1587
|
-
// if appName exists, this is in sub app
|
|
1588
|
-
if (appName) {
|
|
1589
|
-
cb.__APP_NAME__ = appName;
|
|
1590
|
-
cb.__AUTO_TRIGGER__ = autoTrigger;
|
|
1591
|
-
}
|
|
1592
|
-
eventCenter.on('global', cb, autoTrigger);
|
|
1388
|
+
removeDataListener(appName, cb) {
|
|
1389
|
+
isFunction(cb) && eventCenter.off(formatEventName(formatAppName(appName), false), cb);
|
|
1593
1390
|
}
|
|
1594
1391
|
/**
|
|
1595
|
-
*
|
|
1596
|
-
* @param
|
|
1392
|
+
* get data from micro app or base app
|
|
1393
|
+
* @param appName app.name
|
|
1394
|
+
* @param fromBaseApp whether get data from base app, default is false
|
|
1597
1395
|
*/
|
|
1598
|
-
|
|
1599
|
-
|
|
1396
|
+
getData(appName, fromBaseApp = false) {
|
|
1397
|
+
return eventCenter.getData(formatEventName(formatAppName(appName), fromBaseApp));
|
|
1600
1398
|
}
|
|
1601
1399
|
/**
|
|
1602
|
-
*
|
|
1400
|
+
* Dispatch data to the specified micro app
|
|
1401
|
+
* @param appName app.name
|
|
1603
1402
|
* @param data data
|
|
1604
1403
|
*/
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
removeDomScope();
|
|
1608
|
-
eventCenter.dispatch('global', data);
|
|
1404
|
+
setData(appName, data) {
|
|
1405
|
+
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data);
|
|
1609
1406
|
}
|
|
1610
1407
|
/**
|
|
1611
|
-
*
|
|
1408
|
+
* clear all listener for specified micro app
|
|
1409
|
+
* @param appName app.name
|
|
1612
1410
|
*/
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
}
|
|
1616
|
-
/**
|
|
1617
|
-
* clear all listener of global data
|
|
1618
|
-
* if appName exists, only the specified functions is cleared
|
|
1619
|
-
* if appName not exists, only clear the base app functions
|
|
1620
|
-
*/
|
|
1621
|
-
clearGlobalDataListener() {
|
|
1622
|
-
const appName = this.appName;
|
|
1623
|
-
const eventInfo = eventCenter.eventList.get('global');
|
|
1624
|
-
if (eventInfo) {
|
|
1625
|
-
for (const cb of eventInfo.callbacks) {
|
|
1626
|
-
if ((appName && appName === cb.__APP_NAME__) ||
|
|
1627
|
-
!(appName || cb.__APP_NAME__)) {
|
|
1628
|
-
eventInfo.callbacks.delete(cb);
|
|
1629
|
-
}
|
|
1630
|
-
}
|
|
1631
|
-
}
|
|
1632
|
-
}
|
|
1633
|
-
}
|
|
1634
|
-
// Event center for base app
|
|
1635
|
-
class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
1636
|
-
/**
|
|
1637
|
-
* add listener
|
|
1638
|
-
* @param appName app.name
|
|
1639
|
-
* @param cb listener
|
|
1640
|
-
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
1641
|
-
*/
|
|
1642
|
-
addDataListener(appName, cb, autoTrigger) {
|
|
1643
|
-
eventCenter.on(formatEventName(formatAppName(appName), false), cb, autoTrigger);
|
|
1644
|
-
}
|
|
1645
|
-
/**
|
|
1646
|
-
* remove listener
|
|
1647
|
-
* @param appName app.name
|
|
1648
|
-
* @param cb listener
|
|
1649
|
-
*/
|
|
1650
|
-
removeDataListener(appName, cb) {
|
|
1651
|
-
isFunction(cb) && eventCenter.off(formatEventName(formatAppName(appName), false), cb);
|
|
1652
|
-
}
|
|
1653
|
-
/**
|
|
1654
|
-
* get data from micro app or base app
|
|
1655
|
-
* @param appName app.name
|
|
1656
|
-
* @param fromBaseApp whether get data from base app, default is false
|
|
1657
|
-
*/
|
|
1658
|
-
getData(appName, fromBaseApp = false) {
|
|
1659
|
-
return eventCenter.getData(formatEventName(formatAppName(appName), fromBaseApp));
|
|
1660
|
-
}
|
|
1661
|
-
/**
|
|
1662
|
-
* Dispatch data to the specified micro app
|
|
1663
|
-
* @param appName app.name
|
|
1664
|
-
* @param data data
|
|
1665
|
-
*/
|
|
1666
|
-
setData(appName, data) {
|
|
1667
|
-
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data);
|
|
1668
|
-
}
|
|
1669
|
-
/**
|
|
1670
|
-
* clear all listener for specified micro app
|
|
1671
|
-
* @param appName app.name
|
|
1672
|
-
*/
|
|
1673
|
-
clearDataListener(appName) {
|
|
1674
|
-
eventCenter.off(formatEventName(formatAppName(appName), false));
|
|
1411
|
+
clearDataListener(appName) {
|
|
1412
|
+
eventCenter.off(formatEventName(formatAppName(appName), false));
|
|
1675
1413
|
}
|
|
1676
1414
|
}
|
|
1677
1415
|
// Event center for sub app
|
|
@@ -1760,178 +1498,365 @@ function rebuildDataCenterSnapshot(microAppEventCneter) {
|
|
|
1760
1498
|
}
|
|
1761
1499
|
}
|
|
1762
1500
|
|
|
1763
|
-
|
|
1764
|
-
|
|
1765
|
-
|
|
1766
|
-
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
1770
|
-
|
|
1771
|
-
|
|
1772
|
-
|
|
1773
|
-
const
|
|
1774
|
-
|
|
1775
|
-
|
|
1776
|
-
|
|
1777
|
-
|
|
1778
|
-
|
|
1779
|
-
|
|
1780
|
-
|
|
1781
|
-
|
|
1782
|
-
|
|
1783
|
-
|
|
1784
|
-
|
|
1501
|
+
/* eslint-disable no-return-assign */
|
|
1502
|
+
function isBoundedFunction(value) {
|
|
1503
|
+
if (isBoolean(value.__MICRO_APP_ISBOUND_FUNCTION))
|
|
1504
|
+
return value.__MICRO_APP_ISBOUND_FUNCTION;
|
|
1505
|
+
return value.__MICRO_APP_ISBOUND_FUNCTION = isBoundFunction(value);
|
|
1506
|
+
}
|
|
1507
|
+
function isConstructor(value) {
|
|
1508
|
+
var _a;
|
|
1509
|
+
if (isBoolean(value.__MICRO_APP_ISCONSTRUCTOR))
|
|
1510
|
+
return value.__MICRO_APP_ISCONSTRUCTOR;
|
|
1511
|
+
const valueStr = value.toString();
|
|
1512
|
+
const result = (((_a = value.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === value &&
|
|
1513
|
+
Object.getOwnPropertyNames(value.prototype).length > 1) ||
|
|
1514
|
+
/^function\s+[A-Z]/.test(valueStr) ||
|
|
1515
|
+
/^class\s+/.test(valueStr);
|
|
1516
|
+
return value.__MICRO_APP_ISCONSTRUCTOR = result;
|
|
1517
|
+
}
|
|
1518
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
1519
|
+
function bindFunctionToRawWindow(rawWindow, value) {
|
|
1520
|
+
if (value.__MICRO_APP_BOUND_WINDOW_FUNCTION)
|
|
1521
|
+
return value.__MICRO_APP_BOUND_WINDOW_FUNCTION;
|
|
1522
|
+
if (!isConstructor(value) && !isBoundedFunction(value)) {
|
|
1523
|
+
const bindRawWindowValue = value.bind(rawWindow);
|
|
1524
|
+
for (const key in value) {
|
|
1525
|
+
bindRawWindowValue[key] = value[key];
|
|
1526
|
+
}
|
|
1527
|
+
if (value.hasOwnProperty('prototype')) {
|
|
1528
|
+
rawDefineProperty(bindRawWindowValue, 'prototype', {
|
|
1529
|
+
value: value.prototype,
|
|
1530
|
+
configurable: true,
|
|
1531
|
+
enumerable: false,
|
|
1532
|
+
writable: true,
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
return value.__MICRO_APP_BOUND_WINDOW_FUNCTION = bindRawWindowValue;
|
|
1536
|
+
}
|
|
1537
|
+
return value;
|
|
1538
|
+
}
|
|
1539
|
+
|
|
1540
|
+
// document.onclick binding list, the binding function of each application is unique
|
|
1541
|
+
const documentClickListMap = new Map();
|
|
1542
|
+
let hasRewriteDocumentOnClick = false;
|
|
1785
1543
|
/**
|
|
1786
|
-
*
|
|
1544
|
+
* Rewrite document.onclick and execute it only once
|
|
1787
1545
|
*/
|
|
1788
|
-
|
|
1789
|
-
|
|
1790
|
-
|
|
1791
|
-
|
|
1546
|
+
function overwriteDocumentOnClick() {
|
|
1547
|
+
hasRewriteDocumentOnClick = true;
|
|
1548
|
+
if (Object.getOwnPropertyDescriptor(document, 'onclick')) {
|
|
1549
|
+
return logWarn('Cannot redefine document property onclick');
|
|
1550
|
+
}
|
|
1551
|
+
const rawOnClick = document.onclick;
|
|
1552
|
+
document.onclick = null;
|
|
1553
|
+
let hasDocumentClickInited = false;
|
|
1554
|
+
function onClickHandler(e) {
|
|
1555
|
+
documentClickListMap.forEach((f) => {
|
|
1556
|
+
isFunction(f) && f.call(document, e);
|
|
1557
|
+
});
|
|
1558
|
+
}
|
|
1559
|
+
rawDefineProperty(document, 'onclick', {
|
|
1560
|
+
configurable: true,
|
|
1561
|
+
enumerable: true,
|
|
1562
|
+
get() {
|
|
1563
|
+
const appName = getCurrentAppName();
|
|
1564
|
+
return appName ? documentClickListMap.get(appName) : documentClickListMap.get('base');
|
|
1565
|
+
},
|
|
1566
|
+
set(f) {
|
|
1567
|
+
const appName = getCurrentAppName();
|
|
1568
|
+
if (appName) {
|
|
1569
|
+
documentClickListMap.set(appName, f);
|
|
1570
|
+
}
|
|
1571
|
+
else {
|
|
1572
|
+
documentClickListMap.set('base', f);
|
|
1573
|
+
}
|
|
1574
|
+
if (!hasDocumentClickInited && isFunction(f)) {
|
|
1575
|
+
hasDocumentClickInited = true;
|
|
1576
|
+
globalEnv.rawDocumentAddEventListener.call(globalEnv.rawDocument, 'click', onClickHandler, false);
|
|
1577
|
+
}
|
|
1578
|
+
}
|
|
1579
|
+
});
|
|
1580
|
+
rawOnClick && (document.onclick = rawOnClick);
|
|
1792
1581
|
}
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
1796
|
-
|
|
1797
|
-
|
|
1798
|
-
|
|
1799
|
-
|
|
1800
|
-
|
|
1801
|
-
|
|
1802
|
-
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1808
|
-
|
|
1809
|
-
|
|
1810
|
-
|
|
1811
|
-
|
|
1812
|
-
// inject global properties
|
|
1813
|
-
this.inject(this.microWindow, appName, url);
|
|
1814
|
-
// Rewrite global event listener & timeout
|
|
1815
|
-
Object.assign(this, effect(this.microWindow));
|
|
1816
|
-
this.proxyWindow = new Proxy(this.microWindow, {
|
|
1817
|
-
get: (target, key) => {
|
|
1818
|
-
if (key === Symbol.unscopables)
|
|
1819
|
-
return unscopables;
|
|
1820
|
-
if (['window', 'self', 'globalThis'].includes(key)) {
|
|
1821
|
-
return this.proxyWindow;
|
|
1822
|
-
}
|
|
1823
|
-
if (key === 'top' || key === 'parent') {
|
|
1824
|
-
if (rawWindow === rawWindow.parent) { // not in iframe
|
|
1825
|
-
return this.proxyWindow;
|
|
1826
|
-
}
|
|
1827
|
-
return Reflect.get(rawWindow, key); // iframe
|
|
1828
|
-
}
|
|
1829
|
-
if (key === 'hasOwnProperty')
|
|
1830
|
-
return hasOwnProperty;
|
|
1831
|
-
if (key === 'document' || key === 'eval') {
|
|
1832
|
-
if (this.active) {
|
|
1833
|
-
setCurrentAppName(appName);
|
|
1834
|
-
(macro ? macroTask : defer)(() => setCurrentAppName(null));
|
|
1835
|
-
}
|
|
1836
|
-
switch (key) {
|
|
1837
|
-
case 'document':
|
|
1838
|
-
return rawDocument;
|
|
1839
|
-
case 'eval':
|
|
1840
|
-
return eval;
|
|
1841
|
-
}
|
|
1842
|
-
}
|
|
1843
|
-
if (Reflect.has(target, key)) {
|
|
1844
|
-
return Reflect.get(target, key);
|
|
1845
|
-
}
|
|
1846
|
-
if (this.scopeProperties.includes(key) ||
|
|
1847
|
-
(isString(key) && /^__MICRO_APP_/.test(key))) {
|
|
1848
|
-
return Reflect.get(target, key);
|
|
1582
|
+
/**
|
|
1583
|
+
* The document event is globally, we need to clear these event bindings when micro application unmounted
|
|
1584
|
+
*/
|
|
1585
|
+
const documentEventListenerMap = new Map();
|
|
1586
|
+
function effectDocumentEvent() {
|
|
1587
|
+
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1588
|
+
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
1589
|
+
document.addEventListener = function (type, listener, options) {
|
|
1590
|
+
var _a;
|
|
1591
|
+
const appName = getCurrentAppName();
|
|
1592
|
+
/**
|
|
1593
|
+
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
1594
|
+
*/
|
|
1595
|
+
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1596
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1597
|
+
if (appListenersMap) {
|
|
1598
|
+
const appListenerList = appListenersMap.get(type);
|
|
1599
|
+
if (appListenerList) {
|
|
1600
|
+
appListenerList.add(listener);
|
|
1849
1601
|
}
|
|
1850
|
-
|
|
1851
|
-
|
|
1852
|
-
},
|
|
1853
|
-
set: (target, key, value) => {
|
|
1854
|
-
if (this.active) {
|
|
1855
|
-
if (escapeSetterKeyList.includes(key)) {
|
|
1856
|
-
Reflect.set(rawWindow, key, value);
|
|
1857
|
-
}
|
|
1858
|
-
else if (!target.hasOwnProperty(key) &&
|
|
1859
|
-
rawWindow.hasOwnProperty(key) &&
|
|
1860
|
-
!this.scopeProperties.includes(key)) {
|
|
1861
|
-
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1862
|
-
const { writable, configurable, enumerable } = descriptor;
|
|
1863
|
-
if (writable) {
|
|
1864
|
-
Object.defineProperty(target, key, {
|
|
1865
|
-
configurable,
|
|
1866
|
-
enumerable,
|
|
1867
|
-
writable,
|
|
1868
|
-
value,
|
|
1869
|
-
});
|
|
1870
|
-
this.injectedKeys.add(key);
|
|
1871
|
-
}
|
|
1872
|
-
}
|
|
1873
|
-
else {
|
|
1874
|
-
Reflect.set(target, key, value);
|
|
1875
|
-
this.injectedKeys.add(key);
|
|
1876
|
-
}
|
|
1877
|
-
if ((this.escapeProperties.includes(key) ||
|
|
1878
|
-
(staticEscapeProperties.includes(key) && !Reflect.has(rawWindow, key))) &&
|
|
1879
|
-
!this.scopeProperties.includes(key)) {
|
|
1880
|
-
Reflect.set(rawWindow, key, value);
|
|
1881
|
-
this.escapeKeys.add(key);
|
|
1882
|
-
}
|
|
1602
|
+
else {
|
|
1603
|
+
appListenersMap.set(type, new Set([listener]));
|
|
1883
1604
|
}
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
|
|
1888
|
-
|
|
1889
|
-
|
|
1890
|
-
|
|
1891
|
-
|
|
1892
|
-
|
|
1893
|
-
|
|
1894
|
-
|
|
1895
|
-
|
|
1896
|
-
|
|
1605
|
+
}
|
|
1606
|
+
else {
|
|
1607
|
+
documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
|
|
1608
|
+
}
|
|
1609
|
+
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
1610
|
+
}
|
|
1611
|
+
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
1612
|
+
};
|
|
1613
|
+
document.removeEventListener = function (type, listener, options) {
|
|
1614
|
+
var _a;
|
|
1615
|
+
const appName = getCurrentAppName();
|
|
1616
|
+
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1617
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1618
|
+
if (appListenersMap) {
|
|
1619
|
+
const appListenerList = appListenersMap.get(type);
|
|
1620
|
+
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
1621
|
+
appListenerList.delete(listener);
|
|
1897
1622
|
}
|
|
1898
|
-
|
|
1899
|
-
|
|
1900
|
-
|
|
1901
|
-
|
|
1902
|
-
|
|
1903
|
-
|
|
1904
|
-
|
|
1905
|
-
|
|
1623
|
+
}
|
|
1624
|
+
}
|
|
1625
|
+
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
1626
|
+
};
|
|
1627
|
+
}
|
|
1628
|
+
// Clear the document event agent
|
|
1629
|
+
function releaseEffectDocumentEvent() {
|
|
1630
|
+
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
1631
|
+
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
1632
|
+
}
|
|
1633
|
+
// this events should be sent to the specified app
|
|
1634
|
+
const formatEventList = ['unmount', 'appstate-change'];
|
|
1635
|
+
/**
|
|
1636
|
+
* Format event name
|
|
1637
|
+
* @param type event name
|
|
1638
|
+
* @param microAppWindow micro window
|
|
1639
|
+
*/
|
|
1640
|
+
function formatEventType(type, microAppWindow) {
|
|
1641
|
+
if (formatEventList.includes(type)) {
|
|
1642
|
+
return `${type}-${microAppWindow.__MICRO_APP_NAME__}`;
|
|
1643
|
+
}
|
|
1644
|
+
return type;
|
|
1645
|
+
}
|
|
1646
|
+
/**
|
|
1647
|
+
* Rewrite side-effect events
|
|
1648
|
+
* @param microAppWindow micro window
|
|
1649
|
+
*/
|
|
1650
|
+
function effect(microAppWindow) {
|
|
1651
|
+
const appName = microAppWindow.__MICRO_APP_NAME__;
|
|
1652
|
+
const eventListenerMap = new Map();
|
|
1653
|
+
const intervalIdMap = new Map();
|
|
1654
|
+
const timeoutIdMap = new Map();
|
|
1655
|
+
const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1656
|
+
// listener may be null, e.g test-passive
|
|
1657
|
+
microAppWindow.addEventListener = function (type, listener, options) {
|
|
1658
|
+
type = formatEventType(type, microAppWindow);
|
|
1659
|
+
const listenerList = eventListenerMap.get(type);
|
|
1660
|
+
if (listenerList) {
|
|
1661
|
+
listenerList.add(listener);
|
|
1662
|
+
}
|
|
1663
|
+
else {
|
|
1664
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
1665
|
+
}
|
|
1666
|
+
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
1667
|
+
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
1668
|
+
};
|
|
1669
|
+
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
1670
|
+
type = formatEventType(type, microAppWindow);
|
|
1671
|
+
const listenerList = eventListenerMap.get(type);
|
|
1672
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
1673
|
+
listenerList.delete(listener);
|
|
1674
|
+
}
|
|
1675
|
+
rawWindowRemoveEventListener.call(rawWindow, type, listener, options);
|
|
1676
|
+
};
|
|
1677
|
+
microAppWindow.setInterval = function (handler, timeout, ...args) {
|
|
1678
|
+
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
1679
|
+
intervalIdMap.set(intervalId, { handler, timeout, args });
|
|
1680
|
+
return intervalId;
|
|
1681
|
+
};
|
|
1682
|
+
microAppWindow.setTimeout = function (handler, timeout, ...args) {
|
|
1683
|
+
const timeoutId = rawSetTimeout.call(rawWindow, handler, timeout, ...args);
|
|
1684
|
+
timeoutIdMap.set(timeoutId, { handler, timeout, args });
|
|
1685
|
+
return timeoutId;
|
|
1686
|
+
};
|
|
1687
|
+
microAppWindow.clearInterval = function (intervalId) {
|
|
1688
|
+
intervalIdMap.delete(intervalId);
|
|
1689
|
+
rawClearInterval.call(rawWindow, intervalId);
|
|
1690
|
+
};
|
|
1691
|
+
microAppWindow.clearTimeout = function (timeoutId) {
|
|
1692
|
+
timeoutIdMap.delete(timeoutId);
|
|
1693
|
+
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1694
|
+
};
|
|
1695
|
+
const umdWindowListenerMap = new Map();
|
|
1696
|
+
const umdDocumentListenerMap = new Map();
|
|
1697
|
+
let umdIntervalIdMap = new Map();
|
|
1698
|
+
let umdTimeoutIdMap = new Map();
|
|
1699
|
+
let umdOnClickHandler;
|
|
1700
|
+
// record event and timer before exec umdMountHook
|
|
1701
|
+
const recordUmdEffect = () => {
|
|
1702
|
+
// record window event
|
|
1703
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
1704
|
+
if (listenerList.size) {
|
|
1705
|
+
umdWindowListenerMap.set(type, new Set(listenerList));
|
|
1706
|
+
}
|
|
1707
|
+
});
|
|
1708
|
+
// record timers
|
|
1709
|
+
if (intervalIdMap.size) {
|
|
1710
|
+
umdIntervalIdMap = new Map(intervalIdMap);
|
|
1711
|
+
}
|
|
1712
|
+
if (timeoutIdMap.size) {
|
|
1713
|
+
umdTimeoutIdMap = new Map(timeoutIdMap);
|
|
1714
|
+
}
|
|
1715
|
+
// record onclick handler
|
|
1716
|
+
umdOnClickHandler = documentClickListMap.get(appName);
|
|
1717
|
+
// record document event
|
|
1718
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1719
|
+
if (documentAppListenersMap) {
|
|
1720
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1721
|
+
if (listenerList.size) {
|
|
1722
|
+
umdDocumentListenerMap.set(type, new Set(listenerList));
|
|
1906
1723
|
}
|
|
1907
|
-
|
|
1908
|
-
|
|
1909
|
-
|
|
1910
|
-
|
|
1911
|
-
|
|
1912
|
-
|
|
1913
|
-
|
|
1724
|
+
});
|
|
1725
|
+
}
|
|
1726
|
+
};
|
|
1727
|
+
// rebuild event and timer before remount umd app
|
|
1728
|
+
const rebuildUmdEffect = () => {
|
|
1729
|
+
// rebuild window event
|
|
1730
|
+
umdWindowListenerMap.forEach((listenerList, type) => {
|
|
1731
|
+
for (const listener of listenerList) {
|
|
1732
|
+
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
1733
|
+
}
|
|
1734
|
+
});
|
|
1735
|
+
// rebuild timer
|
|
1736
|
+
umdIntervalIdMap.forEach((info) => {
|
|
1737
|
+
microAppWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
1738
|
+
});
|
|
1739
|
+
umdTimeoutIdMap.forEach((info) => {
|
|
1740
|
+
microAppWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
1741
|
+
});
|
|
1742
|
+
// rebuild onclick event
|
|
1743
|
+
umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
|
|
1744
|
+
// rebuild document event
|
|
1745
|
+
setCurrentAppName(appName);
|
|
1746
|
+
umdDocumentListenerMap.forEach((listenerList, type) => {
|
|
1747
|
+
for (const listener of listenerList) {
|
|
1748
|
+
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
1749
|
+
}
|
|
1750
|
+
});
|
|
1751
|
+
setCurrentAppName(null);
|
|
1752
|
+
};
|
|
1753
|
+
// release all event listener & interval & timeout when unmount app
|
|
1754
|
+
const releaseEffect = () => {
|
|
1755
|
+
// Clear window binding events
|
|
1756
|
+
if (eventListenerMap.size) {
|
|
1757
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
1758
|
+
for (const listener of listenerList) {
|
|
1759
|
+
rawWindowRemoveEventListener.call(rawWindow, type, listener);
|
|
1914
1760
|
}
|
|
1915
|
-
|
|
1916
|
-
|
|
1917
|
-
|
|
1918
|
-
|
|
1919
|
-
|
|
1920
|
-
|
|
1921
|
-
|
|
1922
|
-
|
|
1923
|
-
|
|
1924
|
-
|
|
1925
|
-
|
|
1761
|
+
});
|
|
1762
|
+
eventListenerMap.clear();
|
|
1763
|
+
}
|
|
1764
|
+
// Clear timers
|
|
1765
|
+
if (intervalIdMap.size) {
|
|
1766
|
+
intervalIdMap.forEach((_, intervalId) => {
|
|
1767
|
+
rawClearInterval.call(rawWindow, intervalId);
|
|
1768
|
+
});
|
|
1769
|
+
intervalIdMap.clear();
|
|
1770
|
+
}
|
|
1771
|
+
if (timeoutIdMap.size) {
|
|
1772
|
+
timeoutIdMap.forEach((_, timeoutId) => {
|
|
1773
|
+
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1774
|
+
});
|
|
1775
|
+
timeoutIdMap.clear();
|
|
1776
|
+
}
|
|
1777
|
+
// Clear the function bound by micro application through document.onclick
|
|
1778
|
+
documentClickListMap.delete(appName);
|
|
1779
|
+
// Clear document binding event
|
|
1780
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1781
|
+
if (documentAppListenersMap) {
|
|
1782
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1783
|
+
for (const listener of listenerList) {
|
|
1784
|
+
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
1926
1785
|
}
|
|
1927
|
-
|
|
1928
|
-
|
|
1929
|
-
}
|
|
1786
|
+
});
|
|
1787
|
+
documentAppListenersMap.clear();
|
|
1788
|
+
}
|
|
1789
|
+
};
|
|
1790
|
+
return {
|
|
1791
|
+
recordUmdEffect,
|
|
1792
|
+
rebuildUmdEffect,
|
|
1793
|
+
releaseEffect,
|
|
1794
|
+
};
|
|
1795
|
+
}
|
|
1796
|
+
// window.addEventListener('mousedown', (e: Event) => {
|
|
1797
|
+
// const targetNode = e.target
|
|
1798
|
+
// const activeApps = getActiveApps(true)
|
|
1799
|
+
// let isScopeOfMicroApp = false
|
|
1800
|
+
// for (const appName of activeApps) {
|
|
1801
|
+
// const app = appInstanceMap.get(appName)!
|
|
1802
|
+
// if (targetNode instanceof Node && app.container!.contains(targetNode)) {
|
|
1803
|
+
// isScopeOfMicroApp = true
|
|
1804
|
+
// // console.log(111111, appName)
|
|
1805
|
+
// setCurrentAppName(appName)
|
|
1806
|
+
// break
|
|
1807
|
+
// }
|
|
1808
|
+
// }
|
|
1809
|
+
// if (!isScopeOfMicroApp) {
|
|
1810
|
+
// setCurrentAppName(null)
|
|
1811
|
+
// }
|
|
1812
|
+
// }, false)
|
|
1813
|
+
// let isWaitingForMacroReset = false
|
|
1814
|
+
// window.addEventListener('mouseup', () => {
|
|
1815
|
+
// if (!isWaitingForMacroReset && getCurrentAppName()) {
|
|
1816
|
+
// isWaitingForMacroReset = true
|
|
1817
|
+
// setTimeout(() => {
|
|
1818
|
+
// setCurrentAppName(null)
|
|
1819
|
+
// isWaitingForMacroReset = false
|
|
1820
|
+
// })
|
|
1821
|
+
// }
|
|
1822
|
+
// }, false)
|
|
1823
|
+
|
|
1824
|
+
// Variables that can escape to rawWindow
|
|
1825
|
+
const staticEscapeProperties = [
|
|
1826
|
+
'System',
|
|
1827
|
+
'__cjsWrapper',
|
|
1828
|
+
];
|
|
1829
|
+
// Variables that can only assigned to rawWindow
|
|
1830
|
+
const escapeSetterKeyList = [
|
|
1831
|
+
'location',
|
|
1832
|
+
];
|
|
1833
|
+
const globalPropertyList = ['window', 'self', 'globalThis'];
|
|
1834
|
+
class SandBox {
|
|
1835
|
+
constructor(appName, url) {
|
|
1836
|
+
// Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
1837
|
+
this.scopeProperties = ['webpackJsonp'];
|
|
1838
|
+
// Properties that can be escape to rawWindow
|
|
1839
|
+
this.escapeProperties = [];
|
|
1840
|
+
// Properties newly added to microAppWindow
|
|
1841
|
+
this.injectedKeys = new Set();
|
|
1842
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
1843
|
+
this.escapeKeys = new Set();
|
|
1844
|
+
// sandbox state
|
|
1845
|
+
this.active = false;
|
|
1846
|
+
this.microAppWindow = {}; // Proxy target
|
|
1847
|
+
// get scopeProperties and escapeProperties from plugins
|
|
1848
|
+
this.getScopeProperties(appName);
|
|
1849
|
+
// create proxyWindow with Proxy(microAppWindow)
|
|
1850
|
+
this.proxyWindow = this.createProxyWindow();
|
|
1851
|
+
// inject global properties
|
|
1852
|
+
this.initMicroAppWindow(this.microAppWindow, appName, url);
|
|
1853
|
+
// Rewrite global event listener & timeout
|
|
1854
|
+
Object.assign(this, effect(this.microAppWindow));
|
|
1930
1855
|
}
|
|
1931
1856
|
start(baseroute) {
|
|
1932
1857
|
if (!this.active) {
|
|
1933
1858
|
this.active = true;
|
|
1934
|
-
this.
|
|
1859
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
1935
1860
|
// BUG FIX: bable-polyfill@6.x
|
|
1936
1861
|
globalEnv.rawWindow._babelPolyfill && (globalEnv.rawWindow._babelPolyfill = false);
|
|
1937
1862
|
if (++SandBox.activeCount === 1) {
|
|
@@ -1943,10 +1868,10 @@ class SandBox {
|
|
|
1943
1868
|
if (this.active) {
|
|
1944
1869
|
this.active = false;
|
|
1945
1870
|
this.releaseEffect();
|
|
1946
|
-
this.
|
|
1947
|
-
this.
|
|
1871
|
+
this.microAppWindow.microApp.clearDataListener();
|
|
1872
|
+
this.microAppWindow.microApp.clearGlobalDataListener();
|
|
1948
1873
|
this.injectedKeys.forEach((key) => {
|
|
1949
|
-
Reflect.deleteProperty(this.
|
|
1874
|
+
Reflect.deleteProperty(this.microAppWindow, key);
|
|
1950
1875
|
});
|
|
1951
1876
|
this.injectedKeys.clear();
|
|
1952
1877
|
this.escapeKeys.forEach((key) => {
|
|
@@ -1960,12 +1885,12 @@ class SandBox {
|
|
|
1960
1885
|
}
|
|
1961
1886
|
// record umd snapshot before the first execution of umdHookMount
|
|
1962
1887
|
recordUmdSnapshot() {
|
|
1963
|
-
this.
|
|
1888
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = true;
|
|
1964
1889
|
this.recordUmdEffect();
|
|
1965
|
-
recordDataCenterSnapshot(this.
|
|
1890
|
+
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
1966
1891
|
this.recordUmdinjectedValues = new Map();
|
|
1967
1892
|
this.injectedKeys.forEach((key) => {
|
|
1968
|
-
this.recordUmdinjectedValues.set(key, Reflect.get(this.
|
|
1893
|
+
this.recordUmdinjectedValues.set(key, Reflect.get(this.microAppWindow, key));
|
|
1969
1894
|
});
|
|
1970
1895
|
}
|
|
1971
1896
|
// rebuild umd snapshot before remount umd app
|
|
@@ -1974,7 +1899,7 @@ class SandBox {
|
|
|
1974
1899
|
Reflect.set(this.proxyWindow, key, value);
|
|
1975
1900
|
});
|
|
1976
1901
|
this.rebuildUmdEffect();
|
|
1977
|
-
rebuildDataCenterSnapshot(this.
|
|
1902
|
+
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
1978
1903
|
}
|
|
1979
1904
|
/**
|
|
1980
1905
|
* get scopeProperties and escapeProperties from plugins
|
|
@@ -2009,25 +1934,183 @@ class SandBox {
|
|
|
2009
1934
|
}
|
|
2010
1935
|
}
|
|
2011
1936
|
}
|
|
1937
|
+
// create proxyWindow with Proxy(microAppWindow)
|
|
1938
|
+
createProxyWindow() {
|
|
1939
|
+
const rawWindow = globalEnv.rawWindow;
|
|
1940
|
+
const descriptorTargetMap = new Map();
|
|
1941
|
+
// window.xxx will trigger proxy
|
|
1942
|
+
return new Proxy(this.microAppWindow, {
|
|
1943
|
+
get: (target, key) => {
|
|
1944
|
+
if (Reflect.has(target, key) ||
|
|
1945
|
+
(isString(key) && /^__MICRO_APP_/.test(key)) ||
|
|
1946
|
+
this.scopeProperties.includes(key))
|
|
1947
|
+
return Reflect.get(target, key);
|
|
1948
|
+
const rawValue = Reflect.get(rawWindow, key);
|
|
1949
|
+
return isFunction(rawValue) ? bindFunctionToRawWindow(rawWindow, rawValue) : rawValue;
|
|
1950
|
+
},
|
|
1951
|
+
set: (target, key, value) => {
|
|
1952
|
+
if (this.active) {
|
|
1953
|
+
if (escapeSetterKeyList.includes(key)) {
|
|
1954
|
+
Reflect.set(rawWindow, key, value);
|
|
1955
|
+
}
|
|
1956
|
+
else if (
|
|
1957
|
+
// target.hasOwnProperty has been rewritten
|
|
1958
|
+
!rawHasOwnProperty.call(target, key) &&
|
|
1959
|
+
rawHasOwnProperty.call(rawWindow, key) &&
|
|
1960
|
+
!this.scopeProperties.includes(key)) {
|
|
1961
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1962
|
+
const { configurable, enumerable, writable, set } = descriptor;
|
|
1963
|
+
// set value because it can be set
|
|
1964
|
+
rawDefineProperty(target, key, {
|
|
1965
|
+
value,
|
|
1966
|
+
configurable,
|
|
1967
|
+
enumerable,
|
|
1968
|
+
writable: writable !== null && writable !== void 0 ? writable : !!set,
|
|
1969
|
+
});
|
|
1970
|
+
this.injectedKeys.add(key);
|
|
1971
|
+
}
|
|
1972
|
+
else {
|
|
1973
|
+
Reflect.set(target, key, value);
|
|
1974
|
+
this.injectedKeys.add(key);
|
|
1975
|
+
}
|
|
1976
|
+
if ((this.escapeProperties.includes(key) ||
|
|
1977
|
+
(staticEscapeProperties.includes(key) && !Reflect.has(rawWindow, key))) &&
|
|
1978
|
+
!this.scopeProperties.includes(key)) {
|
|
1979
|
+
Reflect.set(rawWindow, key, value);
|
|
1980
|
+
this.escapeKeys.add(key);
|
|
1981
|
+
}
|
|
1982
|
+
}
|
|
1983
|
+
return true;
|
|
1984
|
+
},
|
|
1985
|
+
has: (target, key) => {
|
|
1986
|
+
if (this.scopeProperties.includes(key))
|
|
1987
|
+
return key in target;
|
|
1988
|
+
return key in target || key in rawWindow;
|
|
1989
|
+
},
|
|
1990
|
+
// Object.getOwnPropertyDescriptor(window, key)
|
|
1991
|
+
getOwnPropertyDescriptor: (target, key) => {
|
|
1992
|
+
if (rawHasOwnProperty.call(target, key)) {
|
|
1993
|
+
descriptorTargetMap.set(key, 'target');
|
|
1994
|
+
return Object.getOwnPropertyDescriptor(target, key);
|
|
1995
|
+
}
|
|
1996
|
+
if (rawHasOwnProperty.call(rawWindow, key)) {
|
|
1997
|
+
descriptorTargetMap.set(key, 'rawWindow');
|
|
1998
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1999
|
+
if (descriptor && !descriptor.configurable) {
|
|
2000
|
+
descriptor.configurable = true;
|
|
2001
|
+
}
|
|
2002
|
+
return descriptor;
|
|
2003
|
+
}
|
|
2004
|
+
return undefined;
|
|
2005
|
+
},
|
|
2006
|
+
// Object.defineProperty(window, key, Descriptor)
|
|
2007
|
+
defineProperty: (target, key, value) => {
|
|
2008
|
+
const from = descriptorTargetMap.get(key);
|
|
2009
|
+
if (from === 'rawWindow') {
|
|
2010
|
+
return Reflect.defineProperty(rawWindow, key, value);
|
|
2011
|
+
}
|
|
2012
|
+
return Reflect.defineProperty(target, key, value);
|
|
2013
|
+
},
|
|
2014
|
+
// Object.getOwnPropertyNames(window)
|
|
2015
|
+
ownKeys: (target) => {
|
|
2016
|
+
return unique(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)));
|
|
2017
|
+
},
|
|
2018
|
+
deleteProperty: (target, key) => {
|
|
2019
|
+
if (rawHasOwnProperty.call(target, key)) {
|
|
2020
|
+
this.injectedKeys.has(key) && this.injectedKeys.delete(key);
|
|
2021
|
+
this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
2022
|
+
return Reflect.deleteProperty(target, key);
|
|
2023
|
+
}
|
|
2024
|
+
return true;
|
|
2025
|
+
},
|
|
2026
|
+
});
|
|
2027
|
+
}
|
|
2012
2028
|
/**
|
|
2013
|
-
* inject global properties to
|
|
2014
|
-
* @param
|
|
2029
|
+
* inject global properties to microAppWindow
|
|
2030
|
+
* @param microAppWindow micro window
|
|
2015
2031
|
* @param appName app name
|
|
2016
2032
|
* @param url app url
|
|
2017
2033
|
*/
|
|
2018
|
-
|
|
2019
|
-
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2034
|
+
initMicroAppWindow(microAppWindow, appName, url) {
|
|
2035
|
+
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
2036
|
+
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
2037
|
+
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
2038
|
+
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
2039
|
+
microAppWindow.microApp = new EventCenterForMicroApp(appName);
|
|
2040
|
+
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
2041
|
+
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
2042
|
+
microAppWindow.removeDomScope = removeDomScope;
|
|
2043
|
+
microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
|
|
2044
|
+
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
2045
|
+
this.setHijackProperties(microAppWindow, appName);
|
|
2046
|
+
}
|
|
2047
|
+
// properties associated with the native window
|
|
2048
|
+
setMappingPropertiesWithRawDescriptor(microAppWindow) {
|
|
2049
|
+
let topValue, parentValue;
|
|
2050
|
+
const rawWindow = globalEnv.rawWindow;
|
|
2051
|
+
if (rawWindow === rawWindow.parent) { // not in iframe
|
|
2052
|
+
topValue = parentValue = this.proxyWindow;
|
|
2053
|
+
}
|
|
2054
|
+
else { // in iframe
|
|
2055
|
+
topValue = rawWindow.top;
|
|
2056
|
+
parentValue = rawWindow.parent;
|
|
2057
|
+
}
|
|
2058
|
+
rawDefineProperty(microAppWindow, 'top', this.createDescriptorFormicroAppWindow('top', topValue));
|
|
2059
|
+
rawDefineProperty(microAppWindow, 'parent', this.createDescriptorFormicroAppWindow('parent', parentValue));
|
|
2060
|
+
globalPropertyList.forEach((key) => {
|
|
2061
|
+
rawDefineProperty(microAppWindow, key, this.createDescriptorFormicroAppWindow(key, this.proxyWindow));
|
|
2062
|
+
});
|
|
2063
|
+
}
|
|
2064
|
+
createDescriptorFormicroAppWindow(key, value) {
|
|
2065
|
+
const { configurable = true, enumerable = true, writable, set } = Object.getOwnPropertyDescriptor(globalEnv.rawWindow, key) || {};
|
|
2066
|
+
const descriptor = {
|
|
2067
|
+
value,
|
|
2068
|
+
configurable,
|
|
2069
|
+
enumerable,
|
|
2070
|
+
writable: writable !== null && writable !== void 0 ? writable : !!set
|
|
2071
|
+
};
|
|
2072
|
+
return descriptor;
|
|
2073
|
+
}
|
|
2074
|
+
// set hijack Properties to microAppWindow
|
|
2075
|
+
setHijackProperties(microAppWindow, appName) {
|
|
2076
|
+
let modifiedEval, modifiedImage;
|
|
2077
|
+
rawDefineProperties(microAppWindow, {
|
|
2078
|
+
document: {
|
|
2079
|
+
get() {
|
|
2080
|
+
throttleDeferForSetAppName(appName);
|
|
2081
|
+
return globalEnv.rawDocument;
|
|
2082
|
+
},
|
|
2083
|
+
configurable: false,
|
|
2084
|
+
enumerable: true,
|
|
2085
|
+
},
|
|
2086
|
+
eval: {
|
|
2087
|
+
get() {
|
|
2088
|
+
throttleDeferForSetAppName(appName);
|
|
2089
|
+
return modifiedEval || eval;
|
|
2090
|
+
},
|
|
2091
|
+
set: (value) => {
|
|
2092
|
+
modifiedEval = value;
|
|
2093
|
+
},
|
|
2094
|
+
configurable: true,
|
|
2095
|
+
enumerable: false,
|
|
2096
|
+
},
|
|
2097
|
+
Image: {
|
|
2098
|
+
get() {
|
|
2099
|
+
throttleDeferForSetAppName(appName);
|
|
2100
|
+
return modifiedImage || globalEnv.ImageProxy;
|
|
2101
|
+
},
|
|
2102
|
+
set: (value) => {
|
|
2103
|
+
modifiedImage = value;
|
|
2104
|
+
},
|
|
2105
|
+
configurable: true,
|
|
2106
|
+
enumerable: false,
|
|
2107
|
+
},
|
|
2108
|
+
});
|
|
2026
2109
|
}
|
|
2027
2110
|
}
|
|
2028
2111
|
SandBox.activeCount = 0; // number of active sandbox
|
|
2029
2112
|
|
|
2030
|
-
function
|
|
2113
|
+
function formatEventInfo(event, element) {
|
|
2031
2114
|
Object.defineProperties(event, {
|
|
2032
2115
|
currentTarget: {
|
|
2033
2116
|
get() {
|
|
@@ -2066,7 +2149,7 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2066
2149
|
const event = new CustomEvent(lifecycleName, {
|
|
2067
2150
|
detail,
|
|
2068
2151
|
});
|
|
2069
|
-
|
|
2152
|
+
formatEventInfo(event, element);
|
|
2070
2153
|
// global hooks
|
|
2071
2154
|
// @ts-ignore
|
|
2072
2155
|
if (isFunction((_a = microApp.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
@@ -2076,19 +2159,25 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2076
2159
|
element.dispatchEvent(event);
|
|
2077
2160
|
}
|
|
2078
2161
|
/**
|
|
2079
|
-
* Dispatch
|
|
2080
|
-
* @param
|
|
2162
|
+
* Dispatch custom event to micro app
|
|
2163
|
+
* @param eventName event name
|
|
2164
|
+
* @param appName app name
|
|
2165
|
+
* @param detail event detail
|
|
2081
2166
|
*/
|
|
2082
|
-
function
|
|
2083
|
-
const event = new CustomEvent(
|
|
2167
|
+
function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
2168
|
+
const event = new CustomEvent(`${eventName}-${appName}`, {
|
|
2169
|
+
detail,
|
|
2170
|
+
});
|
|
2084
2171
|
window.dispatchEvent(event);
|
|
2085
2172
|
}
|
|
2086
2173
|
|
|
2087
2174
|
// micro app instances
|
|
2088
2175
|
const appInstanceMap = new Map();
|
|
2089
2176
|
class CreateApp {
|
|
2090
|
-
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox,
|
|
2091
|
-
this.
|
|
2177
|
+
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, baseroute, }) {
|
|
2178
|
+
this.state = appStates.NOT_LOADED;
|
|
2179
|
+
this.keepAliveState = null;
|
|
2180
|
+
this.keepAliveContainer = null;
|
|
2092
2181
|
this.loadSourceLevel = 0;
|
|
2093
2182
|
this.umdHookMount = null;
|
|
2094
2183
|
this.umdHookUnmount = null;
|
|
@@ -2096,7 +2185,6 @@ class CreateApp {
|
|
|
2096
2185
|
this.umdMode = false;
|
|
2097
2186
|
this.isPrefetch = false;
|
|
2098
2187
|
this.container = null;
|
|
2099
|
-
this.macro = false;
|
|
2100
2188
|
this.baseroute = '';
|
|
2101
2189
|
this.sandBox = null;
|
|
2102
2190
|
this.container = container !== null && container !== void 0 ? container : null;
|
|
@@ -2108,17 +2196,16 @@ class CreateApp {
|
|
|
2108
2196
|
this.url = url;
|
|
2109
2197
|
this.useSandbox = useSandbox;
|
|
2110
2198
|
this.scopecss = this.useSandbox && scopecss;
|
|
2111
|
-
this.macro = macro !== null && macro !== void 0 ? macro : false;
|
|
2112
2199
|
this.source = {
|
|
2113
2200
|
links: new Map(),
|
|
2114
2201
|
scripts: new Map(),
|
|
2115
2202
|
};
|
|
2116
2203
|
this.loadSourceCode();
|
|
2117
|
-
this.useSandbox && (this.sandBox = new SandBox(name, url
|
|
2204
|
+
this.useSandbox && (this.sandBox = new SandBox(name, url));
|
|
2118
2205
|
}
|
|
2119
2206
|
// Load resources
|
|
2120
2207
|
loadSourceCode() {
|
|
2121
|
-
this.
|
|
2208
|
+
this.state = appStates.LOADING_SOURCE_CODE;
|
|
2122
2209
|
extractHtml(this);
|
|
2123
2210
|
}
|
|
2124
2211
|
/**
|
|
@@ -2127,9 +2214,9 @@ class CreateApp {
|
|
|
2127
2214
|
onLoad(html) {
|
|
2128
2215
|
if (++this.loadSourceLevel === 2) {
|
|
2129
2216
|
this.source.html = html;
|
|
2130
|
-
if (this.isPrefetch ||
|
|
2217
|
+
if (this.isPrefetch || appStates.UNMOUNT === this.state)
|
|
2131
2218
|
return;
|
|
2132
|
-
this.
|
|
2219
|
+
this.state = appStates.LOAD_SOURCE_FINISHED;
|
|
2133
2220
|
this.mount();
|
|
2134
2221
|
}
|
|
2135
2222
|
}
|
|
@@ -2139,9 +2226,9 @@ class CreateApp {
|
|
|
2139
2226
|
*/
|
|
2140
2227
|
onLoadError(e) {
|
|
2141
2228
|
this.loadSourceLevel = -1;
|
|
2142
|
-
if (
|
|
2229
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2143
2230
|
this.onerror(e);
|
|
2144
|
-
this.
|
|
2231
|
+
this.state = appStates.LOAD_SOURCE_ERROR;
|
|
2145
2232
|
}
|
|
2146
2233
|
}
|
|
2147
2234
|
/**
|
|
@@ -2158,11 +2245,11 @@ class CreateApp {
|
|
|
2158
2245
|
this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
|
|
2159
2246
|
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
|
|
2160
2247
|
if (this.loadSourceLevel !== 2) {
|
|
2161
|
-
this.
|
|
2248
|
+
this.state = appStates.LOADING_SOURCE_CODE;
|
|
2162
2249
|
return;
|
|
2163
2250
|
}
|
|
2164
2251
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
2165
|
-
this.
|
|
2252
|
+
this.state = appStates.MOUNTING;
|
|
2166
2253
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
2167
2254
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute);
|
|
2168
2255
|
let umdHookMountResult; // result of mount function
|
|
@@ -2222,20 +2309,23 @@ class CreateApp {
|
|
|
2222
2309
|
* dispatch mounted event when app run finished
|
|
2223
2310
|
*/
|
|
2224
2311
|
dispatchMountedEvent() {
|
|
2225
|
-
if (
|
|
2226
|
-
this.
|
|
2312
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2313
|
+
this.state = appStates.MOUNTED;
|
|
2227
2314
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
2228
2315
|
}
|
|
2229
2316
|
}
|
|
2230
2317
|
/**
|
|
2231
2318
|
* unmount app
|
|
2232
2319
|
* @param destroy completely destroy, delete cache resources
|
|
2320
|
+
* @param unmountcb callback of unmount
|
|
2233
2321
|
*/
|
|
2234
|
-
unmount(destroy) {
|
|
2235
|
-
if (this.
|
|
2322
|
+
unmount(destroy, unmountcb) {
|
|
2323
|
+
if (this.state === appStates.LOAD_SOURCE_ERROR) {
|
|
2236
2324
|
destroy = true;
|
|
2237
2325
|
}
|
|
2238
|
-
this.
|
|
2326
|
+
this.state = appStates.UNMOUNT;
|
|
2327
|
+
this.keepAliveState = null;
|
|
2328
|
+
this.keepAliveContainer = null;
|
|
2239
2329
|
// result of unmount function
|
|
2240
2330
|
let umdHookUnmountResult;
|
|
2241
2331
|
/**
|
|
@@ -2251,50 +2341,84 @@ class CreateApp {
|
|
|
2251
2341
|
}
|
|
2252
2342
|
}
|
|
2253
2343
|
// dispatch unmount event to micro app
|
|
2254
|
-
|
|
2255
|
-
this.handleUnmounted(destroy, umdHookUnmountResult);
|
|
2344
|
+
dispatchCustomEventToMicroApp('unmount', this.name);
|
|
2345
|
+
this.handleUnmounted(destroy, umdHookUnmountResult, unmountcb);
|
|
2256
2346
|
}
|
|
2257
2347
|
/**
|
|
2258
2348
|
* handle for promise umdHookUnmount
|
|
2349
|
+
* @param destroy completely destroy, delete cache resources
|
|
2259
2350
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
2351
|
+
* @param unmountcb callback of unmount
|
|
2260
2352
|
*/
|
|
2261
|
-
handleUnmounted(destroy, umdHookUnmountResult) {
|
|
2353
|
+
handleUnmounted(destroy, umdHookUnmountResult, unmountcb) {
|
|
2262
2354
|
if (isPromise(umdHookUnmountResult)) {
|
|
2263
2355
|
umdHookUnmountResult
|
|
2264
|
-
.then(() => this.actionsForUnmount(destroy))
|
|
2265
|
-
.catch(() => this.actionsForUnmount(destroy));
|
|
2356
|
+
.then(() => this.actionsForUnmount(destroy, unmountcb))
|
|
2357
|
+
.catch(() => this.actionsForUnmount(destroy, unmountcb));
|
|
2266
2358
|
}
|
|
2267
2359
|
else {
|
|
2268
|
-
this.actionsForUnmount(destroy);
|
|
2360
|
+
this.actionsForUnmount(destroy, unmountcb);
|
|
2269
2361
|
}
|
|
2270
2362
|
}
|
|
2271
2363
|
/**
|
|
2272
2364
|
* actions for unmount app
|
|
2273
2365
|
* @param destroy completely destroy, delete cache resources
|
|
2366
|
+
* @param unmountcb callback of unmount
|
|
2274
2367
|
*/
|
|
2275
|
-
actionsForUnmount(destroy) {
|
|
2368
|
+
actionsForUnmount(destroy, unmountcb) {
|
|
2276
2369
|
var _a;
|
|
2277
|
-
// dispatch unmount event to base app
|
|
2278
|
-
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
2279
2370
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop();
|
|
2280
2371
|
if (destroy) {
|
|
2281
|
-
this.
|
|
2372
|
+
this.actionsForCompletelyDestroy();
|
|
2282
2373
|
}
|
|
2283
2374
|
else if (this.umdMode && this.container.childElementCount) {
|
|
2284
|
-
/**
|
|
2285
|
-
* In umd mode, ui frameworks will no longer create style elements to head in lazy load page when render again, so we should save container to keep these elements
|
|
2286
|
-
*/
|
|
2287
2375
|
cloneContainer(this.container, this.source.html, false);
|
|
2288
2376
|
}
|
|
2377
|
+
// dispatch unmount event to base app
|
|
2378
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
2379
|
+
this.container.innerHTML = '';
|
|
2289
2380
|
this.container = null;
|
|
2381
|
+
unmountcb && unmountcb();
|
|
2290
2382
|
}
|
|
2291
2383
|
// actions for completely destroy
|
|
2292
|
-
|
|
2384
|
+
actionsForCompletelyDestroy() {
|
|
2293
2385
|
if (!this.useSandbox && this.umdMode) {
|
|
2294
2386
|
delete window[this.libraryName];
|
|
2295
2387
|
}
|
|
2296
2388
|
appInstanceMap.delete(this.name);
|
|
2297
2389
|
}
|
|
2390
|
+
// hidden app when disconnectedCallback called with keep-alive
|
|
2391
|
+
hiddenKeepAliveApp() {
|
|
2392
|
+
const oldContainer = this.container;
|
|
2393
|
+
cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
|
|
2394
|
+
this.container = this.keepAliveContainer;
|
|
2395
|
+
this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
|
|
2396
|
+
// event should dispatch before clone node
|
|
2397
|
+
// dispatch afterhidden event to micro-app
|
|
2398
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2399
|
+
appState: 'afterhidden',
|
|
2400
|
+
});
|
|
2401
|
+
// dispatch afterhidden event to base app
|
|
2402
|
+
dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
|
|
2403
|
+
}
|
|
2404
|
+
// show app when connectedCallback called with keep-alive
|
|
2405
|
+
showKeepAliveApp(container) {
|
|
2406
|
+
// dispatch beforeshow event to micro-app
|
|
2407
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2408
|
+
appState: 'beforeshow',
|
|
2409
|
+
});
|
|
2410
|
+
// dispatch beforeshow event to base app
|
|
2411
|
+
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
2412
|
+
cloneContainer(this.container, container, false);
|
|
2413
|
+
this.container = container;
|
|
2414
|
+
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
2415
|
+
// dispatch aftershow event to micro-app
|
|
2416
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2417
|
+
appState: 'aftershow',
|
|
2418
|
+
});
|
|
2419
|
+
// dispatch aftershow event to base app
|
|
2420
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
|
|
2421
|
+
}
|
|
2298
2422
|
/**
|
|
2299
2423
|
* app rendering error
|
|
2300
2424
|
* @param e Error
|
|
@@ -2302,15 +2426,19 @@ class CreateApp {
|
|
|
2302
2426
|
onerror(e) {
|
|
2303
2427
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
2304
2428
|
}
|
|
2305
|
-
// get app
|
|
2306
|
-
|
|
2307
|
-
return this.
|
|
2429
|
+
// get app state
|
|
2430
|
+
getAppState() {
|
|
2431
|
+
return this.state;
|
|
2432
|
+
}
|
|
2433
|
+
// get keep-alive state
|
|
2434
|
+
getKeepAliveState() {
|
|
2435
|
+
return this.keepAliveState;
|
|
2308
2436
|
}
|
|
2309
2437
|
// get umd library, if it not exist, return empty object
|
|
2310
2438
|
getUmdLibraryHooks() {
|
|
2311
2439
|
var _a, _b;
|
|
2312
2440
|
// after execScripts, the app maybe unmounted
|
|
2313
|
-
if (
|
|
2441
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2314
2442
|
const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
|
|
2315
2443
|
this.libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
2316
2444
|
// do not use isObject
|
|
@@ -2319,20 +2447,6 @@ class CreateApp {
|
|
|
2319
2447
|
return {};
|
|
2320
2448
|
}
|
|
2321
2449
|
}
|
|
2322
|
-
// if app not prefetch & not unmount, then app is active
|
|
2323
|
-
function getActiveApps() {
|
|
2324
|
-
const activeApps = [];
|
|
2325
|
-
appInstanceMap.forEach((app, appName) => {
|
|
2326
|
-
if (appStatus.UNMOUNT !== app.getAppStatus() && !app.isPrefetch) {
|
|
2327
|
-
activeApps.push(appName);
|
|
2328
|
-
}
|
|
2329
|
-
});
|
|
2330
|
-
return activeApps;
|
|
2331
|
-
}
|
|
2332
|
-
// get all registered apps
|
|
2333
|
-
function getAllApps() {
|
|
2334
|
-
return Array.from(appInstanceMap.keys());
|
|
2335
|
-
}
|
|
2336
2450
|
|
|
2337
2451
|
// Record element and map element
|
|
2338
2452
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
@@ -2527,13 +2641,13 @@ function patchElementPrototypeMethods() {
|
|
|
2527
2641
|
}
|
|
2528
2642
|
};
|
|
2529
2643
|
// prototype methods of add element👇
|
|
2530
|
-
|
|
2644
|
+
Element.prototype.appendChild = function appendChild(newChild) {
|
|
2531
2645
|
return commonElementHander(this, newChild, null, globalEnv.rawAppendChild);
|
|
2532
2646
|
};
|
|
2533
|
-
|
|
2647
|
+
Element.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
2534
2648
|
return commonElementHander(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
2535
2649
|
};
|
|
2536
|
-
|
|
2650
|
+
Element.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
2537
2651
|
return commonElementHander(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
2538
2652
|
};
|
|
2539
2653
|
Element.prototype.append = function append(...nodes) {
|
|
@@ -2552,7 +2666,7 @@ function patchElementPrototypeMethods() {
|
|
|
2552
2666
|
}
|
|
2553
2667
|
};
|
|
2554
2668
|
// prototype methods of delete element👇
|
|
2555
|
-
|
|
2669
|
+
Element.prototype.removeChild = function removeChild(oldChild) {
|
|
2556
2670
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
2557
2671
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
2558
2672
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -2562,6 +2676,12 @@ function patchElementPrototypeMethods() {
|
|
|
2562
2676
|
}
|
|
2563
2677
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
2564
2678
|
};
|
|
2679
|
+
// patch cloneNode
|
|
2680
|
+
Element.prototype.cloneNode = function cloneNode(deep) {
|
|
2681
|
+
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
2682
|
+
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
2683
|
+
return clonedNode;
|
|
2684
|
+
};
|
|
2565
2685
|
}
|
|
2566
2686
|
/**
|
|
2567
2687
|
* Mark the newly created element in the micro application
|
|
@@ -2680,12 +2800,13 @@ function releasePatches() {
|
|
|
2680
2800
|
setCurrentAppName(null);
|
|
2681
2801
|
releasePatchDocument();
|
|
2682
2802
|
Element.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2803
|
+
Element.prototype.appendChild = globalEnv.rawAppendChild;
|
|
2804
|
+
Element.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
2805
|
+
Element.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
2806
|
+
Element.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
2687
2807
|
Element.prototype.append = globalEnv.rawAppend;
|
|
2688
2808
|
Element.prototype.prepend = globalEnv.rawPrepend;
|
|
2809
|
+
Element.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
2689
2810
|
}
|
|
2690
2811
|
// Set the style of micro-app-head and micro-app-body
|
|
2691
2812
|
let hasRejectMicroAppStyle = false;
|
|
@@ -2700,7 +2821,7 @@ function rejectMicroAppStyle() {
|
|
|
2700
2821
|
}
|
|
2701
2822
|
|
|
2702
2823
|
function unmountNestedApp() {
|
|
2703
|
-
|
|
2824
|
+
releaseUnmountOfNestedApp();
|
|
2704
2825
|
appInstanceMap.forEach(app => {
|
|
2705
2826
|
// @ts-ignore
|
|
2706
2827
|
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
@@ -2718,7 +2839,7 @@ function listenUmountOfNestedApp() {
|
|
|
2718
2839
|
}
|
|
2719
2840
|
}
|
|
2720
2841
|
// release listener
|
|
2721
|
-
function
|
|
2842
|
+
function releaseUnmountOfNestedApp() {
|
|
2722
2843
|
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2723
2844
|
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
2724
2845
|
}
|
|
@@ -2745,7 +2866,6 @@ function defineElement(tagName) {
|
|
|
2745
2866
|
* handle for change of name an url after element inited
|
|
2746
2867
|
*/
|
|
2747
2868
|
this.handleAttributeUpdate = () => {
|
|
2748
|
-
var _a;
|
|
2749
2869
|
this.isWating = false;
|
|
2750
2870
|
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
2751
2871
|
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
@@ -2753,44 +2873,27 @@ function defineElement(tagName) {
|
|
|
2753
2873
|
const existApp = appInstanceMap.get(formatAttrName);
|
|
2754
2874
|
if (formatAttrName !== this.appName && existApp) {
|
|
2755
2875
|
// handling of cached and non-prefetch apps
|
|
2756
|
-
if (
|
|
2876
|
+
if (appStates.UNMOUNT !== existApp.getAppState() &&
|
|
2877
|
+
keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
|
|
2878
|
+
!existApp.isPrefetch) {
|
|
2757
2879
|
this.setAttribute('name', this.appName);
|
|
2758
|
-
return logError(`an app named ${formatAttrName}
|
|
2880
|
+
return logError(`app name conflict, an app named ${formatAttrName} is running`, this.appName);
|
|
2759
2881
|
}
|
|
2760
2882
|
}
|
|
2761
2883
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
2762
|
-
|
|
2763
|
-
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
*/
|
|
2767
|
-
if (this.getDisposeResult('ssr')) {
|
|
2768
|
-
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
2769
|
-
}
|
|
2770
|
-
else if (this.ssrUrl) {
|
|
2771
|
-
this.ssrUrl = '';
|
|
2772
|
-
}
|
|
2773
|
-
this.appName = formatAttrName;
|
|
2774
|
-
this.appUrl = formatAttrUrl;
|
|
2775
|
-
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
2776
|
-
if (formatAttrName !== this.getAttribute('name')) {
|
|
2777
|
-
this.setAttribute('name', this.appName);
|
|
2884
|
+
if (formatAttrName === this.appName) {
|
|
2885
|
+
this.handleUnmount(true, () => {
|
|
2886
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2887
|
+
});
|
|
2778
2888
|
}
|
|
2779
|
-
|
|
2780
|
-
|
|
2781
|
-
|
|
2782
|
-
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
2783
|
-
* scene3: url is different but ssrUrl is equal
|
|
2784
|
-
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
2785
|
-
*/
|
|
2786
|
-
if (existApp &&
|
|
2787
|
-
existApp.url === this.appUrl &&
|
|
2788
|
-
existApp.ssrUrl === this.ssrUrl) {
|
|
2789
|
-
// mount app
|
|
2790
|
-
this.handleAppMount(existApp);
|
|
2889
|
+
else if (this.getKeepAliveModeResult()) {
|
|
2890
|
+
this.handleHiddenKeepAliveApp();
|
|
2891
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2791
2892
|
}
|
|
2792
2893
|
else {
|
|
2793
|
-
this.
|
|
2894
|
+
this.handleUnmount(this.getDestroyCompatibleResult(), () => {
|
|
2895
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2896
|
+
});
|
|
2794
2897
|
}
|
|
2795
2898
|
}
|
|
2796
2899
|
}
|
|
@@ -2814,8 +2917,8 @@ function defineElement(tagName) {
|
|
|
2814
2917
|
// inline: whether js runs in inline script mode, default is false
|
|
2815
2918
|
// disableScopecss: whether disable css scoped, default is false
|
|
2816
2919
|
// disableSandbox: whether disable sandbox, default is false
|
|
2817
|
-
// macro: used to solve the async render problem of vue3, default is false
|
|
2818
2920
|
// baseRoute: route prefix, default is ''
|
|
2921
|
+
// keep-alive: open keep-alive mode
|
|
2819
2922
|
connectedCallback() {
|
|
2820
2923
|
this.hasConnected = true;
|
|
2821
2924
|
if (!elementInstanceMap.has(this)) {
|
|
@@ -2826,10 +2929,17 @@ function defineElement(tagName) {
|
|
|
2826
2929
|
}
|
|
2827
2930
|
disconnectedCallback() {
|
|
2828
2931
|
this.hasConnected = false;
|
|
2829
|
-
|
|
2830
|
-
|
|
2831
|
-
|
|
2832
|
-
|
|
2932
|
+
// keep-alive
|
|
2933
|
+
if (this.getKeepAliveModeResult()) {
|
|
2934
|
+
this.handleHiddenKeepAliveApp();
|
|
2935
|
+
}
|
|
2936
|
+
else {
|
|
2937
|
+
elementInstanceMap.delete(this);
|
|
2938
|
+
this.handleUnmount(this.getDestroyCompatibleResult(), () => {
|
|
2939
|
+
if (elementInstanceMap.size === 0) {
|
|
2940
|
+
releasePatches();
|
|
2941
|
+
}
|
|
2942
|
+
});
|
|
2833
2943
|
}
|
|
2834
2944
|
}
|
|
2835
2945
|
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
@@ -2873,7 +2983,7 @@ function defineElement(tagName) {
|
|
|
2873
2983
|
if (elementInstanceMap.set(this, true).size === 1) {
|
|
2874
2984
|
patchElementPrototypeMethods();
|
|
2875
2985
|
rejectMicroAppStyle();
|
|
2876
|
-
|
|
2986
|
+
releaseUnmountOfNestedApp();
|
|
2877
2987
|
listenUmountOfNestedApp();
|
|
2878
2988
|
}
|
|
2879
2989
|
}
|
|
@@ -2892,15 +3002,21 @@ function defineElement(tagName) {
|
|
|
2892
3002
|
else if (this.ssrUrl) {
|
|
2893
3003
|
this.ssrUrl = '';
|
|
2894
3004
|
}
|
|
2895
|
-
|
|
2896
|
-
|
|
3005
|
+
if (appInstanceMap.has(this.appName)) {
|
|
3006
|
+
const app = appInstanceMap.get(this.appName);
|
|
2897
3007
|
const existAppUrl = app.ssrUrl || app.url;
|
|
2898
3008
|
const activeAppUrl = this.ssrUrl || this.appUrl;
|
|
2899
|
-
|
|
2900
|
-
|
|
3009
|
+
// keep-alive don't care about ssrUrl
|
|
3010
|
+
// Even if the keep-alive app is pushed into the background, it is still active and cannot be replaced. Otherwise, it is difficult for developers to troubleshoot in case of conflict and will leave developers at a loss
|
|
3011
|
+
if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
3012
|
+
app.url === this.appUrl) {
|
|
3013
|
+
this.handleShowKeepAliveApp(app);
|
|
3014
|
+
}
|
|
3015
|
+
else if (existAppUrl === activeAppUrl && (app.isPrefetch ||
|
|
3016
|
+
app.getAppState() === appStates.UNMOUNT)) {
|
|
2901
3017
|
this.handleAppMount(app);
|
|
2902
3018
|
}
|
|
2903
|
-
else if (app.isPrefetch || app.
|
|
3019
|
+
else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
|
|
2904
3020
|
/**
|
|
2905
3021
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
2906
3022
|
*/
|
|
@@ -2908,7 +3024,56 @@ function defineElement(tagName) {
|
|
|
2908
3024
|
this.handleCreateApp();
|
|
2909
3025
|
}
|
|
2910
3026
|
else {
|
|
2911
|
-
logError(`an app named ${this.appName}
|
|
3027
|
+
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
3028
|
+
}
|
|
3029
|
+
}
|
|
3030
|
+
else {
|
|
3031
|
+
this.handleCreateApp();
|
|
3032
|
+
}
|
|
3033
|
+
}
|
|
3034
|
+
// remount app or create app if attribute url or name change
|
|
3035
|
+
actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
|
|
3036
|
+
var _a;
|
|
3037
|
+
/**
|
|
3038
|
+
* change ssrUrl in ssr mode
|
|
3039
|
+
* do not add judgment of formatAttrUrl === this.appUrl
|
|
3040
|
+
*/
|
|
3041
|
+
if (this.getDisposeResult('ssr')) {
|
|
3042
|
+
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
3043
|
+
}
|
|
3044
|
+
else if (this.ssrUrl) {
|
|
3045
|
+
this.ssrUrl = '';
|
|
3046
|
+
}
|
|
3047
|
+
this.appName = formatAttrName;
|
|
3048
|
+
this.appUrl = formatAttrUrl;
|
|
3049
|
+
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
3050
|
+
if (formatAttrName !== this.getAttribute('name')) {
|
|
3051
|
+
this.setAttribute('name', this.appName);
|
|
3052
|
+
}
|
|
3053
|
+
/**
|
|
3054
|
+
* when existApp not null: this.appName === existApp.name
|
|
3055
|
+
* scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, existApp has been unmounted
|
|
3056
|
+
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
3057
|
+
* scene3: url is different but ssrUrl is equal
|
|
3058
|
+
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
3059
|
+
* scene5: if existApp is KEEP_ALIVE_HIDDEN, name must different
|
|
3060
|
+
*/
|
|
3061
|
+
if (existApp) {
|
|
3062
|
+
if (existApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
3063
|
+
if (existApp.url === this.appUrl) {
|
|
3064
|
+
this.handleShowKeepAliveApp(existApp);
|
|
3065
|
+
}
|
|
3066
|
+
else {
|
|
3067
|
+
// the hidden keep-alive app is still active
|
|
3068
|
+
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
|
|
3072
|
+
// mount app
|
|
3073
|
+
this.handleAppMount(existApp);
|
|
3074
|
+
}
|
|
3075
|
+
else {
|
|
3076
|
+
this.handleCreateApp();
|
|
2912
3077
|
}
|
|
2913
3078
|
}
|
|
2914
3079
|
else {
|
|
@@ -2949,7 +3114,7 @@ function defineElement(tagName) {
|
|
|
2949
3114
|
* fix of unmounted umd app with disableSandbox
|
|
2950
3115
|
*/
|
|
2951
3116
|
if (appInstanceMap.has(this.appName)) {
|
|
2952
|
-
appInstanceMap.get(this.appName).
|
|
3117
|
+
appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
|
|
2953
3118
|
}
|
|
2954
3119
|
const instance = new CreateApp({
|
|
2955
3120
|
name: this.appName,
|
|
@@ -2959,7 +3124,6 @@ function defineElement(tagName) {
|
|
|
2959
3124
|
inline: this.getDisposeResult('inline'),
|
|
2960
3125
|
scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')),
|
|
2961
3126
|
useSandbox: !this.getDisposeResult('disableSandbox'),
|
|
2962
|
-
macro: this.getDisposeResult('macro'),
|
|
2963
3127
|
baseroute: this.getBaseRouteCompatible(),
|
|
2964
3128
|
});
|
|
2965
3129
|
appInstanceMap.set(this.appName, instance);
|
|
@@ -2968,10 +3132,24 @@ function defineElement(tagName) {
|
|
|
2968
3132
|
* unmount app
|
|
2969
3133
|
* @param destroy delete cache resources when unmount
|
|
2970
3134
|
*/
|
|
2971
|
-
handleUnmount(destroy) {
|
|
3135
|
+
handleUnmount(destroy, unmountcb) {
|
|
3136
|
+
const app = appInstanceMap.get(this.appName);
|
|
3137
|
+
if (app &&
|
|
3138
|
+
app.getAppState() !== appStates.UNMOUNT)
|
|
3139
|
+
app.unmount(destroy, unmountcb);
|
|
3140
|
+
}
|
|
3141
|
+
// hidden app when disconnectedCallback called with keep-alive
|
|
3142
|
+
handleHiddenKeepAliveApp() {
|
|
2972
3143
|
const app = appInstanceMap.get(this.appName);
|
|
2973
|
-
if (app &&
|
|
2974
|
-
app.
|
|
3144
|
+
if (app &&
|
|
3145
|
+
app.getAppState() !== appStates.UNMOUNT &&
|
|
3146
|
+
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN)
|
|
3147
|
+
app.hiddenKeepAliveApp();
|
|
3148
|
+
}
|
|
3149
|
+
// show app when connectedCallback called with keep-alive
|
|
3150
|
+
handleShowKeepAliveApp(app) {
|
|
3151
|
+
// must be asnyc
|
|
3152
|
+
defer(() => { var _a; return app.showKeepAliveApp((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this); });
|
|
2975
3153
|
}
|
|
2976
3154
|
/**
|
|
2977
3155
|
* Get configuration
|
|
@@ -2980,7 +3158,27 @@ function defineElement(tagName) {
|
|
|
2980
3158
|
*/
|
|
2981
3159
|
getDisposeResult(name) {
|
|
2982
3160
|
// @ts-ignore
|
|
2983
|
-
return (this.
|
|
3161
|
+
return (this.compatibleSpecialProperties(name) || microApp[name]) && this.compatibleDisablSpecialProperties(name);
|
|
3162
|
+
}
|
|
3163
|
+
// compatible of disableScopecss & disableSandbox
|
|
3164
|
+
compatibleSpecialProperties(name) {
|
|
3165
|
+
if (name === 'disableScopecss') {
|
|
3166
|
+
return this.hasAttribute('disableScopecss') || this.hasAttribute('disable-scopecss');
|
|
3167
|
+
}
|
|
3168
|
+
else if (name === 'disableSandbox') {
|
|
3169
|
+
return this.hasAttribute('disableSandbox') || this.hasAttribute('disable-sandbox');
|
|
3170
|
+
}
|
|
3171
|
+
return this.hasAttribute(name);
|
|
3172
|
+
}
|
|
3173
|
+
// compatible of disableScopecss & disableSandbox
|
|
3174
|
+
compatibleDisablSpecialProperties(name) {
|
|
3175
|
+
if (name === 'disableScopecss') {
|
|
3176
|
+
return this.getAttribute('disableScopecss') !== 'false' && this.getAttribute('disable-scopecss') !== 'false';
|
|
3177
|
+
}
|
|
3178
|
+
else if (name === 'disableSandbox') {
|
|
3179
|
+
return this.getAttribute('disableSandbox') !== 'false' && this.getAttribute('disable-sandbox') !== 'false';
|
|
3180
|
+
}
|
|
3181
|
+
return this.getAttribute(name) !== 'false';
|
|
2984
3182
|
}
|
|
2985
3183
|
/**
|
|
2986
3184
|
* 2021-09-08
|
|
@@ -2991,6 +3189,16 @@ function defineElement(tagName) {
|
|
|
2991
3189
|
var _a, _b;
|
|
2992
3190
|
return (_b = (_a = this.getAttribute('baseroute')) !== null && _a !== void 0 ? _a : this.getAttribute('baseurl')) !== null && _b !== void 0 ? _b : '';
|
|
2993
3191
|
}
|
|
3192
|
+
// compatible of destroy
|
|
3193
|
+
getDestroyCompatibleResult() {
|
|
3194
|
+
return this.getDisposeResult('destroy') || this.getDisposeResult('destory');
|
|
3195
|
+
}
|
|
3196
|
+
/**
|
|
3197
|
+
* destroy has priority over destroy keep-alive
|
|
3198
|
+
*/
|
|
3199
|
+
getKeepAliveModeResult() {
|
|
3200
|
+
return this.getDisposeResult('keep-alive') && !this.getDestroyCompatibleResult();
|
|
3201
|
+
}
|
|
2994
3202
|
/**
|
|
2995
3203
|
* Data from the base application
|
|
2996
3204
|
*/
|
|
@@ -3040,13 +3248,12 @@ function filterPreFetchTarget(apps) {
|
|
|
3040
3248
|
* url: string,
|
|
3041
3249
|
* disableScopecss?: boolean,
|
|
3042
3250
|
* disableSandbox?: boolean,
|
|
3043
|
-
* macro?: boolean,
|
|
3044
3251
|
* },
|
|
3045
3252
|
* ...
|
|
3046
3253
|
* ])
|
|
3047
3254
|
* Note:
|
|
3048
3255
|
* 1: preFetch is asynchronous and is performed only when the browser is idle
|
|
3049
|
-
* 2: disableScopecss, disableSandbox
|
|
3256
|
+
* 2: disableScopecss, disableSandbox must be same with micro-app element, if conflict, the one who executes first shall prevail
|
|
3050
3257
|
* @param apps micro apps
|
|
3051
3258
|
*/
|
|
3052
3259
|
function preFetch(apps) {
|
|
@@ -3056,13 +3263,12 @@ function preFetch(apps) {
|
|
|
3056
3263
|
requestIdleCallback(() => {
|
|
3057
3264
|
isFunction(apps) && (apps = apps());
|
|
3058
3265
|
filterPreFetchTarget(apps).forEach((item) => {
|
|
3059
|
-
var _a, _b
|
|
3266
|
+
var _a, _b;
|
|
3060
3267
|
const app = new CreateApp({
|
|
3061
3268
|
name: item.name,
|
|
3062
3269
|
url: item.url,
|
|
3063
3270
|
scopecss: !((_a = item.disableScopecss) !== null && _a !== void 0 ? _a : microApp.disableScopecss),
|
|
3064
3271
|
useSandbox: !((_b = item.disableSandbox) !== null && _b !== void 0 ? _b : microApp.disableSandbox),
|
|
3065
|
-
macro: (_c = item.macro) !== null && _c !== void 0 ? _c : microApp.macro,
|
|
3066
3272
|
});
|
|
3067
3273
|
app.isPrefetch = true;
|
|
3068
3274
|
appInstanceMap.set(item.name, app);
|
|
@@ -3112,6 +3318,99 @@ function getGlobalAssets(assets) {
|
|
|
3112
3318
|
}
|
|
3113
3319
|
}
|
|
3114
3320
|
|
|
3321
|
+
/**
|
|
3322
|
+
* if app not prefetch & not unmount, then app is active
|
|
3323
|
+
* @param excludeHiddenApp exclude hidden keep-alive app
|
|
3324
|
+
* @returns active apps
|
|
3325
|
+
*/
|
|
3326
|
+
function getActiveApps(excludeHiddenApp) {
|
|
3327
|
+
const activeApps = [];
|
|
3328
|
+
appInstanceMap.forEach((app, appName) => {
|
|
3329
|
+
if (appStates.UNMOUNT !== app.getAppState() &&
|
|
3330
|
+
!app.isPrefetch &&
|
|
3331
|
+
(!excludeHiddenApp ||
|
|
3332
|
+
keepAliveStates.KEEP_ALIVE_HIDDEN !== app.getKeepAliveState())) {
|
|
3333
|
+
activeApps.push(appName);
|
|
3334
|
+
}
|
|
3335
|
+
});
|
|
3336
|
+
return activeApps;
|
|
3337
|
+
}
|
|
3338
|
+
// get all registered apps
|
|
3339
|
+
function getAllApps() {
|
|
3340
|
+
return Array.from(appInstanceMap.keys());
|
|
3341
|
+
}
|
|
3342
|
+
/**
|
|
3343
|
+
* unmount app by appname
|
|
3344
|
+
* @param appName
|
|
3345
|
+
* @param options unmountAppParams
|
|
3346
|
+
* @returns Promise<void>
|
|
3347
|
+
*/
|
|
3348
|
+
function unmountApp(appName, options) {
|
|
3349
|
+
const app = appInstanceMap.get(formatAppName(appName));
|
|
3350
|
+
return new Promise((reslove) => {
|
|
3351
|
+
if (app) {
|
|
3352
|
+
if (app.getAppState() === appStates.UNMOUNT || app.isPrefetch) {
|
|
3353
|
+
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
3354
|
+
app.actionsForCompletelyDestroy();
|
|
3355
|
+
}
|
|
3356
|
+
reslove();
|
|
3357
|
+
}
|
|
3358
|
+
else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
3359
|
+
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
3360
|
+
app.unmount(true, reslove);
|
|
3361
|
+
}
|
|
3362
|
+
else if (options === null || options === void 0 ? void 0 : options.clearAliveState) {
|
|
3363
|
+
app.unmount(false, reslove);
|
|
3364
|
+
}
|
|
3365
|
+
else {
|
|
3366
|
+
reslove();
|
|
3367
|
+
}
|
|
3368
|
+
}
|
|
3369
|
+
else {
|
|
3370
|
+
const container = getRootContainer(app.container);
|
|
3371
|
+
const unmountHandler = () => {
|
|
3372
|
+
container.removeEventListener('unmount', unmountHandler);
|
|
3373
|
+
container.removeEventListener('afterhidden', afterhiddenHandler);
|
|
3374
|
+
reslove();
|
|
3375
|
+
};
|
|
3376
|
+
const afterhiddenHandler = () => {
|
|
3377
|
+
container.removeEventListener('unmount', unmountHandler);
|
|
3378
|
+
container.removeEventListener('afterhidden', afterhiddenHandler);
|
|
3379
|
+
reslove();
|
|
3380
|
+
};
|
|
3381
|
+
container.addEventListener('unmount', unmountHandler);
|
|
3382
|
+
container.addEventListener('afterhidden', afterhiddenHandler);
|
|
3383
|
+
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
3384
|
+
let destroyAttrValue, destoryAttrValue;
|
|
3385
|
+
container.hasAttribute('destroy') && (destroyAttrValue = container.getAttribute('destroy'));
|
|
3386
|
+
container.hasAttribute('destory') && (destoryAttrValue = container.getAttribute('destory'));
|
|
3387
|
+
container.setAttribute('destroy', 'true');
|
|
3388
|
+
container.parentNode.removeChild(container);
|
|
3389
|
+
container.removeAttribute('destroy');
|
|
3390
|
+
typeof destroyAttrValue === 'string' && container.setAttribute('destroy', destroyAttrValue);
|
|
3391
|
+
typeof destoryAttrValue === 'string' && container.setAttribute('destory', destoryAttrValue);
|
|
3392
|
+
}
|
|
3393
|
+
else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
|
|
3394
|
+
const keepAliveAttrValue = container.getAttribute('keep-alive');
|
|
3395
|
+
container.removeAttribute('keep-alive');
|
|
3396
|
+
container.parentNode.removeChild(container);
|
|
3397
|
+
container.setAttribute('keep-alive', keepAliveAttrValue);
|
|
3398
|
+
}
|
|
3399
|
+
else {
|
|
3400
|
+
container.parentNode.removeChild(container);
|
|
3401
|
+
}
|
|
3402
|
+
}
|
|
3403
|
+
}
|
|
3404
|
+
else {
|
|
3405
|
+
logWarn(`app ${appName} does not exist`);
|
|
3406
|
+
reslove();
|
|
3407
|
+
}
|
|
3408
|
+
});
|
|
3409
|
+
}
|
|
3410
|
+
// unmount all apps in turn
|
|
3411
|
+
function unmountAllApps(options) {
|
|
3412
|
+
return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve());
|
|
3413
|
+
}
|
|
3115
3414
|
class MicroApp extends EventCenterForBaseApp {
|
|
3116
3415
|
constructor() {
|
|
3117
3416
|
super(...arguments);
|
|
@@ -3146,7 +3445,6 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3146
3445
|
this.inline = options.inline;
|
|
3147
3446
|
this.disableScopecss = options.disableScopecss;
|
|
3148
3447
|
this.disableSandbox = options.disableSandbox;
|
|
3149
|
-
this.macro = options.macro;
|
|
3150
3448
|
this.ssr = options.ssr;
|
|
3151
3449
|
isFunction(options.fetch) && (this.fetch = options.fetch);
|
|
3152
3450
|
isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);
|
|
@@ -3175,5 +3473,5 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3175
3473
|
var microApp = new MicroApp();
|
|
3176
3474
|
|
|
3177
3475
|
export default microApp;
|
|
3178
|
-
export { EventCenterForMicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, version };
|
|
3476
|
+
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, unmountAllApps, unmountApp, version };
|
|
3179
3477
|
//# sourceMappingURL=index.esm.js.map
|