@micro-zoe/micro-app 1.0.0-alpha.6 → 1.0.0-alpha.9
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/lib/index.d.ts +87 -21
- package/lib/index.esm.js +894 -277
- 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 +1 -1
- package/typings/global.d.ts +75 -31
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-alpha.
|
|
1
|
+
const version = '1.0.0-alpha.9';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -33,6 +33,10 @@ function isString(target) {
|
|
|
33
33
|
function isBoolean(target) {
|
|
34
34
|
return typeof target === 'boolean';
|
|
35
35
|
}
|
|
36
|
+
// is Number
|
|
37
|
+
function isNumber(target) {
|
|
38
|
+
return typeof target === 'number';
|
|
39
|
+
}
|
|
36
40
|
// is function
|
|
37
41
|
function isFunction(target) {
|
|
38
42
|
return typeof target === 'function';
|
|
@@ -72,6 +76,12 @@ function isShadowRoot(target) {
|
|
|
72
76
|
function isURL(target) {
|
|
73
77
|
return target instanceof URL;
|
|
74
78
|
}
|
|
79
|
+
function isElement(target) {
|
|
80
|
+
return target instanceof Element;
|
|
81
|
+
}
|
|
82
|
+
function isNode(target) {
|
|
83
|
+
return target instanceof Node;
|
|
84
|
+
}
|
|
75
85
|
// is ProxyDocument
|
|
76
86
|
function isProxyDocument(target) {
|
|
77
87
|
return toString.call(target) === '[object ProxyDocument]';
|
|
@@ -334,7 +344,8 @@ function isInvalidQuerySelectorKey(key) {
|
|
|
334
344
|
function isUniqueElement(key) {
|
|
335
345
|
return (/^body$/i.test(key) ||
|
|
336
346
|
/^head$/i.test(key) ||
|
|
337
|
-
/^html$/i.test(key)
|
|
347
|
+
/^html$/i.test(key) ||
|
|
348
|
+
/^title$/i.test(key));
|
|
338
349
|
}
|
|
339
350
|
/**
|
|
340
351
|
* get micro-app element
|
|
@@ -483,6 +494,20 @@ function serialExecFiberTasks(tasks) {
|
|
|
483
494
|
function isInlineScript(address) {
|
|
484
495
|
return address.startsWith('inline-');
|
|
485
496
|
}
|
|
497
|
+
/**
|
|
498
|
+
* call function with try catch
|
|
499
|
+
* @param fn target function
|
|
500
|
+
* @param appName app.name
|
|
501
|
+
* @param args arguments
|
|
502
|
+
*/
|
|
503
|
+
function callFnWithTryCatch(fn, appName, msgSuffix, ...args) {
|
|
504
|
+
try {
|
|
505
|
+
isFunction(fn) && fn(...args);
|
|
506
|
+
}
|
|
507
|
+
catch (e) {
|
|
508
|
+
logError(`an error occurred in app ${appName} ${msgSuffix} \n`, null, e);
|
|
509
|
+
}
|
|
510
|
+
}
|
|
486
511
|
|
|
487
512
|
var ObservedAttrName;
|
|
488
513
|
(function (ObservedAttrName) {
|
|
@@ -513,12 +538,39 @@ var lifeCycles;
|
|
|
513
538
|
lifeCycles["AFTERSHOW"] = "aftershow";
|
|
514
539
|
lifeCycles["AFTERHIDDEN"] = "afterhidden";
|
|
515
540
|
})(lifeCycles || (lifeCycles = {}));
|
|
541
|
+
// global event of child app
|
|
542
|
+
var microGlobalEvent;
|
|
543
|
+
(function (microGlobalEvent) {
|
|
544
|
+
microGlobalEvent["ONMOUNT"] = "onmount";
|
|
545
|
+
microGlobalEvent["ONUNMOUNT"] = "onunmount";
|
|
546
|
+
})(microGlobalEvent || (microGlobalEvent = {}));
|
|
516
547
|
// keep-alive status
|
|
517
548
|
var keepAliveStates;
|
|
518
549
|
(function (keepAliveStates) {
|
|
519
550
|
keepAliveStates["KEEP_ALIVE_SHOW"] = "keep_alive_show";
|
|
520
551
|
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "keep_alive_hidden";
|
|
521
552
|
})(keepAliveStates || (keepAliveStates = {}));
|
|
553
|
+
// micro-app config
|
|
554
|
+
var MicroAppConfig;
|
|
555
|
+
(function (MicroAppConfig) {
|
|
556
|
+
MicroAppConfig["DESTROY"] = "destroy";
|
|
557
|
+
MicroAppConfig["DESTORY"] = "destory";
|
|
558
|
+
MicroAppConfig["INLINE"] = "inline";
|
|
559
|
+
MicroAppConfig["DISABLESCOPECSS"] = "disableScopecss";
|
|
560
|
+
MicroAppConfig["DISABLESANDBOX"] = "disableSandbox";
|
|
561
|
+
MicroAppConfig["DISABLE_SCOPECSS"] = "disable-scopecss";
|
|
562
|
+
MicroAppConfig["DISABLE_SANDBOX"] = "disable-sandbox";
|
|
563
|
+
MicroAppConfig["DISABLE_MEMORY_ROUTER"] = "disable-memory-router";
|
|
564
|
+
MicroAppConfig["DISABLE_PATCH_REQUEST"] = "disable-patch-request";
|
|
565
|
+
MicroAppConfig["KEEP_ROUTER_STATE"] = "keep-router-state";
|
|
566
|
+
MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
|
|
567
|
+
MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
|
|
568
|
+
MicroAppConfig["CLEAR_DATA"] = "clear-data";
|
|
569
|
+
MicroAppConfig["ESMODULE"] = "esmodule";
|
|
570
|
+
MicroAppConfig["SSR"] = "ssr";
|
|
571
|
+
MicroAppConfig["FIBER"] = "fiber";
|
|
572
|
+
})(MicroAppConfig || (MicroAppConfig = {}));
|
|
573
|
+
const PREFETCH_LEVEL = [1, 2, 3];
|
|
522
574
|
/**
|
|
523
575
|
* global key must be static key, they can not rewrite
|
|
524
576
|
* e.g.
|
|
@@ -527,7 +579,7 @@ var keepAliveStates;
|
|
|
527
579
|
* NOTE:
|
|
528
580
|
* 1. Do not add fetch, XMLHttpRequest, EventSource
|
|
529
581
|
*/
|
|
530
|
-
const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,
|
|
582
|
+
const globalKeyToBeCached = 'window,self,globalThis,document,Document,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
|
|
531
583
|
|
|
532
584
|
/**
|
|
533
585
|
* fetch source of html, js, css
|
|
@@ -1319,10 +1371,9 @@ class Adapter {
|
|
|
1319
1371
|
];
|
|
1320
1372
|
this.injectReactHRMProperty();
|
|
1321
1373
|
}
|
|
1322
|
-
// TODO: __DEV__ process.env.NODE_ENV !== 'production'
|
|
1323
1374
|
// adapter for react
|
|
1324
1375
|
injectReactHRMProperty() {
|
|
1325
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1376
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
1326
1377
|
// react child in non-react env
|
|
1327
1378
|
this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
|
|
1328
1379
|
// in react parent
|
|
@@ -1346,7 +1397,7 @@ function fixBabelPolyfill6() {
|
|
|
1346
1397
|
*/
|
|
1347
1398
|
function fixReactHMRConflict(app) {
|
|
1348
1399
|
var _a;
|
|
1349
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1400
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
1350
1401
|
const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
1351
1402
|
const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
1352
1403
|
if (rawReactErrorHook && childReactErrorHook) {
|
|
@@ -1366,16 +1417,21 @@ function fixReactHMRConflict(app) {
|
|
|
1366
1417
|
function throttleDeferForParentNode(proxyDocument) {
|
|
1367
1418
|
const html = globalEnv.rawDocument.firstElementChild;
|
|
1368
1419
|
if (html && html.parentNode !== proxyDocument) {
|
|
1369
|
-
|
|
1420
|
+
setParentNode(html, proxyDocument);
|
|
1370
1421
|
defer(() => {
|
|
1371
|
-
|
|
1422
|
+
setParentNode(html, globalEnv.rawDocument);
|
|
1372
1423
|
});
|
|
1373
1424
|
}
|
|
1374
1425
|
}
|
|
1375
|
-
|
|
1376
|
-
|
|
1426
|
+
/**
|
|
1427
|
+
* Modify the point of parentNode
|
|
1428
|
+
* @param target target Node
|
|
1429
|
+
* @param value parentNode
|
|
1430
|
+
*/
|
|
1431
|
+
function setParentNode(target, value) {
|
|
1432
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, 'parentNode');
|
|
1377
1433
|
if (!descriptor || descriptor.configurable) {
|
|
1378
|
-
|
|
1434
|
+
rawDefineProperty(target, 'parentNode', {
|
|
1379
1435
|
value,
|
|
1380
1436
|
configurable: true,
|
|
1381
1437
|
});
|
|
@@ -1457,37 +1513,56 @@ function handleNewNode(parent, child, app) {
|
|
|
1457
1513
|
* @param passiveChild second param of insertBefore and replaceChild
|
|
1458
1514
|
*/
|
|
1459
1515
|
function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
|
|
1460
|
-
const
|
|
1516
|
+
const hijackParent = getHijackParent(parent, app);
|
|
1461
1517
|
/**
|
|
1462
1518
|
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
1463
1519
|
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
1464
1520
|
*/
|
|
1465
|
-
if (
|
|
1521
|
+
if (hijackParent) {
|
|
1522
|
+
/**
|
|
1523
|
+
* WARNING:
|
|
1524
|
+
* Verifying that the parentNode of the targetChild points to document.body will cause other problems ?
|
|
1525
|
+
*/
|
|
1526
|
+
if (hijackParent.tagName === 'MICRO-APP-BODY' && rawMethod !== globalEnv.rawRemoveChild) {
|
|
1527
|
+
const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
|
|
1528
|
+
if (!descriptor || descriptor.configurable) {
|
|
1529
|
+
rawDefineProperty(targetChild, 'parentNode', {
|
|
1530
|
+
configurable: true,
|
|
1531
|
+
get() {
|
|
1532
|
+
/**
|
|
1533
|
+
* When operate child from parentNode async, may have been unmount
|
|
1534
|
+
* e.g.
|
|
1535
|
+
* target.parentNode.remove(target)
|
|
1536
|
+
*/
|
|
1537
|
+
return !app.container ? hijackParent : document.body;
|
|
1538
|
+
},
|
|
1539
|
+
});
|
|
1540
|
+
}
|
|
1541
|
+
}
|
|
1466
1542
|
/**
|
|
1467
1543
|
* 1. If passiveChild exists, it must be insertBefore or replaceChild
|
|
1468
1544
|
* 2. When removeChild, targetChild may not be in microAppHead or head
|
|
1469
1545
|
*/
|
|
1470
|
-
if (passiveChild && !
|
|
1471
|
-
return globalEnv.rawAppendChild.call(
|
|
1546
|
+
if (passiveChild && !hijackParent.contains(passiveChild)) {
|
|
1547
|
+
return globalEnv.rawAppendChild.call(hijackParent, targetChild);
|
|
1472
1548
|
}
|
|
1473
|
-
else if (rawMethod === globalEnv.rawRemoveChild && !
|
|
1549
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
|
|
1474
1550
|
if (parent.contains(targetChild)) {
|
|
1475
1551
|
return rawMethod.call(parent, targetChild);
|
|
1476
1552
|
}
|
|
1477
1553
|
return targetChild;
|
|
1478
1554
|
}
|
|
1479
|
-
|
|
1480
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
1555
|
+
if ((process.env.NODE_ENV !== 'production') &&
|
|
1481
1556
|
targetChild instanceof HTMLIFrameElement &&
|
|
1482
1557
|
rawMethod === globalEnv.rawAppendChild) {
|
|
1483
1558
|
fixReactHMRConflict(app);
|
|
1484
1559
|
}
|
|
1485
|
-
return invokeRawMethod(rawMethod,
|
|
1560
|
+
return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
|
|
1486
1561
|
}
|
|
1487
1562
|
return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
|
|
1488
1563
|
}
|
|
1489
1564
|
// head/body map to micro-app-head/micro-app-body
|
|
1490
|
-
function
|
|
1565
|
+
function getHijackParent(node, app) {
|
|
1491
1566
|
var _a, _b;
|
|
1492
1567
|
if (node === document.head) {
|
|
1493
1568
|
return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
|
|
@@ -1520,13 +1595,13 @@ function getMappingNode(node) {
|
|
|
1520
1595
|
*/
|
|
1521
1596
|
function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
1522
1597
|
const currentAppName = getCurrentAppName();
|
|
1523
|
-
if (newChild
|
|
1598
|
+
if (isNode(newChild) &&
|
|
1524
1599
|
(newChild.__MICRO_APP_NAME__ ||
|
|
1525
1600
|
(currentAppName && !newChild.__PURE_ELEMENT__))) {
|
|
1526
1601
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1527
1602
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1528
1603
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1529
|
-
if (newChild
|
|
1604
|
+
if (isElement(newChild)) {
|
|
1530
1605
|
if (/^(img|script)$/i.test(newChild.tagName)) {
|
|
1531
1606
|
if (newChild.hasAttribute('src')) {
|
|
1532
1607
|
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
@@ -1546,7 +1621,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1546
1621
|
}
|
|
1547
1622
|
}
|
|
1548
1623
|
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1549
|
-
if (!(newChild
|
|
1624
|
+
if (!isNode(newChild) && currentAppName) {
|
|
1550
1625
|
const app = appInstanceMap.get(currentAppName);
|
|
1551
1626
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1552
1627
|
if (parent === document.head) {
|
|
@@ -1593,7 +1668,6 @@ function patchElementPrototypeMethods() {
|
|
|
1593
1668
|
};
|
|
1594
1669
|
// prototype methods of delete element👇
|
|
1595
1670
|
Element.prototype.removeChild = function removeChild(oldChild) {
|
|
1596
|
-
var _a;
|
|
1597
1671
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1598
1672
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1599
1673
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -1602,8 +1676,8 @@ function patchElementPrototypeMethods() {
|
|
|
1602
1676
|
try {
|
|
1603
1677
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1604
1678
|
}
|
|
1605
|
-
catch (
|
|
1606
|
-
return (
|
|
1679
|
+
catch (_a) {
|
|
1680
|
+
return ((oldChild === null || oldChild === void 0 ? void 0 : oldChild.parentNode) && globalEnv.rawRemoveChild.call(oldChild.parentNode, oldChild));
|
|
1607
1681
|
}
|
|
1608
1682
|
}
|
|
1609
1683
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
@@ -2142,7 +2216,7 @@ function fetchScriptsFromHtml(wrapElement, app) {
|
|
|
2142
2216
|
for (const address of scriptList) {
|
|
2143
2217
|
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2144
2218
|
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2145
|
-
if ((!appSpaceData.defer && !appSpaceData.async) || app.isPrefetch) {
|
|
2219
|
+
if ((!appSpaceData.defer && !appSpaceData.async) || (app.isPrefetch && !app.isPrerender)) {
|
|
2146
2220
|
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
2147
2221
|
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
2148
2222
|
}
|
|
@@ -2183,7 +2257,7 @@ function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
|
2183
2257
|
* 2. if app is inline or script is esmodule, skip this step
|
|
2184
2258
|
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
2185
2259
|
*/
|
|
2186
|
-
if (app.isPrefetch) {
|
|
2260
|
+
if (app.isPrefetch && app.prefetchLevel === 2) {
|
|
2187
2261
|
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2188
2262
|
/**
|
|
2189
2263
|
* When prefetch app is replaced by a new app in the processing phase, since the scriptInfo is common, when the scriptInfo of the prefetch app is processed, it may have already been processed.
|
|
@@ -2503,12 +2577,20 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2503
2577
|
else if (dom instanceof HTMLScriptElement) {
|
|
2504
2578
|
extractScriptElement(dom, parent, app);
|
|
2505
2579
|
}
|
|
2506
|
-
else if (dom instanceof HTMLMetaElement || dom instanceof HTMLTitleElement) {
|
|
2507
|
-
parent.removeChild(dom);
|
|
2508
|
-
}
|
|
2509
2580
|
else if (dom instanceof HTMLImageElement && dom.hasAttribute('src')) {
|
|
2510
2581
|
dom.setAttribute('src', CompletionPath(dom.getAttribute('src'), app.url));
|
|
2511
2582
|
}
|
|
2583
|
+
/**
|
|
2584
|
+
* Don't remove meta and title, they have some special scenes
|
|
2585
|
+
* e.g.
|
|
2586
|
+
* document.querySelector('meta[name="viewport"]') // for flexible
|
|
2587
|
+
* document.querySelector('meta[name="baseurl"]').baseurl // for api request
|
|
2588
|
+
*
|
|
2589
|
+
* Title point to main app title, child app title used to be compatible with some special scenes
|
|
2590
|
+
*/
|
|
2591
|
+
// else if (dom instanceof HTMLMetaElement || dom instanceof HTMLTitleElement) {
|
|
2592
|
+
// parent.removeChild(dom)
|
|
2593
|
+
// }
|
|
2512
2594
|
}
|
|
2513
2595
|
}
|
|
2514
2596
|
/**
|
|
@@ -2551,6 +2633,39 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2551
2633
|
class EventCenter {
|
|
2552
2634
|
constructor() {
|
|
2553
2635
|
this.eventList = new Map();
|
|
2636
|
+
this.queue = [];
|
|
2637
|
+
this.recordStep = {};
|
|
2638
|
+
// run task
|
|
2639
|
+
this.process = () => {
|
|
2640
|
+
var _a, _b;
|
|
2641
|
+
let name;
|
|
2642
|
+
const temRecordStep = this.recordStep;
|
|
2643
|
+
const queue = this.queue;
|
|
2644
|
+
this.recordStep = {};
|
|
2645
|
+
this.queue = [];
|
|
2646
|
+
while (name = queue.shift()) {
|
|
2647
|
+
const eventInfo = this.eventList.get(name);
|
|
2648
|
+
// clear tempData, force before exec nextStep
|
|
2649
|
+
const tempData = eventInfo.tempData;
|
|
2650
|
+
const force = eventInfo.force;
|
|
2651
|
+
eventInfo.tempData = null;
|
|
2652
|
+
eventInfo.force = false;
|
|
2653
|
+
let resArr;
|
|
2654
|
+
if (force || !this.isEqual(eventInfo.data, tempData)) {
|
|
2655
|
+
eventInfo.data = tempData || eventInfo.data;
|
|
2656
|
+
for (const f of eventInfo.callbacks) {
|
|
2657
|
+
const res = f(eventInfo.data);
|
|
2658
|
+
res && (resArr !== null && resArr !== void 0 ? resArr : (resArr = [])).push(res);
|
|
2659
|
+
}
|
|
2660
|
+
(_b = (_a = temRecordStep[name]).dispatchDataEvent) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
2661
|
+
/**
|
|
2662
|
+
* WARING:
|
|
2663
|
+
* If data of other app is sent in nextStep, it may cause confusion of tempData and force
|
|
2664
|
+
*/
|
|
2665
|
+
temRecordStep[name].nextStepList.forEach((nextStep) => nextStep(resArr));
|
|
2666
|
+
}
|
|
2667
|
+
}
|
|
2668
|
+
};
|
|
2554
2669
|
}
|
|
2555
2670
|
// whether the name is legal
|
|
2556
2671
|
isLegalName(name) {
|
|
@@ -2560,6 +2675,39 @@ class EventCenter {
|
|
|
2560
2675
|
}
|
|
2561
2676
|
return true;
|
|
2562
2677
|
}
|
|
2678
|
+
// add appName to queue
|
|
2679
|
+
enqueue(name, nextStep, dispatchDataEvent) {
|
|
2680
|
+
// this.nextStepList.push(nextStep)
|
|
2681
|
+
if (this.recordStep[name]) {
|
|
2682
|
+
this.recordStep[name].nextStepList.push(nextStep);
|
|
2683
|
+
dispatchDataEvent && (this.recordStep[name].dispatchDataEvent = dispatchDataEvent);
|
|
2684
|
+
}
|
|
2685
|
+
else {
|
|
2686
|
+
this.recordStep[name] = {
|
|
2687
|
+
nextStepList: [nextStep],
|
|
2688
|
+
dispatchDataEvent,
|
|
2689
|
+
};
|
|
2690
|
+
}
|
|
2691
|
+
/**
|
|
2692
|
+
* The micro task is executed async when the second render of child.
|
|
2693
|
+
* We should ensure that the data changes are executed before binding the listening function
|
|
2694
|
+
*/
|
|
2695
|
+
(!this.queue.includes(name) && this.queue.push(name) === 1) && defer(this.process);
|
|
2696
|
+
}
|
|
2697
|
+
/**
|
|
2698
|
+
* In react, each setState will trigger setData, so we need a filter operation to avoid repeated trigger
|
|
2699
|
+
*/
|
|
2700
|
+
isEqual(oldData, newData) {
|
|
2701
|
+
if (!newData || Object.keys(oldData).length !== Object.keys(newData).length)
|
|
2702
|
+
return false;
|
|
2703
|
+
for (const key in oldData) {
|
|
2704
|
+
if (Object.prototype.hasOwnProperty.call(oldData, key)) {
|
|
2705
|
+
if (oldData[key] !== newData[key])
|
|
2706
|
+
return false;
|
|
2707
|
+
}
|
|
2708
|
+
}
|
|
2709
|
+
return true;
|
|
2710
|
+
}
|
|
2563
2711
|
/**
|
|
2564
2712
|
* add listener
|
|
2565
2713
|
* @param name event name
|
|
@@ -2579,7 +2727,10 @@ class EventCenter {
|
|
|
2579
2727
|
};
|
|
2580
2728
|
this.eventList.set(name, eventInfo);
|
|
2581
2729
|
}
|
|
2582
|
-
else if (autoTrigger &&
|
|
2730
|
+
else if (autoTrigger &&
|
|
2731
|
+
Object.keys(eventInfo.data).length &&
|
|
2732
|
+
(!this.queue.includes(name) ||
|
|
2733
|
+
this.isEqual(eventInfo.data, eventInfo.tempData))) {
|
|
2583
2734
|
// auto trigger when data not null
|
|
2584
2735
|
f(eventInfo.data);
|
|
2585
2736
|
}
|
|
@@ -2600,21 +2751,27 @@ class EventCenter {
|
|
|
2600
2751
|
}
|
|
2601
2752
|
}
|
|
2602
2753
|
}
|
|
2754
|
+
/**
|
|
2755
|
+
* clearData
|
|
2756
|
+
*/
|
|
2757
|
+
clearData(name) {
|
|
2758
|
+
if (this.isLegalName(name)) {
|
|
2759
|
+
const eventInfo = this.eventList.get(name);
|
|
2760
|
+
if (eventInfo) {
|
|
2761
|
+
eventInfo.data = {};
|
|
2762
|
+
}
|
|
2763
|
+
}
|
|
2764
|
+
}
|
|
2603
2765
|
// dispatch data
|
|
2604
|
-
dispatch(name, data) {
|
|
2766
|
+
dispatch(name, data, nextStep, force, dispatchDataEvent) {
|
|
2605
2767
|
if (this.isLegalName(name)) {
|
|
2606
2768
|
if (!isPlainObject(data)) {
|
|
2607
2769
|
return logError('event-center: data must be object');
|
|
2608
2770
|
}
|
|
2609
2771
|
let eventInfo = this.eventList.get(name);
|
|
2610
2772
|
if (eventInfo) {
|
|
2611
|
-
|
|
2612
|
-
|
|
2613
|
-
eventInfo.data = data;
|
|
2614
|
-
for (const f of eventInfo.callbacks) {
|
|
2615
|
-
f(data);
|
|
2616
|
-
}
|
|
2617
|
-
}
|
|
2773
|
+
eventInfo.tempData = assign({}, eventInfo.tempData || eventInfo.data, data);
|
|
2774
|
+
!eventInfo.force && (eventInfo.force = !!force);
|
|
2618
2775
|
}
|
|
2619
2776
|
else {
|
|
2620
2777
|
eventInfo = {
|
|
@@ -2622,7 +2779,13 @@ class EventCenter {
|
|
|
2622
2779
|
callbacks: new Set(),
|
|
2623
2780
|
};
|
|
2624
2781
|
this.eventList.set(name, eventInfo);
|
|
2782
|
+
/**
|
|
2783
|
+
* When sent data to parent, eventInfo probably does not exist, because parent may listen to datachange
|
|
2784
|
+
*/
|
|
2785
|
+
eventInfo.force = true;
|
|
2625
2786
|
}
|
|
2787
|
+
// add to queue, event eventInfo is null
|
|
2788
|
+
this.enqueue(name, nextStep, dispatchDataEvent);
|
|
2626
2789
|
}
|
|
2627
2790
|
}
|
|
2628
2791
|
// get data
|
|
@@ -2671,10 +2834,13 @@ class EventCenterForGlobal {
|
|
|
2671
2834
|
* dispatch global data
|
|
2672
2835
|
* @param data data
|
|
2673
2836
|
*/
|
|
2674
|
-
setGlobalData(data) {
|
|
2837
|
+
setGlobalData(data, nextStep, force) {
|
|
2675
2838
|
// clear dom scope before dispatch global data, apply to micro app
|
|
2676
2839
|
removeDomScope();
|
|
2677
|
-
eventCenter.dispatch('global', data);
|
|
2840
|
+
eventCenter.dispatch('global', data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
|
|
2841
|
+
}
|
|
2842
|
+
forceSetGlobalData(data, nextStep) {
|
|
2843
|
+
this.setGlobalData(data, nextStep, true);
|
|
2678
2844
|
}
|
|
2679
2845
|
/**
|
|
2680
2846
|
* get global data
|
|
@@ -2682,6 +2848,12 @@ class EventCenterForGlobal {
|
|
|
2682
2848
|
getGlobalData() {
|
|
2683
2849
|
return eventCenter.getData('global');
|
|
2684
2850
|
}
|
|
2851
|
+
/**
|
|
2852
|
+
* clear global data
|
|
2853
|
+
*/
|
|
2854
|
+
clearGlobalData() {
|
|
2855
|
+
eventCenter.clearData('global');
|
|
2856
|
+
}
|
|
2685
2857
|
/**
|
|
2686
2858
|
* clear all listener of global data
|
|
2687
2859
|
* if appName exists, only the specified functions is cleared
|
|
@@ -2732,8 +2904,19 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2732
2904
|
* @param appName app.name
|
|
2733
2905
|
* @param data data
|
|
2734
2906
|
*/
|
|
2735
|
-
setData(appName, data) {
|
|
2736
|
-
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data);
|
|
2907
|
+
setData(appName, data, nextStep, force) {
|
|
2908
|
+
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
|
|
2909
|
+
}
|
|
2910
|
+
forceSetData(appName, data, nextStep) {
|
|
2911
|
+
this.setData(appName, data, nextStep, true);
|
|
2912
|
+
}
|
|
2913
|
+
/**
|
|
2914
|
+
* clear data from base app
|
|
2915
|
+
* @param appName app.name
|
|
2916
|
+
* @param fromBaseApp whether clear data from child app, default is true
|
|
2917
|
+
*/
|
|
2918
|
+
clearData(appName, fromBaseApp = true) {
|
|
2919
|
+
eventCenter.clearData(formatEventName(formatAppName(appName), fromBaseApp));
|
|
2737
2920
|
}
|
|
2738
2921
|
/**
|
|
2739
2922
|
* clear all listener for specified micro app
|
|
@@ -2769,25 +2952,36 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
2769
2952
|
/**
|
|
2770
2953
|
* get data from base app
|
|
2771
2954
|
*/
|
|
2772
|
-
getData() {
|
|
2773
|
-
return eventCenter.getData(formatEventName(this.appName,
|
|
2955
|
+
getData(fromBaseApp = true) {
|
|
2956
|
+
return eventCenter.getData(formatEventName(this.appName, fromBaseApp));
|
|
2774
2957
|
}
|
|
2775
2958
|
/**
|
|
2776
2959
|
* dispatch data to base app
|
|
2777
2960
|
* @param data data
|
|
2778
2961
|
*/
|
|
2779
|
-
dispatch(data) {
|
|
2962
|
+
dispatch(data, nextStep, force) {
|
|
2780
2963
|
removeDomScope();
|
|
2781
|
-
eventCenter.dispatch(formatEventName(this.appName, false), data)
|
|
2782
|
-
|
|
2783
|
-
|
|
2784
|
-
|
|
2785
|
-
|
|
2786
|
-
|
|
2787
|
-
|
|
2788
|
-
|
|
2789
|
-
|
|
2790
|
-
|
|
2964
|
+
eventCenter.dispatch(formatEventName(this.appName, false), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force, () => {
|
|
2965
|
+
const app = appInstanceMap.get(this.appName);
|
|
2966
|
+
if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
|
|
2967
|
+
const event = new CustomEvent('datachange', {
|
|
2968
|
+
detail: {
|
|
2969
|
+
data: eventCenter.getData(formatEventName(this.appName, false))
|
|
2970
|
+
}
|
|
2971
|
+
});
|
|
2972
|
+
getRootContainer(app.container).dispatchEvent(event);
|
|
2973
|
+
}
|
|
2974
|
+
});
|
|
2975
|
+
}
|
|
2976
|
+
forceDispatch(data, nextStep) {
|
|
2977
|
+
this.dispatch(data, nextStep, true);
|
|
2978
|
+
}
|
|
2979
|
+
/**
|
|
2980
|
+
* clear data from child app
|
|
2981
|
+
* @param fromBaseApp whether clear data from base app, default is false
|
|
2982
|
+
*/
|
|
2983
|
+
clearData(fromBaseApp = false) {
|
|
2984
|
+
eventCenter.clearData(formatEventName(this.appName, fromBaseApp));
|
|
2791
2985
|
}
|
|
2792
2986
|
/**
|
|
2793
2987
|
* clear all listeners
|
|
@@ -2977,12 +3171,14 @@ function effectDocumentEvent() {
|
|
|
2977
3171
|
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
2978
3172
|
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
2979
3173
|
document.addEventListener = function (type, listener, options) {
|
|
2980
|
-
var _a;
|
|
2981
3174
|
const appName = getCurrentAppName();
|
|
2982
3175
|
/**
|
|
2983
3176
|
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
3177
|
+
* update in 2022-09-02:
|
|
3178
|
+
* boundFunction is no longer exclude, because events in UMD mode will not cleared from v1.0.0-alpha.4
|
|
3179
|
+
* if (appName && !(appInstanceMap.get(appName)?.umdMode && isBoundFunction(listener))) {
|
|
2984
3180
|
*/
|
|
2985
|
-
if (appName
|
|
3181
|
+
if (appName) {
|
|
2986
3182
|
const appListenersMap = documentEventListenerMap.get(appName);
|
|
2987
3183
|
if (appListenersMap) {
|
|
2988
3184
|
const appListenerList = appListenersMap.get(type);
|
|
@@ -3001,9 +3197,13 @@ function effectDocumentEvent() {
|
|
|
3001
3197
|
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
3002
3198
|
};
|
|
3003
3199
|
document.removeEventListener = function (type, listener, options) {
|
|
3004
|
-
var _a;
|
|
3005
3200
|
const appName = getCurrentAppName();
|
|
3006
|
-
|
|
3201
|
+
/**
|
|
3202
|
+
* update in 2022-09-02:
|
|
3203
|
+
* boundFunction is no longer exclude, because events in UMD mode will not cleared from v1.0.0-alpha.4
|
|
3204
|
+
* if (appName && !(appInstanceMap.get(appName)?.umdMode && isBoundFunction(listener))) {
|
|
3205
|
+
*/
|
|
3206
|
+
if (appName) {
|
|
3007
3207
|
const appListenersMap = documentEventListenerMap.get(appName);
|
|
3008
3208
|
if (appListenersMap) {
|
|
3009
3209
|
const appListenerList = appListenersMap.get(type);
|
|
@@ -3068,69 +3268,80 @@ function effect(appName, microAppWindow) {
|
|
|
3068
3268
|
timeoutIdMap.delete(timeoutId);
|
|
3069
3269
|
rawClearTimeout.call(rawWindow, timeoutId);
|
|
3070
3270
|
};
|
|
3071
|
-
const
|
|
3072
|
-
const
|
|
3073
|
-
let
|
|
3074
|
-
let
|
|
3075
|
-
let
|
|
3076
|
-
const
|
|
3077
|
-
|
|
3078
|
-
|
|
3079
|
-
|
|
3080
|
-
|
|
3081
|
-
|
|
3271
|
+
const sstWindowListenerMap = new Map();
|
|
3272
|
+
const sstDocumentListenerMap = new Map();
|
|
3273
|
+
let sstIntervalIdMap = new Map();
|
|
3274
|
+
let sstTimeoutIdMap = new Map();
|
|
3275
|
+
let sstOnClickHandler;
|
|
3276
|
+
const clearSnapshotData = () => {
|
|
3277
|
+
sstWindowListenerMap.clear();
|
|
3278
|
+
sstIntervalIdMap.clear();
|
|
3279
|
+
sstTimeoutIdMap.clear();
|
|
3280
|
+
sstDocumentListenerMap.clear();
|
|
3281
|
+
sstOnClickHandler = null;
|
|
3082
3282
|
};
|
|
3083
|
-
|
|
3084
|
-
|
|
3283
|
+
/**
|
|
3284
|
+
* record event and timer
|
|
3285
|
+
* Scenes:
|
|
3286
|
+
* 1. exec umdMountHook in umd mode
|
|
3287
|
+
* 2. hidden keep-alive app
|
|
3288
|
+
* 3. after init prerender app
|
|
3289
|
+
*/
|
|
3290
|
+
const recordEffect = () => {
|
|
3085
3291
|
// record window event
|
|
3086
3292
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3087
3293
|
if (listenerList.size) {
|
|
3088
|
-
|
|
3294
|
+
sstWindowListenerMap.set(type, new Set(listenerList));
|
|
3089
3295
|
}
|
|
3090
3296
|
});
|
|
3091
3297
|
// record timers
|
|
3092
3298
|
if (intervalIdMap.size) {
|
|
3093
|
-
|
|
3299
|
+
sstIntervalIdMap = new Map(intervalIdMap);
|
|
3094
3300
|
}
|
|
3095
3301
|
if (timeoutIdMap.size) {
|
|
3096
|
-
|
|
3302
|
+
sstTimeoutIdMap = new Map(timeoutIdMap);
|
|
3097
3303
|
}
|
|
3098
3304
|
// record onclick handler
|
|
3099
|
-
|
|
3305
|
+
sstOnClickHandler = documentClickListMap.get(appName);
|
|
3100
3306
|
// record document event
|
|
3101
3307
|
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
3102
3308
|
if (documentAppListenersMap) {
|
|
3103
3309
|
documentAppListenersMap.forEach((listenerList, type) => {
|
|
3104
3310
|
if (listenerList.size) {
|
|
3105
|
-
|
|
3311
|
+
sstDocumentListenerMap.set(type, new Set(listenerList));
|
|
3106
3312
|
}
|
|
3107
3313
|
});
|
|
3108
3314
|
}
|
|
3109
3315
|
};
|
|
3110
|
-
// rebuild event and timer before remount
|
|
3111
|
-
const
|
|
3316
|
+
// rebuild event and timer before remount app
|
|
3317
|
+
const rebuildEffect = () => {
|
|
3112
3318
|
// rebuild window event
|
|
3113
|
-
|
|
3319
|
+
sstWindowListenerMap.forEach((listenerList, type) => {
|
|
3114
3320
|
for (const listener of listenerList) {
|
|
3115
3321
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3116
3322
|
}
|
|
3117
3323
|
});
|
|
3118
3324
|
// rebuild timer
|
|
3119
|
-
|
|
3325
|
+
sstIntervalIdMap.forEach((info) => {
|
|
3120
3326
|
microAppWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
3121
3327
|
});
|
|
3122
|
-
|
|
3328
|
+
sstTimeoutIdMap.forEach((info) => {
|
|
3123
3329
|
microAppWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
3124
3330
|
});
|
|
3125
3331
|
// rebuild onclick event
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3332
|
+
sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
|
|
3333
|
+
/**
|
|
3334
|
+
* rebuild document event
|
|
3335
|
+
* WARNING!!: do not delete setCurrentAppName & removeDomScope
|
|
3336
|
+
*/
|
|
3337
|
+
setCurrentAppName(appName);
|
|
3338
|
+
sstDocumentListenerMap.forEach((listenerList, type) => {
|
|
3129
3339
|
for (const listener of listenerList) {
|
|
3130
3340
|
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3131
3341
|
}
|
|
3132
3342
|
});
|
|
3133
|
-
|
|
3343
|
+
removeDomScope();
|
|
3344
|
+
clearSnapshotData();
|
|
3134
3345
|
};
|
|
3135
3346
|
// release all event listener & interval & timeout when unmount app
|
|
3136
3347
|
const releaseEffect = () => {
|
|
@@ -3170,8 +3381,8 @@ function effect(appName, microAppWindow) {
|
|
|
3170
3381
|
}
|
|
3171
3382
|
};
|
|
3172
3383
|
return {
|
|
3173
|
-
|
|
3174
|
-
|
|
3384
|
+
recordEffect,
|
|
3385
|
+
rebuildEffect,
|
|
3175
3386
|
releaseEffect,
|
|
3176
3387
|
};
|
|
3177
3388
|
}
|
|
@@ -3197,7 +3408,6 @@ function removeMicroState(appName, rawState) {
|
|
|
3197
3408
|
delete rawState.microAppState;
|
|
3198
3409
|
}
|
|
3199
3410
|
}
|
|
3200
|
-
// 生成新的state对象
|
|
3201
3411
|
return assign({}, rawState);
|
|
3202
3412
|
}
|
|
3203
3413
|
// get micro app state form origin state
|
|
@@ -3209,12 +3419,15 @@ const ENC_AD_RE = /&/g; // %M1
|
|
|
3209
3419
|
const ENC_EQ_RE = /=/g; // %M2
|
|
3210
3420
|
const DEC_AD_RE = /%M1/g; // &
|
|
3211
3421
|
const DEC_EQ_RE = /%M2/g; // =
|
|
3422
|
+
// encode path with special symbol
|
|
3212
3423
|
function encodeMicroPath(path) {
|
|
3213
3424
|
return encodeURIComponent(commonDecode(path).replace(ENC_AD_RE, '%M1').replace(ENC_EQ_RE, '%M2'));
|
|
3214
3425
|
}
|
|
3426
|
+
// decode path
|
|
3215
3427
|
function decodeMicroPath(path) {
|
|
3216
3428
|
return commonDecode(path).replace(DEC_AD_RE, '&').replace(DEC_EQ_RE, '=');
|
|
3217
3429
|
}
|
|
3430
|
+
// Recursively resolve address
|
|
3218
3431
|
function commonDecode(path) {
|
|
3219
3432
|
try {
|
|
3220
3433
|
const decPath = decodeURIComponent(path);
|
|
@@ -3226,12 +3439,15 @@ function commonDecode(path) {
|
|
|
3226
3439
|
return path;
|
|
3227
3440
|
}
|
|
3228
3441
|
}
|
|
3229
|
-
//
|
|
3442
|
+
// Format the query parameter key to prevent conflicts with the original parameters
|
|
3230
3443
|
function formatQueryAppName(appName) {
|
|
3231
3444
|
// return `app-${appName}`
|
|
3232
3445
|
return appName;
|
|
3233
3446
|
}
|
|
3234
|
-
|
|
3447
|
+
/**
|
|
3448
|
+
* Get app fullPath from browser url
|
|
3449
|
+
* @param appName app.name
|
|
3450
|
+
*/
|
|
3235
3451
|
function getMicroPathFromURL(appName) {
|
|
3236
3452
|
var _a, _b;
|
|
3237
3453
|
const rawLocation = globalEnv.rawWindow.location;
|
|
@@ -3239,15 +3455,23 @@ function getMicroPathFromURL(appName) {
|
|
|
3239
3455
|
const microPath = ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) || ((_b = queryObject.searchQuery) === null || _b === void 0 ? void 0 : _b[formatQueryAppName(appName)]);
|
|
3240
3456
|
return isString(microPath) ? decodeMicroPath(microPath) : null;
|
|
3241
3457
|
}
|
|
3242
|
-
|
|
3458
|
+
/**
|
|
3459
|
+
* Attach child app fullPath to browser url
|
|
3460
|
+
* @param appName app.name
|
|
3461
|
+
* @param microLocation location of child app
|
|
3462
|
+
*/
|
|
3243
3463
|
function setMicroPathToURL(appName, microLocation) {
|
|
3244
3464
|
let { pathname, search, hash } = globalEnv.rawWindow.location;
|
|
3245
3465
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
3246
3466
|
const encodedMicroPath = encodeMicroPath(microLocation.pathname +
|
|
3247
3467
|
microLocation.search +
|
|
3248
3468
|
microLocation.hash);
|
|
3249
|
-
|
|
3250
|
-
|
|
3469
|
+
/**
|
|
3470
|
+
* Is parent is hash router
|
|
3471
|
+
* In fact, this is not true. It just means that the parameter is added to the hash
|
|
3472
|
+
*/
|
|
3473
|
+
let isAttach2Hash = false;
|
|
3474
|
+
// If hash exists and search does not exist, it is considered as a hash route
|
|
3251
3475
|
if (hash && !search) {
|
|
3252
3476
|
isAttach2Hash = true;
|
|
3253
3477
|
if (queryObject.hashQuery) {
|
|
@@ -3277,7 +3501,11 @@ function setMicroPathToURL(appName, microLocation) {
|
|
|
3277
3501
|
isAttach2Hash,
|
|
3278
3502
|
};
|
|
3279
3503
|
}
|
|
3280
|
-
|
|
3504
|
+
/**
|
|
3505
|
+
* Delete child app fullPath from browser url
|
|
3506
|
+
* @param appName app.name
|
|
3507
|
+
* @param targetLocation target Location, default is rawLocation
|
|
3508
|
+
*/
|
|
3281
3509
|
function removeMicroPathFromURL(appName, targetLocation) {
|
|
3282
3510
|
var _a, _b, _c, _d;
|
|
3283
3511
|
let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
|
|
@@ -3300,7 +3528,7 @@ function removeMicroPathFromURL(appName, targetLocation) {
|
|
|
3300
3528
|
};
|
|
3301
3529
|
}
|
|
3302
3530
|
/**
|
|
3303
|
-
*
|
|
3531
|
+
* Format search, hash to object
|
|
3304
3532
|
*/
|
|
3305
3533
|
function getQueryObjectFromURL(search, hash) {
|
|
3306
3534
|
const queryObject = {};
|
|
@@ -3322,6 +3550,18 @@ function getNoHashMicroPathFromURL(appName, baseUrl) {
|
|
|
3322
3550
|
const formatLocation = createURL(microPath, baseUrl);
|
|
3323
3551
|
return formatLocation.origin + formatLocation.pathname + formatLocation.search;
|
|
3324
3552
|
}
|
|
3553
|
+
/**
|
|
3554
|
+
* Effect app is an app that can perform route navigation
|
|
3555
|
+
* NOTE: Invalid app action
|
|
3556
|
+
* 1. prevent update browser url, dispatch popStateEvent, reload browser
|
|
3557
|
+
* 2. It can update path with pushState/replaceState
|
|
3558
|
+
* 3. Can not update path outside (with router api)
|
|
3559
|
+
* 3. Can not update path by location
|
|
3560
|
+
*/
|
|
3561
|
+
function isEffectiveApp(appName) {
|
|
3562
|
+
const app = appInstanceMap.get(appName);
|
|
3563
|
+
return !!(app && !app.isPrefetch);
|
|
3564
|
+
}
|
|
3325
3565
|
|
|
3326
3566
|
/**
|
|
3327
3567
|
* dispatch PopStateEvent & HashChangeEvent to child app
|
|
@@ -3338,7 +3578,8 @@ function addHistoryListener(appName) {
|
|
|
3338
3578
|
* 1. unmount app & hidden keep-alive app will not receive popstate event
|
|
3339
3579
|
* 2. filter out onlyForBrowser
|
|
3340
3580
|
*/
|
|
3341
|
-
if (getActiveApps(true).includes(appName) &&
|
|
3581
|
+
if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName) &&
|
|
3582
|
+
!e.onlyForBrowser) {
|
|
3342
3583
|
const microPath = getMicroPathFromURL(appName);
|
|
3343
3584
|
const app = appInstanceMap.get(appName);
|
|
3344
3585
|
const proxyWindow = app.sandBox.proxyWindow;
|
|
@@ -3426,15 +3667,18 @@ function dispatchNativeHashChangeEvent(oldHref) {
|
|
|
3426
3667
|
}
|
|
3427
3668
|
/**
|
|
3428
3669
|
* dispatch popstate & hashchange event to browser
|
|
3670
|
+
* @param appName app.name
|
|
3429
3671
|
* @param onlyForBrowser only dispatch event to browser
|
|
3430
3672
|
* @param oldHref old href of rawWindow.location
|
|
3431
3673
|
*/
|
|
3432
|
-
function dispatchNativeEvent(onlyForBrowser, oldHref) {
|
|
3674
|
+
function dispatchNativeEvent(appName, onlyForBrowser, oldHref) {
|
|
3433
3675
|
// clear element scope before dispatch global event
|
|
3434
3676
|
removeDomScope();
|
|
3435
|
-
|
|
3436
|
-
|
|
3437
|
-
|
|
3677
|
+
if (isEffectiveApp(appName)) {
|
|
3678
|
+
dispatchNativePopStateEvent(onlyForBrowser);
|
|
3679
|
+
if (oldHref) {
|
|
3680
|
+
dispatchNativeHashChangeEvent(oldHref);
|
|
3681
|
+
}
|
|
3438
3682
|
}
|
|
3439
3683
|
}
|
|
3440
3684
|
|
|
@@ -3451,7 +3695,7 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3451
3695
|
if (isString(rests[2]) || isURL(rests[2])) {
|
|
3452
3696
|
const targetLocation = createURL(rests[2], microLocation.href);
|
|
3453
3697
|
if (targetLocation.origin === microLocation.origin) {
|
|
3454
|
-
navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
|
|
3698
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
|
|
3455
3699
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3456
3700
|
if (targetFullPath !== microLocation.fullPath) {
|
|
3457
3701
|
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
@@ -3459,7 +3703,7 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3459
3703
|
return void 0;
|
|
3460
3704
|
}
|
|
3461
3705
|
}
|
|
3462
|
-
nativeHistoryNavigate(methodName, rests[2], rests[0], rests[1]);
|
|
3706
|
+
nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
|
|
3463
3707
|
};
|
|
3464
3708
|
}
|
|
3465
3709
|
const pushState = getMicroHistoryMethod('pushState');
|
|
@@ -3491,14 +3735,17 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3491
3735
|
}
|
|
3492
3736
|
/**
|
|
3493
3737
|
* navigate to new path base on native method of history
|
|
3738
|
+
* @param appName app.name
|
|
3494
3739
|
* @param methodName pushState/replaceState
|
|
3495
3740
|
* @param fullPath full path
|
|
3496
3741
|
* @param state history.state, default is null
|
|
3497
3742
|
* @param title history.title, default is ''
|
|
3498
3743
|
*/
|
|
3499
|
-
function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
|
|
3500
|
-
|
|
3501
|
-
|
|
3744
|
+
function nativeHistoryNavigate(appName, methodName, fullPath, state = null, title = '') {
|
|
3745
|
+
if (isEffectiveApp(appName)) {
|
|
3746
|
+
const method = methodName === 'pushState' ? globalEnv.rawPushState : globalEnv.rawReplaceState;
|
|
3747
|
+
method.call(globalEnv.rawWindow.history, state, title, fullPath);
|
|
3748
|
+
}
|
|
3502
3749
|
}
|
|
3503
3750
|
/**
|
|
3504
3751
|
* Navigate to new path, and dispatch native popStateEvent/hashChangeEvent to browser
|
|
@@ -3507,29 +3754,33 @@ function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
|
|
|
3507
3754
|
* 2. proxyHistory.pushState/replaceState with limited popstateEvent
|
|
3508
3755
|
* 3. api microApp.router.push/replace
|
|
3509
3756
|
* 4. proxyLocation.hash = xxx
|
|
3757
|
+
* @param appName app.name
|
|
3510
3758
|
* @param methodName pushState/replaceState
|
|
3511
3759
|
* @param result result of add/remove microApp path on browser url
|
|
3512
3760
|
* @param onlyForBrowser only dispatch event to browser
|
|
3513
3761
|
* @param state history.state, not required
|
|
3514
3762
|
* @param title history.title, not required
|
|
3515
3763
|
*/
|
|
3516
|
-
function navigateWithNativeEvent(methodName, result, onlyForBrowser, state, title) {
|
|
3517
|
-
|
|
3518
|
-
|
|
3519
|
-
|
|
3520
|
-
|
|
3521
|
-
|
|
3522
|
-
|
|
3523
|
-
|
|
3764
|
+
function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, state, title) {
|
|
3765
|
+
if (isEffectiveApp(appName)) {
|
|
3766
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
3767
|
+
const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
3768
|
+
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
3769
|
+
// navigate with native history method
|
|
3770
|
+
nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
|
|
3771
|
+
if (oldFullPath !== result.fullPath)
|
|
3772
|
+
dispatchNativeEvent(appName, onlyForBrowser, oldHref);
|
|
3773
|
+
}
|
|
3524
3774
|
}
|
|
3525
3775
|
/**
|
|
3526
3776
|
* update browser url when mount/unmount/hidden/show/attachToURL/attachAllToURL
|
|
3527
3777
|
* just attach microRoute info to browser, dispatch event to base app(exclude child)
|
|
3778
|
+
* @param appName app.name
|
|
3528
3779
|
* @param result result of add/remove microApp path on browser url
|
|
3529
3780
|
* @param state history.state
|
|
3530
3781
|
*/
|
|
3531
|
-
function attachRouteToBrowserURL(result, state) {
|
|
3532
|
-
navigateWithNativeEvent('replaceState', result, true, state);
|
|
3782
|
+
function attachRouteToBrowserURL(appName, result, state) {
|
|
3783
|
+
navigateWithNativeEvent(appName, 'replaceState', result, true, state);
|
|
3533
3784
|
}
|
|
3534
3785
|
/**
|
|
3535
3786
|
* When path is same, keep the microAppState in history.state
|
|
@@ -3559,10 +3810,13 @@ function reWriteHistoryMethod(method) {
|
|
|
3559
3810
|
* 2. Unable to catch when base app navigate with location
|
|
3560
3811
|
* 3. When in nest app, rawPushState/rawReplaceState has been modified by parent
|
|
3561
3812
|
*/
|
|
3562
|
-
getActiveApps(
|
|
3813
|
+
getActiveApps({
|
|
3814
|
+
excludeHiddenApp: true,
|
|
3815
|
+
excludePreRender: true,
|
|
3816
|
+
}).forEach(appName => {
|
|
3563
3817
|
const app = appInstanceMap.get(appName);
|
|
3564
3818
|
if (app.sandBox && app.useMemoryRouter && !getMicroPathFromURL(appName)) {
|
|
3565
|
-
attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3819
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3566
3820
|
}
|
|
3567
3821
|
});
|
|
3568
3822
|
// fix bug for nest app
|
|
@@ -3594,7 +3848,7 @@ function createRouterApi() {
|
|
|
3594
3848
|
* @param state to.state
|
|
3595
3849
|
*/
|
|
3596
3850
|
function navigateWithRawHistory(appName, methodName, targetLocation, state) {
|
|
3597
|
-
navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
3851
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
3598
3852
|
// clear element scope after navigate
|
|
3599
3853
|
removeDomScope();
|
|
3600
3854
|
}
|
|
@@ -3615,7 +3869,7 @@ function createRouterApi() {
|
|
|
3615
3869
|
return logError(`navigation failed, memory router of app ${appName} is closed`);
|
|
3616
3870
|
}
|
|
3617
3871
|
// active apps, include hidden keep-alive app
|
|
3618
|
-
if (getActiveApps().includes(appName)) {
|
|
3872
|
+
if (getActiveApps({ excludePreRender: true }).includes(appName)) {
|
|
3619
3873
|
const microLocation = app.sandBox.proxyWindow.location;
|
|
3620
3874
|
const targetLocation = createURL(to.path, microLocation.href);
|
|
3621
3875
|
// Only get path data, even if the origin is different from microApp
|
|
@@ -3698,7 +3952,7 @@ function createRouterApi() {
|
|
|
3698
3952
|
function commonHandlerForAttachToURL(appName) {
|
|
3699
3953
|
const app = appInstanceMap.get(appName);
|
|
3700
3954
|
if (app.sandBox && app.useMemoryRouter) {
|
|
3701
|
-
attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3955
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3702
3956
|
}
|
|
3703
3957
|
}
|
|
3704
3958
|
/**
|
|
@@ -3713,10 +3967,14 @@ function createRouterApi() {
|
|
|
3713
3967
|
}
|
|
3714
3968
|
/**
|
|
3715
3969
|
* Attach all active app router info to browser url
|
|
3716
|
-
*
|
|
3970
|
+
* @param includeHiddenApp include hidden keep-alive app
|
|
3971
|
+
* @param includePreRender include preRender app
|
|
3717
3972
|
*/
|
|
3718
|
-
function attachAllToURL(includeHiddenApp = false) {
|
|
3719
|
-
getActiveApps(
|
|
3973
|
+
function attachAllToURL({ includeHiddenApp = false, includePreRender = false, }) {
|
|
3974
|
+
getActiveApps({
|
|
3975
|
+
excludeHiddenApp: !includeHiddenApp,
|
|
3976
|
+
excludePreRender: !includePreRender,
|
|
3977
|
+
}).forEach(appName => commonHandlerForAttachToURL(appName));
|
|
3720
3978
|
}
|
|
3721
3979
|
function createDefaultPageApi() {
|
|
3722
3980
|
// defaultPage data
|
|
@@ -3731,7 +3989,7 @@ function createRouterApi() {
|
|
|
3731
3989
|
function setDefaultPage(options) {
|
|
3732
3990
|
const appName = formatAppName(options.name);
|
|
3733
3991
|
if (!appName || !options.path) {
|
|
3734
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
3992
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
3735
3993
|
if (!appName) {
|
|
3736
3994
|
logWarn(`setDefaultPage: invalid appName "${appName}"`);
|
|
3737
3995
|
}
|
|
@@ -3774,7 +4032,7 @@ function createRouterApi() {
|
|
|
3774
4032
|
}
|
|
3775
4033
|
});
|
|
3776
4034
|
}
|
|
3777
|
-
else if (process.env.NODE_ENV !== 'production') {
|
|
4035
|
+
else if ((process.env.NODE_ENV !== 'production')) {
|
|
3778
4036
|
logWarn('setBaseAppRouter: Invalid base router');
|
|
3779
4037
|
}
|
|
3780
4038
|
}
|
|
@@ -3842,13 +4100,13 @@ function createMicroLocation(appName, url) {
|
|
|
3842
4100
|
if (targetLocation.hash !== shadowLocation.hash) {
|
|
3843
4101
|
if (setMicroPathResult.isAttach2Hash)
|
|
3844
4102
|
oldHref = rawLocation.href;
|
|
3845
|
-
nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
|
|
4103
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
3846
4104
|
}
|
|
3847
4105
|
if (targetLocation.hash) {
|
|
3848
|
-
dispatchNativeEvent(false, oldHref);
|
|
4106
|
+
dispatchNativeEvent(appName, false, oldHref);
|
|
3849
4107
|
}
|
|
3850
4108
|
else {
|
|
3851
|
-
|
|
4109
|
+
rawReload();
|
|
3852
4110
|
}
|
|
3853
4111
|
return void 0;
|
|
3854
4112
|
/**
|
|
@@ -3857,8 +4115,8 @@ function createMicroLocation(appName, url) {
|
|
|
3857
4115
|
*/
|
|
3858
4116
|
}
|
|
3859
4117
|
else if (setMicroPathResult.isAttach2Hash) {
|
|
3860
|
-
nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
|
|
3861
|
-
|
|
4118
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
4119
|
+
rawReload();
|
|
3862
4120
|
return void 0;
|
|
3863
4121
|
}
|
|
3864
4122
|
value = setMicroPathResult.fullPath;
|
|
@@ -3888,7 +4146,7 @@ function createMicroLocation(appName, url) {
|
|
|
3888
4146
|
// When the browser url has a hash value, the same pathname/search will not refresh browser
|
|
3889
4147
|
if (targetLocation[key] === shadowLocation[key] && shadowLocation.hash) {
|
|
3890
4148
|
// The href has not changed, not need to dispatch hashchange event
|
|
3891
|
-
dispatchNativeEvent(false);
|
|
4149
|
+
dispatchNativeEvent(appName, false);
|
|
3892
4150
|
}
|
|
3893
4151
|
else {
|
|
3894
4152
|
/**
|
|
@@ -3897,19 +4155,24 @@ function createMicroLocation(appName, url) {
|
|
|
3897
4155
|
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
3898
4156
|
* search: ?query ==> ?query#hash
|
|
3899
4157
|
*/
|
|
3900
|
-
nativeHistoryNavigate(targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
|
|
3901
|
-
|
|
4158
|
+
nativeHistoryNavigate(appName, targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
|
|
4159
|
+
rawReload();
|
|
3902
4160
|
}
|
|
3903
4161
|
}
|
|
4162
|
+
function rawReload() {
|
|
4163
|
+
isEffectiveApp(appName) && rawLocation.reload();
|
|
4164
|
+
}
|
|
3904
4165
|
/**
|
|
3905
4166
|
* Special processing for four keys: href, pathname, search and hash
|
|
3906
4167
|
* They take values from shadowLocation, and require special operations when assigning values
|
|
3907
4168
|
*/
|
|
3908
4169
|
rawDefineProperties(microLocation, {
|
|
3909
4170
|
href: createPropertyDescriptor(() => shadowLocation.href, (value) => {
|
|
3910
|
-
|
|
3911
|
-
|
|
3912
|
-
|
|
4171
|
+
if (isEffectiveApp(appName)) {
|
|
4172
|
+
const targetPath = commonHandler(value, 'pushState');
|
|
4173
|
+
if (targetPath)
|
|
4174
|
+
rawLocation.href = targetPath;
|
|
4175
|
+
}
|
|
3913
4176
|
}),
|
|
3914
4177
|
pathname: createPropertyDescriptor(() => shadowLocation.pathname, (value) => {
|
|
3915
4178
|
const targetPath = ('/' + value).replace(/^\/+/, '/') + shadowLocation.search + shadowLocation.hash;
|
|
@@ -3924,16 +4187,18 @@ function createMicroLocation(appName, url) {
|
|
|
3924
4187
|
const targetLocation = createURL(targetPath, url);
|
|
3925
4188
|
// The same hash will not trigger popStateEvent
|
|
3926
4189
|
if (targetLocation.hash !== shadowLocation.hash) {
|
|
3927
|
-
navigateWithNativeEvent('pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
4190
|
+
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
3928
4191
|
}
|
|
3929
4192
|
}),
|
|
3930
4193
|
fullPath: createPropertyDescriptor(() => shadowLocation.pathname + shadowLocation.search + shadowLocation.hash, noop),
|
|
3931
4194
|
});
|
|
3932
4195
|
const createLocationMethod = (locationMethodName) => {
|
|
3933
4196
|
return function (value) {
|
|
3934
|
-
|
|
3935
|
-
|
|
3936
|
-
|
|
4197
|
+
if (isEffectiveApp(appName)) {
|
|
4198
|
+
const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
|
|
4199
|
+
if (targetPath)
|
|
4200
|
+
rawLocation[locationMethodName](targetPath);
|
|
4201
|
+
}
|
|
3937
4202
|
};
|
|
3938
4203
|
};
|
|
3939
4204
|
return assign(microLocation, {
|
|
@@ -4032,7 +4297,7 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4032
4297
|
if (defaultPage)
|
|
4033
4298
|
updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
|
|
4034
4299
|
// attach microApp route info to browser URL
|
|
4035
|
-
attachRouteToBrowserURL(setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
|
|
4300
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
|
|
4036
4301
|
// trigger guards after change browser URL
|
|
4037
4302
|
autoTriggerNavigationGuard(appName, microLocation);
|
|
4038
4303
|
}
|
|
@@ -4056,7 +4321,7 @@ function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
|
|
|
4056
4321
|
* called on sandbox.stop or hidden of keep-alive app
|
|
4057
4322
|
*/
|
|
4058
4323
|
function removeStateAndPathFromBrowser(appName) {
|
|
4059
|
-
attachRouteToBrowserURL(removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
4324
|
+
attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
4060
4325
|
}
|
|
4061
4326
|
|
|
4062
4327
|
/**
|
|
@@ -4079,8 +4344,6 @@ function createMicroFetch(url, target) {
|
|
|
4079
4344
|
* When fetch rewrite by baseApp, domScope still active when exec rawWindow.fetch
|
|
4080
4345
|
* If baseApp operate dom in fetch, it will cause error
|
|
4081
4346
|
* The same for XMLHttpRequest, EventSource
|
|
4082
|
-
* e.g.
|
|
4083
|
-
* baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
|
|
4084
4347
|
*/
|
|
4085
4348
|
removeDomScope();
|
|
4086
4349
|
return rawFetch.call(globalEnv.rawWindow, input, init, ...rests);
|
|
@@ -4188,7 +4451,7 @@ class SandBox {
|
|
|
4188
4451
|
// create proxyWindow with Proxy(microAppWindow)
|
|
4189
4452
|
this.proxyWindow = this.createProxyWindow(appName);
|
|
4190
4453
|
// Rewrite global event listener & timeout
|
|
4191
|
-
|
|
4454
|
+
this.effectController = effect(appName, this.microAppWindow);
|
|
4192
4455
|
// inject global properties
|
|
4193
4456
|
this.initStaticGlobalKeys(this.microAppWindow, appName, url);
|
|
4194
4457
|
}
|
|
@@ -4215,8 +4478,9 @@ class SandBox {
|
|
|
4215
4478
|
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
4216
4479
|
}
|
|
4217
4480
|
/**
|
|
4218
|
-
* 1.
|
|
4219
|
-
* 2.
|
|
4481
|
+
* 1. Prevent the key deleted during sandBox.stop after rewrite
|
|
4482
|
+
* 2. Umd mode will not delete any keys during sandBox.stop
|
|
4483
|
+
* 3. It must not be umd mode when call sandbox.start at the first time
|
|
4220
4484
|
*/
|
|
4221
4485
|
if (!umdMode) {
|
|
4222
4486
|
this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
|
|
@@ -4235,12 +4499,12 @@ class SandBox {
|
|
|
4235
4499
|
* @param umdMode is umd mode
|
|
4236
4500
|
* @param keepRouteState prevent reset route
|
|
4237
4501
|
* @param clearEventSource clear MicroEventSource when destroy
|
|
4502
|
+
* @param clearData clear data from base app
|
|
4238
4503
|
*/
|
|
4239
|
-
stop({ umdMode, keepRouteState, clearEventSource, }) {
|
|
4504
|
+
stop({ umdMode, keepRouteState, clearEventSource, clearData, }) {
|
|
4240
4505
|
if (this.active) {
|
|
4241
|
-
|
|
4242
|
-
this.
|
|
4243
|
-
this.microAppWindow.microApp.clearGlobalDataListener();
|
|
4506
|
+
// clear global event, timeout, data listener
|
|
4507
|
+
this.releaseGlobalEffect(clearData);
|
|
4244
4508
|
if (this.removeHistoryListener) {
|
|
4245
4509
|
this.clearRouteState(keepRouteState);
|
|
4246
4510
|
// release listener of popstate
|
|
@@ -4273,10 +4537,33 @@ class SandBox {
|
|
|
4273
4537
|
this.active = false;
|
|
4274
4538
|
}
|
|
4275
4539
|
}
|
|
4276
|
-
|
|
4277
|
-
|
|
4540
|
+
/**
|
|
4541
|
+
* clear global event, timeout, data listener
|
|
4542
|
+
* Scenes:
|
|
4543
|
+
* 1. unmount of normal/umd app
|
|
4544
|
+
* 2. hidden keep-alive app
|
|
4545
|
+
* 3. after init prerender app
|
|
4546
|
+
* @param clearData clear data from base app
|
|
4547
|
+
*/
|
|
4548
|
+
releaseGlobalEffect(clearData = false) {
|
|
4549
|
+
this.effectController.releaseEffect();
|
|
4550
|
+
this.microAppWindow.microApp.clearDataListener();
|
|
4551
|
+
this.microAppWindow.microApp.clearGlobalDataListener();
|
|
4552
|
+
if (clearData) {
|
|
4553
|
+
microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4554
|
+
this.microAppWindow.microApp.clearData();
|
|
4555
|
+
}
|
|
4556
|
+
}
|
|
4557
|
+
/**
|
|
4558
|
+
* record umd snapshot before the first execution of umdHookMount
|
|
4559
|
+
* Scenes:
|
|
4560
|
+
* 1. exec umdMountHook in umd mode
|
|
4561
|
+
* 2. hidden keep-alive app
|
|
4562
|
+
* 3. after init prerender app
|
|
4563
|
+
*/
|
|
4564
|
+
recordEffectSnapshot() {
|
|
4278
4565
|
// this.microAppWindow.__MICRO_APP_UMD_MODE__ = true
|
|
4279
|
-
this.
|
|
4566
|
+
this.effectController.recordEffect();
|
|
4280
4567
|
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4281
4568
|
// this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
|
|
4282
4569
|
// this.injectedKeys.forEach((key: PropertyKey) => {
|
|
@@ -4284,13 +4571,17 @@ class SandBox {
|
|
|
4284
4571
|
// })
|
|
4285
4572
|
}
|
|
4286
4573
|
// rebuild umd snapshot before remount umd app
|
|
4287
|
-
|
|
4574
|
+
rebuildEffectSnapshot() {
|
|
4288
4575
|
// this.recordUmdInjectedValues!.forEach((value: unknown, key: PropertyKey) => {
|
|
4289
4576
|
// Reflect.set(this.proxyWindow, key, value)
|
|
4290
4577
|
// })
|
|
4291
|
-
this.
|
|
4578
|
+
this.effectController.rebuildEffect();
|
|
4292
4579
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4293
4580
|
}
|
|
4581
|
+
// set __MICRO_APP_PRE_RENDER__ state
|
|
4582
|
+
setPreRenderState(state) {
|
|
4583
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
4584
|
+
}
|
|
4294
4585
|
/**
|
|
4295
4586
|
* get scopeProperties and escapeProperties from plugins & adapter
|
|
4296
4587
|
* @param appName app name
|
|
@@ -4424,6 +4715,7 @@ class SandBox {
|
|
|
4424
4715
|
microAppWindow.__MICRO_APP_URL__ = url;
|
|
4425
4716
|
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
4426
4717
|
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
4718
|
+
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
4427
4719
|
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
4428
4720
|
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
4429
4721
|
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
@@ -4441,7 +4733,6 @@ class SandBox {
|
|
|
4441
4733
|
configurable: false,
|
|
4442
4734
|
enumerable: true,
|
|
4443
4735
|
get() {
|
|
4444
|
-
throttleDeferForSetAppName(appName);
|
|
4445
4736
|
// return globalEnv.rawDocument
|
|
4446
4737
|
return proxyDocument;
|
|
4447
4738
|
},
|
|
@@ -4450,7 +4741,6 @@ class SandBox {
|
|
|
4450
4741
|
configurable: false,
|
|
4451
4742
|
enumerable: false,
|
|
4452
4743
|
get() {
|
|
4453
|
-
throttleDeferForSetAppName(appName);
|
|
4454
4744
|
// return globalEnv.rawRootDocument
|
|
4455
4745
|
return MicroDocument;
|
|
4456
4746
|
},
|
|
@@ -4496,6 +4786,7 @@ class SandBox {
|
|
|
4496
4786
|
this.setHijackProperty(microAppWindow, appName);
|
|
4497
4787
|
if (!disablePatchRequest)
|
|
4498
4788
|
this.patchRequestApi(microAppWindow, appName, url);
|
|
4789
|
+
this.setScopeProperties(microAppWindow);
|
|
4499
4790
|
}
|
|
4500
4791
|
// set hijack Properties to microAppWindow
|
|
4501
4792
|
setHijackProperty(microAppWindow, appName) {
|
|
@@ -4563,6 +4854,18 @@ class SandBox {
|
|
|
4563
4854
|
},
|
|
4564
4855
|
});
|
|
4565
4856
|
}
|
|
4857
|
+
/**
|
|
4858
|
+
* Init scope keys to microAppWindow, prevent fall to rawWindow from with(microAppWindow)
|
|
4859
|
+
* like: if (!xxx) {}
|
|
4860
|
+
* NOTE:
|
|
4861
|
+
* 1. Symbol.unscopables cannot affect undefined keys
|
|
4862
|
+
* 2. Doesn't use for window.xxx because it fall to proxyWindow
|
|
4863
|
+
*/
|
|
4864
|
+
setScopeProperties(microAppWindow) {
|
|
4865
|
+
this.scopeProperties.forEach((key) => {
|
|
4866
|
+
Reflect.set(microAppWindow, key, microAppWindow[key]);
|
|
4867
|
+
});
|
|
4868
|
+
}
|
|
4566
4869
|
// set location & history for memory router
|
|
4567
4870
|
setMicroAppRouter(microAppWindow, appName, url) {
|
|
4568
4871
|
const { microLocation, microHistory } = createMicroRouter(appName, url);
|
|
@@ -4623,11 +4926,11 @@ class SandBox {
|
|
|
4623
4926
|
return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
|
|
4624
4927
|
},
|
|
4625
4928
|
set: (target, key, value) => {
|
|
4626
|
-
// Fix TypeError: Illegal invocation when set document.title
|
|
4627
|
-
Reflect.set(target, key, value);
|
|
4628
4929
|
/**
|
|
4629
|
-
*
|
|
4930
|
+
* 1. Fix TypeError: Illegal invocation when set document.title
|
|
4931
|
+
* 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
4630
4932
|
*/
|
|
4933
|
+
Reflect.set(target, key, value);
|
|
4631
4934
|
return true;
|
|
4632
4935
|
}
|
|
4633
4936
|
});
|
|
@@ -4735,7 +5038,7 @@ function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
|
4735
5038
|
// micro app instances
|
|
4736
5039
|
const appInstanceMap = new Map();
|
|
4737
5040
|
class CreateApp {
|
|
4738
|
-
constructor({ name, url, container, scopecss, useSandbox, inline, esmodule, ssrUrl, isPrefetch, }) {
|
|
5041
|
+
constructor({ name, url, container, scopecss, useSandbox, inline, esmodule, ssrUrl, isPrefetch, prefetchLevel, }) {
|
|
4739
5042
|
this.state = appStates.CREATED;
|
|
4740
5043
|
this.keepAliveState = null;
|
|
4741
5044
|
this.keepAliveContainer = null;
|
|
@@ -4745,7 +5048,6 @@ class CreateApp {
|
|
|
4745
5048
|
this.libraryName = null;
|
|
4746
5049
|
this.umdMode = false;
|
|
4747
5050
|
this.sandBox = null;
|
|
4748
|
-
this.keepRouteState = false;
|
|
4749
5051
|
this.fiber = false;
|
|
4750
5052
|
this.useMemoryRouter = true;
|
|
4751
5053
|
this.name = name;
|
|
@@ -4757,8 +5059,10 @@ class CreateApp {
|
|
|
4757
5059
|
// not exist when prefetch 👇
|
|
4758
5060
|
this.container = container !== null && container !== void 0 ? container : null;
|
|
4759
5061
|
this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
|
|
4760
|
-
//
|
|
5062
|
+
// exist only prefetch 👇
|
|
4761
5063
|
this.isPrefetch = isPrefetch !== null && isPrefetch !== void 0 ? isPrefetch : false;
|
|
5064
|
+
this.isPrerender = prefetchLevel === 3;
|
|
5065
|
+
this.prefetchLevel = prefetchLevel;
|
|
4762
5066
|
// init actions
|
|
4763
5067
|
appInstanceMap.set(this.name, this);
|
|
4764
5068
|
this.source = { html: null, links: new Set(), scripts: new Set() };
|
|
@@ -4773,14 +5077,46 @@ class CreateApp {
|
|
|
4773
5077
|
/**
|
|
4774
5078
|
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
4775
5079
|
*/
|
|
4776
|
-
onLoad(html) {
|
|
5080
|
+
onLoad(html, defaultPage, disablePatchRequest) {
|
|
5081
|
+
var _a;
|
|
4777
5082
|
if (++this.loadSourceLevel === 2) {
|
|
4778
5083
|
this.source.html = html;
|
|
4779
5084
|
this.state = appStates.LOADED;
|
|
4780
5085
|
if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
|
|
4781
|
-
// @ts-ignore
|
|
4782
5086
|
getRootContainer(this.container).mount(this);
|
|
4783
5087
|
}
|
|
5088
|
+
else if (this.isPrerender) {
|
|
5089
|
+
/**
|
|
5090
|
+
* PreRender is an option of prefetch, it will render app during prefetch
|
|
5091
|
+
* Limit:
|
|
5092
|
+
* 1. fiber forced on
|
|
5093
|
+
* 2. only virtual router support
|
|
5094
|
+
*
|
|
5095
|
+
* NOTE: (4P: not - update browser url, dispatch popstateEvent, reload window, dispatch lifecycle event)
|
|
5096
|
+
* 1. pushState/replaceState in child can update microLocation, but will not attach router info to browser url
|
|
5097
|
+
* 2. prevent dispatch popstate/hashchange event to browser
|
|
5098
|
+
* 3. all navigation actions of location are invalid (In the future, we can consider update microLocation without trigger browser reload)
|
|
5099
|
+
* 4. lifecycle event will not trigger when prerender
|
|
5100
|
+
*
|
|
5101
|
+
* Special scenes
|
|
5102
|
+
* 1. unmount prerender app when loading
|
|
5103
|
+
* 2. unmount prerender app when exec js
|
|
5104
|
+
* 2. unmount prerender app after exec js
|
|
5105
|
+
*/
|
|
5106
|
+
const container = pureCreateElement('div');
|
|
5107
|
+
container.setAttribute('prerender', 'true');
|
|
5108
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setPreRenderState(true);
|
|
5109
|
+
this.mount({
|
|
5110
|
+
container,
|
|
5111
|
+
inline: this.inline,
|
|
5112
|
+
useMemoryRouter: true,
|
|
5113
|
+
baseroute: '',
|
|
5114
|
+
fiber: true,
|
|
5115
|
+
esmodule: this.esmodule,
|
|
5116
|
+
defaultPage: defaultPage !== null && defaultPage !== void 0 ? defaultPage : '',
|
|
5117
|
+
disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
|
|
5118
|
+
});
|
|
5119
|
+
}
|
|
4784
5120
|
}
|
|
4785
5121
|
}
|
|
4786
5122
|
/**
|
|
@@ -4797,29 +5133,86 @@ class CreateApp {
|
|
|
4797
5133
|
/**
|
|
4798
5134
|
* mount app
|
|
4799
5135
|
* @param container app container
|
|
4800
|
-
* @param inline js
|
|
5136
|
+
* @param inline run js in inline mode
|
|
5137
|
+
* @param useMemoryRouter use virtual router
|
|
5138
|
+
* @param defaultPage default page of virtual router
|
|
4801
5139
|
* @param baseroute route prefix, default is ''
|
|
4802
|
-
* @param keepRouteState keep route state when unmount, default is false
|
|
4803
5140
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
5141
|
+
* @param fiber run js in fiber mode
|
|
5142
|
+
* @param esmodule support type='module' script
|
|
4804
5143
|
*/
|
|
4805
|
-
mount({ container, inline,
|
|
4806
|
-
var _a, _b;
|
|
5144
|
+
mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, esmodule, }) {
|
|
5145
|
+
var _a, _b, _c, _d, _e, _f;
|
|
5146
|
+
if (this.loadSourceLevel !== 2) {
|
|
5147
|
+
/**
|
|
5148
|
+
* unmount prefetch app when loading source, when mount again before loading end,
|
|
5149
|
+
* isPrefetch & isPrerender will be reset, and this.container sill be null
|
|
5150
|
+
* so we should set this.container
|
|
5151
|
+
*/
|
|
5152
|
+
this.container = container;
|
|
5153
|
+
// mount before prerender exec mount (loading source), set isPrerender to false
|
|
5154
|
+
this.isPrerender = false;
|
|
5155
|
+
// reset app state to LOADING
|
|
5156
|
+
this.state = appStates.LOADING;
|
|
5157
|
+
return;
|
|
5158
|
+
}
|
|
5159
|
+
/**
|
|
5160
|
+
* Mount app with prerender, this.container is empty
|
|
5161
|
+
* When rendering again, identify prerender by this.container
|
|
5162
|
+
* Transfer the contents of div to the <micro-app> tag
|
|
5163
|
+
*
|
|
5164
|
+
* Special scenes:
|
|
5165
|
+
* 1. mount before prerender exec mount (loading source)
|
|
5166
|
+
* 2. mount when prerender js executing
|
|
5167
|
+
* 3. mount after prerender js exec end
|
|
5168
|
+
*
|
|
5169
|
+
* TODO: test shadowDOM
|
|
5170
|
+
*/
|
|
5171
|
+
if (this.container instanceof HTMLDivElement &&
|
|
5172
|
+
this.container.hasAttribute('prerender')) {
|
|
5173
|
+
/**
|
|
5174
|
+
* rebuild effect event of window, document, data center
|
|
5175
|
+
* explain:
|
|
5176
|
+
* 1. rebuild before exec mount, do nothing
|
|
5177
|
+
* 2. rebuild when js executing, recovery recorded effect event, because prerender fiber mode
|
|
5178
|
+
* 3. rebuild after js exec end, normal recovery effect event
|
|
5179
|
+
*/
|
|
5180
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
5181
|
+
// current this.container is <div prerender='true'></div>
|
|
5182
|
+
cloneContainer(this.container, container, false);
|
|
5183
|
+
/**
|
|
5184
|
+
* set this.container to <micro-app></micro-app>
|
|
5185
|
+
* NOTE:
|
|
5186
|
+
* must before exec this.preRenderEvent?.forEach((cb) => cb())
|
|
5187
|
+
*/
|
|
5188
|
+
this.container = container;
|
|
5189
|
+
(_b = this.preRenderEvent) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
|
|
5190
|
+
// reset isPrerender config
|
|
5191
|
+
this.isPrerender = false;
|
|
5192
|
+
this.preRenderEvent = undefined;
|
|
5193
|
+
// attach router info to browser url
|
|
5194
|
+
router.attachToURL(this.name);
|
|
5195
|
+
return (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.setPreRenderState(false);
|
|
5196
|
+
}
|
|
4807
5197
|
this.container = container;
|
|
4808
5198
|
this.inline = inline;
|
|
4809
5199
|
this.esmodule = esmodule;
|
|
4810
|
-
this.keepRouteState = keepRouteState;
|
|
4811
5200
|
this.fiber = fiber;
|
|
4812
5201
|
// use in sandbox/effect
|
|
4813
5202
|
this.useMemoryRouter = useMemoryRouter;
|
|
4814
5203
|
// this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
|
|
4815
|
-
|
|
4816
|
-
this.
|
|
4817
|
-
|
|
5204
|
+
const dispatchBeforeMount = () => {
|
|
5205
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
5206
|
+
};
|
|
5207
|
+
if (this.isPrerender) {
|
|
5208
|
+
((_d = this.preRenderEvent) !== null && _d !== void 0 ? _d : (this.preRenderEvent = [])).push(dispatchBeforeMount);
|
|
5209
|
+
}
|
|
5210
|
+
else {
|
|
5211
|
+
dispatchBeforeMount();
|
|
4818
5212
|
}
|
|
4819
|
-
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
4820
5213
|
this.state = appStates.MOUNTING;
|
|
4821
5214
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
4822
|
-
(
|
|
5215
|
+
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
4823
5216
|
umdMode: this.umdMode,
|
|
4824
5217
|
baseroute,
|
|
4825
5218
|
useMemoryRouter,
|
|
@@ -4831,6 +5224,7 @@ class CreateApp {
|
|
|
4831
5224
|
let hasDispatchMountedEvent = false;
|
|
4832
5225
|
// if all js are executed, param isFinished will be true
|
|
4833
5226
|
execScripts(this, (isFinished) => {
|
|
5227
|
+
var _a;
|
|
4834
5228
|
if (!this.umdMode) {
|
|
4835
5229
|
const { mount, unmount } = this.getUmdLibraryHooks();
|
|
4836
5230
|
/**
|
|
@@ -4844,9 +5238,9 @@ class CreateApp {
|
|
|
4844
5238
|
this.umdMode = true;
|
|
4845
5239
|
if (this.sandBox)
|
|
4846
5240
|
this.sandBox.proxyWindow.__MICRO_APP_UMD_MODE__ = true;
|
|
4847
|
-
// this.sandBox?.
|
|
5241
|
+
// this.sandBox?.recordEffectSnapshot()
|
|
4848
5242
|
try {
|
|
4849
|
-
umdHookMountResult = this.umdHookMount();
|
|
5243
|
+
umdHookMountResult = this.umdHookMount(microApp.getData(this.name, true));
|
|
4850
5244
|
}
|
|
4851
5245
|
catch (e) {
|
|
4852
5246
|
logError('an error occurred in the mount function \n', this.name, e);
|
|
@@ -4855,12 +5249,19 @@ class CreateApp {
|
|
|
4855
5249
|
}
|
|
4856
5250
|
if (!hasDispatchMountedEvent && (isFinished === true || this.umdMode)) {
|
|
4857
5251
|
hasDispatchMountedEvent = true;
|
|
4858
|
-
this.handleMounted(umdHookMountResult);
|
|
5252
|
+
const dispatchMounted = () => this.handleMounted(umdHookMountResult);
|
|
5253
|
+
if (this.isPrerender) {
|
|
5254
|
+
((_a = this.preRenderEvent) !== null && _a !== void 0 ? _a : (this.preRenderEvent = [])).push(dispatchMounted);
|
|
5255
|
+
this.recordAndReleaseEffect();
|
|
5256
|
+
}
|
|
5257
|
+
else {
|
|
5258
|
+
dispatchMounted();
|
|
5259
|
+
}
|
|
4859
5260
|
}
|
|
4860
5261
|
});
|
|
4861
5262
|
}
|
|
4862
5263
|
else {
|
|
4863
|
-
(
|
|
5264
|
+
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.rebuildEffectSnapshot();
|
|
4864
5265
|
try {
|
|
4865
5266
|
umdHookMountResult = this.umdHookMount();
|
|
4866
5267
|
}
|
|
@@ -4890,6 +5291,9 @@ class CreateApp {
|
|
|
4890
5291
|
dispatchMountedEvent() {
|
|
4891
5292
|
if (appStates.UNMOUNT !== this.state) {
|
|
4892
5293
|
this.state = appStates.MOUNTED;
|
|
5294
|
+
// call window.onmount of child app
|
|
5295
|
+
callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONMOUNT), this.name, `window.${microGlobalEvent.ONMOUNT}`, microApp.getData(this.name, true));
|
|
5296
|
+
// dispatch event mounted to parent
|
|
4893
5297
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
4894
5298
|
}
|
|
4895
5299
|
}
|
|
@@ -4897,9 +5301,11 @@ class CreateApp {
|
|
|
4897
5301
|
* unmount app
|
|
4898
5302
|
* NOTE: Do not add any params on account of unmountApp
|
|
4899
5303
|
* @param destroy completely destroy, delete cache resources
|
|
5304
|
+
* @param clearData clear data of dateCenter
|
|
5305
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
4900
5306
|
* @param unmountcb callback of unmount
|
|
4901
5307
|
*/
|
|
4902
|
-
unmount(destroy, unmountcb) {
|
|
5308
|
+
unmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
4903
5309
|
if (this.state === appStates.LOAD_FAILED) {
|
|
4904
5310
|
destroy = true;
|
|
4905
5311
|
}
|
|
@@ -4914,38 +5320,50 @@ class CreateApp {
|
|
|
4914
5320
|
*/
|
|
4915
5321
|
if (isFunction(this.umdHookUnmount)) {
|
|
4916
5322
|
try {
|
|
4917
|
-
umdHookUnmountResult = this.umdHookUnmount();
|
|
5323
|
+
umdHookUnmountResult = this.umdHookUnmount(microApp.getData(this.name, true));
|
|
4918
5324
|
}
|
|
4919
5325
|
catch (e) {
|
|
4920
5326
|
logError('an error occurred in the unmount function \n', this.name, e);
|
|
4921
5327
|
}
|
|
4922
5328
|
}
|
|
5329
|
+
// call window.onunmount of child app
|
|
5330
|
+
callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONUNMOUNT), this.name, `window.${microGlobalEvent.ONUNMOUNT}`);
|
|
4923
5331
|
// dispatch unmount event to micro app
|
|
4924
5332
|
dispatchCustomEventToMicroApp('unmount', this.name);
|
|
4925
|
-
this.handleUnmounted(destroy, umdHookUnmountResult, unmountcb);
|
|
5333
|
+
this.handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb);
|
|
4926
5334
|
}
|
|
4927
5335
|
/**
|
|
4928
5336
|
* handle for promise umdHookUnmount
|
|
4929
5337
|
* @param destroy completely destroy, delete cache resources
|
|
5338
|
+
* @param clearData clear data of dateCenter
|
|
5339
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
4930
5340
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
4931
5341
|
* @param unmountcb callback of unmount
|
|
4932
5342
|
*/
|
|
4933
|
-
handleUnmounted(destroy, umdHookUnmountResult, unmountcb) {
|
|
5343
|
+
handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb) {
|
|
5344
|
+
const unmountParam = {
|
|
5345
|
+
destroy,
|
|
5346
|
+
clearData,
|
|
5347
|
+
keepRouteState,
|
|
5348
|
+
unmountcb,
|
|
5349
|
+
};
|
|
4934
5350
|
if (isPromise(umdHookUnmountResult)) {
|
|
4935
5351
|
umdHookUnmountResult
|
|
4936
|
-
.then(() => this.actionsForUnmount(
|
|
4937
|
-
.catch(() => this.actionsForUnmount(
|
|
5352
|
+
.then(() => this.actionsForUnmount(unmountParam))
|
|
5353
|
+
.catch(() => this.actionsForUnmount(unmountParam));
|
|
4938
5354
|
}
|
|
4939
5355
|
else {
|
|
4940
|
-
this.actionsForUnmount(
|
|
5356
|
+
this.actionsForUnmount(unmountParam);
|
|
4941
5357
|
}
|
|
4942
5358
|
}
|
|
4943
5359
|
/**
|
|
4944
5360
|
* actions for unmount app
|
|
4945
5361
|
* @param destroy completely destroy, delete cache resources
|
|
5362
|
+
* @param clearData clear data of dateCenter
|
|
5363
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
4946
5364
|
* @param unmountcb callback of unmount
|
|
4947
5365
|
*/
|
|
4948
|
-
actionsForUnmount(destroy, unmountcb) {
|
|
5366
|
+
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
|
|
4949
5367
|
var _a, _b;
|
|
4950
5368
|
if (destroy) {
|
|
4951
5369
|
this.actionsForCompletelyDestroy();
|
|
@@ -4954,7 +5372,7 @@ class CreateApp {
|
|
|
4954
5372
|
cloneContainer(this.container, this.source.html, false);
|
|
4955
5373
|
}
|
|
4956
5374
|
if (this.umdMode) {
|
|
4957
|
-
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.
|
|
5375
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
|
|
4958
5376
|
}
|
|
4959
5377
|
/**
|
|
4960
5378
|
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
@@ -4964,27 +5382,34 @@ class CreateApp {
|
|
|
4964
5382
|
*/
|
|
4965
5383
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop({
|
|
4966
5384
|
umdMode: this.umdMode,
|
|
4967
|
-
keepRouteState:
|
|
5385
|
+
keepRouteState: keepRouteState && !destroy,
|
|
4968
5386
|
clearEventSource: !this.umdMode || destroy,
|
|
5387
|
+
clearData: clearData || destroy,
|
|
4969
5388
|
});
|
|
4970
5389
|
if (!getActiveApps().length) {
|
|
4971
5390
|
releasePatchSetAttribute();
|
|
4972
5391
|
}
|
|
4973
5392
|
// dispatch unmount event to base app
|
|
4974
5393
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
5394
|
+
this.resetConfig();
|
|
5395
|
+
unmountcb && unmountcb();
|
|
5396
|
+
}
|
|
5397
|
+
resetConfig() {
|
|
4975
5398
|
this.container.innerHTML = '';
|
|
4976
5399
|
this.container = null;
|
|
4977
|
-
|
|
5400
|
+
this.isPrerender = false;
|
|
5401
|
+
this.preRenderEvent = undefined;
|
|
4978
5402
|
}
|
|
4979
5403
|
// actions for completely destroy
|
|
4980
5404
|
actionsForCompletelyDestroy() {
|
|
4981
5405
|
if (!this.useSandbox && this.umdMode) {
|
|
4982
5406
|
delete window[this.libraryName];
|
|
4983
5407
|
}
|
|
5408
|
+
sourceCenter.script.deleteInlineInfo(this.source.scripts);
|
|
4984
5409
|
appInstanceMap.delete(this.name);
|
|
4985
5410
|
}
|
|
4986
5411
|
// hidden app when disconnectedCallback called with keep-alive
|
|
4987
|
-
hiddenKeepAliveApp() {
|
|
5412
|
+
hiddenKeepAliveApp(callback) {
|
|
4988
5413
|
var _a;
|
|
4989
5414
|
const oldContainer = this.container;
|
|
4990
5415
|
cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
|
|
@@ -4997,12 +5422,17 @@ class CreateApp {
|
|
|
4997
5422
|
});
|
|
4998
5423
|
// dispatch afterHidden event to base app
|
|
4999
5424
|
dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
|
|
5000
|
-
|
|
5001
|
-
|
|
5425
|
+
if (this.useMemoryRouter) {
|
|
5426
|
+
// called after lifeCyclesEvent
|
|
5427
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
5428
|
+
}
|
|
5429
|
+
this.recordAndReleaseEffect();
|
|
5430
|
+
callback && callback();
|
|
5002
5431
|
}
|
|
5003
5432
|
// show app when connectedCallback called with keep-alive
|
|
5004
5433
|
showKeepAliveApp(container) {
|
|
5005
|
-
var _a;
|
|
5434
|
+
var _a, _b;
|
|
5435
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
5006
5436
|
// dispatch beforeShow event to micro-app
|
|
5007
5437
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
5008
5438
|
appState: 'beforeshow',
|
|
@@ -5012,8 +5442,10 @@ class CreateApp {
|
|
|
5012
5442
|
cloneContainer(this.container, container, false);
|
|
5013
5443
|
this.container = container;
|
|
5014
5444
|
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
5015
|
-
|
|
5016
|
-
|
|
5445
|
+
if (this.useMemoryRouter) {
|
|
5446
|
+
// called before lifeCyclesEvent
|
|
5447
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
|
|
5448
|
+
}
|
|
5017
5449
|
// dispatch afterShow event to micro-app
|
|
5018
5450
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
5019
5451
|
appState: 'aftershow',
|
|
@@ -5053,6 +5485,23 @@ class CreateApp {
|
|
|
5053
5485
|
}
|
|
5054
5486
|
return {};
|
|
5055
5487
|
}
|
|
5488
|
+
getGlobalEventListener(eventName) {
|
|
5489
|
+
var _a;
|
|
5490
|
+
// @ts-ignore
|
|
5491
|
+
const listener = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow[eventName];
|
|
5492
|
+
return isFunction(listener) ? listener : null;
|
|
5493
|
+
}
|
|
5494
|
+
/**
|
|
5495
|
+
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
5496
|
+
* Scenes:
|
|
5497
|
+
* 1. hidden keep-alive app
|
|
5498
|
+
* 2. after init prerender app
|
|
5499
|
+
*/
|
|
5500
|
+
recordAndReleaseEffect() {
|
|
5501
|
+
var _a, _b;
|
|
5502
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
|
|
5503
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.releaseGlobalEffect();
|
|
5504
|
+
}
|
|
5056
5505
|
}
|
|
5057
5506
|
|
|
5058
5507
|
/**
|
|
@@ -5088,7 +5537,7 @@ function defineElement(tagName) {
|
|
|
5088
5537
|
keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
|
|
5089
5538
|
!existApp.isPrefetch) {
|
|
5090
5539
|
this.setAttribute('name', this.appName);
|
|
5091
|
-
return logError(`app name conflict, an app named ${formatAttrName} is running
|
|
5540
|
+
return logError(`app name conflict, an app named ${formatAttrName} is running`);
|
|
5092
5541
|
}
|
|
5093
5542
|
}
|
|
5094
5543
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
@@ -5135,25 +5584,56 @@ function defineElement(tagName) {
|
|
|
5135
5584
|
* In some special scenes, such as vue's keep-alive, the micro-app will be inserted and deleted twice in an instant
|
|
5136
5585
|
* So we execute the mount method async and record connectState to prevent repeated rendering
|
|
5137
5586
|
*/
|
|
5587
|
+
const effectiveApp = this.appName && this.appUrl;
|
|
5138
5588
|
defer(() => {
|
|
5139
5589
|
if (this.connectStateMap.get(cacheCount)) {
|
|
5140
5590
|
dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED);
|
|
5141
|
-
|
|
5591
|
+
/**
|
|
5592
|
+
* If insert micro-app element without name or url, and set them in next action like angular,
|
|
5593
|
+
* handleConnected will be executed twice, causing the app render repeatedly,
|
|
5594
|
+
* so we only execute handleConnected() if url and name exist when connectedCallback
|
|
5595
|
+
*/
|
|
5596
|
+
effectiveApp && this.handleConnected();
|
|
5142
5597
|
}
|
|
5143
5598
|
});
|
|
5144
5599
|
}
|
|
5145
5600
|
disconnectedCallback() {
|
|
5146
5601
|
this.connectStateMap.set(this.connectedCount, false);
|
|
5602
|
+
this.handleDisconnected();
|
|
5603
|
+
}
|
|
5604
|
+
/**
|
|
5605
|
+
* Re render app from the command line
|
|
5606
|
+
* MicroAppElement.reload(destroy)
|
|
5607
|
+
*/
|
|
5608
|
+
reload(destroy) {
|
|
5609
|
+
return new Promise((resolve) => {
|
|
5610
|
+
const handleAfterReload = () => {
|
|
5611
|
+
this.removeEventListener(lifeCycles.MOUNTED, handleAfterReload);
|
|
5612
|
+
this.removeEventListener(lifeCycles.AFTERSHOW, handleAfterReload);
|
|
5613
|
+
resolve(true);
|
|
5614
|
+
};
|
|
5615
|
+
this.addEventListener(lifeCycles.MOUNTED, handleAfterReload);
|
|
5616
|
+
this.addEventListener(lifeCycles.AFTERSHOW, handleAfterReload);
|
|
5617
|
+
this.handleDisconnected(destroy, () => {
|
|
5618
|
+
this.handleConnected();
|
|
5619
|
+
});
|
|
5620
|
+
});
|
|
5621
|
+
}
|
|
5622
|
+
/**
|
|
5623
|
+
* common action for unmount
|
|
5624
|
+
* @param destroy reload param
|
|
5625
|
+
*/
|
|
5626
|
+
handleDisconnected(destroy = false, callback) {
|
|
5147
5627
|
const app = appInstanceMap.get(this.appName);
|
|
5148
5628
|
if (app &&
|
|
5149
5629
|
app.getAppState() !== appStates.UNMOUNT &&
|
|
5150
5630
|
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
5151
5631
|
// keep-alive
|
|
5152
|
-
if (this.getKeepAliveModeResult()) {
|
|
5153
|
-
this.handleHiddenKeepAliveApp();
|
|
5632
|
+
if (this.getKeepAliveModeResult() && !destroy) {
|
|
5633
|
+
this.handleHiddenKeepAliveApp(callback);
|
|
5154
5634
|
}
|
|
5155
5635
|
else {
|
|
5156
|
-
this.handleUnmount(this.getDestroyCompatibleResult());
|
|
5636
|
+
this.handleUnmount(destroy || this.getDestroyCompatibleResult(), callback);
|
|
5157
5637
|
}
|
|
5158
5638
|
}
|
|
5159
5639
|
}
|
|
@@ -5191,12 +5671,12 @@ function defineElement(tagName) {
|
|
|
5191
5671
|
}
|
|
5192
5672
|
// handle for connectedCallback run before attributeChangedCallback
|
|
5193
5673
|
handleInitialNameAndUrl() {
|
|
5194
|
-
this.connectStateMap.get(this.connectedCount) && this.
|
|
5674
|
+
this.connectStateMap.get(this.connectedCount) && this.handleConnected();
|
|
5195
5675
|
}
|
|
5196
5676
|
/**
|
|
5197
5677
|
* first mount of this app
|
|
5198
5678
|
*/
|
|
5199
|
-
|
|
5679
|
+
handleConnected() {
|
|
5200
5680
|
if (!this.appName || !this.appUrl)
|
|
5201
5681
|
return;
|
|
5202
5682
|
if (this.getDisposeResult('shadowDOM') && !this.shadowRoot && isFunction(this.attachShadow)) {
|
|
@@ -5223,7 +5703,7 @@ function defineElement(tagName) {
|
|
|
5223
5703
|
this.handleAppMount(app);
|
|
5224
5704
|
}
|
|
5225
5705
|
else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
|
|
5226
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
5706
|
+
if ((process.env.NODE_ENV !== 'production') &&
|
|
5227
5707
|
app.scopecss === this.isScopecss() &&
|
|
5228
5708
|
app.useSandbox === this.isSandbox()) {
|
|
5229
5709
|
/**
|
|
@@ -5234,7 +5714,7 @@ function defineElement(tagName) {
|
|
|
5234
5714
|
this.handleCreateApp();
|
|
5235
5715
|
}
|
|
5236
5716
|
else {
|
|
5237
|
-
logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running
|
|
5717
|
+
logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running`);
|
|
5238
5718
|
}
|
|
5239
5719
|
}
|
|
5240
5720
|
else {
|
|
@@ -5269,7 +5749,7 @@ function defineElement(tagName) {
|
|
|
5269
5749
|
}
|
|
5270
5750
|
else {
|
|
5271
5751
|
// the hidden keep-alive app is still active
|
|
5272
|
-
logError(`app name conflict, an app named ${this.appName} is running
|
|
5752
|
+
logError(`app name conflict, an app named ${this.appName} is running`);
|
|
5273
5753
|
}
|
|
5274
5754
|
}
|
|
5275
5755
|
else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
|
|
@@ -5296,6 +5776,27 @@ function defineElement(tagName) {
|
|
|
5296
5776
|
}
|
|
5297
5777
|
return true;
|
|
5298
5778
|
}
|
|
5779
|
+
// create app instance
|
|
5780
|
+
handleCreateApp() {
|
|
5781
|
+
var _a;
|
|
5782
|
+
/**
|
|
5783
|
+
* actions for destroy old app
|
|
5784
|
+
* fix of unmounted umd app with disableSandbox
|
|
5785
|
+
*/
|
|
5786
|
+
if (appInstanceMap.has(this.appName)) {
|
|
5787
|
+
appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
|
|
5788
|
+
}
|
|
5789
|
+
new CreateApp({
|
|
5790
|
+
name: this.appName,
|
|
5791
|
+
url: this.appUrl,
|
|
5792
|
+
scopecss: this.isScopecss(),
|
|
5793
|
+
useSandbox: this.isSandbox(),
|
|
5794
|
+
inline: this.getDisposeResult('inline'),
|
|
5795
|
+
esmodule: this.getDisposeResult('esmodule'),
|
|
5796
|
+
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
5797
|
+
ssrUrl: this.ssrUrl,
|
|
5798
|
+
});
|
|
5799
|
+
}
|
|
5299
5800
|
/**
|
|
5300
5801
|
* mount app
|
|
5301
5802
|
* some serious note before mount:
|
|
@@ -5315,55 +5816,38 @@ function defineElement(tagName) {
|
|
|
5315
5816
|
app.mount({
|
|
5316
5817
|
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
5317
5818
|
inline: this.getDisposeResult('inline'),
|
|
5318
|
-
esmodule: this.getDisposeResult('esmodule'),
|
|
5319
5819
|
useMemoryRouter: !this.getDisposeResult('disable-memory-router'),
|
|
5320
|
-
baseroute: this.getBaseRouteCompatible(),
|
|
5321
|
-
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
5322
5820
|
defaultPage: this.getDefaultPageValue(),
|
|
5323
|
-
|
|
5821
|
+
baseroute: this.getBaseRouteCompatible(),
|
|
5324
5822
|
disablePatchRequest: this.getDisposeResult('disable-patch-request'),
|
|
5325
5823
|
fiber: this.getDisposeResult('fiber'),
|
|
5326
|
-
});
|
|
5327
|
-
}
|
|
5328
|
-
// create app instance
|
|
5329
|
-
handleCreateApp() {
|
|
5330
|
-
var _a;
|
|
5331
|
-
/**
|
|
5332
|
-
* actions for destroy old app
|
|
5333
|
-
* fix of unmounted umd app with disableSandbox
|
|
5334
|
-
*/
|
|
5335
|
-
if (appInstanceMap.has(this.appName)) {
|
|
5336
|
-
appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
|
|
5337
|
-
}
|
|
5338
|
-
new CreateApp({
|
|
5339
|
-
name: this.appName,
|
|
5340
|
-
url: this.appUrl,
|
|
5341
|
-
scopecss: this.isScopecss(),
|
|
5342
|
-
useSandbox: this.isSandbox(),
|
|
5343
|
-
inline: this.getDisposeResult('inline'),
|
|
5344
5824
|
esmodule: this.getDisposeResult('esmodule'),
|
|
5345
|
-
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
5346
|
-
ssrUrl: this.ssrUrl,
|
|
5347
5825
|
});
|
|
5348
5826
|
}
|
|
5349
5827
|
/**
|
|
5350
5828
|
* unmount app
|
|
5351
5829
|
* @param destroy delete cache resources when unmount
|
|
5352
5830
|
*/
|
|
5353
|
-
handleUnmount(destroy,
|
|
5831
|
+
handleUnmount(destroy, unmountcb) {
|
|
5354
5832
|
const app = appInstanceMap.get(this.appName);
|
|
5355
5833
|
if (app &&
|
|
5356
5834
|
app.getAppState() !== appStates.UNMOUNT) {
|
|
5357
|
-
app.unmount(
|
|
5835
|
+
app.unmount({
|
|
5836
|
+
destroy,
|
|
5837
|
+
clearData: this.getDisposeResult('clear-data'),
|
|
5838
|
+
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
5839
|
+
unmountcb,
|
|
5840
|
+
});
|
|
5358
5841
|
}
|
|
5359
5842
|
}
|
|
5360
5843
|
// hidden app when disconnectedCallback called with keep-alive
|
|
5361
|
-
handleHiddenKeepAliveApp() {
|
|
5844
|
+
handleHiddenKeepAliveApp(callback) {
|
|
5362
5845
|
const app = appInstanceMap.get(this.appName);
|
|
5363
5846
|
if (app &&
|
|
5364
5847
|
app.getAppState() !== appStates.UNMOUNT &&
|
|
5365
|
-
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN)
|
|
5366
|
-
app.hiddenKeepAliveApp();
|
|
5848
|
+
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
5849
|
+
app.hiddenKeepAliveApp(callback);
|
|
5850
|
+
}
|
|
5367
5851
|
}
|
|
5368
5852
|
// show app when connectedCallback called with keep-alive
|
|
5369
5853
|
handleShowKeepAliveApp(app) {
|
|
@@ -5480,7 +5964,7 @@ function defineElement(tagName) {
|
|
|
5480
5964
|
return null;
|
|
5481
5965
|
}
|
|
5482
5966
|
}
|
|
5483
|
-
|
|
5967
|
+
globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
|
|
5484
5968
|
}
|
|
5485
5969
|
|
|
5486
5970
|
/**
|
|
@@ -5488,30 +5972,57 @@ function defineElement(tagName) {
|
|
|
5488
5972
|
* {
|
|
5489
5973
|
* name: string,
|
|
5490
5974
|
* url: string,
|
|
5491
|
-
*
|
|
5492
|
-
*
|
|
5493
|
-
*
|
|
5975
|
+
* esmodule: boolean,
|
|
5976
|
+
* inline: boolean,
|
|
5977
|
+
* 'disable-scopecss': boolean,
|
|
5978
|
+
* 'disable-sandbox': boolean,
|
|
5979
|
+
* level: number,
|
|
5980
|
+
* 'default-page': string,
|
|
5981
|
+
* 'disable-patch-request': boolean,
|
|
5494
5982
|
* },
|
|
5495
5983
|
* ...
|
|
5496
5984
|
* ])
|
|
5497
5985
|
* Note:
|
|
5498
|
-
* 1: preFetch is
|
|
5499
|
-
* 2:
|
|
5500
|
-
* @param apps micro
|
|
5986
|
+
* 1: preFetch is async and is performed only when the browser is idle
|
|
5987
|
+
* 2: options of prefetch preferably match the config of the micro-app element, although this is not required
|
|
5988
|
+
* @param apps micro app options
|
|
5989
|
+
* @param delay delay time
|
|
5501
5990
|
*/
|
|
5502
|
-
function preFetch(apps) {
|
|
5991
|
+
function preFetch(apps, delay) {
|
|
5503
5992
|
if (!isBrowser) {
|
|
5504
5993
|
return logError('preFetch is only supported in browser environment');
|
|
5505
5994
|
}
|
|
5506
5995
|
requestIdleCallback(() => {
|
|
5507
|
-
|
|
5508
|
-
|
|
5509
|
-
|
|
5510
|
-
|
|
5996
|
+
const delayTime = isNumber(delay) ? delay : microApp.options.prefetchDelay;
|
|
5997
|
+
/**
|
|
5998
|
+
* TODO: remove setTimeout
|
|
5999
|
+
* Is there a better way?
|
|
6000
|
+
*/
|
|
6001
|
+
setTimeout(() => {
|
|
6002
|
+
// releasePrefetchEffect()
|
|
6003
|
+
preFetchInSerial(apps);
|
|
6004
|
+
}, isNumber(delayTime) ? delayTime : 3000);
|
|
5511
6005
|
});
|
|
6006
|
+
// const handleOnLoad = (): void => {
|
|
6007
|
+
// releasePrefetchEffect()
|
|
6008
|
+
// requestIdleCallback(() => {
|
|
6009
|
+
// preFetchInSerial(apps)
|
|
6010
|
+
// })
|
|
6011
|
+
// }
|
|
6012
|
+
// const releasePrefetchEffect = (): void => {
|
|
6013
|
+
// window.removeEventListener('load', handleOnLoad)
|
|
6014
|
+
// clearTimeout(preFetchTime)
|
|
6015
|
+
// }
|
|
6016
|
+
// window.addEventListener('load', handleOnLoad)
|
|
6017
|
+
}
|
|
6018
|
+
function preFetchInSerial(apps) {
|
|
6019
|
+
isFunction(apps) && (apps = apps());
|
|
6020
|
+
if (isArray(apps)) {
|
|
6021
|
+
apps.reduce((pre, next) => pre.then(() => preFetchAction(next)), Promise.resolve());
|
|
6022
|
+
}
|
|
5512
6023
|
}
|
|
5513
6024
|
// sequential preload app
|
|
5514
|
-
function
|
|
6025
|
+
function preFetchAction(options) {
|
|
5515
6026
|
return promiseRequestIdle((resolve) => {
|
|
5516
6027
|
var _a, _b, _c, _d, _e, _f;
|
|
5517
6028
|
if (isPlainObject(options) && navigator.onLine) {
|
|
@@ -5521,21 +6032,22 @@ function preFetchInSerial(options) {
|
|
|
5521
6032
|
const app = new CreateApp({
|
|
5522
6033
|
name: options.name,
|
|
5523
6034
|
url: options.url,
|
|
6035
|
+
isPrefetch: true,
|
|
5524
6036
|
scopecss: !((_b = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss) !== null && _b !== void 0 ? _b : microApp.options['disable-scopecss']),
|
|
5525
6037
|
useSandbox: !((_d = (_c = options['disable-sandbox']) !== null && _c !== void 0 ? _c : options.disableSandbox) !== null && _d !== void 0 ? _d : microApp.options['disable-sandbox']),
|
|
5526
6038
|
inline: (_e = options.inline) !== null && _e !== void 0 ? _e : microApp.options.inline,
|
|
5527
6039
|
esmodule: (_f = options.esmodule) !== null && _f !== void 0 ? _f : microApp.options.esmodule,
|
|
5528
|
-
|
|
6040
|
+
prefetchLevel: options.level && PREFETCH_LEVEL.includes(options.level) ? options.level : microApp.options.prefetchLevel && PREFETCH_LEVEL.includes(microApp.options.prefetchLevel) ? microApp.options.prefetchLevel : 2,
|
|
5529
6041
|
});
|
|
5530
6042
|
const oldOnload = app.onLoad;
|
|
5531
6043
|
const oldOnLoadError = app.onLoadError;
|
|
5532
6044
|
app.onLoad = (html) => {
|
|
5533
6045
|
resolve();
|
|
5534
|
-
oldOnload.call(app, html);
|
|
6046
|
+
oldOnload.call(app, html, options['default-page'], options['disable-patch-request']);
|
|
5535
6047
|
};
|
|
5536
|
-
app.onLoadError = (
|
|
6048
|
+
app.onLoadError = (...rests) => {
|
|
5537
6049
|
resolve();
|
|
5538
|
-
oldOnLoadError.call(app,
|
|
6050
|
+
oldOnLoadError.call(app, ...rests);
|
|
5539
6051
|
};
|
|
5540
6052
|
}
|
|
5541
6053
|
else {
|
|
@@ -5593,13 +6105,14 @@ function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
|
5593
6105
|
/**
|
|
5594
6106
|
* if app not prefetch & not unmount, then app is active
|
|
5595
6107
|
* @param excludeHiddenApp exclude hidden keep-alive app, default is false
|
|
6108
|
+
* @param excludePreRender exclude pre render app
|
|
5596
6109
|
* @returns active apps
|
|
5597
6110
|
*/
|
|
5598
|
-
function getActiveApps(excludeHiddenApp = false) {
|
|
6111
|
+
function getActiveApps({ excludeHiddenApp = false, excludePreRender = false, } = {}) {
|
|
5599
6112
|
const activeApps = [];
|
|
5600
6113
|
appInstanceMap.forEach((app, appName) => {
|
|
5601
6114
|
if (appStates.UNMOUNT !== app.getAppState() &&
|
|
5602
|
-
!app.isPrefetch &&
|
|
6115
|
+
(!app.isPrefetch || (app.isPrerender && !excludePreRender)) &&
|
|
5603
6116
|
(!excludeHiddenApp ||
|
|
5604
6117
|
keepAliveStates.KEEP_ALIVE_HIDDEN !== app.getKeepAliveState())) {
|
|
5605
6118
|
activeApps.push(appName);
|
|
@@ -5625,33 +6138,43 @@ function unmountApp(appName, options) {
|
|
|
5625
6138
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
5626
6139
|
app.actionsForCompletelyDestroy();
|
|
5627
6140
|
}
|
|
5628
|
-
resolve();
|
|
6141
|
+
resolve(true);
|
|
5629
6142
|
}
|
|
5630
6143
|
else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
5631
6144
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
5632
|
-
app.unmount(
|
|
6145
|
+
app.unmount({
|
|
6146
|
+
destroy: true,
|
|
6147
|
+
clearData: true,
|
|
6148
|
+
keepRouteState: true,
|
|
6149
|
+
unmountcb: resolve.bind(null, true)
|
|
6150
|
+
});
|
|
5633
6151
|
}
|
|
5634
6152
|
else if (options === null || options === void 0 ? void 0 : options.clearAliveState) {
|
|
5635
|
-
app.unmount(
|
|
6153
|
+
app.unmount({
|
|
6154
|
+
destroy: false,
|
|
6155
|
+
clearData: !!options.clearData,
|
|
6156
|
+
keepRouteState: true,
|
|
6157
|
+
unmountcb: resolve.bind(null, true)
|
|
6158
|
+
});
|
|
5636
6159
|
}
|
|
5637
6160
|
else {
|
|
5638
|
-
resolve();
|
|
6161
|
+
resolve(true);
|
|
5639
6162
|
}
|
|
5640
6163
|
}
|
|
5641
6164
|
else {
|
|
5642
6165
|
const container = getRootContainer(app.container);
|
|
5643
6166
|
const unmountHandler = () => {
|
|
5644
|
-
container.removeEventListener(
|
|
5645
|
-
container.removeEventListener(
|
|
5646
|
-
resolve();
|
|
6167
|
+
container.removeEventListener(lifeCycles.UNMOUNT, unmountHandler);
|
|
6168
|
+
container.removeEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
|
|
6169
|
+
resolve(true);
|
|
5647
6170
|
};
|
|
5648
6171
|
const afterhiddenHandler = () => {
|
|
5649
|
-
container.removeEventListener(
|
|
5650
|
-
container.removeEventListener(
|
|
5651
|
-
resolve();
|
|
6172
|
+
container.removeEventListener(lifeCycles.UNMOUNT, unmountHandler);
|
|
6173
|
+
container.removeEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
|
|
6174
|
+
resolve(true);
|
|
5652
6175
|
};
|
|
5653
|
-
container.addEventListener(
|
|
5654
|
-
container.addEventListener(
|
|
6176
|
+
container.addEventListener(lifeCycles.UNMOUNT, unmountHandler);
|
|
6177
|
+
container.addEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
|
|
5655
6178
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
5656
6179
|
let destroyAttrValue, destoryAttrValue;
|
|
5657
6180
|
container.hasAttribute('destroy') && (destroyAttrValue = container.getAttribute('destroy'));
|
|
@@ -5659,37 +6182,131 @@ function unmountApp(appName, options) {
|
|
|
5659
6182
|
container.setAttribute('destroy', 'true');
|
|
5660
6183
|
container.parentNode.removeChild(container);
|
|
5661
6184
|
container.removeAttribute('destroy');
|
|
5662
|
-
|
|
5663
|
-
|
|
6185
|
+
isString(destroyAttrValue) && container.setAttribute('destroy', destroyAttrValue);
|
|
6186
|
+
isString(destoryAttrValue) && container.setAttribute('destory', destoryAttrValue);
|
|
5664
6187
|
}
|
|
5665
6188
|
else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
|
|
5666
6189
|
const keepAliveAttrValue = container.getAttribute('keep-alive');
|
|
5667
6190
|
container.removeAttribute('keep-alive');
|
|
6191
|
+
let clearDataAttrValue;
|
|
6192
|
+
if (options.clearData) {
|
|
6193
|
+
clearDataAttrValue = container.getAttribute('clear-data');
|
|
6194
|
+
container.setAttribute('clear-data', 'true');
|
|
6195
|
+
}
|
|
5668
6196
|
container.parentNode.removeChild(container);
|
|
5669
6197
|
container.setAttribute('keep-alive', keepAliveAttrValue);
|
|
6198
|
+
isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
|
|
5670
6199
|
}
|
|
5671
6200
|
else {
|
|
6201
|
+
let clearDataAttrValue;
|
|
6202
|
+
if (options === null || options === void 0 ? void 0 : options.clearData) {
|
|
6203
|
+
clearDataAttrValue = container.getAttribute('clear-data');
|
|
6204
|
+
container.setAttribute('clear-data', 'true');
|
|
6205
|
+
}
|
|
5672
6206
|
container.parentNode.removeChild(container);
|
|
6207
|
+
isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
|
|
5673
6208
|
}
|
|
5674
6209
|
}
|
|
5675
6210
|
}
|
|
5676
6211
|
else {
|
|
5677
6212
|
logWarn(`app ${appName} does not exist`);
|
|
5678
|
-
resolve();
|
|
6213
|
+
resolve(false);
|
|
5679
6214
|
}
|
|
5680
6215
|
});
|
|
5681
6216
|
}
|
|
5682
6217
|
// unmount all apps in turn
|
|
5683
6218
|
function unmountAllApps(options) {
|
|
5684
|
-
return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve());
|
|
6219
|
+
return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve(true));
|
|
6220
|
+
}
|
|
6221
|
+
/**
|
|
6222
|
+
* Re render app from the command line
|
|
6223
|
+
* microApp.reload(destroy)
|
|
6224
|
+
* @param appName app.name
|
|
6225
|
+
* @param destroy unmount app with destroy mode
|
|
6226
|
+
* @returns Promise<boolean>
|
|
6227
|
+
*/
|
|
6228
|
+
function reload(appName, destroy) {
|
|
6229
|
+
return new Promise((resolve) => {
|
|
6230
|
+
const app = appInstanceMap.get(formatAppName(appName));
|
|
6231
|
+
if (app) {
|
|
6232
|
+
const rootContainer = app.container && getRootContainer(app.container);
|
|
6233
|
+
if (rootContainer) {
|
|
6234
|
+
resolve(rootContainer.reload(destroy));
|
|
6235
|
+
}
|
|
6236
|
+
else {
|
|
6237
|
+
logWarn(`app ${appName} is not rendered, cannot use reload`);
|
|
6238
|
+
resolve(false);
|
|
6239
|
+
}
|
|
6240
|
+
}
|
|
6241
|
+
else {
|
|
6242
|
+
logWarn(`app ${appName} does not exist`);
|
|
6243
|
+
resolve(false);
|
|
6244
|
+
}
|
|
6245
|
+
});
|
|
6246
|
+
}
|
|
6247
|
+
/**
|
|
6248
|
+
* Manually render app
|
|
6249
|
+
* @param options RenderAppOptions
|
|
6250
|
+
* @returns Promise<boolean>
|
|
6251
|
+
*/
|
|
6252
|
+
function renderApp(options) {
|
|
6253
|
+
return new Promise((resolve) => {
|
|
6254
|
+
if (!isPlainObject(options))
|
|
6255
|
+
return logError('renderApp options must be an object');
|
|
6256
|
+
const container = isElement(options.container) ? options.container : isString(options.container) ? document.querySelector(options.container) : null;
|
|
6257
|
+
if (!isElement(container))
|
|
6258
|
+
return logError('Target container is not a DOM element.');
|
|
6259
|
+
const microAppElement = pureCreateElement(microApp.tagName);
|
|
6260
|
+
for (const attr in options) {
|
|
6261
|
+
if (attr === 'onDataChange') {
|
|
6262
|
+
if (isFunction(options[attr])) {
|
|
6263
|
+
microAppElement.addEventListener('datachange', options[attr]);
|
|
6264
|
+
}
|
|
6265
|
+
}
|
|
6266
|
+
else if (attr === 'lifeCycles') {
|
|
6267
|
+
const lifeCycleConfig = options[attr];
|
|
6268
|
+
if (isPlainObject(lifeCycleConfig)) {
|
|
6269
|
+
for (const lifeName in lifeCycleConfig) {
|
|
6270
|
+
if (lifeName.toUpperCase() in lifeCycles && isFunction(lifeCycleConfig[lifeName])) {
|
|
6271
|
+
microAppElement.addEventListener(lifeName.toLowerCase(), lifeCycleConfig[lifeName]);
|
|
6272
|
+
}
|
|
6273
|
+
}
|
|
6274
|
+
}
|
|
6275
|
+
}
|
|
6276
|
+
else if (attr !== 'container') {
|
|
6277
|
+
microAppElement.setAttribute(attr, options[attr]);
|
|
6278
|
+
}
|
|
6279
|
+
}
|
|
6280
|
+
const handleMount = () => {
|
|
6281
|
+
releaseListener();
|
|
6282
|
+
resolve(true);
|
|
6283
|
+
};
|
|
6284
|
+
const handleError = () => {
|
|
6285
|
+
releaseListener();
|
|
6286
|
+
resolve(false);
|
|
6287
|
+
};
|
|
6288
|
+
const releaseListener = () => {
|
|
6289
|
+
microAppElement.removeEventListener(lifeCycles.MOUNTED, handleMount);
|
|
6290
|
+
microAppElement.removeEventListener(lifeCycles.ERROR, handleError);
|
|
6291
|
+
};
|
|
6292
|
+
microAppElement.addEventListener(lifeCycles.MOUNTED, handleMount);
|
|
6293
|
+
microAppElement.addEventListener(lifeCycles.ERROR, handleError);
|
|
6294
|
+
container.appendChild(microAppElement);
|
|
6295
|
+
});
|
|
5685
6296
|
}
|
|
5686
6297
|
class MicroApp extends EventCenterForBaseApp {
|
|
5687
6298
|
constructor() {
|
|
5688
6299
|
super(...arguments);
|
|
5689
6300
|
this.tagName = 'micro-app';
|
|
5690
6301
|
this.options = {};
|
|
5691
|
-
this.preFetch = preFetch;
|
|
5692
6302
|
this.router = router;
|
|
6303
|
+
this.preFetch = preFetch;
|
|
6304
|
+
this.unmountApp = unmountApp;
|
|
6305
|
+
this.unmountAllApps = unmountAllApps;
|
|
6306
|
+
this.getActiveApps = getActiveApps;
|
|
6307
|
+
this.getAllApps = getAllApps;
|
|
6308
|
+
this.reload = reload;
|
|
6309
|
+
this.renderApp = renderApp;
|
|
5693
6310
|
}
|
|
5694
6311
|
start(options) {
|
|
5695
6312
|
var _a, _b;
|
|
@@ -5733,8 +6350,8 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
5733
6350
|
defineElement(this.tagName);
|
|
5734
6351
|
}
|
|
5735
6352
|
}
|
|
5736
|
-
|
|
6353
|
+
const microApp = new MicroApp();
|
|
5737
6354
|
|
|
5738
6355
|
export default microApp;
|
|
5739
|
-
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, unmountAllApps, unmountApp, version };
|
|
6356
|
+
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
|
|
5740
6357
|
//# sourceMappingURL=index.esm.js.map
|