@micro-zoe/micro-app 1.0.0-alpha.9 → 1.0.0-beta.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/README.zh-cn.md +4 -3
- package/lib/index.d.ts +19 -4
- package/lib/index.esm.js +2169 -673
- 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 +3 -3
- package/typings/global.d.ts +54 -19
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-
|
|
1
|
+
const version = '1.0.0-beta.1';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -7,7 +7,6 @@ const globalThis = (typeof global !== 'undefined')
|
|
|
7
7
|
: ((typeof window !== 'undefined')
|
|
8
8
|
? window
|
|
9
9
|
: ((typeof self !== 'undefined') ? self : Function('return this')()));
|
|
10
|
-
const noop = () => { };
|
|
11
10
|
const noopFalse = () => false;
|
|
12
11
|
// Array.isArray
|
|
13
12
|
const isArray = Array.isArray;
|
|
@@ -74,13 +73,50 @@ function isShadowRoot(target) {
|
|
|
74
73
|
return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
|
|
75
74
|
}
|
|
76
75
|
function isURL(target) {
|
|
77
|
-
|
|
76
|
+
var _a;
|
|
77
|
+
return target instanceof URL || !!((_a = target) === null || _a === void 0 ? void 0 : _a.href);
|
|
78
78
|
}
|
|
79
|
+
// iframe element not instanceof base app Element, use tagName instead
|
|
79
80
|
function isElement(target) {
|
|
80
|
-
|
|
81
|
+
var _a;
|
|
82
|
+
return target instanceof Element || isString((_a = target) === null || _a === void 0 ? void 0 : _a.tagName);
|
|
81
83
|
}
|
|
84
|
+
// iframe node not instanceof base app Node, use nodeType instead
|
|
82
85
|
function isNode(target) {
|
|
83
|
-
|
|
86
|
+
var _a;
|
|
87
|
+
return target instanceof Node || isNumber((_a = target) === null || _a === void 0 ? void 0 : _a.nodeType);
|
|
88
|
+
}
|
|
89
|
+
function isLinkElement(target) {
|
|
90
|
+
var _a, _b;
|
|
91
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'LINK';
|
|
92
|
+
}
|
|
93
|
+
function isStyleElement(target) {
|
|
94
|
+
var _a, _b;
|
|
95
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'STYLE';
|
|
96
|
+
}
|
|
97
|
+
function isScriptElement(target) {
|
|
98
|
+
var _a, _b;
|
|
99
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'SCRIPT';
|
|
100
|
+
}
|
|
101
|
+
function isIFrameElement(target) {
|
|
102
|
+
var _a, _b;
|
|
103
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IFRAME';
|
|
104
|
+
}
|
|
105
|
+
function isDivElement(target) {
|
|
106
|
+
var _a, _b;
|
|
107
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'DIV';
|
|
108
|
+
}
|
|
109
|
+
function isImageElement(target) {
|
|
110
|
+
var _a, _b;
|
|
111
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IMG';
|
|
112
|
+
}
|
|
113
|
+
function isBaseElement(target) {
|
|
114
|
+
var _a, _b;
|
|
115
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'BASE';
|
|
116
|
+
}
|
|
117
|
+
function isMicroAppBody(target) {
|
|
118
|
+
var _a, _b;
|
|
119
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'MICRO-APP-BODY';
|
|
84
120
|
}
|
|
85
121
|
// is ProxyDocument
|
|
86
122
|
function isProxyDocument(target) {
|
|
@@ -323,6 +359,7 @@ function pureCreateElement(tagName, options) {
|
|
|
323
359
|
function cloneContainer(origin, target, deep) {
|
|
324
360
|
target.innerHTML = '';
|
|
325
361
|
if (deep) {
|
|
362
|
+
// TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
|
|
326
363
|
const clonedNode = origin.cloneNode(true);
|
|
327
364
|
const fragment = document.createDocumentFragment();
|
|
328
365
|
Array.from(clonedNode.childNodes).forEach((node) => {
|
|
@@ -335,6 +372,7 @@ function cloneContainer(origin, target, deep) {
|
|
|
335
372
|
target.appendChild(node);
|
|
336
373
|
});
|
|
337
374
|
}
|
|
375
|
+
return target;
|
|
338
376
|
}
|
|
339
377
|
// is invalid key of querySelector
|
|
340
378
|
function isInvalidQuerySelectorKey(key) {
|
|
@@ -500,12 +538,17 @@ function isInlineScript(address) {
|
|
|
500
538
|
* @param appName app.name
|
|
501
539
|
* @param args arguments
|
|
502
540
|
*/
|
|
503
|
-
function
|
|
541
|
+
function execMicroAppGlobalHook(fn, appName, hookName, ...args) {
|
|
504
542
|
try {
|
|
505
543
|
isFunction(fn) && fn(...args);
|
|
506
544
|
}
|
|
507
545
|
catch (e) {
|
|
508
|
-
logError(`
|
|
546
|
+
logError(`An error occurred in app ${appName} window.${hookName} \n`, null, e);
|
|
547
|
+
}
|
|
548
|
+
}
|
|
549
|
+
function clearDOM($dom) {
|
|
550
|
+
while ($dom === null || $dom === void 0 ? void 0 : $dom.firstChild) {
|
|
551
|
+
$dom.removeChild($dom.firstChild);
|
|
509
552
|
}
|
|
510
553
|
}
|
|
511
554
|
|
|
@@ -544,6 +587,11 @@ var microGlobalEvent;
|
|
|
544
587
|
microGlobalEvent["ONMOUNT"] = "onmount";
|
|
545
588
|
microGlobalEvent["ONUNMOUNT"] = "onunmount";
|
|
546
589
|
})(microGlobalEvent || (microGlobalEvent = {}));
|
|
590
|
+
// custom event of child app
|
|
591
|
+
const microAppCustomEvent = [
|
|
592
|
+
'unmount',
|
|
593
|
+
'appstate-change',
|
|
594
|
+
];
|
|
547
595
|
// keep-alive status
|
|
548
596
|
var keepAliveStates;
|
|
549
597
|
(function (keepAliveStates) {
|
|
@@ -566,7 +614,6 @@ var MicroAppConfig;
|
|
|
566
614
|
MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
|
|
567
615
|
MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
|
|
568
616
|
MicroAppConfig["CLEAR_DATA"] = "clear-data";
|
|
569
|
-
MicroAppConfig["ESMODULE"] = "esmodule";
|
|
570
617
|
MicroAppConfig["SSR"] = "ssr";
|
|
571
618
|
MicroAppConfig["FIBER"] = "fiber";
|
|
572
619
|
})(MicroAppConfig || (MicroAppConfig = {}));
|
|
@@ -1094,9 +1141,6 @@ function dispatchOnErrorEvent(element) {
|
|
|
1094
1141
|
function createSourceCenter() {
|
|
1095
1142
|
const linkList = new Map();
|
|
1096
1143
|
const scriptList = new Map();
|
|
1097
|
-
// setInterval(() => {
|
|
1098
|
-
// console.log(linkList, scriptList)
|
|
1099
|
-
// }, 10000);
|
|
1100
1144
|
function createSourceHandler(targetList) {
|
|
1101
1145
|
return {
|
|
1102
1146
|
setInfo(address, info) {
|
|
@@ -1138,7 +1182,7 @@ function getExistParseCode(appName, prefix, linkInfo) {
|
|
|
1138
1182
|
if (item !== appName) {
|
|
1139
1183
|
const appSpaceData = appSpace[item];
|
|
1140
1184
|
if (appSpaceData.parsedCode) {
|
|
1141
|
-
return appSpaceData.parsedCode.
|
|
1185
|
+
return appSpaceData.parsedCode.replace(new RegExp(createPrefix(item, true), 'g'), prefix);
|
|
1142
1186
|
}
|
|
1143
1187
|
}
|
|
1144
1188
|
}
|
|
@@ -1224,18 +1268,18 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
|
1224
1268
|
const linkInfo = sourceCenter.link.getInfo(address);
|
|
1225
1269
|
return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
|
|
1226
1270
|
});
|
|
1227
|
-
const fiberLinkTasks =
|
|
1271
|
+
const fiberLinkTasks = fiberStyleResult ? [] : null;
|
|
1228
1272
|
promiseStream(fetchLinkPromise, (res) => {
|
|
1229
1273
|
injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
|
|
1230
1274
|
}, (err) => {
|
|
1231
1275
|
logError(err, app.name);
|
|
1232
1276
|
}, () => {
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1277
|
+
/**
|
|
1278
|
+
* 1. If fiberStyleResult exist, fiberLinkTasks must exist
|
|
1279
|
+
* 2. Download link source while processing style
|
|
1280
|
+
* 3. Process style first, and then process link
|
|
1281
|
+
*/
|
|
1282
|
+
if (fiberStyleResult) {
|
|
1239
1283
|
fiberStyleResult.then(() => {
|
|
1240
1284
|
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1241
1285
|
serialExecFiberTasks(fiberLinkTasks);
|
|
@@ -1369,10 +1413,10 @@ class Adapter {
|
|
|
1369
1413
|
'webpackHotUpdate',
|
|
1370
1414
|
'Vue',
|
|
1371
1415
|
];
|
|
1372
|
-
this.
|
|
1416
|
+
this.injectReactHMRProperty();
|
|
1373
1417
|
}
|
|
1374
1418
|
// adapter for react
|
|
1375
|
-
|
|
1419
|
+
injectReactHMRProperty() {
|
|
1376
1420
|
if ((process.env.NODE_ENV !== 'production')) {
|
|
1377
1421
|
// react child in non-react env
|
|
1378
1422
|
this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
|
|
@@ -1411,13 +1455,15 @@ function fixReactHMRConflict(app) {
|
|
|
1411
1455
|
/**
|
|
1412
1456
|
* reDefine parentNode of html
|
|
1413
1457
|
* Scenes:
|
|
1414
|
-
* 1. element-ui
|
|
1415
|
-
*
|
|
1458
|
+
* 1. element-ui@2/lib/utils/popper.js
|
|
1459
|
+
* var parent = element.parentNode;
|
|
1460
|
+
* // root is child app window
|
|
1461
|
+
* if (parent === root.document) ...
|
|
1416
1462
|
*/
|
|
1417
|
-
function throttleDeferForParentNode(
|
|
1463
|
+
function throttleDeferForParentNode(microDocument) {
|
|
1418
1464
|
const html = globalEnv.rawDocument.firstElementChild;
|
|
1419
|
-
if (html
|
|
1420
|
-
setParentNode(html,
|
|
1465
|
+
if ((html === null || html === void 0 ? void 0 : html.parentNode) === globalEnv.rawDocument) {
|
|
1466
|
+
setParentNode(html, microDocument);
|
|
1421
1467
|
defer(() => {
|
|
1422
1468
|
setParentNode(html, globalEnv.rawDocument);
|
|
1423
1469
|
});
|
|
@@ -1437,6 +1483,72 @@ function setParentNode(target, value) {
|
|
|
1437
1483
|
});
|
|
1438
1484
|
}
|
|
1439
1485
|
}
|
|
1486
|
+
// this events should be sent to the specified app
|
|
1487
|
+
const formatEventList = ['unmount', 'appstate-change'];
|
|
1488
|
+
/**
|
|
1489
|
+
* Format event name
|
|
1490
|
+
* @param eventName event name
|
|
1491
|
+
* @param appName app name
|
|
1492
|
+
*/
|
|
1493
|
+
function formatEventName(eventName, appName) {
|
|
1494
|
+
var _a;
|
|
1495
|
+
if (!isIframeSandbox(appName) && (formatEventList.includes(eventName) ||
|
|
1496
|
+
((eventName === 'popstate' || eventName === 'hashchange') && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.useMemoryRouter)))) {
|
|
1497
|
+
return `${eventName}-${appName}`;
|
|
1498
|
+
}
|
|
1499
|
+
return eventName;
|
|
1500
|
+
}
|
|
1501
|
+
/**
|
|
1502
|
+
* update dom tree of target dom
|
|
1503
|
+
* @param container target dom
|
|
1504
|
+
* @param appName app name
|
|
1505
|
+
*/
|
|
1506
|
+
function patchElementTree(container, appName) {
|
|
1507
|
+
const children = Array.from(container.children);
|
|
1508
|
+
children.length && children.forEach((child) => {
|
|
1509
|
+
patchElementTree(child, appName);
|
|
1510
|
+
});
|
|
1511
|
+
for (const child of children) {
|
|
1512
|
+
updateElementInfo(child, appName);
|
|
1513
|
+
}
|
|
1514
|
+
}
|
|
1515
|
+
/**
|
|
1516
|
+
* rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
|
|
1517
|
+
* @param node target node
|
|
1518
|
+
* @param appName app name
|
|
1519
|
+
* @returns target node
|
|
1520
|
+
*/
|
|
1521
|
+
function updateElementInfo(node, appName) {
|
|
1522
|
+
var _a, _b;
|
|
1523
|
+
const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
|
|
1524
|
+
if (proxyWindow && isNode(node) && !node.__MICRO_APP_NAME__) {
|
|
1525
|
+
/**
|
|
1526
|
+
* TODO:
|
|
1527
|
+
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
1528
|
+
* 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
|
|
1529
|
+
* 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
|
|
1530
|
+
* 3. 性能: defineProperty的性能肯定不如直接设置
|
|
1531
|
+
*/
|
|
1532
|
+
rawDefineProperties(node, {
|
|
1533
|
+
baseURI: {
|
|
1534
|
+
configurable: true,
|
|
1535
|
+
get: () => proxyWindow.location.href,
|
|
1536
|
+
},
|
|
1537
|
+
__MICRO_APP_NAME__: {
|
|
1538
|
+
configurable: true,
|
|
1539
|
+
writable: true,
|
|
1540
|
+
value: appName,
|
|
1541
|
+
},
|
|
1542
|
+
});
|
|
1543
|
+
if (isIframeSandbox(appName)) {
|
|
1544
|
+
rawDefineProperty(node, 'ownerDocument', {
|
|
1545
|
+
configurable: true,
|
|
1546
|
+
get: () => proxyWindow.document,
|
|
1547
|
+
});
|
|
1548
|
+
}
|
|
1549
|
+
}
|
|
1550
|
+
return node;
|
|
1551
|
+
}
|
|
1440
1552
|
|
|
1441
1553
|
// Record element and map element
|
|
1442
1554
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
@@ -1447,7 +1559,7 @@ const dynamicElementInMicroAppMap = new WeakMap();
|
|
|
1447
1559
|
* @param app app
|
|
1448
1560
|
*/
|
|
1449
1561
|
function handleNewNode(parent, child, app) {
|
|
1450
|
-
if (child
|
|
1562
|
+
if (isStyleElement(child)) {
|
|
1451
1563
|
if (child.hasAttribute('exclude')) {
|
|
1452
1564
|
const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
|
|
1453
1565
|
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
@@ -1458,7 +1570,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1458
1570
|
}
|
|
1459
1571
|
return child;
|
|
1460
1572
|
}
|
|
1461
|
-
else if (child
|
|
1573
|
+
else if (isLinkElement(child)) {
|
|
1462
1574
|
if (child.hasAttribute('exclude') || checkExcludeUrl(child.getAttribute('href'), app.name)) {
|
|
1463
1575
|
const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
|
|
1464
1576
|
dynamicElementInMicroAppMap.set(child, linkReplaceComment);
|
|
@@ -1483,7 +1595,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1483
1595
|
}
|
|
1484
1596
|
return child;
|
|
1485
1597
|
}
|
|
1486
|
-
else if (child
|
|
1598
|
+
else if (isScriptElement(child)) {
|
|
1487
1599
|
if (child.src &&
|
|
1488
1600
|
isFunction(microApp.options.excludeAssetFilter) &&
|
|
1489
1601
|
microApp.options.excludeAssetFilter(child.src)) {
|
|
@@ -1513,29 +1625,46 @@ function handleNewNode(parent, child, app) {
|
|
|
1513
1625
|
* @param passiveChild second param of insertBefore and replaceChild
|
|
1514
1626
|
*/
|
|
1515
1627
|
function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
|
|
1516
|
-
const hijackParent = getHijackParent(parent, app);
|
|
1628
|
+
const hijackParent = getHijackParent(parent, targetChild, app);
|
|
1517
1629
|
/**
|
|
1518
1630
|
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
1519
1631
|
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
1520
1632
|
*/
|
|
1521
1633
|
if (hijackParent) {
|
|
1522
1634
|
/**
|
|
1635
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
1636
|
+
* Scenes:
|
|
1637
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
1638
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
1523
1639
|
* WARNING:
|
|
1524
|
-
*
|
|
1640
|
+
* 1. When operate child from parentNode async, may have been unmount
|
|
1641
|
+
* e.g. target.parentNode.remove(target)
|
|
1642
|
+
* ISSUE:
|
|
1643
|
+
* 1. https://github.com/micro-zoe/micro-app/issues/739
|
|
1644
|
+
* Solution: Return the true value when node not in document
|
|
1525
1645
|
*/
|
|
1526
|
-
if (
|
|
1646
|
+
if (!isIframeSandbox(app.name) &&
|
|
1647
|
+
isMicroAppBody(hijackParent) &&
|
|
1648
|
+
rawMethod !== globalEnv.rawRemoveChild) {
|
|
1527
1649
|
const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
|
|
1528
|
-
if (!descriptor || descriptor.configurable) {
|
|
1529
|
-
|
|
1530
|
-
|
|
1531
|
-
|
|
1532
|
-
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1650
|
+
if ((!descriptor || descriptor.configurable) && !targetChild.__MICRO_APP_HAS_DPN__) {
|
|
1651
|
+
rawDefineProperties(targetChild, {
|
|
1652
|
+
parentNode: {
|
|
1653
|
+
configurable: true,
|
|
1654
|
+
get() {
|
|
1655
|
+
var _a, _b;
|
|
1656
|
+
const result = globalEnv.rawParentNodeDesc.get.call(this);
|
|
1657
|
+
if (isMicroAppBody(result) && app.container) {
|
|
1658
|
+
// TODO: remove getRootElementParentNode
|
|
1659
|
+
return ((_b = (_a = microApp.options).getRootElementParentNode) === null || _b === void 0 ? void 0 : _b.call(_a, this, app.name)) || document.body;
|
|
1660
|
+
}
|
|
1661
|
+
return result;
|
|
1662
|
+
},
|
|
1538
1663
|
},
|
|
1664
|
+
__MICRO_APP_HAS_DPN__: {
|
|
1665
|
+
configurable: true,
|
|
1666
|
+
get: () => true,
|
|
1667
|
+
}
|
|
1539
1668
|
});
|
|
1540
1669
|
}
|
|
1541
1670
|
}
|
|
@@ -1553,7 +1682,7 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
1553
1682
|
return targetChild;
|
|
1554
1683
|
}
|
|
1555
1684
|
if ((process.env.NODE_ENV !== 'production') &&
|
|
1556
|
-
targetChild
|
|
1685
|
+
isIFrameElement(targetChild) &&
|
|
1557
1686
|
rawMethod === globalEnv.rawAppendChild) {
|
|
1558
1687
|
fixReactHMRConflict(app);
|
|
1559
1688
|
}
|
|
@@ -1562,13 +1691,20 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
1562
1691
|
return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
|
|
1563
1692
|
}
|
|
1564
1693
|
// head/body map to micro-app-head/micro-app-body
|
|
1565
|
-
function getHijackParent(
|
|
1566
|
-
|
|
1567
|
-
|
|
1568
|
-
|
|
1569
|
-
|
|
1570
|
-
|
|
1571
|
-
|
|
1694
|
+
function getHijackParent(parent, targetChild, app) {
|
|
1695
|
+
if (app) {
|
|
1696
|
+
if (parent === document.head) {
|
|
1697
|
+
if (app.iframe && isScriptElement(targetChild)) {
|
|
1698
|
+
return app.sandBox.microHead;
|
|
1699
|
+
}
|
|
1700
|
+
return app.querySelector('micro-app-head');
|
|
1701
|
+
}
|
|
1702
|
+
if (parent === document.body || parent === document.body.parentNode) {
|
|
1703
|
+
if (app.iframe && isScriptElement(targetChild)) {
|
|
1704
|
+
return app.sandBox.microBody;
|
|
1705
|
+
}
|
|
1706
|
+
return app.querySelector('micro-app-body');
|
|
1707
|
+
}
|
|
1572
1708
|
}
|
|
1573
1709
|
return null;
|
|
1574
1710
|
}
|
|
@@ -1596,8 +1732,9 @@ function getMappingNode(node) {
|
|
|
1596
1732
|
function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
1597
1733
|
const currentAppName = getCurrentAppName();
|
|
1598
1734
|
if (isNode(newChild) &&
|
|
1735
|
+
!newChild.__PURE_ELEMENT__ &&
|
|
1599
1736
|
(newChild.__MICRO_APP_NAME__ ||
|
|
1600
|
-
|
|
1737
|
+
currentAppName)) {
|
|
1601
1738
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1602
1739
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1603
1740
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -1625,10 +1762,10 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1625
1762
|
const app = appInstanceMap.get(currentAppName);
|
|
1626
1763
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1627
1764
|
if (parent === document.head) {
|
|
1628
|
-
return rawMethod.call(app.
|
|
1765
|
+
return rawMethod.call(app.querySelector('micro-app-head'), newChild);
|
|
1629
1766
|
}
|
|
1630
1767
|
else if (parent === document.body) {
|
|
1631
|
-
return rawMethod.call(app.
|
|
1768
|
+
return rawMethod.call(app.querySelector('micro-app-body'), newChild);
|
|
1632
1769
|
}
|
|
1633
1770
|
}
|
|
1634
1771
|
}
|
|
@@ -1639,7 +1776,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1639
1776
|
/**
|
|
1640
1777
|
* Rewrite element prototype method
|
|
1641
1778
|
*/
|
|
1642
|
-
function
|
|
1779
|
+
function patchElementAndDocument() {
|
|
1643
1780
|
patchDocument();
|
|
1644
1781
|
// prototype methods of add element👇
|
|
1645
1782
|
Element.prototype.appendChild = function appendChild(newChild) {
|
|
@@ -1688,6 +1825,71 @@ function patchElementPrototypeMethods() {
|
|
|
1688
1825
|
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
1689
1826
|
return clonedNode;
|
|
1690
1827
|
};
|
|
1828
|
+
function getQueryTarget(node) {
|
|
1829
|
+
const currentAppName = getCurrentAppName();
|
|
1830
|
+
if ((node === document.body || node === document.head) && currentAppName) {
|
|
1831
|
+
const app = appInstanceMap.get(currentAppName);
|
|
1832
|
+
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1833
|
+
if (node === document.body) {
|
|
1834
|
+
return app.querySelector('micro-app-body');
|
|
1835
|
+
}
|
|
1836
|
+
else if (node === document.head) {
|
|
1837
|
+
return app.querySelector('micro-app-head');
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
}
|
|
1841
|
+
return null;
|
|
1842
|
+
}
|
|
1843
|
+
Element.prototype.querySelector = function querySelector(selectors) {
|
|
1844
|
+
var _a;
|
|
1845
|
+
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1846
|
+
return globalEnv.rawElementQuerySelector.call(target, selectors);
|
|
1847
|
+
};
|
|
1848
|
+
Element.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
1849
|
+
var _a;
|
|
1850
|
+
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1851
|
+
return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
|
|
1852
|
+
};
|
|
1853
|
+
rawDefineProperty(Element.prototype, 'innerHTML', {
|
|
1854
|
+
configurable: true,
|
|
1855
|
+
enumerable: true,
|
|
1856
|
+
get() {
|
|
1857
|
+
return globalEnv.rawInnerHTMLDesc.get.call(this);
|
|
1858
|
+
},
|
|
1859
|
+
set(code) {
|
|
1860
|
+
globalEnv.rawInnerHTMLDesc.set.call(this, code);
|
|
1861
|
+
const currentAppName = getCurrentAppName();
|
|
1862
|
+
Array.from(this.children).forEach((child) => {
|
|
1863
|
+
if (isElement(child) && currentAppName) {
|
|
1864
|
+
child.__MICRO_APP_NAME__ = currentAppName;
|
|
1865
|
+
}
|
|
1866
|
+
});
|
|
1867
|
+
}
|
|
1868
|
+
});
|
|
1869
|
+
// Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
|
|
1870
|
+
// rawDefineProperty(Node.prototype, 'parentNode', {
|
|
1871
|
+
// configurable: true,
|
|
1872
|
+
// enumerable: true,
|
|
1873
|
+
// get () {
|
|
1874
|
+
// const result = globalEnv.rawParentNodeDesc.get.call(this)
|
|
1875
|
+
// /**
|
|
1876
|
+
// * If parentNode is <micro-app-body>, return rawDocument.body
|
|
1877
|
+
// * Scenes:
|
|
1878
|
+
// * 1. element-ui@2/lib/utils/vue-popper.js
|
|
1879
|
+
// * if (this.popperElm.parentNode === document.body) ...
|
|
1880
|
+
// * WARNING:
|
|
1881
|
+
// * Will it cause other problems ?
|
|
1882
|
+
// * e.g. target.parentNode.remove(target)
|
|
1883
|
+
// * BUG:
|
|
1884
|
+
// * 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again )
|
|
1885
|
+
// */
|
|
1886
|
+
// if (isMicroAppBody(result) && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
|
|
1887
|
+
// return document.body
|
|
1888
|
+
// }
|
|
1889
|
+
// return result
|
|
1890
|
+
// },
|
|
1891
|
+
// set: undefined,
|
|
1892
|
+
// })
|
|
1691
1893
|
}
|
|
1692
1894
|
/**
|
|
1693
1895
|
* Mark the newly created element in the micro application
|
|
@@ -1721,7 +1923,7 @@ function patchDocument() {
|
|
|
1721
1923
|
};
|
|
1722
1924
|
// query element👇
|
|
1723
1925
|
function querySelector(selectors) {
|
|
1724
|
-
var _a, _b, _c
|
|
1926
|
+
var _a, _b, _c;
|
|
1725
1927
|
const _this = getBindTarget(this);
|
|
1726
1928
|
const currentAppName = getCurrentAppName();
|
|
1727
1929
|
if (!currentAppName ||
|
|
@@ -1732,10 +1934,10 @@ function patchDocument() {
|
|
|
1732
1934
|
rawDocument !== _this) {
|
|
1733
1935
|
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
1734
1936
|
}
|
|
1735
|
-
return (
|
|
1937
|
+
return (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.querySelector(selectors)) !== null && _c !== void 0 ? _c : null;
|
|
1736
1938
|
}
|
|
1737
1939
|
function querySelectorAll(selectors) {
|
|
1738
|
-
var _a, _b, _c
|
|
1940
|
+
var _a, _b, _c;
|
|
1739
1941
|
const _this = getBindTarget(this);
|
|
1740
1942
|
const currentAppName = getCurrentAppName();
|
|
1741
1943
|
if (!currentAppName ||
|
|
@@ -1745,7 +1947,7 @@ function patchDocument() {
|
|
|
1745
1947
|
rawDocument !== _this) {
|
|
1746
1948
|
return globalEnv.rawQuerySelectorAll.call(_this, selectors);
|
|
1747
1949
|
}
|
|
1748
|
-
return (
|
|
1950
|
+
return (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.querySelectorAll(selectors)) !== null && _c !== void 0 ? _c : [];
|
|
1749
1951
|
}
|
|
1750
1952
|
rawRootDocument.prototype.querySelector = querySelector;
|
|
1751
1953
|
rawRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
@@ -1833,7 +2035,7 @@ function patchSetAttribute() {
|
|
|
1833
2035
|
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
1834
2036
|
if (appName &&
|
|
1835
2037
|
appInstanceMap.has(appName) &&
|
|
1836
|
-
(((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
|
|
2038
|
+
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
1837
2039
|
(key === 'href' && /^link$/i.test(this.tagName)))) {
|
|
1838
2040
|
const app = appInstanceMap.get(appName);
|
|
1839
2041
|
value = CompletionPath(value, app.url);
|
|
@@ -1855,7 +2057,7 @@ function releasePatchDocument() {
|
|
|
1855
2057
|
rawRootDocument.prototype.getElementsByName = globalEnv.rawGetElementsByName;
|
|
1856
2058
|
}
|
|
1857
2059
|
// release patch
|
|
1858
|
-
function
|
|
2060
|
+
function releasePatchElementAndDocument() {
|
|
1859
2061
|
removeDomScope();
|
|
1860
2062
|
releasePatchDocument();
|
|
1861
2063
|
Element.prototype.appendChild = globalEnv.rawAppendChild;
|
|
@@ -1865,6 +2067,9 @@ function releasePatches() {
|
|
|
1865
2067
|
Element.prototype.append = globalEnv.rawAppend;
|
|
1866
2068
|
Element.prototype.prepend = globalEnv.rawPrepend;
|
|
1867
2069
|
Element.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
2070
|
+
Element.prototype.querySelector = globalEnv.rawElementQuerySelector;
|
|
2071
|
+
Element.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
|
|
2072
|
+
rawDefineProperty(Element.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
|
|
1868
2073
|
}
|
|
1869
2074
|
// exec when last child unmount
|
|
1870
2075
|
function releasePatchSetAttribute() {
|
|
@@ -1883,16 +2088,21 @@ function rejectMicroAppStyle() {
|
|
|
1883
2088
|
}
|
|
1884
2089
|
}
|
|
1885
2090
|
|
|
1886
|
-
const globalEnv = {
|
|
2091
|
+
const globalEnv = {
|
|
2092
|
+
// mark current application as base application
|
|
2093
|
+
__MICRO_APP_BASE_APPLICATION__: true,
|
|
2094
|
+
// active sandbox count
|
|
2095
|
+
activeSandbox: 0,
|
|
2096
|
+
};
|
|
1887
2097
|
/**
|
|
1888
2098
|
* Note loop nesting
|
|
1889
2099
|
* Only prototype or unique values can be put here
|
|
1890
2100
|
*/
|
|
1891
2101
|
function initGlobalEnv() {
|
|
1892
2102
|
if (isBrowser) {
|
|
1893
|
-
const rawWindow = Function('return window')();
|
|
1894
|
-
const rawDocument = Function('return document')();
|
|
1895
|
-
const rawRootDocument = Function('return Document')();
|
|
2103
|
+
const rawWindow = window.rawWindow || Function('return window')();
|
|
2104
|
+
const rawDocument = window.rawDocument || Function('return document')();
|
|
2105
|
+
const rawRootDocument = rawWindow.Document || Function('return Document')();
|
|
1896
2106
|
const supportModuleScript = isSupportModuleScript();
|
|
1897
2107
|
/**
|
|
1898
2108
|
* save patch raw methods
|
|
@@ -1906,9 +2116,14 @@ function initGlobalEnv() {
|
|
|
1906
2116
|
const rawAppend = Element.prototype.append;
|
|
1907
2117
|
const rawPrepend = Element.prototype.prepend;
|
|
1908
2118
|
const rawCloneNode = Element.prototype.cloneNode;
|
|
2119
|
+
const rawElementQuerySelector = Element.prototype.querySelector;
|
|
2120
|
+
const rawElementQuerySelectorAll = Element.prototype.querySelectorAll;
|
|
2121
|
+
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
|
|
2122
|
+
const rawParentNodeDesc = Object.getOwnPropertyDescriptor(Node.prototype, 'parentNode');
|
|
1909
2123
|
const rawCreateElement = rawRootDocument.prototype.createElement;
|
|
1910
2124
|
const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
|
|
1911
2125
|
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
2126
|
+
const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
|
|
1912
2127
|
const rawQuerySelector = rawRootDocument.prototype.querySelector;
|
|
1913
2128
|
const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
|
|
1914
2129
|
const rawGetElementById = rawRootDocument.prototype.getElementById;
|
|
@@ -1926,18 +2141,19 @@ function initGlobalEnv() {
|
|
|
1926
2141
|
* save effect raw methods
|
|
1927
2142
|
* pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
|
|
1928
2143
|
*/
|
|
1929
|
-
const rawWindowAddEventListener = rawWindow.addEventListener;
|
|
1930
|
-
const rawWindowRemoveEventListener = rawWindow.removeEventListener;
|
|
1931
2144
|
const rawSetInterval = rawWindow.setInterval;
|
|
1932
2145
|
const rawSetTimeout = rawWindow.setTimeout;
|
|
1933
2146
|
const rawClearInterval = rawWindow.clearInterval;
|
|
1934
2147
|
const rawClearTimeout = rawWindow.clearTimeout;
|
|
1935
2148
|
const rawPushState = rawWindow.history.pushState;
|
|
1936
2149
|
const rawReplaceState = rawWindow.history.replaceState;
|
|
2150
|
+
const rawWindowAddEventListener = rawWindow.addEventListener;
|
|
2151
|
+
const rawWindowRemoveEventListener = rawWindow.removeEventListener;
|
|
1937
2152
|
const rawDocumentAddEventListener = rawDocument.addEventListener;
|
|
1938
2153
|
const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
|
|
1939
|
-
//
|
|
1940
|
-
|
|
2154
|
+
// TODO: 统一使用 EventTarget 去掉上面四个
|
|
2155
|
+
const rawAddEventListener = EventTarget.prototype.addEventListener;
|
|
2156
|
+
const rawRemoveEventListener = EventTarget.prototype.removeEventListener;
|
|
1941
2157
|
assign(globalEnv, {
|
|
1942
2158
|
// common global vars
|
|
1943
2159
|
rawWindow,
|
|
@@ -1953,9 +2169,14 @@ function initGlobalEnv() {
|
|
|
1953
2169
|
rawAppend,
|
|
1954
2170
|
rawPrepend,
|
|
1955
2171
|
rawCloneNode,
|
|
2172
|
+
rawElementQuerySelector,
|
|
2173
|
+
rawElementQuerySelectorAll,
|
|
2174
|
+
rawInnerHTMLDesc,
|
|
2175
|
+
rawParentNodeDesc,
|
|
1956
2176
|
rawCreateElement,
|
|
1957
2177
|
rawCreateElementNS,
|
|
1958
2178
|
rawCreateDocumentFragment,
|
|
2179
|
+
rawCreateTextNode,
|
|
1959
2180
|
rawQuerySelector,
|
|
1960
2181
|
rawQuerySelectorAll,
|
|
1961
2182
|
rawGetElementById,
|
|
@@ -1974,6 +2195,8 @@ function initGlobalEnv() {
|
|
|
1974
2195
|
rawDocumentRemoveEventListener,
|
|
1975
2196
|
rawPushState,
|
|
1976
2197
|
rawReplaceState,
|
|
2198
|
+
rawAddEventListener,
|
|
2199
|
+
rawRemoveEventListener,
|
|
1977
2200
|
});
|
|
1978
2201
|
// global effect
|
|
1979
2202
|
rejectMicroAppStyle();
|
|
@@ -1983,7 +2206,7 @@ function initGlobalEnv() {
|
|
|
1983
2206
|
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1984
2207
|
// whether use type='module' script
|
|
1985
2208
|
function isTypeModule(app, scriptInfo) {
|
|
1986
|
-
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.
|
|
2209
|
+
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
|
|
1987
2210
|
}
|
|
1988
2211
|
// special script element
|
|
1989
2212
|
function isSpecialScript(app, scriptInfo) {
|
|
@@ -2002,11 +2225,17 @@ function isInlineMode(app, scriptInfo) {
|
|
|
2002
2225
|
return (app.inline ||
|
|
2003
2226
|
scriptInfo.appSpace[app.name].inline ||
|
|
2004
2227
|
isTypeModule(app, scriptInfo) ||
|
|
2005
|
-
isSpecialScript(app, scriptInfo)
|
|
2228
|
+
isSpecialScript(app, scriptInfo) ||
|
|
2229
|
+
app.iframe);
|
|
2230
|
+
}
|
|
2231
|
+
// TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
|
|
2232
|
+
function getEffectWindow(app) {
|
|
2233
|
+
return app.iframe ? app.sandBox.microAppWindow : globalEnv.rawWindow;
|
|
2006
2234
|
}
|
|
2007
2235
|
// Convert string code to function
|
|
2008
|
-
function code2Function(code) {
|
|
2009
|
-
|
|
2236
|
+
function code2Function(app, code) {
|
|
2237
|
+
const targetWindow = getEffectWindow(app);
|
|
2238
|
+
return new targetWindow.Function(code);
|
|
2010
2239
|
}
|
|
2011
2240
|
/**
|
|
2012
2241
|
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
@@ -2014,10 +2243,10 @@ function code2Function(code) {
|
|
|
2014
2243
|
* @param scriptInfo scriptInfo of current address
|
|
2015
2244
|
* @param currentCode pure code of current address
|
|
2016
2245
|
*/
|
|
2017
|
-
function getExistParseResult(
|
|
2246
|
+
function getExistParseResult(app, scriptInfo, currentCode) {
|
|
2018
2247
|
const appSpace = scriptInfo.appSpace;
|
|
2019
2248
|
for (const item in appSpace) {
|
|
2020
|
-
if (item !==
|
|
2249
|
+
if (item !== app.name) {
|
|
2021
2250
|
const appSpaceData = appSpace[item];
|
|
2022
2251
|
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
2023
2252
|
return appSpaceData.parsedFunction;
|
|
@@ -2030,7 +2259,7 @@ function getExistParseResult(appName, scriptInfo, currentCode) {
|
|
|
2030
2259
|
* @returns parsedFunction
|
|
2031
2260
|
*/
|
|
2032
2261
|
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
2033
|
-
return getExistParseResult(app
|
|
2262
|
+
return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
|
|
2034
2263
|
}
|
|
2035
2264
|
// Prevent randomly created strings from repeating
|
|
2036
2265
|
function getUniqueNonceSrc() {
|
|
@@ -2054,6 +2283,9 @@ function setConvertScriptAttr(convertScript, attrs) {
|
|
|
2054
2283
|
function isWrapInSandBox(app, scriptInfo) {
|
|
2055
2284
|
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
2056
2285
|
}
|
|
2286
|
+
function getSandboxType(app, scriptInfo) {
|
|
2287
|
+
return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
|
|
2288
|
+
}
|
|
2057
2289
|
/**
|
|
2058
2290
|
* Extract script elements
|
|
2059
2291
|
* @param script script element
|
|
@@ -2062,6 +2294,7 @@ function isWrapInSandBox(app, scriptInfo) {
|
|
|
2062
2294
|
* @param isDynamic dynamic insert
|
|
2063
2295
|
*/
|
|
2064
2296
|
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
2297
|
+
var _a;
|
|
2065
2298
|
let replaceComment = null;
|
|
2066
2299
|
let src = script.getAttribute('src');
|
|
2067
2300
|
if (src)
|
|
@@ -2073,6 +2306,10 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
2073
2306
|
!scriptTypes.includes(script.type)) ||
|
|
2074
2307
|
script.hasAttribute('ignore') ||
|
|
2075
2308
|
checkIgnoreUrl(src, app.name)) {
|
|
2309
|
+
// 配置为忽略的脚本,清空 rawDocument.currentScript,避免被忽略的脚本内获取 currentScript 出错
|
|
2310
|
+
if ((_a = globalEnv.rawDocument) === null || _a === void 0 ? void 0 : _a.currentScript) {
|
|
2311
|
+
delete globalEnv.rawDocument.currentScript;
|
|
2312
|
+
}
|
|
2076
2313
|
return null;
|
|
2077
2314
|
}
|
|
2078
2315
|
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
@@ -2268,13 +2505,13 @@ function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
|
2268
2505
|
*/
|
|
2269
2506
|
if (!appSpaceData.parsedCode) {
|
|
2270
2507
|
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
2271
|
-
appSpaceData.
|
|
2508
|
+
appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
|
|
2272
2509
|
if (!isInlineMode(app, scriptInfo)) {
|
|
2273
2510
|
try {
|
|
2274
2511
|
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2275
2512
|
}
|
|
2276
2513
|
catch (err) {
|
|
2277
|
-
|
|
2514
|
+
logError('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
2278
2515
|
}
|
|
2279
2516
|
}
|
|
2280
2517
|
}
|
|
@@ -2295,7 +2532,8 @@ function execScripts(app, initHook) {
|
|
|
2295
2532
|
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2296
2533
|
// Notice the second render
|
|
2297
2534
|
if (appSpaceData.defer || appSpaceData.async) {
|
|
2298
|
-
|
|
2535
|
+
// TODO: defer和module彻底分开,不要混在一起
|
|
2536
|
+
if (scriptInfo.isExternal && !scriptInfo.code && !(app.iframe && appSpaceData.module)) {
|
|
2299
2537
|
deferScriptPromise.push(fetchSource(address, app.name));
|
|
2300
2538
|
}
|
|
2301
2539
|
else {
|
|
@@ -2320,7 +2558,7 @@ function execScripts(app, initHook) {
|
|
|
2320
2558
|
logError(err, app.name);
|
|
2321
2559
|
}, () => {
|
|
2322
2560
|
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
2323
|
-
if (scriptInfo.code) {
|
|
2561
|
+
if (isString(scriptInfo.code)) {
|
|
2324
2562
|
injectFiberTask(fiberScriptTasks, () => {
|
|
2325
2563
|
runScript(address, app, scriptInfo, initHook);
|
|
2326
2564
|
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
@@ -2364,20 +2602,19 @@ function execScripts(app, initHook) {
|
|
|
2364
2602
|
* @param callback callback of module script
|
|
2365
2603
|
*/
|
|
2366
2604
|
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
2367
|
-
var _a;
|
|
2368
2605
|
try {
|
|
2369
2606
|
actionsBeforeRunScript(app);
|
|
2370
2607
|
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2371
|
-
const
|
|
2608
|
+
const sandboxType = getSandboxType(app, scriptInfo);
|
|
2372
2609
|
/**
|
|
2373
2610
|
* NOTE:
|
|
2374
2611
|
* 1. plugins and wrapCode will only be executed once
|
|
2375
2612
|
* 2. if parsedCode not exist, parsedFunction is not exist
|
|
2376
2613
|
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
2377
2614
|
*/
|
|
2378
|
-
if (!appSpaceData.parsedCode || appSpaceData.
|
|
2615
|
+
if (!appSpaceData.parsedCode || appSpaceData.sandboxType !== sandboxType) {
|
|
2379
2616
|
appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
|
|
2380
|
-
appSpaceData.
|
|
2617
|
+
appSpaceData.sandboxType = sandboxType;
|
|
2381
2618
|
appSpaceData.parsedFunction = null;
|
|
2382
2619
|
}
|
|
2383
2620
|
if (isInlineMode(app, scriptInfo)) {
|
|
@@ -2385,7 +2622,8 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
|
2385
2622
|
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
2386
2623
|
if (!replaceElement) {
|
|
2387
2624
|
// TEST IGNORE
|
|
2388
|
-
|
|
2625
|
+
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
2626
|
+
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
2389
2627
|
}
|
|
2390
2628
|
}
|
|
2391
2629
|
else {
|
|
@@ -2417,7 +2655,7 @@ function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
|
2417
2655
|
runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
|
|
2418
2656
|
!isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
|
|
2419
2657
|
};
|
|
2420
|
-
if (scriptInfo.code) {
|
|
2658
|
+
if (scriptInfo.code || (app.iframe && scriptInfo.appSpace[app.name].module)) {
|
|
2421
2659
|
defer(runDynamicScript);
|
|
2422
2660
|
}
|
|
2423
2661
|
else {
|
|
@@ -2464,6 +2702,9 @@ function runCode2InlineScript(address, code, module, scriptElement, attrs, callb
|
|
|
2464
2702
|
scriptElement.setAttribute('type', 'module');
|
|
2465
2703
|
if (callback) {
|
|
2466
2704
|
callback.moduleCount && callback.moduleCount--;
|
|
2705
|
+
/**
|
|
2706
|
+
* module script will execute onload method only after it insert to document/iframe
|
|
2707
|
+
*/
|
|
2467
2708
|
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
2468
2709
|
}
|
|
2469
2710
|
}
|
|
@@ -2478,7 +2719,7 @@ function runParsedFunction(app, scriptInfo) {
|
|
|
2478
2719
|
if (!appSpaceData.parsedFunction) {
|
|
2479
2720
|
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2480
2721
|
}
|
|
2481
|
-
appSpaceData.parsedFunction.call(
|
|
2722
|
+
appSpaceData.parsedFunction.call(getEffectWindow(app));
|
|
2482
2723
|
}
|
|
2483
2724
|
/**
|
|
2484
2725
|
* bind js scope
|
|
@@ -2487,12 +2728,12 @@ function runParsedFunction(app, scriptInfo) {
|
|
|
2487
2728
|
* @param scriptInfo source script info
|
|
2488
2729
|
*/
|
|
2489
2730
|
function bindScope(address, app, code, scriptInfo) {
|
|
2490
|
-
// TODO: cache
|
|
2731
|
+
// TODO: 1、cache 2、esm code is null
|
|
2491
2732
|
if (isPlainObject(microApp.options.plugins)) {
|
|
2492
2733
|
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
2493
2734
|
}
|
|
2494
2735
|
if (isWrapInSandBox(app, scriptInfo)) {
|
|
2495
|
-
return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
2736
|
+
return app.iframe ? `(function(window,self,global,location){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyLocation);` : `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
2496
2737
|
}
|
|
2497
2738
|
return code;
|
|
2498
2739
|
}
|
|
@@ -2555,7 +2796,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2555
2796
|
flatChildren(child, app, microAppHead, fiberStyleTasks);
|
|
2556
2797
|
});
|
|
2557
2798
|
for (const dom of children) {
|
|
2558
|
-
if (dom
|
|
2799
|
+
if (isLinkElement(dom)) {
|
|
2559
2800
|
if (dom.hasAttribute('exclude') || checkExcludeUrl(dom.getAttribute('href'), app.name)) {
|
|
2560
2801
|
parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
|
|
2561
2802
|
}
|
|
@@ -2566,7 +2807,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2566
2807
|
dom.setAttribute('href', CompletionPath(dom.getAttribute('href'), app.url));
|
|
2567
2808
|
}
|
|
2568
2809
|
}
|
|
2569
|
-
else if (dom
|
|
2810
|
+
else if (isStyleElement(dom)) {
|
|
2570
2811
|
if (dom.hasAttribute('exclude')) {
|
|
2571
2812
|
parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
|
|
2572
2813
|
}
|
|
@@ -2574,10 +2815,10 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2574
2815
|
injectFiberTask(fiberStyleTasks, () => scopedCSS(dom, app));
|
|
2575
2816
|
}
|
|
2576
2817
|
}
|
|
2577
|
-
else if (dom
|
|
2818
|
+
else if (isScriptElement(dom)) {
|
|
2578
2819
|
extractScriptElement(dom, parent, app);
|
|
2579
2820
|
}
|
|
2580
|
-
else if (dom
|
|
2821
|
+
else if (isImageElement(dom) && dom.hasAttribute('src')) {
|
|
2581
2822
|
dom.setAttribute('src', CompletionPath(dom.getAttribute('src'), app.url));
|
|
2582
2823
|
}
|
|
2583
2824
|
/**
|
|
@@ -2600,8 +2841,8 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2600
2841
|
*/
|
|
2601
2842
|
function extractSourceDom(htmlStr, app) {
|
|
2602
2843
|
const wrapElement = getWrapElement(htmlStr);
|
|
2603
|
-
const microAppHead =
|
|
2604
|
-
const microAppBody =
|
|
2844
|
+
const microAppHead = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-head');
|
|
2845
|
+
const microAppBody = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-body');
|
|
2605
2846
|
if (!microAppHead || !microAppBody) {
|
|
2606
2847
|
const msg = `element ${microAppHead ? 'body' : 'head'} is missing`;
|
|
2607
2848
|
app.onerror(new Error(msg));
|
|
@@ -2802,7 +3043,7 @@ const eventCenter = new EventCenter();
|
|
|
2802
3043
|
* @param appName app.name
|
|
2803
3044
|
* @param fromBaseApp is from base app
|
|
2804
3045
|
*/
|
|
2805
|
-
function
|
|
3046
|
+
function createEventName(appName, fromBaseApp) {
|
|
2806
3047
|
if (!isString(appName) || !appName)
|
|
2807
3048
|
return '';
|
|
2808
3049
|
return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`;
|
|
@@ -2881,7 +3122,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2881
3122
|
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
2882
3123
|
*/
|
|
2883
3124
|
addDataListener(appName, cb, autoTrigger) {
|
|
2884
|
-
eventCenter.on(
|
|
3125
|
+
eventCenter.on(createEventName(formatAppName(appName), false), cb, autoTrigger);
|
|
2885
3126
|
}
|
|
2886
3127
|
/**
|
|
2887
3128
|
* remove listener
|
|
@@ -2889,7 +3130,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2889
3130
|
* @param cb listener
|
|
2890
3131
|
*/
|
|
2891
3132
|
removeDataListener(appName, cb) {
|
|
2892
|
-
isFunction(cb) && eventCenter.off(
|
|
3133
|
+
isFunction(cb) && eventCenter.off(createEventName(formatAppName(appName), false), cb);
|
|
2893
3134
|
}
|
|
2894
3135
|
/**
|
|
2895
3136
|
* get data from micro app or base app
|
|
@@ -2897,7 +3138,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2897
3138
|
* @param fromBaseApp whether get data from base app, default is false
|
|
2898
3139
|
*/
|
|
2899
3140
|
getData(appName, fromBaseApp = false) {
|
|
2900
|
-
return eventCenter.getData(
|
|
3141
|
+
return eventCenter.getData(createEventName(formatAppName(appName), fromBaseApp));
|
|
2901
3142
|
}
|
|
2902
3143
|
/**
|
|
2903
3144
|
* Dispatch data to the specified micro app
|
|
@@ -2905,7 +3146,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2905
3146
|
* @param data data
|
|
2906
3147
|
*/
|
|
2907
3148
|
setData(appName, data, nextStep, force) {
|
|
2908
|
-
eventCenter.dispatch(
|
|
3149
|
+
eventCenter.dispatch(createEventName(formatAppName(appName), true), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
|
|
2909
3150
|
}
|
|
2910
3151
|
forceSetData(appName, data, nextStep) {
|
|
2911
3152
|
this.setData(appName, data, nextStep, true);
|
|
@@ -2916,14 +3157,14 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2916
3157
|
* @param fromBaseApp whether clear data from child app, default is true
|
|
2917
3158
|
*/
|
|
2918
3159
|
clearData(appName, fromBaseApp = true) {
|
|
2919
|
-
eventCenter.clearData(
|
|
3160
|
+
eventCenter.clearData(createEventName(formatAppName(appName), fromBaseApp));
|
|
2920
3161
|
}
|
|
2921
3162
|
/**
|
|
2922
3163
|
* clear all listener for specified micro app
|
|
2923
3164
|
* @param appName app.name
|
|
2924
3165
|
*/
|
|
2925
3166
|
clearDataListener(appName) {
|
|
2926
|
-
eventCenter.off(
|
|
3167
|
+
eventCenter.off(createEventName(formatAppName(appName), false));
|
|
2927
3168
|
}
|
|
2928
3169
|
}
|
|
2929
3170
|
// Event center for sub app
|
|
@@ -2940,20 +3181,20 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
2940
3181
|
*/
|
|
2941
3182
|
addDataListener(cb, autoTrigger) {
|
|
2942
3183
|
cb.__AUTO_TRIGGER__ = autoTrigger;
|
|
2943
|
-
eventCenter.on(
|
|
3184
|
+
eventCenter.on(createEventName(this.appName, true), cb, autoTrigger);
|
|
2944
3185
|
}
|
|
2945
3186
|
/**
|
|
2946
3187
|
* remove listener
|
|
2947
3188
|
* @param cb listener
|
|
2948
3189
|
*/
|
|
2949
3190
|
removeDataListener(cb) {
|
|
2950
|
-
isFunction(cb) && eventCenter.off(
|
|
3191
|
+
isFunction(cb) && eventCenter.off(createEventName(this.appName, true), cb);
|
|
2951
3192
|
}
|
|
2952
3193
|
/**
|
|
2953
3194
|
* get data from base app
|
|
2954
3195
|
*/
|
|
2955
3196
|
getData(fromBaseApp = true) {
|
|
2956
|
-
return eventCenter.getData(
|
|
3197
|
+
return eventCenter.getData(createEventName(this.appName, fromBaseApp));
|
|
2957
3198
|
}
|
|
2958
3199
|
/**
|
|
2959
3200
|
* dispatch data to base app
|
|
@@ -2961,12 +3202,12 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
2961
3202
|
*/
|
|
2962
3203
|
dispatch(data, nextStep, force) {
|
|
2963
3204
|
removeDomScope();
|
|
2964
|
-
eventCenter.dispatch(
|
|
3205
|
+
eventCenter.dispatch(createEventName(this.appName, false), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force, () => {
|
|
2965
3206
|
const app = appInstanceMap.get(this.appName);
|
|
2966
3207
|
if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
|
|
2967
3208
|
const event = new CustomEvent('datachange', {
|
|
2968
3209
|
detail: {
|
|
2969
|
-
data: eventCenter.getData(
|
|
3210
|
+
data: eventCenter.getData(createEventName(this.appName, false))
|
|
2970
3211
|
}
|
|
2971
3212
|
});
|
|
2972
3213
|
getRootContainer(app.container).dispatchEvent(event);
|
|
@@ -2981,33 +3222,35 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
2981
3222
|
* @param fromBaseApp whether clear data from base app, default is false
|
|
2982
3223
|
*/
|
|
2983
3224
|
clearData(fromBaseApp = false) {
|
|
2984
|
-
eventCenter.clearData(
|
|
3225
|
+
eventCenter.clearData(createEventName(this.appName, fromBaseApp));
|
|
2985
3226
|
}
|
|
2986
3227
|
/**
|
|
2987
3228
|
* clear all listeners
|
|
2988
3229
|
*/
|
|
2989
3230
|
clearDataListener() {
|
|
2990
|
-
eventCenter.off(
|
|
3231
|
+
eventCenter.off(createEventName(this.appName, true));
|
|
2991
3232
|
}
|
|
2992
3233
|
}
|
|
2993
3234
|
/**
|
|
2994
3235
|
* Record UMD function before exec umdHookMount
|
|
2995
|
-
*
|
|
3236
|
+
* NOTE: record maybe call twice when unmount prerender, keep-alive app manually with umd mode
|
|
3237
|
+
* @param microAppEventCenter instance of EventCenterForMicroApp
|
|
2996
3238
|
*/
|
|
2997
3239
|
function recordDataCenterSnapshot(microAppEventCenter) {
|
|
2998
|
-
|
|
2999
|
-
|
|
3000
|
-
|
|
3001
|
-
|
|
3002
|
-
|
|
3003
|
-
|
|
3004
|
-
|
|
3240
|
+
if (microAppEventCenter && !microAppEventCenter.umdDataListeners) {
|
|
3241
|
+
microAppEventCenter.umdDataListeners = { global: new Set(), normal: new Set() };
|
|
3242
|
+
const globalEventInfo = eventCenter.eventList.get('global');
|
|
3243
|
+
if (globalEventInfo) {
|
|
3244
|
+
for (const cb of globalEventInfo.callbacks) {
|
|
3245
|
+
if (microAppEventCenter.appName === cb.__APP_NAME__) {
|
|
3246
|
+
microAppEventCenter.umdDataListeners.global.add(cb);
|
|
3247
|
+
}
|
|
3005
3248
|
}
|
|
3006
3249
|
}
|
|
3007
|
-
|
|
3008
|
-
|
|
3009
|
-
|
|
3010
|
-
|
|
3250
|
+
const subAppEventInfo = eventCenter.eventList.get(createEventName(microAppEventCenter.appName, true));
|
|
3251
|
+
if (subAppEventInfo) {
|
|
3252
|
+
microAppEventCenter.umdDataListeners.normal = new Set(subAppEventInfo.callbacks);
|
|
3253
|
+
}
|
|
3011
3254
|
}
|
|
3012
3255
|
}
|
|
3013
3256
|
/**
|
|
@@ -3015,13 +3258,24 @@ function recordDataCenterSnapshot(microAppEventCenter) {
|
|
|
3015
3258
|
* @param microAppEventCenter instance of EventCenterForMicroApp
|
|
3016
3259
|
*/
|
|
3017
3260
|
function rebuildDataCenterSnapshot(microAppEventCenter) {
|
|
3018
|
-
|
|
3019
|
-
|
|
3020
|
-
|
|
3021
|
-
|
|
3022
|
-
|
|
3261
|
+
// in withSandbox preRender mode with module script, umdDataListeners maybe undefined
|
|
3262
|
+
if (microAppEventCenter === null || microAppEventCenter === void 0 ? void 0 : microAppEventCenter.umdDataListeners) {
|
|
3263
|
+
for (const cb of microAppEventCenter.umdDataListeners.global) {
|
|
3264
|
+
microAppEventCenter.addGlobalDataListener(cb, cb.__AUTO_TRIGGER__);
|
|
3265
|
+
}
|
|
3266
|
+
for (const cb of microAppEventCenter.umdDataListeners.normal) {
|
|
3267
|
+
microAppEventCenter.addDataListener(cb, cb.__AUTO_TRIGGER__);
|
|
3268
|
+
}
|
|
3269
|
+
resetDataCenterSnapshot(microAppEventCenter);
|
|
3023
3270
|
}
|
|
3024
3271
|
}
|
|
3272
|
+
/**
|
|
3273
|
+
* delete umdDataListeners from microAppEventCenter
|
|
3274
|
+
* @param microAppEventCenter instance of EventCenterForMicroApp
|
|
3275
|
+
*/
|
|
3276
|
+
function resetDataCenterSnapshot(microAppEventCenter) {
|
|
3277
|
+
delete microAppEventCenter.umdDataListeners;
|
|
3278
|
+
}
|
|
3025
3279
|
|
|
3026
3280
|
// 管理 app 的单例
|
|
3027
3281
|
class AppManager {
|
|
@@ -3084,12 +3338,12 @@ function isConstructorFunction(value) {
|
|
|
3084
3338
|
return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
|
|
3085
3339
|
}
|
|
3086
3340
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
3087
|
-
function
|
|
3088
|
-
|
|
3089
|
-
|
|
3090
|
-
|
|
3091
|
-
|
|
3092
|
-
const bindRawObjectValue = value.bind(
|
|
3341
|
+
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
3342
|
+
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
|
|
3343
|
+
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
3344
|
+
if (value[cacheKey])
|
|
3345
|
+
return value[cacheKey];
|
|
3346
|
+
const bindRawObjectValue = value.bind(rawTarget);
|
|
3093
3347
|
for (const key in value) {
|
|
3094
3348
|
bindRawObjectValue[key] = value[key];
|
|
3095
3349
|
}
|
|
@@ -3106,21 +3360,6 @@ function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
|
|
|
3106
3360
|
return value;
|
|
3107
3361
|
}
|
|
3108
3362
|
|
|
3109
|
-
// this events should be sent to the specified app
|
|
3110
|
-
const formatEventList = ['unmount', 'appstate-change'];
|
|
3111
|
-
/**
|
|
3112
|
-
* Format event name
|
|
3113
|
-
* @param eventName event name
|
|
3114
|
-
* @param appName app name
|
|
3115
|
-
*/
|
|
3116
|
-
function formatEventName$1(eventName, appName) {
|
|
3117
|
-
var _a;
|
|
3118
|
-
if (formatEventList.includes(eventName) ||
|
|
3119
|
-
((eventName === 'popstate' || eventName === 'hashchange') && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.useMemoryRouter))) {
|
|
3120
|
-
return `${eventName}-${appName}`;
|
|
3121
|
-
}
|
|
3122
|
-
return eventName;
|
|
3123
|
-
}
|
|
3124
3363
|
// document.onclick binding list, the binding function of each application is unique
|
|
3125
3364
|
const documentClickListMap = new Map();
|
|
3126
3365
|
let hasRewriteDocumentOnClick = false;
|
|
@@ -3231,7 +3470,7 @@ function effect(appName, microAppWindow) {
|
|
|
3231
3470
|
const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
|
|
3232
3471
|
// listener may be null, e.g test-passive
|
|
3233
3472
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3234
|
-
type = formatEventName
|
|
3473
|
+
type = formatEventName(type, appName);
|
|
3235
3474
|
const listenerList = eventListenerMap.get(type);
|
|
3236
3475
|
if (listenerList) {
|
|
3237
3476
|
listenerList.add(listener);
|
|
@@ -3243,7 +3482,7 @@ function effect(appName, microAppWindow) {
|
|
|
3243
3482
|
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
3244
3483
|
};
|
|
3245
3484
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3246
|
-
type = formatEventName
|
|
3485
|
+
type = formatEventName(type, appName);
|
|
3247
3486
|
const listenerList = eventListenerMap.get(type);
|
|
3248
3487
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3249
3488
|
listenerList.delete(listener);
|
|
@@ -3270,39 +3509,32 @@ function effect(appName, microAppWindow) {
|
|
|
3270
3509
|
};
|
|
3271
3510
|
const sstWindowListenerMap = new Map();
|
|
3272
3511
|
const sstDocumentListenerMap = new Map();
|
|
3273
|
-
let sstIntervalIdMap = new Map();
|
|
3274
|
-
let sstTimeoutIdMap = new Map();
|
|
3275
3512
|
let sstOnClickHandler;
|
|
3276
|
-
|
|
3513
|
+
// reset snapshot data
|
|
3514
|
+
const reset = () => {
|
|
3277
3515
|
sstWindowListenerMap.clear();
|
|
3278
|
-
sstIntervalIdMap.clear();
|
|
3279
|
-
sstTimeoutIdMap.clear();
|
|
3280
3516
|
sstDocumentListenerMap.clear();
|
|
3281
3517
|
sstOnClickHandler = null;
|
|
3282
3518
|
};
|
|
3283
3519
|
/**
|
|
3284
|
-
*
|
|
3285
|
-
*
|
|
3286
|
-
*
|
|
3287
|
-
*
|
|
3288
|
-
*
|
|
3520
|
+
* NOTE:
|
|
3521
|
+
* 1. about timer(events & properties should record & rebuild at all modes, exclude default mode)
|
|
3522
|
+
* 2. record maybe call twice when unmount prerender, keep-alive app manually with umd mode
|
|
3523
|
+
* 4 modes: default-mode、umd-mode、prerender、keep-alive
|
|
3524
|
+
* Solution:
|
|
3525
|
+
* 1. default-mode(normal): clear events & timers, not record & rebuild anything
|
|
3526
|
+
* 2. umd-mode(normal): not clear timers, record & rebuild events
|
|
3527
|
+
* 3. prerender/keep-alive(default, umd): not clear timers, record & rebuild events
|
|
3289
3528
|
*/
|
|
3290
|
-
const
|
|
3529
|
+
const record = () => {
|
|
3291
3530
|
// record window event
|
|
3292
3531
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3293
3532
|
if (listenerList.size) {
|
|
3294
3533
|
sstWindowListenerMap.set(type, new Set(listenerList));
|
|
3295
3534
|
}
|
|
3296
3535
|
});
|
|
3297
|
-
// record timers
|
|
3298
|
-
if (intervalIdMap.size) {
|
|
3299
|
-
sstIntervalIdMap = new Map(intervalIdMap);
|
|
3300
|
-
}
|
|
3301
|
-
if (timeoutIdMap.size) {
|
|
3302
|
-
sstTimeoutIdMap = new Map(timeoutIdMap);
|
|
3303
|
-
}
|
|
3304
3536
|
// record onclick handler
|
|
3305
|
-
sstOnClickHandler = documentClickListMap.get(appName);
|
|
3537
|
+
sstOnClickHandler = sstOnClickHandler || documentClickListMap.get(appName);
|
|
3306
3538
|
// record document event
|
|
3307
3539
|
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
3308
3540
|
if (documentAppListenersMap) {
|
|
@@ -3314,20 +3546,13 @@ function effect(appName, microAppWindow) {
|
|
|
3314
3546
|
}
|
|
3315
3547
|
};
|
|
3316
3548
|
// rebuild event and timer before remount app
|
|
3317
|
-
const
|
|
3549
|
+
const rebuild = () => {
|
|
3318
3550
|
// rebuild window event
|
|
3319
3551
|
sstWindowListenerMap.forEach((listenerList, type) => {
|
|
3320
3552
|
for (const listener of listenerList) {
|
|
3321
3553
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3322
3554
|
}
|
|
3323
3555
|
});
|
|
3324
|
-
// rebuild timer
|
|
3325
|
-
sstIntervalIdMap.forEach((info) => {
|
|
3326
|
-
microAppWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
3327
|
-
});
|
|
3328
|
-
sstTimeoutIdMap.forEach((info) => {
|
|
3329
|
-
microAppWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
3330
|
-
});
|
|
3331
3556
|
// rebuild onclick event
|
|
3332
3557
|
sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
|
|
3333
3558
|
/**
|
|
@@ -3341,10 +3566,10 @@ function effect(appName, microAppWindow) {
|
|
|
3341
3566
|
}
|
|
3342
3567
|
});
|
|
3343
3568
|
removeDomScope();
|
|
3344
|
-
|
|
3569
|
+
reset();
|
|
3345
3570
|
};
|
|
3346
3571
|
// release all event listener & interval & timeout when unmount app
|
|
3347
|
-
const
|
|
3572
|
+
const release = ({ umdMode, isPrerender, keepAlive, destroy }) => {
|
|
3348
3573
|
// Clear window binding events
|
|
3349
3574
|
if (eventListenerMap.size) {
|
|
3350
3575
|
eventListenerMap.forEach((listenerList, type) => {
|
|
@@ -3354,17 +3579,15 @@ function effect(appName, microAppWindow) {
|
|
|
3354
3579
|
});
|
|
3355
3580
|
eventListenerMap.clear();
|
|
3356
3581
|
}
|
|
3357
|
-
//
|
|
3358
|
-
if (
|
|
3582
|
+
// default mode(not keep-alive or isPrerender)
|
|
3583
|
+
if ((!umdMode && !keepAlive && !isPrerender) || destroy) {
|
|
3359
3584
|
intervalIdMap.forEach((_, intervalId) => {
|
|
3360
3585
|
rawClearInterval.call(rawWindow, intervalId);
|
|
3361
3586
|
});
|
|
3362
|
-
intervalIdMap.clear();
|
|
3363
|
-
}
|
|
3364
|
-
if (timeoutIdMap.size) {
|
|
3365
3587
|
timeoutIdMap.forEach((_, timeoutId) => {
|
|
3366
3588
|
rawClearTimeout.call(rawWindow, timeoutId);
|
|
3367
3589
|
});
|
|
3590
|
+
intervalIdMap.clear();
|
|
3368
3591
|
timeoutIdMap.clear();
|
|
3369
3592
|
}
|
|
3370
3593
|
// Clear the function bound by micro application through document.onclick
|
|
@@ -3381,9 +3604,10 @@ function effect(appName, microAppWindow) {
|
|
|
3381
3604
|
}
|
|
3382
3605
|
};
|
|
3383
3606
|
return {
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3607
|
+
reset,
|
|
3608
|
+
record,
|
|
3609
|
+
rebuild,
|
|
3610
|
+
release,
|
|
3387
3611
|
};
|
|
3388
3612
|
}
|
|
3389
3613
|
|
|
@@ -3578,25 +3802,29 @@ function addHistoryListener(appName) {
|
|
|
3578
3802
|
* 1. unmount app & hidden keep-alive app will not receive popstate event
|
|
3579
3803
|
* 2. filter out onlyForBrowser
|
|
3580
3804
|
*/
|
|
3581
|
-
if (getActiveApps({
|
|
3805
|
+
if (getActiveApps({
|
|
3806
|
+
excludeHiddenApp: true,
|
|
3807
|
+
excludePreRender: true,
|
|
3808
|
+
}).includes(appName) &&
|
|
3582
3809
|
!e.onlyForBrowser) {
|
|
3583
3810
|
const microPath = getMicroPathFromURL(appName);
|
|
3584
3811
|
const app = appInstanceMap.get(appName);
|
|
3585
3812
|
const proxyWindow = app.sandBox.proxyWindow;
|
|
3813
|
+
const microAppWindow = app.sandBox.microAppWindow;
|
|
3586
3814
|
let isHashChange = false;
|
|
3587
3815
|
// for hashChangeEvent
|
|
3588
3816
|
const oldHref = proxyWindow.location.href;
|
|
3589
3817
|
// Do not attach micro state to url when microPath is empty
|
|
3590
3818
|
if (microPath) {
|
|
3591
3819
|
const oldHash = proxyWindow.location.hash;
|
|
3592
|
-
updateMicroLocation(appName, microPath,
|
|
3820
|
+
updateMicroLocation(appName, microPath, microAppWindow.location);
|
|
3593
3821
|
isHashChange = proxyWindow.location.hash !== oldHash;
|
|
3594
3822
|
}
|
|
3595
3823
|
// dispatch formatted popStateEvent to child
|
|
3596
|
-
dispatchPopStateEventToMicroApp(appName, proxyWindow);
|
|
3824
|
+
dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
|
|
3597
3825
|
// dispatch formatted hashChangeEvent to child when hash change
|
|
3598
3826
|
if (isHashChange)
|
|
3599
|
-
dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref);
|
|
3827
|
+
dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
|
|
3600
3828
|
// clear element scope before trigger event of next app
|
|
3601
3829
|
removeDomScope();
|
|
3602
3830
|
}
|
|
@@ -3612,10 +3840,9 @@ function addHistoryListener(appName) {
|
|
|
3612
3840
|
* @param proxyWindow sandbox window
|
|
3613
3841
|
* @param eventState history.state
|
|
3614
3842
|
*/
|
|
3615
|
-
function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
|
|
3616
|
-
// create PopStateEvent named popstate-appName with sub app state
|
|
3617
|
-
const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName) });
|
|
3843
|
+
function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
|
|
3618
3844
|
/**
|
|
3845
|
+
* TODO: test
|
|
3619
3846
|
* angular14 takes e.type as type judgment
|
|
3620
3847
|
* when e.type is popstate-appName popstate event will be invalid
|
|
3621
3848
|
*/
|
|
@@ -3625,7 +3852,14 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
|
|
|
3625
3852
|
// configurable: true,
|
|
3626
3853
|
// enumerable: true,
|
|
3627
3854
|
// })
|
|
3628
|
-
|
|
3855
|
+
// create PopStateEvent named popstate-appName with sub app state
|
|
3856
|
+
const newPopStateEvent = new PopStateEvent(formatEventName('popstate', appName), { state: getMicroState(appName) });
|
|
3857
|
+
if (isIframeSandbox(appName)) {
|
|
3858
|
+
microAppWindow.dispatchEvent(newPopStateEvent);
|
|
3859
|
+
}
|
|
3860
|
+
else {
|
|
3861
|
+
globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
|
|
3862
|
+
}
|
|
3629
3863
|
// call function window.onpopstate if it exists
|
|
3630
3864
|
isFunction(proxyWindow.onpopstate) && proxyWindow.onpopstate(newPopStateEvent);
|
|
3631
3865
|
}
|
|
@@ -3635,12 +3869,17 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
|
|
|
3635
3869
|
* @param proxyWindow sandbox window
|
|
3636
3870
|
* @param oldHref old href
|
|
3637
3871
|
*/
|
|
3638
|
-
function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
|
|
3639
|
-
const newHashChangeEvent = new HashChangeEvent(formatEventName
|
|
3872
|
+
function dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref) {
|
|
3873
|
+
const newHashChangeEvent = new HashChangeEvent(formatEventName('hashchange', appName), {
|
|
3640
3874
|
newURL: proxyWindow.location.href,
|
|
3641
3875
|
oldURL: oldHref,
|
|
3642
3876
|
});
|
|
3643
|
-
|
|
3877
|
+
if (isIframeSandbox(appName)) {
|
|
3878
|
+
microAppWindow.dispatchEvent(newHashChangeEvent);
|
|
3879
|
+
}
|
|
3880
|
+
else {
|
|
3881
|
+
globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
|
|
3882
|
+
}
|
|
3644
3883
|
// call function window.onhashchange if it exists
|
|
3645
3884
|
isFunction(proxyWindow.onhashchange) && proxyWindow.onhashchange(newHashChangeEvent);
|
|
3646
3885
|
}
|
|
@@ -3692,22 +3931,26 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3692
3931
|
const rawHistory = globalEnv.rawWindow.history;
|
|
3693
3932
|
function getMicroHistoryMethod(methodName) {
|
|
3694
3933
|
return function (...rests) {
|
|
3934
|
+
var _a, _b, _c;
|
|
3935
|
+
// TODO: 测试iframe的URL兼容isURL的情况
|
|
3695
3936
|
if (isString(rests[2]) || isURL(rests[2])) {
|
|
3696
3937
|
const targetLocation = createURL(rests[2], microLocation.href);
|
|
3697
|
-
|
|
3698
|
-
|
|
3699
|
-
|
|
3700
|
-
|
|
3701
|
-
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3702
|
-
}
|
|
3703
|
-
return void 0;
|
|
3938
|
+
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3939
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
|
|
3940
|
+
if (targetFullPath !== microLocation.fullPath) {
|
|
3941
|
+
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3704
3942
|
}
|
|
3943
|
+
(_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
3944
|
+
}
|
|
3945
|
+
else {
|
|
3946
|
+
nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
|
|
3705
3947
|
}
|
|
3706
|
-
nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
|
|
3707
3948
|
};
|
|
3708
3949
|
}
|
|
3709
3950
|
const pushState = getMicroHistoryMethod('pushState');
|
|
3710
3951
|
const replaceState = getMicroHistoryMethod('replaceState');
|
|
3952
|
+
if (isIframeSandbox(appName))
|
|
3953
|
+
return { pushState, replaceState };
|
|
3711
3954
|
return new Proxy(rawHistory, {
|
|
3712
3955
|
get(target, key) {
|
|
3713
3956
|
if (key === 'state') {
|
|
@@ -3719,8 +3962,7 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3719
3962
|
else if (key === 'replaceState') {
|
|
3720
3963
|
return replaceState;
|
|
3721
3964
|
}
|
|
3722
|
-
|
|
3723
|
-
return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'HISTORY') : rawValue;
|
|
3965
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), target, 'HISTORY');
|
|
3724
3966
|
},
|
|
3725
3967
|
set(target, key, value) {
|
|
3726
3968
|
Reflect.set(target, key, value);
|
|
@@ -3765,6 +4007,7 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
|
|
|
3765
4007
|
if (isEffectiveApp(appName)) {
|
|
3766
4008
|
const rawLocation = globalEnv.rawWindow.location;
|
|
3767
4009
|
const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
4010
|
+
// oldHref use for hashChangeEvent of base app
|
|
3768
4011
|
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
3769
4012
|
// navigate with native history method
|
|
3770
4013
|
nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
|
|
@@ -3873,8 +4116,9 @@ function createRouterApi() {
|
|
|
3873
4116
|
const microLocation = app.sandBox.proxyWindow.location;
|
|
3874
4117
|
const targetLocation = createURL(to.path, microLocation.href);
|
|
3875
4118
|
// Only get path data, even if the origin is different from microApp
|
|
4119
|
+
const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
|
|
3876
4120
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3877
|
-
if (
|
|
4121
|
+
if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
|
|
3878
4122
|
const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
|
|
3879
4123
|
navigateWithRawHistory(appName, methodName, targetLocation, to.state);
|
|
3880
4124
|
}
|
|
@@ -4023,8 +4267,7 @@ function createRouterApi() {
|
|
|
4023
4267
|
baseRouterProxy = new Proxy(baseRouter, {
|
|
4024
4268
|
get(target, key) {
|
|
4025
4269
|
removeDomScope();
|
|
4026
|
-
|
|
4027
|
-
return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'BASEROUTER') : rawValue;
|
|
4270
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), target, 'BASEROUTER');
|
|
4028
4271
|
},
|
|
4029
4272
|
set(target, key, value) {
|
|
4030
4273
|
Reflect.set(target, key, value);
|
|
@@ -4052,9 +4295,118 @@ function createRouterApi() {
|
|
|
4052
4295
|
}
|
|
4053
4296
|
const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
|
|
4054
4297
|
|
|
4055
|
-
const
|
|
4298
|
+
const escape2RawWindowKeys = [
|
|
4299
|
+
'getComputedStyle',
|
|
4300
|
+
'visualViewport',
|
|
4301
|
+
'matchMedia',
|
|
4302
|
+
// 'DOMParser',
|
|
4303
|
+
'ResizeObserver',
|
|
4304
|
+
'IntersectionObserver',
|
|
4305
|
+
];
|
|
4306
|
+
const escape2RawWindowRegExpKeys = [
|
|
4307
|
+
/animationFrame$/i,
|
|
4308
|
+
/mutationObserver$/i,
|
|
4309
|
+
/height$|width$/i,
|
|
4310
|
+
/offset$/i,
|
|
4311
|
+
// /event$/i,
|
|
4312
|
+
/^screen/i,
|
|
4313
|
+
/^scroll/i,
|
|
4314
|
+
/X$|Y$/,
|
|
4315
|
+
];
|
|
4316
|
+
const scopeIframeWindowOnEvent = [
|
|
4317
|
+
'onload',
|
|
4318
|
+
'onbeforeunload',
|
|
4319
|
+
'onunload',
|
|
4320
|
+
];
|
|
4321
|
+
const scopeIframeWindowEvent = [
|
|
4322
|
+
'hashchange',
|
|
4323
|
+
'popstate',
|
|
4324
|
+
'DOMContentLoaded',
|
|
4325
|
+
'load',
|
|
4326
|
+
'beforeunload',
|
|
4327
|
+
'unload',
|
|
4328
|
+
].concat(microAppCustomEvent);
|
|
4329
|
+
const scopeIframeDocumentEvent = [
|
|
4330
|
+
'DOMContentLoaded',
|
|
4331
|
+
'readystatechange',
|
|
4332
|
+
];
|
|
4333
|
+
const scopeIframeDocumentOnEvent = [
|
|
4334
|
+
'onreadystatechange',
|
|
4335
|
+
];
|
|
4336
|
+
const uniqueDocumentElement = [
|
|
4337
|
+
'body',
|
|
4338
|
+
'head',
|
|
4339
|
+
'html',
|
|
4340
|
+
'title',
|
|
4341
|
+
];
|
|
4342
|
+
const hijackMicroLocationKeys = [
|
|
4343
|
+
'host',
|
|
4344
|
+
'hostname',
|
|
4345
|
+
'port',
|
|
4346
|
+
'protocol',
|
|
4347
|
+
'origin',
|
|
4348
|
+
];
|
|
4349
|
+
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
|
|
4350
|
+
const proxy2RawDocOrShadowKeys = [
|
|
4351
|
+
'childElementCount',
|
|
4352
|
+
'children',
|
|
4353
|
+
'firstElementChild',
|
|
4354
|
+
'firstChild',
|
|
4355
|
+
'lastElementChild',
|
|
4356
|
+
'activeElement',
|
|
4357
|
+
'fullscreenElement',
|
|
4358
|
+
'pictureInPictureElement',
|
|
4359
|
+
'pointerLockElement',
|
|
4360
|
+
'styleSheets',
|
|
4361
|
+
];
|
|
4362
|
+
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
|
|
4363
|
+
const proxy2RawDocOrShadowMethods = [
|
|
4364
|
+
'append',
|
|
4365
|
+
'contains',
|
|
4366
|
+
'replaceChildren',
|
|
4367
|
+
'getSelection',
|
|
4368
|
+
'elementFromPoint',
|
|
4369
|
+
'elementsFromPoint',
|
|
4370
|
+
'getAnimations',
|
|
4371
|
+
];
|
|
4372
|
+
// 直接代理到原生document上 (属性)
|
|
4373
|
+
const proxy2RawDocumentKeys = [
|
|
4374
|
+
'characterSet',
|
|
4375
|
+
'compatMode',
|
|
4376
|
+
'contentType',
|
|
4377
|
+
'designMode',
|
|
4378
|
+
'dir',
|
|
4379
|
+
'doctype',
|
|
4380
|
+
'embeds',
|
|
4381
|
+
'fullscreenEnabled',
|
|
4382
|
+
'hidden',
|
|
4383
|
+
'implementation',
|
|
4384
|
+
'lastModified',
|
|
4385
|
+
'pictureInPictureEnabled',
|
|
4386
|
+
'plugins',
|
|
4387
|
+
'readyState',
|
|
4388
|
+
'referrer',
|
|
4389
|
+
'visibilityState',
|
|
4390
|
+
'fonts',
|
|
4391
|
+
];
|
|
4392
|
+
// 直接代理到原生document上 (方法)
|
|
4393
|
+
const proxy2RawDocumentMethods = [
|
|
4394
|
+
'execCommand',
|
|
4395
|
+
'createRange',
|
|
4396
|
+
'exitFullscreen',
|
|
4397
|
+
'exitPictureInPicture',
|
|
4398
|
+
'getElementsByTagNameNS',
|
|
4399
|
+
'hasFocus',
|
|
4400
|
+
'prepend',
|
|
4401
|
+
];
|
|
4402
|
+
const globalPropertyList = [
|
|
4403
|
+
'window',
|
|
4404
|
+
'self',
|
|
4405
|
+
'globalThis'
|
|
4406
|
+
];
|
|
4407
|
+
|
|
4056
4408
|
// origin is readonly, so we ignore when updateMicroLocation
|
|
4057
|
-
const locationKeys = [
|
|
4409
|
+
const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
|
|
4058
4410
|
// origin, fullPath is necessary for guardLocation
|
|
4059
4411
|
const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
|
|
4060
4412
|
/**
|
|
@@ -4062,19 +4414,27 @@ const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
|
|
|
4062
4414
|
* MDN https://developer.mozilla.org/en-US/docs/Web/API/Location
|
|
4063
4415
|
* @param appName app name
|
|
4064
4416
|
* @param url app url
|
|
4417
|
+
* @param microAppWindow iframeWindow, iframe only
|
|
4418
|
+
* @param childStaticLocation real child location info, iframe only
|
|
4419
|
+
* @param browserHost host of browser, iframe only
|
|
4420
|
+
* @param childHost host of child app, iframe only
|
|
4065
4421
|
*/
|
|
4066
|
-
function createMicroLocation(appName, url) {
|
|
4422
|
+
function createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
|
|
4067
4423
|
const rawWindow = globalEnv.rawWindow;
|
|
4068
4424
|
const rawLocation = rawWindow.location;
|
|
4069
|
-
|
|
4070
|
-
|
|
4071
|
-
|
|
4072
|
-
|
|
4073
|
-
|
|
4074
|
-
|
|
4075
|
-
|
|
4076
|
-
|
|
4077
|
-
|
|
4425
|
+
const isIframe = !!microAppWindow;
|
|
4426
|
+
/**
|
|
4427
|
+
* withLocation is microLocation for with sandbox
|
|
4428
|
+
* it is globally unique for child app
|
|
4429
|
+
*/
|
|
4430
|
+
const withLocation = createURL(url);
|
|
4431
|
+
/**
|
|
4432
|
+
* In iframe, jump through raw iframeLocation will cause microAppWindow.location reset
|
|
4433
|
+
* So we get location dynamically
|
|
4434
|
+
*/
|
|
4435
|
+
function getTarget() {
|
|
4436
|
+
return isIframe ? microAppWindow.location : withLocation;
|
|
4437
|
+
}
|
|
4078
4438
|
/**
|
|
4079
4439
|
* Common handler for href, assign, replace
|
|
4080
4440
|
* It is mainly used to deal with special scenes about hash
|
|
@@ -4082,10 +4442,10 @@ function createMicroLocation(appName, url) {
|
|
|
4082
4442
|
* @param methodName pushState/replaceState
|
|
4083
4443
|
* @returns origin value or formatted value
|
|
4084
4444
|
*/
|
|
4085
|
-
|
|
4086
|
-
const targetLocation = createURL(value,
|
|
4445
|
+
function commonHandler(value, methodName) {
|
|
4446
|
+
const targetLocation = createURL(value, proxyLocation.href);
|
|
4087
4447
|
// Even if the origin is the same, developers still have the possibility of want to jump to a new page
|
|
4088
|
-
if (targetLocation.origin ===
|
|
4448
|
+
if (targetLocation.origin === proxyLocation.origin) {
|
|
4089
4449
|
const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
|
|
4090
4450
|
/**
|
|
4091
4451
|
* change hash with location.href will not trigger the browser reload
|
|
@@ -4094,10 +4454,10 @@ function createMicroLocation(appName, url) {
|
|
|
4094
4454
|
* 1. if child app only change hash, it should not trigger browser reload
|
|
4095
4455
|
* 2. if address is same and has hash, it should not add route stack
|
|
4096
4456
|
*/
|
|
4097
|
-
if (targetLocation.pathname ===
|
|
4098
|
-
targetLocation.search ===
|
|
4457
|
+
if (targetLocation.pathname === proxyLocation.pathname &&
|
|
4458
|
+
targetLocation.search === proxyLocation.search) {
|
|
4099
4459
|
let oldHref = null;
|
|
4100
|
-
if (targetLocation.hash !==
|
|
4460
|
+
if (targetLocation.hash !== proxyLocation.hash) {
|
|
4101
4461
|
if (setMicroPathResult.isAttach2Hash)
|
|
4102
4462
|
oldHref = rawLocation.href;
|
|
4103
4463
|
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
@@ -4106,35 +4466,22 @@ function createMicroLocation(appName, url) {
|
|
|
4106
4466
|
dispatchNativeEvent(appName, false, oldHref);
|
|
4107
4467
|
}
|
|
4108
4468
|
else {
|
|
4109
|
-
|
|
4469
|
+
reload();
|
|
4110
4470
|
}
|
|
4111
4471
|
return void 0;
|
|
4112
4472
|
/**
|
|
4113
4473
|
* when baseApp is hash router, address change of child can not reload browser
|
|
4114
|
-
* so we imitate behavior of browser (reload)
|
|
4474
|
+
* so we imitate behavior of browser (reload) manually
|
|
4115
4475
|
*/
|
|
4116
4476
|
}
|
|
4117
4477
|
else if (setMicroPathResult.isAttach2Hash) {
|
|
4118
4478
|
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
4119
|
-
|
|
4479
|
+
reload();
|
|
4120
4480
|
return void 0;
|
|
4121
4481
|
}
|
|
4122
|
-
|
|
4482
|
+
return setMicroPathResult.fullPath;
|
|
4123
4483
|
}
|
|
4124
4484
|
return value;
|
|
4125
|
-
};
|
|
4126
|
-
/**
|
|
4127
|
-
* create location PropertyDescriptor (href, pathname, search, hash)
|
|
4128
|
-
* @param key property name
|
|
4129
|
-
* @param setter setter of location property
|
|
4130
|
-
*/
|
|
4131
|
-
function createPropertyDescriptor(getter, setter) {
|
|
4132
|
-
return {
|
|
4133
|
-
enumerable: true,
|
|
4134
|
-
configurable: true,
|
|
4135
|
-
get: getter,
|
|
4136
|
-
set: setter,
|
|
4137
|
-
};
|
|
4138
4485
|
}
|
|
4139
4486
|
/**
|
|
4140
4487
|
* common handler for location.pathname & location.search
|
|
@@ -4144,7 +4491,7 @@ function createMicroLocation(appName, url) {
|
|
|
4144
4491
|
function handleForPathNameAndSearch(targetPath, key) {
|
|
4145
4492
|
const targetLocation = createURL(targetPath, url);
|
|
4146
4493
|
// When the browser url has a hash value, the same pathname/search will not refresh browser
|
|
4147
|
-
if (targetLocation[key] ===
|
|
4494
|
+
if (targetLocation[key] === proxyLocation[key] && proxyLocation.hash) {
|
|
4148
4495
|
// The href has not changed, not need to dispatch hashchange event
|
|
4149
4496
|
dispatchNativeEvent(appName, false);
|
|
4150
4497
|
}
|
|
@@ -4155,58 +4502,96 @@ function createMicroLocation(appName, url) {
|
|
|
4155
4502
|
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
4156
4503
|
* search: ?query ==> ?query#hash
|
|
4157
4504
|
*/
|
|
4158
|
-
nativeHistoryNavigate(appName, targetLocation[key] ===
|
|
4159
|
-
|
|
4505
|
+
nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
|
|
4506
|
+
reload();
|
|
4160
4507
|
}
|
|
4161
4508
|
}
|
|
4162
|
-
function rawReload() {
|
|
4163
|
-
isEffectiveApp(appName) && rawLocation.reload();
|
|
4164
|
-
}
|
|
4165
|
-
/**
|
|
4166
|
-
* Special processing for four keys: href, pathname, search and hash
|
|
4167
|
-
* They take values from shadowLocation, and require special operations when assigning values
|
|
4168
|
-
*/
|
|
4169
|
-
rawDefineProperties(microLocation, {
|
|
4170
|
-
href: createPropertyDescriptor(() => shadowLocation.href, (value) => {
|
|
4171
|
-
if (isEffectiveApp(appName)) {
|
|
4172
|
-
const targetPath = commonHandler(value, 'pushState');
|
|
4173
|
-
if (targetPath)
|
|
4174
|
-
rawLocation.href = targetPath;
|
|
4175
|
-
}
|
|
4176
|
-
}),
|
|
4177
|
-
pathname: createPropertyDescriptor(() => shadowLocation.pathname, (value) => {
|
|
4178
|
-
const targetPath = ('/' + value).replace(/^\/+/, '/') + shadowLocation.search + shadowLocation.hash;
|
|
4179
|
-
handleForPathNameAndSearch(targetPath, 'pathname');
|
|
4180
|
-
}),
|
|
4181
|
-
search: createPropertyDescriptor(() => shadowLocation.search, (value) => {
|
|
4182
|
-
const targetPath = shadowLocation.pathname + ('?' + value).replace(/^\?+/, '?') + shadowLocation.hash;
|
|
4183
|
-
handleForPathNameAndSearch(targetPath, 'search');
|
|
4184
|
-
}),
|
|
4185
|
-
hash: createPropertyDescriptor(() => shadowLocation.hash, (value) => {
|
|
4186
|
-
const targetPath = shadowLocation.pathname + shadowLocation.search + ('#' + value).replace(/^#+/, '#');
|
|
4187
|
-
const targetLocation = createURL(targetPath, url);
|
|
4188
|
-
// The same hash will not trigger popStateEvent
|
|
4189
|
-
if (targetLocation.hash !== shadowLocation.hash) {
|
|
4190
|
-
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
4191
|
-
}
|
|
4192
|
-
}),
|
|
4193
|
-
fullPath: createPropertyDescriptor(() => shadowLocation.pathname + shadowLocation.search + shadowLocation.hash, noop),
|
|
4194
|
-
});
|
|
4195
4509
|
const createLocationMethod = (locationMethodName) => {
|
|
4196
4510
|
return function (value) {
|
|
4197
4511
|
if (isEffectiveApp(appName)) {
|
|
4198
4512
|
const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
|
|
4199
|
-
if (targetPath)
|
|
4200
|
-
|
|
4513
|
+
if (targetPath) {
|
|
4514
|
+
// Same as href, complete targetPath with browser origin in vite env
|
|
4515
|
+
rawLocation[locationMethodName](createURL(targetPath, rawLocation.origin).href);
|
|
4516
|
+
}
|
|
4201
4517
|
}
|
|
4202
4518
|
};
|
|
4203
4519
|
};
|
|
4204
|
-
|
|
4205
|
-
|
|
4206
|
-
|
|
4207
|
-
|
|
4208
|
-
|
|
4520
|
+
const assign = createLocationMethod('assign');
|
|
4521
|
+
const replace = createLocationMethod('replace');
|
|
4522
|
+
const reload = (forcedReload) => rawLocation.reload(forcedReload);
|
|
4523
|
+
rawDefineProperty(getTarget(), 'fullPath', {
|
|
4524
|
+
enumerable: true,
|
|
4525
|
+
configurable: true,
|
|
4526
|
+
get: () => proxyLocation.pathname + proxyLocation.search + proxyLocation.hash,
|
|
4527
|
+
});
|
|
4528
|
+
/**
|
|
4529
|
+
* location.assign/replace is readonly, cannot be proxy, so we use empty object as proxy target
|
|
4530
|
+
*/
|
|
4531
|
+
const proxyLocation = new Proxy({}, {
|
|
4532
|
+
get: (_, key) => {
|
|
4533
|
+
const target = getTarget();
|
|
4534
|
+
if (isIframe) {
|
|
4535
|
+
// host hostname port protocol
|
|
4536
|
+
if (hijackMicroLocationKeys.includes(key)) {
|
|
4537
|
+
return childStaticLocation[key];
|
|
4538
|
+
}
|
|
4539
|
+
if (key === 'href') {
|
|
4540
|
+
// do not use target, because target may be deleted
|
|
4541
|
+
return target[key].replace(browserHost, childHost);
|
|
4542
|
+
}
|
|
4543
|
+
}
|
|
4544
|
+
if (key === 'assign')
|
|
4545
|
+
return assign;
|
|
4546
|
+
if (key === 'replace')
|
|
4547
|
+
return replace;
|
|
4548
|
+
if (key === 'reload')
|
|
4549
|
+
return reload;
|
|
4550
|
+
if (key === 'self')
|
|
4551
|
+
return target;
|
|
4552
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), target, 'LOCATION');
|
|
4553
|
+
},
|
|
4554
|
+
set: (_, key, value) => {
|
|
4555
|
+
if (isEffectiveApp(appName)) {
|
|
4556
|
+
const target = getTarget();
|
|
4557
|
+
if (key === 'href') {
|
|
4558
|
+
const targetPath = commonHandler(value, 'pushState');
|
|
4559
|
+
/**
|
|
4560
|
+
* In vite, targetPath without origin will be completed with child origin
|
|
4561
|
+
* So we use browser origin to complete targetPath to avoid this problem
|
|
4562
|
+
* But, why child app can affect browser jump?
|
|
4563
|
+
* Guess(need check):
|
|
4564
|
+
* 1. vite records the origin when init
|
|
4565
|
+
* 2. listen for browser jump and automatically complete the address
|
|
4566
|
+
*/
|
|
4567
|
+
if (targetPath) {
|
|
4568
|
+
rawLocation.href = createURL(targetPath, rawLocation.origin).href;
|
|
4569
|
+
}
|
|
4570
|
+
}
|
|
4571
|
+
else if (key === 'pathname') {
|
|
4572
|
+
const targetPath = ('/' + value).replace(/^\/+/, '/') + proxyLocation.search + proxyLocation.hash;
|
|
4573
|
+
handleForPathNameAndSearch(targetPath, 'pathname');
|
|
4574
|
+
}
|
|
4575
|
+
else if (key === 'search') {
|
|
4576
|
+
const targetPath = proxyLocation.pathname + ('?' + value).replace(/^\?+/, '?') + proxyLocation.hash;
|
|
4577
|
+
handleForPathNameAndSearch(targetPath, 'search');
|
|
4578
|
+
}
|
|
4579
|
+
else if (key === 'hash') {
|
|
4580
|
+
const targetPath = proxyLocation.pathname + proxyLocation.search + ('#' + value).replace(/^#+/, '#');
|
|
4581
|
+
const targetLocation = createURL(targetPath, url);
|
|
4582
|
+
// The same hash will not trigger popStateEvent
|
|
4583
|
+
if (targetLocation.hash !== proxyLocation.hash) {
|
|
4584
|
+
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
4585
|
+
}
|
|
4586
|
+
}
|
|
4587
|
+
else {
|
|
4588
|
+
Reflect.set(target, key, value);
|
|
4589
|
+
}
|
|
4590
|
+
}
|
|
4591
|
+
return true;
|
|
4592
|
+
},
|
|
4209
4593
|
});
|
|
4594
|
+
return proxyLocation;
|
|
4210
4595
|
}
|
|
4211
4596
|
/**
|
|
4212
4597
|
* create guardLocation by microLocation, used for router guard
|
|
@@ -4238,17 +4623,17 @@ function autoTriggerNavigationGuard(appName, microLocation) {
|
|
|
4238
4623
|
* @param type auto prevent
|
|
4239
4624
|
*/
|
|
4240
4625
|
function updateMicroLocation(appName, path, microLocation, type) {
|
|
4241
|
-
|
|
4626
|
+
var _a;
|
|
4242
4627
|
// record old values of microLocation to `from`
|
|
4243
4628
|
const from = createGuardLocation(appName, microLocation);
|
|
4244
|
-
|
|
4245
|
-
|
|
4246
|
-
|
|
4247
|
-
|
|
4248
|
-
|
|
4249
|
-
|
|
4250
|
-
|
|
4251
|
-
microLocation[key] = newLocation[key];
|
|
4629
|
+
const newLocation = createURL(path, microLocation.href);
|
|
4630
|
+
if (isIframeSandbox(appName)) {
|
|
4631
|
+
const microAppWindow = appInstanceMap.get(appName).sandBox.microAppWindow;
|
|
4632
|
+
(_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
|
|
4633
|
+
}
|
|
4634
|
+
else {
|
|
4635
|
+
for (const key of locationKeys) {
|
|
4636
|
+
microLocation.self[key] = newLocation[key];
|
|
4252
4637
|
}
|
|
4253
4638
|
}
|
|
4254
4639
|
// update latest values of microLocation to `to`
|
|
@@ -4426,8 +4811,8 @@ function useMicroEventSource() {
|
|
|
4426
4811
|
}
|
|
4427
4812
|
|
|
4428
4813
|
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
4429
|
-
const globalPropertyList = ['window', 'self', 'globalThis'];
|
|
4430
|
-
class
|
|
4814
|
+
const globalPropertyList$1 = ['window', 'self', 'globalThis'];
|
|
4815
|
+
class WithSandBox {
|
|
4431
4816
|
constructor(appName, url) {
|
|
4432
4817
|
/**
|
|
4433
4818
|
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
@@ -4478,18 +4863,21 @@ class SandBox {
|
|
|
4478
4863
|
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
4479
4864
|
}
|
|
4480
4865
|
/**
|
|
4481
|
-
*
|
|
4482
|
-
*
|
|
4483
|
-
*
|
|
4866
|
+
* Target: Ensure default mode action exactly same to first time when render again
|
|
4867
|
+
* 1. The following globalKey maybe modified when render, reset them when render again in default mode
|
|
4868
|
+
* 2. Umd mode will not delete any keys during sandBox.stop, ignore umd mode
|
|
4869
|
+
* 3. When sandbox.start called for the first time, it must be the default mode
|
|
4484
4870
|
*/
|
|
4485
4871
|
if (!umdMode) {
|
|
4486
4872
|
this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
|
|
4487
4873
|
}
|
|
4488
|
-
if (++
|
|
4874
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
4875
|
+
patchElementAndDocument();
|
|
4876
|
+
patchHistory();
|
|
4877
|
+
}
|
|
4878
|
+
if (++WithSandBox.activeCount === 1) {
|
|
4489
4879
|
effectDocumentEvent();
|
|
4490
|
-
patchElementPrototypeMethods();
|
|
4491
4880
|
initEnvOfNestedApp();
|
|
4492
|
-
patchHistory();
|
|
4493
4881
|
}
|
|
4494
4882
|
fixBabelPolyfill6();
|
|
4495
4883
|
}
|
|
@@ -4498,28 +4886,25 @@ class SandBox {
|
|
|
4498
4886
|
* close sandbox and perform some clean up actions
|
|
4499
4887
|
* @param umdMode is umd mode
|
|
4500
4888
|
* @param keepRouteState prevent reset route
|
|
4501
|
-
* @param
|
|
4889
|
+
* @param destroy completely destroy, delete cache resources
|
|
4502
4890
|
* @param clearData clear data from base app
|
|
4503
4891
|
*/
|
|
4504
|
-
stop({ umdMode, keepRouteState,
|
|
4892
|
+
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
4505
4893
|
if (this.active) {
|
|
4506
|
-
|
|
4507
|
-
this.releaseGlobalEffect(clearData);
|
|
4894
|
+
this.recordAndReleaseEffect({ clearData, destroy }, !umdMode || destroy);
|
|
4508
4895
|
if (this.removeHistoryListener) {
|
|
4509
4896
|
this.clearRouteState(keepRouteState);
|
|
4510
4897
|
// release listener of popstate
|
|
4511
4898
|
this.removeHistoryListener();
|
|
4512
4899
|
}
|
|
4513
|
-
if (clearEventSource) {
|
|
4514
|
-
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4515
|
-
}
|
|
4516
4900
|
/**
|
|
4517
4901
|
* NOTE:
|
|
4518
4902
|
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
4519
4903
|
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
4520
4904
|
* 3. umd mode will not delete global keys
|
|
4521
4905
|
*/
|
|
4522
|
-
if (!umdMode) {
|
|
4906
|
+
if (!umdMode || destroy) {
|
|
4907
|
+
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4523
4908
|
this.injectedKeys.forEach((key) => {
|
|
4524
4909
|
Reflect.deleteProperty(this.microAppWindow, key);
|
|
4525
4910
|
});
|
|
@@ -4529,30 +4914,47 @@ class SandBox {
|
|
|
4529
4914
|
});
|
|
4530
4915
|
this.escapeKeys.clear();
|
|
4531
4916
|
}
|
|
4532
|
-
if (--
|
|
4533
|
-
|
|
4534
|
-
releasePatches();
|
|
4917
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
4918
|
+
releasePatchElementAndDocument();
|
|
4535
4919
|
releasePatchHistory();
|
|
4536
4920
|
}
|
|
4921
|
+
if (--WithSandBox.activeCount === 0) {
|
|
4922
|
+
releaseEffectDocumentEvent();
|
|
4923
|
+
}
|
|
4537
4924
|
this.active = false;
|
|
4538
4925
|
}
|
|
4539
4926
|
}
|
|
4540
4927
|
/**
|
|
4541
|
-
*
|
|
4928
|
+
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
4542
4929
|
* Scenes:
|
|
4543
|
-
* 1. unmount of
|
|
4930
|
+
* 1. unmount of default/umd app
|
|
4544
4931
|
* 2. hidden keep-alive app
|
|
4545
4932
|
* 3. after init prerender app
|
|
4546
|
-
* @param
|
|
4933
|
+
* @param options {
|
|
4934
|
+
* @param clearData clear data from base app
|
|
4935
|
+
* @param isPrerender is prerender app
|
|
4936
|
+
* @param keepAlive is keep-alive app
|
|
4937
|
+
* }
|
|
4938
|
+
* @param preventRecord prevent record effect events
|
|
4547
4939
|
*/
|
|
4548
|
-
|
|
4549
|
-
|
|
4550
|
-
|
|
4551
|
-
|
|
4552
|
-
|
|
4553
|
-
|
|
4554
|
-
this.microAppWindow.microApp.clearData();
|
|
4940
|
+
recordAndReleaseEffect(options, preventRecord = false) {
|
|
4941
|
+
if (preventRecord) {
|
|
4942
|
+
this.resetEffectSnapshot();
|
|
4943
|
+
}
|
|
4944
|
+
else {
|
|
4945
|
+
this.recordEffectSnapshot();
|
|
4555
4946
|
}
|
|
4947
|
+
this.releaseGlobalEffect(options);
|
|
4948
|
+
}
|
|
4949
|
+
/**
|
|
4950
|
+
* reset effect snapshot data in default mode or destroy
|
|
4951
|
+
* Scenes:
|
|
4952
|
+
* 1. unmount hidden keep-alive app manually
|
|
4953
|
+
* 2. unmount prerender app manually
|
|
4954
|
+
*/
|
|
4955
|
+
resetEffectSnapshot() {
|
|
4956
|
+
this.effectController.reset();
|
|
4957
|
+
resetDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4556
4958
|
}
|
|
4557
4959
|
/**
|
|
4558
4960
|
* record umd snapshot before the first execution of umdHookMount
|
|
@@ -4563,7 +4965,7 @@ class SandBox {
|
|
|
4563
4965
|
*/
|
|
4564
4966
|
recordEffectSnapshot() {
|
|
4565
4967
|
// this.microAppWindow.__MICRO_APP_UMD_MODE__ = true
|
|
4566
|
-
this.effectController.
|
|
4968
|
+
this.effectController.record();
|
|
4567
4969
|
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4568
4970
|
// this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
|
|
4569
4971
|
// this.injectedKeys.forEach((key: PropertyKey) => {
|
|
@@ -4575,12 +4977,34 @@ class SandBox {
|
|
|
4575
4977
|
// this.recordUmdInjectedValues!.forEach((value: unknown, key: PropertyKey) => {
|
|
4576
4978
|
// Reflect.set(this.proxyWindow, key, value)
|
|
4577
4979
|
// })
|
|
4578
|
-
this.effectController.
|
|
4980
|
+
this.effectController.rebuild();
|
|
4579
4981
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4580
4982
|
}
|
|
4581
|
-
|
|
4582
|
-
|
|
4583
|
-
|
|
4983
|
+
/**
|
|
4984
|
+
* clear global event, timeout, data listener
|
|
4985
|
+
* Scenes:
|
|
4986
|
+
* 1. unmount of default/umd app
|
|
4987
|
+
* 2. hidden keep-alive app
|
|
4988
|
+
* 3. after init prerender app
|
|
4989
|
+
* @param clearData clear data from base app
|
|
4990
|
+
* @param isPrerender is prerender app
|
|
4991
|
+
* @param keepAlive is keep-alive app
|
|
4992
|
+
* @param destroy completely destroy
|
|
4993
|
+
*/
|
|
4994
|
+
releaseGlobalEffect({ clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
4995
|
+
var _a, _b, _c;
|
|
4996
|
+
this.effectController.release({
|
|
4997
|
+
umdMode: this.proxyWindow.__MICRO_APP_UMD_MODE__,
|
|
4998
|
+
isPrerender,
|
|
4999
|
+
keepAlive,
|
|
5000
|
+
destroy,
|
|
5001
|
+
});
|
|
5002
|
+
(_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
|
|
5003
|
+
(_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
|
|
5004
|
+
if (clearData) {
|
|
5005
|
+
microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
|
|
5006
|
+
(_c = this.microAppWindow.microApp) === null || _c === void 0 ? void 0 : _c.clearData();
|
|
5007
|
+
}
|
|
4584
5008
|
}
|
|
4585
5009
|
/**
|
|
4586
5010
|
* get scopeProperties and escapeProperties from plugins & adapter
|
|
@@ -4613,7 +5037,6 @@ class SandBox {
|
|
|
4613
5037
|
createProxyWindow(appName) {
|
|
4614
5038
|
const rawWindow = globalEnv.rawWindow;
|
|
4615
5039
|
const descriptorTargetMap = new Map();
|
|
4616
|
-
// window.xxx will trigger proxy
|
|
4617
5040
|
return new Proxy(this.microAppWindow, {
|
|
4618
5041
|
get: (target, key) => {
|
|
4619
5042
|
throttleDeferForSetAppName(appName);
|
|
@@ -4621,11 +5044,14 @@ class SandBox {
|
|
|
4621
5044
|
(isString(key) && /^__MICRO_APP_/.test(key)) ||
|
|
4622
5045
|
this.scopeProperties.includes(key))
|
|
4623
5046
|
return Reflect.get(target, key);
|
|
4624
|
-
|
|
4625
|
-
return isFunction(rawValue) ? bindFunctionToRawObject(rawWindow, rawValue) : rawValue;
|
|
5047
|
+
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
4626
5048
|
},
|
|
4627
5049
|
set: (target, key, value) => {
|
|
4628
5050
|
if (this.active) {
|
|
5051
|
+
/**
|
|
5052
|
+
* TODO:
|
|
5053
|
+
* 1、location域名相同,子应用内部跳转时的处理
|
|
5054
|
+
*/
|
|
4629
5055
|
if (this.adapter.escapeSetterKeyList.includes(key)) {
|
|
4630
5056
|
Reflect.set(rawWindow, key, value);
|
|
4631
5057
|
}
|
|
@@ -4646,15 +5072,15 @@ class SandBox {
|
|
|
4646
5072
|
this.injectedKeys.add(key);
|
|
4647
5073
|
}
|
|
4648
5074
|
else {
|
|
5075
|
+
!Reflect.has(target, key) && this.injectedKeys.add(key);
|
|
4649
5076
|
Reflect.set(target, key, value);
|
|
4650
|
-
this.injectedKeys.add(key);
|
|
4651
5077
|
}
|
|
4652
5078
|
if ((this.escapeProperties.includes(key) ||
|
|
4653
5079
|
(this.adapter.staticEscapeProperties.includes(key) &&
|
|
4654
5080
|
!Reflect.has(rawWindow, key))) &&
|
|
4655
5081
|
!this.scopeProperties.includes(key)) {
|
|
5082
|
+
!Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
|
|
4656
5083
|
Reflect.set(rawWindow, key, value);
|
|
4657
|
-
this.escapeKeys.add(key);
|
|
4658
5084
|
}
|
|
4659
5085
|
}
|
|
4660
5086
|
return true;
|
|
@@ -4702,6 +5128,13 @@ class SandBox {
|
|
|
4702
5128
|
},
|
|
4703
5129
|
});
|
|
4704
5130
|
}
|
|
5131
|
+
// set __MICRO_APP_PRE_RENDER__ state
|
|
5132
|
+
setPreRenderState(state) {
|
|
5133
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
5134
|
+
}
|
|
5135
|
+
markUmdMode(state) {
|
|
5136
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
5137
|
+
}
|
|
4705
5138
|
/**
|
|
4706
5139
|
* inject global properties to microAppWindow
|
|
4707
5140
|
* @param microAppWindow micro window
|
|
@@ -4714,8 +5147,10 @@ class SandBox {
|
|
|
4714
5147
|
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
4715
5148
|
microAppWindow.__MICRO_APP_URL__ = url;
|
|
4716
5149
|
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
5150
|
+
microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
4717
5151
|
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
4718
5152
|
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
5153
|
+
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
4719
5154
|
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
4720
5155
|
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
4721
5156
|
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
@@ -4760,7 +5195,7 @@ class SandBox {
|
|
|
4760
5195
|
}
|
|
4761
5196
|
rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
|
|
4762
5197
|
rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
|
|
4763
|
-
globalPropertyList.forEach((key) => {
|
|
5198
|
+
globalPropertyList$1.forEach((key) => {
|
|
4764
5199
|
rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
|
|
4765
5200
|
});
|
|
4766
5201
|
}
|
|
@@ -4890,23 +5325,39 @@ class SandBox {
|
|
|
4890
5325
|
});
|
|
4891
5326
|
}
|
|
4892
5327
|
initRouteState(defaultPage) {
|
|
4893
|
-
initRouteStateWithURL(this.
|
|
5328
|
+
initRouteStateWithURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location, defaultPage);
|
|
4894
5329
|
}
|
|
4895
5330
|
clearRouteState(keepRouteState) {
|
|
4896
|
-
clearRouteStateFromURL(this.
|
|
5331
|
+
clearRouteStateFromURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow.location, keepRouteState);
|
|
4897
5332
|
}
|
|
4898
5333
|
setRouteInfoForKeepAliveApp() {
|
|
4899
|
-
updateBrowserURLWithLocation(this.
|
|
5334
|
+
updateBrowserURLWithLocation(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location);
|
|
4900
5335
|
}
|
|
4901
5336
|
removeRouteInfoForKeepAliveApp() {
|
|
4902
|
-
removeStateAndPathFromBrowser(this.
|
|
5337
|
+
removeStateAndPathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4903
5338
|
}
|
|
4904
5339
|
/**
|
|
4905
|
-
*
|
|
5340
|
+
* Format all html elements when init
|
|
5341
|
+
* @param container micro app container
|
|
4906
5342
|
*/
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
5343
|
+
patchStaticElement(container) {
|
|
5344
|
+
patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
|
|
5345
|
+
}
|
|
5346
|
+
/**
|
|
5347
|
+
* action before exec scripts when mount
|
|
5348
|
+
* Actions:
|
|
5349
|
+
* 1. patch static elements from html
|
|
5350
|
+
* @param container micro app container
|
|
5351
|
+
*/
|
|
5352
|
+
actionBeforeExecScripts(container) {
|
|
5353
|
+
this.patchStaticElement(container);
|
|
5354
|
+
}
|
|
5355
|
+
/**
|
|
5356
|
+
* Create new document and Document
|
|
5357
|
+
*/
|
|
5358
|
+
createProxyDocument(appName) {
|
|
5359
|
+
const rawDocument = globalEnv.rawDocument;
|
|
5360
|
+
const rawRootDocument = globalEnv.rawRootDocument;
|
|
4910
5361
|
const createElement = function (tagName, options) {
|
|
4911
5362
|
const element = globalEnv.rawCreateElement.call(rawDocument, tagName, options);
|
|
4912
5363
|
element.__MICRO_APP_NAME__ = appName;
|
|
@@ -4914,67 +5365,1055 @@ class SandBox {
|
|
|
4914
5365
|
};
|
|
4915
5366
|
const proxyDocument = new Proxy(rawDocument, {
|
|
4916
5367
|
get: (target, key) => {
|
|
4917
|
-
throttleDeferForSetAppName(appName);
|
|
4918
|
-
throttleDeferForParentNode(proxyDocument);
|
|
4919
|
-
if (key === 'createElement')
|
|
4920
|
-
return createElement;
|
|
4921
|
-
if (key === Symbol.toStringTag)
|
|
4922
|
-
return 'ProxyDocument';
|
|
4923
|
-
if (key === 'defaultView')
|
|
5368
|
+
throttleDeferForSetAppName(appName);
|
|
5369
|
+
throttleDeferForParentNode(proxyDocument);
|
|
5370
|
+
if (key === 'createElement')
|
|
5371
|
+
return createElement;
|
|
5372
|
+
if (key === Symbol.toStringTag)
|
|
5373
|
+
return 'ProxyDocument';
|
|
5374
|
+
if (key === 'defaultView')
|
|
5375
|
+
return this.proxyWindow;
|
|
5376
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
5377
|
+
},
|
|
5378
|
+
set: (target, key, value) => {
|
|
5379
|
+
/**
|
|
5380
|
+
* 1. Fix TypeError: Illegal invocation when set document.title
|
|
5381
|
+
* 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
5382
|
+
*/
|
|
5383
|
+
Reflect.set(target, key, value);
|
|
5384
|
+
return true;
|
|
5385
|
+
}
|
|
5386
|
+
});
|
|
5387
|
+
class MicroDocument {
|
|
5388
|
+
static [Symbol.hasInstance](target) {
|
|
5389
|
+
let proto = target;
|
|
5390
|
+
while (proto = Object.getPrototypeOf(proto)) {
|
|
5391
|
+
if (proto === MicroDocument.prototype) {
|
|
5392
|
+
return true;
|
|
5393
|
+
}
|
|
5394
|
+
}
|
|
5395
|
+
return (target === proxyDocument ||
|
|
5396
|
+
target instanceof rawRootDocument);
|
|
5397
|
+
}
|
|
5398
|
+
}
|
|
5399
|
+
/**
|
|
5400
|
+
* TIP:
|
|
5401
|
+
* 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
|
|
5402
|
+
* 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
|
|
5403
|
+
* e.g.
|
|
5404
|
+
* class B extends A {}
|
|
5405
|
+
* B.__proto__ === A // true
|
|
5406
|
+
* B.prototype.__proto__ === A.prototype // true
|
|
5407
|
+
*/
|
|
5408
|
+
Object.setPrototypeOf(MicroDocument, rawRootDocument);
|
|
5409
|
+
// Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
|
|
5410
|
+
Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
|
|
5411
|
+
get(target, key) {
|
|
5412
|
+
throttleDeferForSetAppName(appName);
|
|
5413
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
5414
|
+
},
|
|
5415
|
+
set(target, key, value) {
|
|
5416
|
+
Reflect.set(target, key, value);
|
|
5417
|
+
return true;
|
|
5418
|
+
}
|
|
5419
|
+
}));
|
|
5420
|
+
return {
|
|
5421
|
+
proxyDocument,
|
|
5422
|
+
MicroDocument,
|
|
5423
|
+
};
|
|
5424
|
+
}
|
|
5425
|
+
}
|
|
5426
|
+
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5427
|
+
|
|
5428
|
+
function patchIframeRoute(appName, microAppWindow, childFullPath) {
|
|
5429
|
+
const microHistory = microAppWindow.history;
|
|
5430
|
+
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5431
|
+
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5432
|
+
// exec updateMicroLocation after patch microHistory
|
|
5433
|
+
updateMicroLocation(appName, childFullPath, microAppWindow.location, 'prevent');
|
|
5434
|
+
}
|
|
5435
|
+
|
|
5436
|
+
function patchIframeWindow(appName, microAppWindow) {
|
|
5437
|
+
const rawWindow = globalEnv.rawWindow;
|
|
5438
|
+
escape2RawWindowKeys.forEach((key) => {
|
|
5439
|
+
microAppWindow[key] = bindFunctionToRawTarget(rawWindow[key], rawWindow);
|
|
5440
|
+
});
|
|
5441
|
+
Object.getOwnPropertyNames(microAppWindow)
|
|
5442
|
+
.filter((key) => {
|
|
5443
|
+
escape2RawWindowRegExpKeys.some((reg) => {
|
|
5444
|
+
if (reg.test(key) && key in microAppWindow.parent) {
|
|
5445
|
+
if (isFunction(rawWindow[key])) {
|
|
5446
|
+
microAppWindow[key] = bindFunctionToRawTarget(rawWindow[key], rawWindow);
|
|
5447
|
+
}
|
|
5448
|
+
else {
|
|
5449
|
+
const { configurable, enumerable } = Object.getOwnPropertyDescriptor(microAppWindow, key) || {
|
|
5450
|
+
configurable: true,
|
|
5451
|
+
enumerable: true,
|
|
5452
|
+
};
|
|
5453
|
+
if (configurable) {
|
|
5454
|
+
rawDefineProperty(microAppWindow, key, {
|
|
5455
|
+
configurable,
|
|
5456
|
+
enumerable,
|
|
5457
|
+
get: () => rawWindow[key],
|
|
5458
|
+
set: (value) => { rawWindow[key] = value; },
|
|
5459
|
+
});
|
|
5460
|
+
}
|
|
5461
|
+
}
|
|
5462
|
+
return true;
|
|
5463
|
+
}
|
|
5464
|
+
return false;
|
|
5465
|
+
});
|
|
5466
|
+
return /^on/.test(key) && !scopeIframeWindowOnEvent.includes(key);
|
|
5467
|
+
})
|
|
5468
|
+
.forEach((eventName) => {
|
|
5469
|
+
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microAppWindow, eventName) || {
|
|
5470
|
+
enumerable: true,
|
|
5471
|
+
writable: true,
|
|
5472
|
+
};
|
|
5473
|
+
try {
|
|
5474
|
+
/**
|
|
5475
|
+
* 如果设置了iframeWindow上的这些on事件,处理函数会设置到原生window上,但this会绑定到iframeWindow
|
|
5476
|
+
* 获取这些值,则直接从原生window上取
|
|
5477
|
+
* 总结:这些on事件全部都代理到原生window上
|
|
5478
|
+
*
|
|
5479
|
+
* 问题:
|
|
5480
|
+
* 1、如果子应用没有设置,基座设置了on事件,子应用触发事件是会不会执行基座的函数?
|
|
5481
|
+
* 比如 基座定义了 window.onpopstate,子应用执行跳转会不会触发基座的onpopstate函数?
|
|
5482
|
+
*
|
|
5483
|
+
* 2、如果基座已经定义了 window.onpopstate,子应用定义会不会覆盖基座的?
|
|
5484
|
+
* 现在的逻辑看来,是会覆盖的,那么问题1就是 肯定的
|
|
5485
|
+
* TODO: 一些特殊事件onpopstate、onhashchange不代理,放在scopeIframeWindowOnEvent中
|
|
5486
|
+
*/
|
|
5487
|
+
rawDefineProperty(microAppWindow, eventName, {
|
|
5488
|
+
enumerable,
|
|
5489
|
+
configurable: true,
|
|
5490
|
+
get: () => rawWindow[eventName],
|
|
5491
|
+
set: (writable !== null && writable !== void 0 ? writable : !!set) ? (value) => { rawWindow[eventName] = isFunction(value) ? value.bind(microAppWindow) : value; }
|
|
5492
|
+
: undefined,
|
|
5493
|
+
});
|
|
5494
|
+
}
|
|
5495
|
+
catch (e) {
|
|
5496
|
+
logWarn(e, appName);
|
|
5497
|
+
}
|
|
5498
|
+
});
|
|
5499
|
+
return windowEffect(microAppWindow);
|
|
5500
|
+
}
|
|
5501
|
+
function windowEffect(microAppWindow) {
|
|
5502
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
5503
|
+
const eventListenerMap = new Map();
|
|
5504
|
+
const sstWindowListenerMap = new Map();
|
|
5505
|
+
function getEventTarget(type) {
|
|
5506
|
+
return scopeIframeWindowEvent.includes(type) ? microAppWindow : rawWindow;
|
|
5507
|
+
}
|
|
5508
|
+
microAppWindow.addEventListener = function (type, listener, options) {
|
|
5509
|
+
const listenerList = eventListenerMap.get(type);
|
|
5510
|
+
if (listenerList) {
|
|
5511
|
+
listenerList.add(listener);
|
|
5512
|
+
}
|
|
5513
|
+
else {
|
|
5514
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
5515
|
+
}
|
|
5516
|
+
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
5517
|
+
rawAddEventListener.call(getEventTarget(type), type, listener, options);
|
|
5518
|
+
};
|
|
5519
|
+
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
5520
|
+
const listenerList = eventListenerMap.get(type);
|
|
5521
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
5522
|
+
listenerList.delete(listener);
|
|
5523
|
+
}
|
|
5524
|
+
rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
|
|
5525
|
+
};
|
|
5526
|
+
const reset = () => {
|
|
5527
|
+
sstWindowListenerMap.clear();
|
|
5528
|
+
};
|
|
5529
|
+
/**
|
|
5530
|
+
* NOTE:
|
|
5531
|
+
* 1. about timer(events & properties should record & rebuild at all modes, exclude default mode)
|
|
5532
|
+
* 2. record maybe call twice when unmount prerender, keep-alive app manually with umd mode
|
|
5533
|
+
* 4 modes: default-mode、umd-mode、prerender、keep-alive
|
|
5534
|
+
* Solution:
|
|
5535
|
+
* 1. default-mode(normal): clear events & timers, not record & rebuild anything
|
|
5536
|
+
* 2. umd-mode(normal): not clear timers, record & rebuild events
|
|
5537
|
+
* 3. prerender/keep-alive(default, umd): not clear timers, record & rebuild events
|
|
5538
|
+
*
|
|
5539
|
+
* TODO: 现在的 清除、记录和恢复操作分散的太零散,sandbox、create_app中都有分散,将代码再优化一下,集中处理
|
|
5540
|
+
*/
|
|
5541
|
+
const record = () => {
|
|
5542
|
+
// record window event
|
|
5543
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5544
|
+
if (listenerList.size) {
|
|
5545
|
+
sstWindowListenerMap.set(type, new Set(listenerList));
|
|
5546
|
+
}
|
|
5547
|
+
});
|
|
5548
|
+
};
|
|
5549
|
+
// rebuild event and timer before remount app
|
|
5550
|
+
const rebuild = () => {
|
|
5551
|
+
// rebuild window event
|
|
5552
|
+
sstWindowListenerMap.forEach((listenerList, type) => {
|
|
5553
|
+
for (const listener of listenerList) {
|
|
5554
|
+
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5555
|
+
}
|
|
5556
|
+
});
|
|
5557
|
+
reset();
|
|
5558
|
+
};
|
|
5559
|
+
const release = () => {
|
|
5560
|
+
// Clear window binding events
|
|
5561
|
+
if (eventListenerMap.size) {
|
|
5562
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5563
|
+
for (const listener of listenerList) {
|
|
5564
|
+
rawRemoveEventListener.call(getEventTarget(type), type, listener);
|
|
5565
|
+
}
|
|
5566
|
+
});
|
|
5567
|
+
eventListenerMap.clear();
|
|
5568
|
+
}
|
|
5569
|
+
};
|
|
5570
|
+
return {
|
|
5571
|
+
reset,
|
|
5572
|
+
record,
|
|
5573
|
+
rebuild,
|
|
5574
|
+
release,
|
|
5575
|
+
};
|
|
5576
|
+
}
|
|
5577
|
+
|
|
5578
|
+
/**
|
|
5579
|
+
* TODO:
|
|
5580
|
+
* 1、shadowDOM
|
|
5581
|
+
* 2、重构
|
|
5582
|
+
*/
|
|
5583
|
+
function patchIframeDocument(appName, microAppWindow, proxyLocation) {
|
|
5584
|
+
patchDocumentPrototype(appName, microAppWindow);
|
|
5585
|
+
patchDocumentProperties(appName, microAppWindow, proxyLocation);
|
|
5586
|
+
return documentEffect(appName, microAppWindow);
|
|
5587
|
+
}
|
|
5588
|
+
function patchDocumentPrototype(appName, microAppWindow) {
|
|
5589
|
+
const rawDocument = globalEnv.rawDocument;
|
|
5590
|
+
const microRootDocument = microAppWindow.Document;
|
|
5591
|
+
const microDocument = microAppWindow.document;
|
|
5592
|
+
microRootDocument.prototype.createElement = function createElement(tagName, options) {
|
|
5593
|
+
const element = globalEnv.rawCreateElement.call(this, tagName, options);
|
|
5594
|
+
return updateElementInfo(element, appName);
|
|
5595
|
+
};
|
|
5596
|
+
microRootDocument.prototype.createTextNode = function createTextNode(data) {
|
|
5597
|
+
const element = globalEnv.rawCreateTextNode.call(this, data);
|
|
5598
|
+
return updateElementInfo(element, appName);
|
|
5599
|
+
};
|
|
5600
|
+
function getDefaultRawTarget(target) {
|
|
5601
|
+
return microDocument !== target ? target : rawDocument;
|
|
5602
|
+
}
|
|
5603
|
+
// query element👇
|
|
5604
|
+
function querySelector(selectors) {
|
|
5605
|
+
var _a, _b;
|
|
5606
|
+
if (isUniqueElement(selectors) ||
|
|
5607
|
+
microDocument !== this) {
|
|
5608
|
+
const _this = getDefaultRawTarget(this);
|
|
5609
|
+
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
5610
|
+
}
|
|
5611
|
+
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
5612
|
+
}
|
|
5613
|
+
function querySelectorAll(selectors) {
|
|
5614
|
+
var _a, _b;
|
|
5615
|
+
if (isUniqueElement(selectors) ||
|
|
5616
|
+
microDocument !== this) {
|
|
5617
|
+
const _this = getDefaultRawTarget(this);
|
|
5618
|
+
return globalEnv.rawQuerySelectorAll.call(_this, selectors);
|
|
5619
|
+
}
|
|
5620
|
+
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
5621
|
+
}
|
|
5622
|
+
microRootDocument.prototype.querySelector = querySelector;
|
|
5623
|
+
microRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
5624
|
+
microRootDocument.prototype.getElementById = function getElementById(key) {
|
|
5625
|
+
const _this = getDefaultRawTarget(this);
|
|
5626
|
+
if (isInvalidQuerySelectorKey(key)) {
|
|
5627
|
+
return globalEnv.rawGetElementById.call(_this, key);
|
|
5628
|
+
}
|
|
5629
|
+
try {
|
|
5630
|
+
return querySelector.call(this, `#${key}`);
|
|
5631
|
+
}
|
|
5632
|
+
catch (_a) {
|
|
5633
|
+
return globalEnv.rawGetElementById.call(_this, key);
|
|
5634
|
+
}
|
|
5635
|
+
};
|
|
5636
|
+
microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
5637
|
+
const _this = getDefaultRawTarget(this);
|
|
5638
|
+
if (isInvalidQuerySelectorKey(key)) {
|
|
5639
|
+
return globalEnv.rawGetElementsByClassName.call(_this, key);
|
|
5640
|
+
}
|
|
5641
|
+
try {
|
|
5642
|
+
return querySelectorAll.call(this, `.${key}`);
|
|
5643
|
+
}
|
|
5644
|
+
catch (_a) {
|
|
5645
|
+
return globalEnv.rawGetElementsByClassName.call(_this, key);
|
|
5646
|
+
}
|
|
5647
|
+
};
|
|
5648
|
+
microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
5649
|
+
var _a;
|
|
5650
|
+
const _this = getDefaultRawTarget(this);
|
|
5651
|
+
if (isUniqueElement(key) ||
|
|
5652
|
+
isInvalidQuerySelectorKey(key) ||
|
|
5653
|
+
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
5654
|
+
return globalEnv.rawGetElementsByTagName.call(_this, key);
|
|
5655
|
+
}
|
|
5656
|
+
try {
|
|
5657
|
+
return querySelectorAll.call(this, key);
|
|
5658
|
+
}
|
|
5659
|
+
catch (_b) {
|
|
5660
|
+
return globalEnv.rawGetElementsByTagName.call(_this, key);
|
|
5661
|
+
}
|
|
5662
|
+
};
|
|
5663
|
+
microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
|
|
5664
|
+
const _this = getDefaultRawTarget(this);
|
|
5665
|
+
if (isInvalidQuerySelectorKey(key)) {
|
|
5666
|
+
return globalEnv.rawGetElementsByName.call(_this, key);
|
|
5667
|
+
}
|
|
5668
|
+
try {
|
|
5669
|
+
return querySelectorAll.call(this, `[name=${key}]`);
|
|
5670
|
+
}
|
|
5671
|
+
catch (_a) {
|
|
5672
|
+
return globalEnv.rawGetElementsByName.call(_this, key);
|
|
5673
|
+
}
|
|
5674
|
+
};
|
|
5675
|
+
}
|
|
5676
|
+
function patchDocumentProperties(appName, microAppWindow, proxyLocation) {
|
|
5677
|
+
const rawDocument = globalEnv.rawDocument;
|
|
5678
|
+
const microRootDocument = microAppWindow.Document;
|
|
5679
|
+
const microDocument = microAppWindow.document;
|
|
5680
|
+
const getCommonDescriptor = (key, getter) => {
|
|
5681
|
+
const { enumerable } = Object.getOwnPropertyDescriptor(microRootDocument.prototype, key) || {
|
|
5682
|
+
enumerable: true,
|
|
5683
|
+
writable: true,
|
|
5684
|
+
};
|
|
5685
|
+
return {
|
|
5686
|
+
configurable: true,
|
|
5687
|
+
enumerable,
|
|
5688
|
+
get: getter,
|
|
5689
|
+
};
|
|
5690
|
+
};
|
|
5691
|
+
const createDescriptors = () => {
|
|
5692
|
+
const result = {};
|
|
5693
|
+
const descList = [
|
|
5694
|
+
['documentURI', () => proxyLocation.href],
|
|
5695
|
+
['URL', () => proxyLocation.href],
|
|
5696
|
+
['documentElement', () => rawDocument.documentElement],
|
|
5697
|
+
['scrollingElement', () => rawDocument.scrollingElement],
|
|
5698
|
+
['forms', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'form')],
|
|
5699
|
+
['images', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'img')],
|
|
5700
|
+
['links', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'a')],
|
|
5701
|
+
];
|
|
5702
|
+
descList.forEach((desc) => {
|
|
5703
|
+
result[desc[0]] = getCommonDescriptor(desc[0], desc[1]);
|
|
5704
|
+
});
|
|
5705
|
+
// TODO: shadowDOM
|
|
5706
|
+
proxy2RawDocOrShadowKeys.forEach((key) => {
|
|
5707
|
+
result[key] = getCommonDescriptor(key, () => rawDocument[key]);
|
|
5708
|
+
});
|
|
5709
|
+
// TODO: shadowDOM
|
|
5710
|
+
proxy2RawDocOrShadowMethods.forEach((key) => {
|
|
5711
|
+
result[key] = getCommonDescriptor(key, () => bindFunctionToRawTarget(rawDocument[key], rawDocument, 'DOCUMENT'));
|
|
5712
|
+
});
|
|
5713
|
+
proxy2RawDocumentKeys.forEach((key) => {
|
|
5714
|
+
result[key] = getCommonDescriptor(key, () => rawDocument[key]);
|
|
5715
|
+
});
|
|
5716
|
+
proxy2RawDocumentMethods.forEach((key) => {
|
|
5717
|
+
result[key] = getCommonDescriptor(key, () => bindFunctionToRawTarget(rawDocument[key], rawDocument, 'DOCUMENT'));
|
|
5718
|
+
});
|
|
5719
|
+
return result;
|
|
5720
|
+
};
|
|
5721
|
+
rawDefineProperties(microRootDocument.prototype, createDescriptors());
|
|
5722
|
+
// head, body, html, title
|
|
5723
|
+
uniqueDocumentElement.forEach((tagName) => {
|
|
5724
|
+
rawDefineProperty(microDocument, tagName, {
|
|
5725
|
+
enumerable: true,
|
|
5726
|
+
configurable: true,
|
|
5727
|
+
get: () => rawDocument[tagName],
|
|
5728
|
+
set: undefined,
|
|
5729
|
+
});
|
|
5730
|
+
});
|
|
5731
|
+
}
|
|
5732
|
+
function documentEffect(appName, microAppWindow) {
|
|
5733
|
+
const documentEventListenerMap = new Map();
|
|
5734
|
+
const sstDocumentListenerMap = new Map();
|
|
5735
|
+
let onClickHandler = null;
|
|
5736
|
+
let sstOnClickHandler = null;
|
|
5737
|
+
const microRootDocument = microAppWindow.Document;
|
|
5738
|
+
const microDocument = microAppWindow.document;
|
|
5739
|
+
const { rawDocument, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
5740
|
+
function getEventTarget(type, bindTarget) {
|
|
5741
|
+
return scopeIframeDocumentEvent.includes(type) ? bindTarget : rawDocument;
|
|
5742
|
+
}
|
|
5743
|
+
microRootDocument.prototype.addEventListener = function (type, listener, options) {
|
|
5744
|
+
const handler = isFunction(listener) ? (listener.__MICRO_APP_BOUND_FUNCTION__ = listener.__MICRO_APP_BOUND_FUNCTION__ || listener.bind(this)) : listener;
|
|
5745
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
5746
|
+
if (appListenersMap) {
|
|
5747
|
+
const appListenerList = appListenersMap.get(type);
|
|
5748
|
+
if (appListenerList) {
|
|
5749
|
+
appListenerList.add(listener);
|
|
5750
|
+
}
|
|
5751
|
+
else {
|
|
5752
|
+
appListenersMap.set(type, new Set([listener]));
|
|
5753
|
+
}
|
|
5754
|
+
}
|
|
5755
|
+
else {
|
|
5756
|
+
documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
|
|
5757
|
+
}
|
|
5758
|
+
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
5759
|
+
rawAddEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5760
|
+
};
|
|
5761
|
+
microRootDocument.prototype.removeEventListener = function (type, listener, options) {
|
|
5762
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
5763
|
+
if (appListenersMap) {
|
|
5764
|
+
const appListenerList = appListenersMap.get(type);
|
|
5765
|
+
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
5766
|
+
appListenerList.delete(listener);
|
|
5767
|
+
}
|
|
5768
|
+
}
|
|
5769
|
+
const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
|
|
5770
|
+
rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5771
|
+
};
|
|
5772
|
+
// 重新定义microRootDocument.prototype 上的on开头方法
|
|
5773
|
+
function createSetterHandler(eventName) {
|
|
5774
|
+
if (eventName === 'onclick') {
|
|
5775
|
+
return (value) => {
|
|
5776
|
+
if (isFunction(onClickHandler)) {
|
|
5777
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
|
|
5778
|
+
}
|
|
5779
|
+
if (isFunction(value)) {
|
|
5780
|
+
onClickHandler = value.bind(microDocument);
|
|
5781
|
+
rawAddEventListener.call(rawDocument, 'click', onClickHandler, false);
|
|
5782
|
+
}
|
|
5783
|
+
else {
|
|
5784
|
+
onClickHandler = value;
|
|
5785
|
+
}
|
|
5786
|
+
};
|
|
5787
|
+
}
|
|
5788
|
+
return (value) => { rawDocument[eventName] = isFunction(value) ? value.bind(microDocument) : value; };
|
|
5789
|
+
}
|
|
5790
|
+
/**
|
|
5791
|
+
* TODO:
|
|
5792
|
+
* 1、直接代理到原生document是否正确
|
|
5793
|
+
* 2、shadowDOM
|
|
5794
|
+
*/
|
|
5795
|
+
Object.getOwnPropertyNames(microRootDocument.prototype)
|
|
5796
|
+
.filter((key) => /^on/.test(key) && !scopeIframeDocumentOnEvent.includes(key))
|
|
5797
|
+
.forEach((eventName) => {
|
|
5798
|
+
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microRootDocument.prototype, eventName) || {
|
|
5799
|
+
enumerable: true,
|
|
5800
|
+
writable: true,
|
|
5801
|
+
};
|
|
5802
|
+
try {
|
|
5803
|
+
rawDefineProperty(microRootDocument.prototype, eventName, {
|
|
5804
|
+
enumerable,
|
|
5805
|
+
configurable: true,
|
|
5806
|
+
get: () => {
|
|
5807
|
+
if (eventName === 'onclick')
|
|
5808
|
+
return onClickHandler;
|
|
5809
|
+
return rawDocument[eventName];
|
|
5810
|
+
},
|
|
5811
|
+
set: (writable !== null && writable !== void 0 ? writable : !!set) ? createSetterHandler(eventName) : undefined,
|
|
5812
|
+
});
|
|
5813
|
+
}
|
|
5814
|
+
catch (e) {
|
|
5815
|
+
logWarn(e, appName);
|
|
5816
|
+
}
|
|
5817
|
+
});
|
|
5818
|
+
const reset = () => {
|
|
5819
|
+
sstDocumentListenerMap.clear();
|
|
5820
|
+
sstOnClickHandler = null;
|
|
5821
|
+
};
|
|
5822
|
+
/**
|
|
5823
|
+
* record event
|
|
5824
|
+
* NOTE:
|
|
5825
|
+
* 1.record maybe call twice when unmount prerender, keep-alive app manually with umd mode
|
|
5826
|
+
* Scenes:
|
|
5827
|
+
* 1. exec umdMountHook in umd mode
|
|
5828
|
+
* 2. hidden keep-alive app
|
|
5829
|
+
* 3. after init prerender app
|
|
5830
|
+
*/
|
|
5831
|
+
const record = () => {
|
|
5832
|
+
// record onclick handler
|
|
5833
|
+
sstOnClickHandler = sstOnClickHandler || onClickHandler;
|
|
5834
|
+
// record document event
|
|
5835
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
5836
|
+
if (documentAppListenersMap) {
|
|
5837
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
5838
|
+
if (listenerList.size) {
|
|
5839
|
+
sstDocumentListenerMap.set(type, new Set(listenerList));
|
|
5840
|
+
}
|
|
5841
|
+
});
|
|
5842
|
+
}
|
|
5843
|
+
};
|
|
5844
|
+
// rebuild event and timer before remount app
|
|
5845
|
+
const rebuild = () => {
|
|
5846
|
+
// rebuild onclick event
|
|
5847
|
+
if (sstOnClickHandler)
|
|
5848
|
+
microDocument.onclick = sstOnClickHandler;
|
|
5849
|
+
sstDocumentListenerMap.forEach((listenerList, type) => {
|
|
5850
|
+
for (const listener of listenerList) {
|
|
5851
|
+
microDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5852
|
+
}
|
|
5853
|
+
});
|
|
5854
|
+
reset();
|
|
5855
|
+
};
|
|
5856
|
+
const release = () => {
|
|
5857
|
+
// Clear the function bound by micro application through document.onclick
|
|
5858
|
+
if (isFunction(onClickHandler)) {
|
|
5859
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
|
|
5860
|
+
onClickHandler = null;
|
|
5861
|
+
}
|
|
5862
|
+
// Clear document binding event
|
|
5863
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
5864
|
+
if (documentAppListenersMap) {
|
|
5865
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
5866
|
+
for (const listener of listenerList) {
|
|
5867
|
+
rawRemoveEventListener.call(getEventTarget(type, microDocument), type, (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener);
|
|
5868
|
+
}
|
|
5869
|
+
});
|
|
5870
|
+
documentAppListenersMap.clear();
|
|
5871
|
+
}
|
|
5872
|
+
};
|
|
5873
|
+
return {
|
|
5874
|
+
reset,
|
|
5875
|
+
record,
|
|
5876
|
+
rebuild,
|
|
5877
|
+
release,
|
|
5878
|
+
};
|
|
5879
|
+
}
|
|
5880
|
+
|
|
5881
|
+
function patchIframeElement(appName, url, microAppWindow, iframeSandbox) {
|
|
5882
|
+
patchIframeNode(appName, microAppWindow, iframeSandbox);
|
|
5883
|
+
patchIframeAttribute(appName, url, microAppWindow);
|
|
5884
|
+
}
|
|
5885
|
+
function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
5886
|
+
const microDocument = microAppWindow.document;
|
|
5887
|
+
const rawDocument = globalEnv.rawDocument;
|
|
5888
|
+
const microRootNode = microAppWindow.Node;
|
|
5889
|
+
const microRootElement = microAppWindow.Element;
|
|
5890
|
+
// const rawMicroGetRootNode = microRootNode.prototype.getRootNode
|
|
5891
|
+
const rawMicroAppendChild = microRootNode.prototype.appendChild;
|
|
5892
|
+
const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
|
|
5893
|
+
const rawMicroReplaceChild = microRootNode.prototype.replaceChild;
|
|
5894
|
+
const rawMicroCloneNode = microRootNode.prototype.cloneNode;
|
|
5895
|
+
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
|
|
5896
|
+
const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
|
|
5897
|
+
const isPureNode = (target) => {
|
|
5898
|
+
return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
|
|
5899
|
+
};
|
|
5900
|
+
const getRawTarget = (target) => {
|
|
5901
|
+
if (target === iframeSandbox.microHead) {
|
|
5902
|
+
return rawDocument.head;
|
|
5903
|
+
}
|
|
5904
|
+
else if (target === iframeSandbox.microBody) {
|
|
5905
|
+
return rawDocument.body;
|
|
5906
|
+
}
|
|
5907
|
+
return target;
|
|
5908
|
+
};
|
|
5909
|
+
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
5910
|
+
return microDocument;
|
|
5911
|
+
// TODO: 什么情况下返回原生document?
|
|
5912
|
+
// const rootNode = rawMicroGetRootNode.call(this, options)
|
|
5913
|
+
// if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
|
|
5914
|
+
// return rootNode
|
|
5915
|
+
};
|
|
5916
|
+
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5917
|
+
updateElementInfo(node, appName);
|
|
5918
|
+
// TODO:只有script才可以这样拦截,link、style不应该拦截
|
|
5919
|
+
if (isPureNode(node)) {
|
|
5920
|
+
return rawMicroAppendChild.call(this, node);
|
|
5921
|
+
}
|
|
5922
|
+
const _this = getRawTarget(this);
|
|
5923
|
+
if (_this !== this) {
|
|
5924
|
+
return _this.appendChild(node);
|
|
5925
|
+
}
|
|
5926
|
+
return rawMicroAppendChild.call(_this, node);
|
|
5927
|
+
};
|
|
5928
|
+
// TODO: 更多场景适配
|
|
5929
|
+
microRootNode.prototype.insertBefore = function insertBefore(node, child) {
|
|
5930
|
+
updateElementInfo(node, appName);
|
|
5931
|
+
if (isPureNode(node)) {
|
|
5932
|
+
return rawMicroInsertBefore.call(this, node, child);
|
|
5933
|
+
}
|
|
5934
|
+
const _this = getRawTarget(this);
|
|
5935
|
+
if (_this !== this) {
|
|
5936
|
+
if (child && !_this.contains(child)) {
|
|
5937
|
+
return _this.appendChild(node);
|
|
5938
|
+
}
|
|
5939
|
+
return _this.insertBefore(node, child);
|
|
5940
|
+
}
|
|
5941
|
+
return rawMicroInsertBefore.call(_this, node, child);
|
|
5942
|
+
};
|
|
5943
|
+
// TODO: 更多场景适配
|
|
5944
|
+
microRootNode.prototype.replaceChild = function replaceChild(node, child) {
|
|
5945
|
+
updateElementInfo(node, appName);
|
|
5946
|
+
if (isPureNode(node)) {
|
|
5947
|
+
return rawMicroReplaceChild.call(this, node, child);
|
|
5948
|
+
}
|
|
5949
|
+
const _this = getRawTarget(this);
|
|
5950
|
+
if (_this !== this) {
|
|
5951
|
+
if (child && !_this.contains(child)) {
|
|
5952
|
+
_this.appendChild(node);
|
|
5953
|
+
return child;
|
|
5954
|
+
}
|
|
5955
|
+
return _this.replaceChild(node, child);
|
|
5956
|
+
}
|
|
5957
|
+
return rawMicroReplaceChild.call(_this, node, child);
|
|
5958
|
+
};
|
|
5959
|
+
// patch cloneNode
|
|
5960
|
+
microRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
5961
|
+
const clonedNode = rawMicroCloneNode.call(this, deep);
|
|
5962
|
+
return updateElementInfo(clonedNode, appName);
|
|
5963
|
+
};
|
|
5964
|
+
rawDefineProperty(microRootElement.prototype, 'innerHTML', {
|
|
5965
|
+
configurable: true,
|
|
5966
|
+
enumerable: true,
|
|
5967
|
+
get() {
|
|
5968
|
+
return rawInnerHTMLDesc.get.call(this);
|
|
5969
|
+
},
|
|
5970
|
+
set(code) {
|
|
5971
|
+
rawInnerHTMLDesc.set.call(this, code);
|
|
5972
|
+
Array.from(this.children).forEach((child) => {
|
|
5973
|
+
if (isElement(child)) {
|
|
5974
|
+
updateElementInfo(child, appName);
|
|
5975
|
+
}
|
|
5976
|
+
});
|
|
5977
|
+
}
|
|
5978
|
+
});
|
|
5979
|
+
// patch parentNode
|
|
5980
|
+
rawDefineProperty(microRootNode.prototype, 'parentNode', {
|
|
5981
|
+
configurable: true,
|
|
5982
|
+
enumerable: true,
|
|
5983
|
+
get() {
|
|
5984
|
+
var _a, _b, _c;
|
|
5985
|
+
// set html.parentNode to microDocument
|
|
5986
|
+
throttleDeferForParentNode(microDocument);
|
|
5987
|
+
const result = rawParentNodeLDesc.get.call(this);
|
|
5988
|
+
/**
|
|
5989
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
5990
|
+
* Scenes:
|
|
5991
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
5992
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
5993
|
+
* WARNING:
|
|
5994
|
+
* Will it cause other problems ?
|
|
5995
|
+
* e.g. target.parentNode.remove(target)
|
|
5996
|
+
*/
|
|
5997
|
+
if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
5998
|
+
return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || rawDocument.body;
|
|
5999
|
+
}
|
|
6000
|
+
return result;
|
|
6001
|
+
},
|
|
6002
|
+
set: undefined,
|
|
6003
|
+
});
|
|
6004
|
+
// Adapt to new image(...) scene
|
|
6005
|
+
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
6006
|
+
construct(Target, args) {
|
|
6007
|
+
const elementImage = new Target(...args);
|
|
6008
|
+
updateElementInfo(elementImage, appName);
|
|
6009
|
+
return elementImage;
|
|
6010
|
+
},
|
|
6011
|
+
});
|
|
6012
|
+
rawDefineProperty(microAppWindow, 'Image', {
|
|
6013
|
+
configurable: true,
|
|
6014
|
+
writable: true,
|
|
6015
|
+
value: ImageProxy,
|
|
6016
|
+
});
|
|
6017
|
+
/**
|
|
6018
|
+
* TODO:
|
|
6019
|
+
* 1、append prepend
|
|
6020
|
+
* 2、cloneNode -- 完成
|
|
6021
|
+
* 3、innerHTML
|
|
6022
|
+
* 4、querySelector、querySelectorAll (head, body)
|
|
6023
|
+
* 5、Image -- 完成
|
|
6024
|
+
* 都是Element原型链上的方法
|
|
6025
|
+
*/
|
|
6026
|
+
}
|
|
6027
|
+
function patchIframeAttribute(appName, url, microAppWindow) {
|
|
6028
|
+
const microRootElement = microAppWindow.Element;
|
|
6029
|
+
const rawMicroSetAttribute = microRootElement.prototype.setAttribute;
|
|
6030
|
+
microRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
6031
|
+
if (((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
|
|
6032
|
+
(key === 'href' && /^link$/i.test(this.tagName))) {
|
|
6033
|
+
value = CompletionPath(value, url);
|
|
6034
|
+
}
|
|
6035
|
+
rawMicroSetAttribute.call(this, key, value);
|
|
6036
|
+
};
|
|
6037
|
+
const protoAttrList = [
|
|
6038
|
+
[microAppWindow.HTMLImageElement.prototype, 'src'],
|
|
6039
|
+
[microAppWindow.HTMLScriptElement.prototype, 'src'],
|
|
6040
|
+
[microAppWindow.HTMLLinkElement.prototype, 'href'],
|
|
6041
|
+
];
|
|
6042
|
+
protoAttrList.forEach(([target, attr]) => {
|
|
6043
|
+
const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
|
|
6044
|
+
enumerable: true,
|
|
6045
|
+
configurable: true,
|
|
6046
|
+
};
|
|
6047
|
+
rawDefineProperty(target, attr, {
|
|
6048
|
+
enumerable,
|
|
6049
|
+
configurable,
|
|
6050
|
+
get: function () {
|
|
6051
|
+
return get === null || get === void 0 ? void 0 : get.call(this);
|
|
6052
|
+
},
|
|
6053
|
+
set: function (value) {
|
|
6054
|
+
set === null || set === void 0 ? void 0 : set.call(this, CompletionPath(value, url));
|
|
6055
|
+
},
|
|
6056
|
+
});
|
|
6057
|
+
});
|
|
6058
|
+
}
|
|
6059
|
+
|
|
6060
|
+
class IframeSandbox {
|
|
6061
|
+
constructor(appName, url) {
|
|
6062
|
+
this.active = false;
|
|
6063
|
+
// Properties that can be escape to rawWindow
|
|
6064
|
+
this.escapeProperties = [];
|
|
6065
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
6066
|
+
this.escapeKeys = new Set();
|
|
6067
|
+
// TODO: 初始化和每次跳转时都要更新base的href
|
|
6068
|
+
this.updateIframeBase = () => {
|
|
6069
|
+
var _a;
|
|
6070
|
+
(_a = this.baseElement) === null || _a === void 0 ? void 0 : _a.setAttribute('href', this.proxyLocation.protocol + '//' + this.proxyLocation.host + this.proxyLocation.pathname);
|
|
6071
|
+
};
|
|
6072
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
6073
|
+
const browserHost = rawLocation.protocol + '//' + rawLocation.host;
|
|
6074
|
+
const childStaticLocation = new URL(url);
|
|
6075
|
+
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
6076
|
+
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
6077
|
+
this.deleteIframeElement = this.createIframeElement(appName, browserHost);
|
|
6078
|
+
this.microAppWindow = this.iframe.contentWindow;
|
|
6079
|
+
this.patchIframe(this.microAppWindow, (resolve) => {
|
|
6080
|
+
// TODO: 优化代码
|
|
6081
|
+
// exec before initStaticGlobalKeys
|
|
6082
|
+
this.createProxyLocation(appName, url, this.microAppWindow, childStaticLocation, browserHost, childHost);
|
|
6083
|
+
this.createProxyWindow(this.microAppWindow);
|
|
6084
|
+
this.initStaticGlobalKeys(appName, url);
|
|
6085
|
+
// get escapeProperties from plugins
|
|
6086
|
+
this.getSpecialProperties(appName);
|
|
6087
|
+
this.createIframeTemplate(this.microAppWindow);
|
|
6088
|
+
patchIframeRoute(appName, this.microAppWindow, childFullPath);
|
|
6089
|
+
this.windowEffect = patchIframeWindow(appName, this.microAppWindow);
|
|
6090
|
+
this.documentEffect = patchIframeDocument(appName, this.microAppWindow, this.proxyLocation);
|
|
6091
|
+
patchIframeElement(appName, url, this.microAppWindow, this);
|
|
6092
|
+
resolve();
|
|
6093
|
+
});
|
|
6094
|
+
}
|
|
6095
|
+
/**
|
|
6096
|
+
* create iframe for sandbox
|
|
6097
|
+
* @param appName app name
|
|
6098
|
+
* @param browserHost browser origin
|
|
6099
|
+
* @returns release callback
|
|
6100
|
+
*/
|
|
6101
|
+
createIframeElement(appName, browserHost) {
|
|
6102
|
+
this.iframe = pureCreateElement('iframe');
|
|
6103
|
+
const iframeAttrs = {
|
|
6104
|
+
src: browserHost,
|
|
6105
|
+
style: 'display: none',
|
|
6106
|
+
id: appName,
|
|
6107
|
+
};
|
|
6108
|
+
Object.keys(iframeAttrs).forEach((key) => this.iframe.setAttribute(key, iframeAttrs[key]));
|
|
6109
|
+
// effect action during construct
|
|
6110
|
+
globalEnv.rawDocument.body.appendChild(this.iframe);
|
|
6111
|
+
/**
|
|
6112
|
+
* If dom operated async when unmount, premature deletion of iframe will cause unexpected problems
|
|
6113
|
+
* e.g.
|
|
6114
|
+
* 1. antd: notification.destroy()
|
|
6115
|
+
* WARNING:
|
|
6116
|
+
* If async operation time is too long, defer cannot avoid the problem
|
|
6117
|
+
* TODO: more test
|
|
6118
|
+
*/
|
|
6119
|
+
return () => defer(() => {
|
|
6120
|
+
var _a, _b;
|
|
6121
|
+
// default mode or destroy, iframe will be deleted when unmount
|
|
6122
|
+
(_b = (_a = this.iframe) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.iframe);
|
|
6123
|
+
this.iframe = null;
|
|
6124
|
+
});
|
|
6125
|
+
}
|
|
6126
|
+
start({ baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
6127
|
+
if (!this.active) {
|
|
6128
|
+
this.active = true;
|
|
6129
|
+
// TODO: 虚拟路由升级
|
|
6130
|
+
if (useMemoryRouter) {
|
|
6131
|
+
this.initRouteState(defaultPage);
|
|
6132
|
+
// unique listener of popstate event for sub app
|
|
6133
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
6134
|
+
}
|
|
6135
|
+
else {
|
|
6136
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
6137
|
+
}
|
|
6138
|
+
/**
|
|
6139
|
+
* create base element to iframe
|
|
6140
|
+
* WARNING: This will also affect a, image, link and script
|
|
6141
|
+
*/
|
|
6142
|
+
if (!disablePatchRequest) {
|
|
6143
|
+
this.createIframeBase();
|
|
6144
|
+
}
|
|
6145
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
6146
|
+
patchElementAndDocument();
|
|
6147
|
+
patchHistory();
|
|
6148
|
+
}
|
|
6149
|
+
if (++IframeSandbox.activeCount === 1) ;
|
|
6150
|
+
}
|
|
6151
|
+
}
|
|
6152
|
+
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
6153
|
+
if (this.active) {
|
|
6154
|
+
this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
|
|
6155
|
+
if (this.removeHistoryListener) {
|
|
6156
|
+
this.clearRouteState(keepRouteState);
|
|
6157
|
+
// release listener of popstate
|
|
6158
|
+
this.removeHistoryListener();
|
|
6159
|
+
}
|
|
6160
|
+
if (!umdMode || destroy) {
|
|
6161
|
+
this.deleteIframeElement();
|
|
6162
|
+
this.escapeKeys.forEach((key) => {
|
|
6163
|
+
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
6164
|
+
});
|
|
6165
|
+
this.escapeKeys.clear();
|
|
6166
|
+
}
|
|
6167
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
6168
|
+
releasePatchElementAndDocument();
|
|
6169
|
+
releasePatchHistory();
|
|
6170
|
+
}
|
|
6171
|
+
if (--IframeSandbox.activeCount === 0) ;
|
|
6172
|
+
this.active = false;
|
|
6173
|
+
}
|
|
6174
|
+
}
|
|
6175
|
+
/**
|
|
6176
|
+
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
6177
|
+
* Scenes:
|
|
6178
|
+
* 1. unmount of default/umd app
|
|
6179
|
+
* 2. hidden keep-alive app
|
|
6180
|
+
* 3. after init prerender app
|
|
6181
|
+
* @param options {
|
|
6182
|
+
* @param clearData clear data from base app
|
|
6183
|
+
* @param isPrerender is prerender app
|
|
6184
|
+
* @param keepAlive is keep-alive app
|
|
6185
|
+
* }
|
|
6186
|
+
* @param preventRecord prevent record effect events (default or destroy)
|
|
6187
|
+
*/
|
|
6188
|
+
recordAndReleaseEffect(options, preventRecord = false) {
|
|
6189
|
+
if (preventRecord) {
|
|
6190
|
+
this.resetEffectSnapshot();
|
|
6191
|
+
}
|
|
6192
|
+
else {
|
|
6193
|
+
this.recordEffectSnapshot();
|
|
6194
|
+
}
|
|
6195
|
+
this.releaseGlobalEffect(options);
|
|
6196
|
+
}
|
|
6197
|
+
/**
|
|
6198
|
+
* reset effect snapshot data in default mode or destroy
|
|
6199
|
+
* Scenes:
|
|
6200
|
+
* 1. unmount hidden keep-alive app manually
|
|
6201
|
+
* 2. unmount prerender app manually
|
|
6202
|
+
*/
|
|
6203
|
+
resetEffectSnapshot() {
|
|
6204
|
+
this.windowEffect.reset();
|
|
6205
|
+
this.documentEffect.reset();
|
|
6206
|
+
resetDataCenterSnapshot(this.microAppWindow.microApp);
|
|
6207
|
+
}
|
|
6208
|
+
/**
|
|
6209
|
+
* record umd snapshot before the first execution of umdHookMount
|
|
6210
|
+
* Scenes:
|
|
6211
|
+
* 1. exec umdMountHook in umd mode
|
|
6212
|
+
* 2. hidden keep-alive app
|
|
6213
|
+
* 3. after init prerender app
|
|
6214
|
+
*/
|
|
6215
|
+
recordEffectSnapshot() {
|
|
6216
|
+
this.windowEffect.record();
|
|
6217
|
+
this.documentEffect.record();
|
|
6218
|
+
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
6219
|
+
}
|
|
6220
|
+
// rebuild umd snapshot before remount umd app
|
|
6221
|
+
rebuildEffectSnapshot() {
|
|
6222
|
+
this.windowEffect.rebuild();
|
|
6223
|
+
this.documentEffect.rebuild();
|
|
6224
|
+
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
6225
|
+
}
|
|
6226
|
+
/**
|
|
6227
|
+
* clear global event, timeout, data listener
|
|
6228
|
+
* Scenes:
|
|
6229
|
+
* 1. unmount of normal/umd app
|
|
6230
|
+
* 2. hidden keep-alive app
|
|
6231
|
+
* 3. after init prerender app
|
|
6232
|
+
* @param clearData clear data from base app
|
|
6233
|
+
* @param isPrerender is prerender app
|
|
6234
|
+
* @param keepAlive is keep-alive app
|
|
6235
|
+
*/
|
|
6236
|
+
releaseGlobalEffect({ clearData = false }) {
|
|
6237
|
+
var _a, _b, _c;
|
|
6238
|
+
this.windowEffect.release();
|
|
6239
|
+
this.documentEffect.release();
|
|
6240
|
+
(_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
|
|
6241
|
+
(_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
|
|
6242
|
+
if (clearData) {
|
|
6243
|
+
microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
|
|
6244
|
+
(_c = this.microAppWindow.microApp) === null || _c === void 0 ? void 0 : _c.clearData();
|
|
6245
|
+
}
|
|
6246
|
+
}
|
|
6247
|
+
// set __MICRO_APP_PRE_RENDER__ state
|
|
6248
|
+
setPreRenderState(state) {
|
|
6249
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
6250
|
+
}
|
|
6251
|
+
markUmdMode(state) {
|
|
6252
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
6253
|
+
}
|
|
6254
|
+
initStaticGlobalKeys(appName, url) {
|
|
6255
|
+
this.microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
6256
|
+
this.microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
6257
|
+
this.microAppWindow.__MICRO_APP_URL__ = url;
|
|
6258
|
+
this.microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
6259
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
6260
|
+
this.microAppWindow.__MICRO_APP_WINDOW__ = this.microAppWindow;
|
|
6261
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
6262
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
6263
|
+
this.microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
6264
|
+
this.microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
6265
|
+
this.microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
6266
|
+
this.microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
6267
|
+
this.microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
6268
|
+
removeDomScope,
|
|
6269
|
+
pureCreateElement,
|
|
6270
|
+
location: this.proxyLocation,
|
|
6271
|
+
router,
|
|
6272
|
+
});
|
|
6273
|
+
}
|
|
6274
|
+
// TODO: RESTRUCTURE
|
|
6275
|
+
patchIframe(microAppWindow, cb) {
|
|
6276
|
+
const oldMicroDocument = microAppWindow.document;
|
|
6277
|
+
this.sandboxReady = new Promise((resolve) => {
|
|
6278
|
+
(function iframeLocationReady() {
|
|
6279
|
+
setTimeout(() => {
|
|
6280
|
+
try {
|
|
6281
|
+
if (microAppWindow.document === oldMicroDocument) {
|
|
6282
|
+
iframeLocationReady();
|
|
6283
|
+
}
|
|
6284
|
+
else {
|
|
6285
|
+
/**
|
|
6286
|
+
* NOTE:
|
|
6287
|
+
* 1. microAppWindow will not be recreated
|
|
6288
|
+
* 2. the properties of microAppWindow may be recreated, such as document
|
|
6289
|
+
* 3. the variables added to microAppWindow may be cleared
|
|
6290
|
+
*/
|
|
6291
|
+
microAppWindow.stop();
|
|
6292
|
+
cb(resolve);
|
|
6293
|
+
}
|
|
6294
|
+
}
|
|
6295
|
+
catch (e) {
|
|
6296
|
+
iframeLocationReady();
|
|
6297
|
+
}
|
|
6298
|
+
}, 0);
|
|
6299
|
+
})();
|
|
6300
|
+
});
|
|
6301
|
+
}
|
|
6302
|
+
// TODO: RESTRUCTURE
|
|
6303
|
+
createIframeTemplate(microAppWindow) {
|
|
6304
|
+
const microDocument = microAppWindow.document;
|
|
6305
|
+
clearDOM(microDocument);
|
|
6306
|
+
const html = microDocument.createElement('html');
|
|
6307
|
+
html.innerHTML = '<head></head><body></body>';
|
|
6308
|
+
microDocument.appendChild(html);
|
|
6309
|
+
// 记录iframe原生body
|
|
6310
|
+
this.microBody = microDocument.body;
|
|
6311
|
+
this.microHead = microDocument.head;
|
|
6312
|
+
}
|
|
6313
|
+
/**
|
|
6314
|
+
* baseElement will complete the relative address of element according to the URL
|
|
6315
|
+
* e.g: a image link script fetch ajax EventSource
|
|
6316
|
+
*/
|
|
6317
|
+
createIframeBase() {
|
|
6318
|
+
this.baseElement = pureCreateElement('base');
|
|
6319
|
+
this.updateIframeBase();
|
|
6320
|
+
this.microHead.appendChild(this.baseElement);
|
|
6321
|
+
}
|
|
6322
|
+
createProxyLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
|
|
6323
|
+
this.proxyLocation = createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
6324
|
+
}
|
|
6325
|
+
createProxyWindow(microAppWindow) {
|
|
6326
|
+
const rawWindow = globalEnv.rawWindow;
|
|
6327
|
+
this.proxyWindow = new Proxy(microAppWindow, {
|
|
6328
|
+
get: (target, key) => {
|
|
6329
|
+
if (key === 'location') {
|
|
6330
|
+
return this.proxyLocation;
|
|
6331
|
+
}
|
|
6332
|
+
if (globalPropertyList.includes(key.toString())) {
|
|
4924
6333
|
return this.proxyWindow;
|
|
4925
|
-
|
|
4926
|
-
return
|
|
6334
|
+
}
|
|
6335
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), target);
|
|
4927
6336
|
},
|
|
4928
6337
|
set: (target, key, value) => {
|
|
4929
|
-
|
|
4930
|
-
|
|
4931
|
-
|
|
4932
|
-
|
|
4933
|
-
|
|
6338
|
+
if (this.active) {
|
|
6339
|
+
/**
|
|
6340
|
+
* TODO:
|
|
6341
|
+
* 1、location域名相同,子应用内部跳转时的处理
|
|
6342
|
+
* 2、和with沙箱的变量相同,提取成公共数组
|
|
6343
|
+
*/
|
|
6344
|
+
if (key === 'location') {
|
|
6345
|
+
return Reflect.set(rawWindow, key, value);
|
|
6346
|
+
}
|
|
6347
|
+
Reflect.set(target, key, value);
|
|
6348
|
+
if (this.escapeProperties.includes(key)) {
|
|
6349
|
+
!Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
|
|
6350
|
+
Reflect.set(rawWindow, key, value);
|
|
6351
|
+
}
|
|
6352
|
+
}
|
|
4934
6353
|
return true;
|
|
4935
|
-
}
|
|
6354
|
+
},
|
|
6355
|
+
has: (target, key) => key in target,
|
|
6356
|
+
deleteProperty: (target, key) => {
|
|
6357
|
+
if (Reflect.has(target, key)) {
|
|
6358
|
+
this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
6359
|
+
return Reflect.deleteProperty(target, key);
|
|
6360
|
+
}
|
|
6361
|
+
return true;
|
|
6362
|
+
},
|
|
4936
6363
|
});
|
|
4937
|
-
|
|
4938
|
-
|
|
4939
|
-
|
|
4940
|
-
|
|
4941
|
-
|
|
4942
|
-
|
|
6364
|
+
}
|
|
6365
|
+
/**
|
|
6366
|
+
* get escapeProperties from plugins & adapter
|
|
6367
|
+
* @param appName app name
|
|
6368
|
+
*/
|
|
6369
|
+
getSpecialProperties(appName) {
|
|
6370
|
+
var _a;
|
|
6371
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
6372
|
+
this.commonActionForSpecialProperties(microApp.options.plugins.global);
|
|
6373
|
+
this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
6374
|
+
}
|
|
6375
|
+
}
|
|
6376
|
+
// common action for global plugins and module plugins
|
|
6377
|
+
commonActionForSpecialProperties(plugins) {
|
|
6378
|
+
if (isArray(plugins)) {
|
|
6379
|
+
for (const plugin of plugins) {
|
|
6380
|
+
if (isPlainObject(plugin)) {
|
|
6381
|
+
if (isArray(plugin.escapeProperties)) {
|
|
6382
|
+
this.escapeProperties = this.escapeProperties.concat(plugin.escapeProperties);
|
|
4943
6383
|
}
|
|
4944
6384
|
}
|
|
4945
|
-
return (target === proxyDocument ||
|
|
4946
|
-
target instanceof rawRootDocument);
|
|
4947
6385
|
}
|
|
4948
6386
|
}
|
|
4949
|
-
|
|
4950
|
-
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
|
|
4954
|
-
|
|
4955
|
-
|
|
4956
|
-
|
|
4957
|
-
|
|
4958
|
-
|
|
4959
|
-
|
|
4960
|
-
|
|
4961
|
-
|
|
4962
|
-
|
|
4963
|
-
|
|
4964
|
-
|
|
4965
|
-
|
|
4966
|
-
|
|
4967
|
-
|
|
4968
|
-
|
|
4969
|
-
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
|
|
4974
|
-
|
|
6387
|
+
}
|
|
6388
|
+
initRouteState(defaultPage) {
|
|
6389
|
+
initRouteStateWithURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location, defaultPage);
|
|
6390
|
+
}
|
|
6391
|
+
clearRouteState(keepRouteState) {
|
|
6392
|
+
clearRouteStateFromURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow.location, keepRouteState);
|
|
6393
|
+
}
|
|
6394
|
+
setRouteInfoForKeepAliveApp() {
|
|
6395
|
+
updateBrowserURLWithLocation(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location);
|
|
6396
|
+
}
|
|
6397
|
+
removeRouteInfoForKeepAliveApp() {
|
|
6398
|
+
removeStateAndPathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__);
|
|
6399
|
+
}
|
|
6400
|
+
/**
|
|
6401
|
+
* Format all html elements when init
|
|
6402
|
+
* @param container micro app container
|
|
6403
|
+
*/
|
|
6404
|
+
patchStaticElement(container) {
|
|
6405
|
+
patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
|
|
6406
|
+
}
|
|
6407
|
+
/**
|
|
6408
|
+
* Actions:
|
|
6409
|
+
* 1. patch static elements from html
|
|
6410
|
+
* @param container micro app container
|
|
6411
|
+
*/
|
|
6412
|
+
actionBeforeExecScripts(container) {
|
|
6413
|
+
this.patchStaticElement(container);
|
|
4975
6414
|
}
|
|
4976
6415
|
}
|
|
4977
|
-
|
|
6416
|
+
IframeSandbox.activeCount = 0; // number of active sandbox
|
|
4978
6417
|
|
|
4979
6418
|
function formatEventInfo(event, element) {
|
|
4980
6419
|
Object.defineProperties(event, {
|
|
@@ -5024,38 +6463,40 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
5024
6463
|
}
|
|
5025
6464
|
/**
|
|
5026
6465
|
* Dispatch custom event to micro app
|
|
6466
|
+
* @param app app
|
|
5027
6467
|
* @param eventName event name
|
|
5028
|
-
* @param appName app name
|
|
5029
6468
|
* @param detail event detail
|
|
5030
6469
|
*/
|
|
5031
|
-
function dispatchCustomEventToMicroApp(
|
|
5032
|
-
const event = new CustomEvent(formatEventName
|
|
6470
|
+
function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
|
|
6471
|
+
const event = new CustomEvent(formatEventName(eventName, app.name), {
|
|
5033
6472
|
detail,
|
|
5034
6473
|
});
|
|
5035
|
-
window
|
|
6474
|
+
const target = app.iframe ? app.sandBox.microAppWindow : window;
|
|
6475
|
+
target.dispatchEvent(event);
|
|
5036
6476
|
}
|
|
5037
6477
|
|
|
5038
6478
|
// micro app instances
|
|
5039
6479
|
const appInstanceMap = new Map();
|
|
5040
6480
|
class CreateApp {
|
|
5041
|
-
constructor({ name, url, container, scopecss, useSandbox, inline,
|
|
6481
|
+
constructor({ name, url, container, scopecss, useSandbox, inline, iframe, ssrUrl, isPrefetch, prefetchLevel, }) {
|
|
5042
6482
|
this.state = appStates.CREATED;
|
|
5043
6483
|
this.keepAliveState = null;
|
|
5044
|
-
this.keepAliveContainer = null;
|
|
5045
6484
|
this.loadSourceLevel = 0;
|
|
5046
6485
|
this.umdHookMount = null;
|
|
5047
6486
|
this.umdHookUnmount = null;
|
|
5048
|
-
this.libraryName = null;
|
|
5049
6487
|
this.umdMode = false;
|
|
6488
|
+
// TODO: 类型优化,加上iframe沙箱
|
|
5050
6489
|
this.sandBox = null;
|
|
5051
6490
|
this.fiber = false;
|
|
5052
6491
|
this.useMemoryRouter = true;
|
|
6492
|
+
appInstanceMap.set(name, this);
|
|
6493
|
+
// init actions
|
|
5053
6494
|
this.name = name;
|
|
5054
6495
|
this.url = url;
|
|
5055
6496
|
this.useSandbox = useSandbox;
|
|
5056
6497
|
this.scopecss = this.useSandbox && scopecss;
|
|
5057
6498
|
this.inline = inline !== null && inline !== void 0 ? inline : false;
|
|
5058
|
-
this.
|
|
6499
|
+
this.iframe = iframe !== null && iframe !== void 0 ? iframe : false;
|
|
5059
6500
|
// not exist when prefetch 👇
|
|
5060
6501
|
this.container = container !== null && container !== void 0 ? container : null;
|
|
5061
6502
|
this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
|
|
@@ -5063,15 +6504,13 @@ class CreateApp {
|
|
|
5063
6504
|
this.isPrefetch = isPrefetch !== null && isPrefetch !== void 0 ? isPrefetch : false;
|
|
5064
6505
|
this.isPrerender = prefetchLevel === 3;
|
|
5065
6506
|
this.prefetchLevel = prefetchLevel;
|
|
5066
|
-
// init actions
|
|
5067
|
-
appInstanceMap.set(this.name, this);
|
|
5068
6507
|
this.source = { html: null, links: new Set(), scripts: new Set() };
|
|
5069
6508
|
this.loadSourceCode();
|
|
5070
|
-
this.
|
|
6509
|
+
this.createSandbox();
|
|
5071
6510
|
}
|
|
5072
6511
|
// Load resources
|
|
5073
6512
|
loadSourceCode() {
|
|
5074
|
-
this.
|
|
6513
|
+
this.setAppState(appStates.LOADING);
|
|
5075
6514
|
HTMLLoader.getInstance().run(this, extractSourceDom);
|
|
5076
6515
|
}
|
|
5077
6516
|
/**
|
|
@@ -5081,7 +6520,7 @@ class CreateApp {
|
|
|
5081
6520
|
var _a;
|
|
5082
6521
|
if (++this.loadSourceLevel === 2) {
|
|
5083
6522
|
this.source.html = html;
|
|
5084
|
-
this.
|
|
6523
|
+
this.setAppState(appStates.LOADED);
|
|
5085
6524
|
if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
|
|
5086
6525
|
getRootContainer(this.container).mount(this);
|
|
5087
6526
|
}
|
|
@@ -5092,7 +6531,7 @@ class CreateApp {
|
|
|
5092
6531
|
* 1. fiber forced on
|
|
5093
6532
|
* 2. only virtual router support
|
|
5094
6533
|
*
|
|
5095
|
-
* NOTE: (
|
|
6534
|
+
* NOTE: (Don't update browser url, dispatch popstateEvent, reload window, dispatch lifecycle event)
|
|
5096
6535
|
* 1. pushState/replaceState in child can update microLocation, but will not attach router info to browser url
|
|
5097
6536
|
* 2. prevent dispatch popstate/hashchange event to browser
|
|
5098
6537
|
* 3. all navigation actions of location are invalid (In the future, we can consider update microLocation without trigger browser reload)
|
|
@@ -5112,7 +6551,6 @@ class CreateApp {
|
|
|
5112
6551
|
useMemoryRouter: true,
|
|
5113
6552
|
baseroute: '',
|
|
5114
6553
|
fiber: true,
|
|
5115
|
-
esmodule: this.esmodule,
|
|
5116
6554
|
defaultPage: defaultPage !== null && defaultPage !== void 0 ? defaultPage : '',
|
|
5117
6555
|
disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
|
|
5118
6556
|
});
|
|
@@ -5127,7 +6565,7 @@ class CreateApp {
|
|
|
5127
6565
|
this.loadSourceLevel = -1;
|
|
5128
6566
|
if (appStates.UNMOUNT !== this.state) {
|
|
5129
6567
|
this.onerror(e);
|
|
5130
|
-
this.
|
|
6568
|
+
this.setAppState(appStates.LOAD_FAILED);
|
|
5131
6569
|
}
|
|
5132
6570
|
}
|
|
5133
6571
|
/**
|
|
@@ -5139,150 +6577,151 @@ class CreateApp {
|
|
|
5139
6577
|
* @param baseroute route prefix, default is ''
|
|
5140
6578
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
5141
6579
|
* @param fiber run js in fiber mode
|
|
5142
|
-
* @param esmodule support type='module' script
|
|
5143
6580
|
*/
|
|
5144
|
-
mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber,
|
|
5145
|
-
var _a, _b, _c, _d, _e, _f;
|
|
6581
|
+
mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, }) {
|
|
5146
6582
|
if (this.loadSourceLevel !== 2) {
|
|
5147
6583
|
/**
|
|
5148
|
-
*
|
|
5149
|
-
*
|
|
5150
|
-
*
|
|
6584
|
+
* container cannot be null when load end
|
|
6585
|
+
* NOTE:
|
|
6586
|
+
* 1. render prefetch app before load end
|
|
6587
|
+
* 2. unmount prefetch app and mount again before load end
|
|
5151
6588
|
*/
|
|
5152
6589
|
this.container = container;
|
|
5153
6590
|
// mount before prerender exec mount (loading source), set isPrerender to false
|
|
5154
6591
|
this.isPrerender = false;
|
|
5155
6592
|
// reset app state to LOADING
|
|
5156
|
-
this.
|
|
6593
|
+
this.setAppState(appStates.LOADING);
|
|
5157
6594
|
return;
|
|
5158
6595
|
}
|
|
5159
|
-
|
|
5160
|
-
|
|
5161
|
-
|
|
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);
|
|
6596
|
+
this.createSandbox();
|
|
6597
|
+
const nextAction = () => {
|
|
6598
|
+
var _a, _b, _c, _d, _e, _f, _g;
|
|
5183
6599
|
/**
|
|
5184
|
-
*
|
|
5185
|
-
*
|
|
5186
|
-
*
|
|
6600
|
+
* Special scenes:
|
|
6601
|
+
* 1. mount before prerender exec mount (loading source)
|
|
6602
|
+
* 2. mount when prerender js executing
|
|
6603
|
+
* 3. mount after prerender js exec end
|
|
6604
|
+
* 4. mount after prerender unmounted
|
|
6605
|
+
*
|
|
6606
|
+
* TODO: test shadowDOM
|
|
5187
6607
|
*/
|
|
5188
|
-
this.
|
|
5189
|
-
|
|
5190
|
-
|
|
5191
|
-
|
|
5192
|
-
|
|
5193
|
-
|
|
5194
|
-
|
|
5195
|
-
|
|
5196
|
-
|
|
5197
|
-
|
|
5198
|
-
|
|
5199
|
-
|
|
5200
|
-
|
|
5201
|
-
|
|
5202
|
-
|
|
5203
|
-
|
|
5204
|
-
|
|
5205
|
-
|
|
5206
|
-
|
|
5207
|
-
|
|
5208
|
-
|
|
5209
|
-
|
|
5210
|
-
|
|
5211
|
-
|
|
5212
|
-
|
|
5213
|
-
|
|
5214
|
-
|
|
5215
|
-
|
|
5216
|
-
|
|
5217
|
-
|
|
5218
|
-
|
|
5219
|
-
|
|
5220
|
-
|
|
5221
|
-
|
|
5222
|
-
|
|
5223
|
-
|
|
5224
|
-
|
|
5225
|
-
|
|
5226
|
-
|
|
5227
|
-
|
|
6608
|
+
if (this.isPrerender &&
|
|
6609
|
+
isDivElement(this.container) &&
|
|
6610
|
+
this.container.hasAttribute('prerender')) {
|
|
6611
|
+
/**
|
|
6612
|
+
* rebuild effect event of window, document, data center
|
|
6613
|
+
* explain:
|
|
6614
|
+
* 1. rebuild before exec mount, do nothing
|
|
6615
|
+
* 2. rebuild when js executing, recovery recorded effect event, because prerender fiber mode
|
|
6616
|
+
* 3. rebuild after js exec end, normal recovery effect event
|
|
6617
|
+
*/
|
|
6618
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6619
|
+
// current this.container is <div prerender='true'></div>
|
|
6620
|
+
cloneContainer(this.container, container, false);
|
|
6621
|
+
/**
|
|
6622
|
+
* set this.container to <micro-app></micro-app>
|
|
6623
|
+
* NOTE:
|
|
6624
|
+
* must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
6625
|
+
*/
|
|
6626
|
+
this.container = container;
|
|
6627
|
+
(_b = this.preRenderEvents) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
|
|
6628
|
+
// reset isPrerender config
|
|
6629
|
+
this.isPrerender = false;
|
|
6630
|
+
this.preRenderEvents = null;
|
|
6631
|
+
// attach router info to browser url
|
|
6632
|
+
router.attachToURL(this.name);
|
|
6633
|
+
(_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.setPreRenderState(false);
|
|
6634
|
+
}
|
|
6635
|
+
else {
|
|
6636
|
+
this.container = container;
|
|
6637
|
+
this.inline = inline;
|
|
6638
|
+
this.fiber = fiber;
|
|
6639
|
+
// use in sandbox/effect
|
|
6640
|
+
this.useMemoryRouter = useMemoryRouter;
|
|
6641
|
+
// this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
|
|
6642
|
+
const dispatchBeforeMount = () => dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
6643
|
+
if (this.isPrerender) {
|
|
6644
|
+
((_d = this.preRenderEvents) !== null && _d !== void 0 ? _d : (this.preRenderEvents = [])).push(dispatchBeforeMount);
|
|
6645
|
+
}
|
|
6646
|
+
else {
|
|
6647
|
+
dispatchBeforeMount();
|
|
6648
|
+
}
|
|
6649
|
+
this.setAppState(appStates.MOUNTING);
|
|
6650
|
+
// TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
|
|
6651
|
+
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
6652
|
+
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
6653
|
+
umdMode: this.umdMode,
|
|
6654
|
+
baseroute,
|
|
6655
|
+
useMemoryRouter,
|
|
6656
|
+
defaultPage,
|
|
6657
|
+
disablePatchRequest,
|
|
6658
|
+
});
|
|
5228
6659
|
if (!this.umdMode) {
|
|
5229
|
-
|
|
5230
|
-
|
|
5231
|
-
|
|
5232
|
-
|
|
5233
|
-
|
|
5234
|
-
|
|
5235
|
-
|
|
5236
|
-
|
|
5237
|
-
|
|
5238
|
-
|
|
5239
|
-
|
|
5240
|
-
|
|
5241
|
-
|
|
5242
|
-
|
|
5243
|
-
|
|
6660
|
+
// update element info of html
|
|
6661
|
+
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.actionBeforeExecScripts(this.container);
|
|
6662
|
+
// if all js are executed, param isFinished will be true
|
|
6663
|
+
execScripts(this, (isFinished) => {
|
|
6664
|
+
if (!this.umdMode) {
|
|
6665
|
+
const { mount, unmount } = this.getUmdLibraryHooks();
|
|
6666
|
+
/**
|
|
6667
|
+
* umdHookUnmount can works in default mode
|
|
6668
|
+
* register through window.unmount
|
|
6669
|
+
*/
|
|
6670
|
+
this.umdHookUnmount = unmount;
|
|
6671
|
+
// if mount & unmount is function, the sub app is umd mode
|
|
6672
|
+
if (isFunction(mount) && isFunction(unmount)) {
|
|
6673
|
+
this.umdHookMount = mount;
|
|
6674
|
+
// sandbox must exist
|
|
6675
|
+
this.sandBox.markUmdMode(this.umdMode = true);
|
|
6676
|
+
try {
|
|
6677
|
+
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6678
|
+
}
|
|
6679
|
+
catch (e) {
|
|
6680
|
+
logError('An error occurred in function mount \n', this.name, e);
|
|
6681
|
+
}
|
|
6682
|
+
}
|
|
6683
|
+
else if (isFinished === true) {
|
|
6684
|
+
this.handleMounted();
|
|
6685
|
+
}
|
|
5244
6686
|
}
|
|
5245
|
-
|
|
5246
|
-
logError('an error occurred in the mount function \n', this.name, e);
|
|
5247
|
-
}
|
|
5248
|
-
}
|
|
6687
|
+
});
|
|
5249
6688
|
}
|
|
5250
|
-
|
|
5251
|
-
|
|
5252
|
-
|
|
5253
|
-
|
|
5254
|
-
((_a = this.preRenderEvent) !== null && _a !== void 0 ? _a : (this.preRenderEvent = [])).push(dispatchMounted);
|
|
5255
|
-
this.recordAndReleaseEffect();
|
|
6689
|
+
else {
|
|
6690
|
+
(_g = this.sandBox) === null || _g === void 0 ? void 0 : _g.rebuildEffectSnapshot();
|
|
6691
|
+
try {
|
|
6692
|
+
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
5256
6693
|
}
|
|
5257
|
-
|
|
5258
|
-
|
|
6694
|
+
catch (e) {
|
|
6695
|
+
logError('An error occurred in function mount \n', this.name, e);
|
|
5259
6696
|
}
|
|
5260
6697
|
}
|
|
5261
|
-
});
|
|
5262
|
-
}
|
|
5263
|
-
else {
|
|
5264
|
-
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.rebuildEffectSnapshot();
|
|
5265
|
-
try {
|
|
5266
|
-
umdHookMountResult = this.umdHookMount();
|
|
5267
|
-
}
|
|
5268
|
-
catch (e) {
|
|
5269
|
-
logError('an error occurred in the mount function \n', this.name, e);
|
|
5270
6698
|
}
|
|
5271
|
-
|
|
5272
|
-
|
|
6699
|
+
};
|
|
6700
|
+
// TODO: any替换为iframe沙箱类型
|
|
6701
|
+
this.iframe ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
|
|
5273
6702
|
}
|
|
5274
6703
|
/**
|
|
5275
6704
|
* handle for promise umdHookMount
|
|
5276
6705
|
* @param umdHookMountResult result of umdHookMount
|
|
5277
6706
|
*/
|
|
5278
6707
|
handleMounted(umdHookMountResult) {
|
|
5279
|
-
|
|
5280
|
-
|
|
5281
|
-
|
|
5282
|
-
|
|
6708
|
+
var _a, _b;
|
|
6709
|
+
const dispatchAction = () => {
|
|
6710
|
+
if (isPromise(umdHookMountResult)) {
|
|
6711
|
+
umdHookMountResult
|
|
6712
|
+
.then(() => this.dispatchMountedEvent())
|
|
6713
|
+
.catch((e) => this.onerror(e));
|
|
6714
|
+
}
|
|
6715
|
+
else {
|
|
6716
|
+
this.dispatchMountedEvent();
|
|
6717
|
+
}
|
|
6718
|
+
};
|
|
6719
|
+
if (this.isPrerender) {
|
|
6720
|
+
(_a = this.preRenderEvents) === null || _a === void 0 ? void 0 : _a.push(dispatchAction);
|
|
6721
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ isPrerender: true });
|
|
5283
6722
|
}
|
|
5284
6723
|
else {
|
|
5285
|
-
|
|
6724
|
+
dispatchAction();
|
|
5286
6725
|
}
|
|
5287
6726
|
}
|
|
5288
6727
|
/**
|
|
@@ -5290,9 +6729,9 @@ class CreateApp {
|
|
|
5290
6729
|
*/
|
|
5291
6730
|
dispatchMountedEvent() {
|
|
5292
6731
|
if (appStates.UNMOUNT !== this.state) {
|
|
5293
|
-
this.
|
|
6732
|
+
this.setAppState(appStates.MOUNTED);
|
|
5294
6733
|
// call window.onmount of child app
|
|
5295
|
-
|
|
6734
|
+
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONMOUNT), this.name, microGlobalEvent.ONMOUNT, microApp.getData(this.name, true));
|
|
5296
6735
|
// dispatch event mounted to parent
|
|
5297
6736
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
5298
6737
|
}
|
|
@@ -5306,30 +6745,25 @@ class CreateApp {
|
|
|
5306
6745
|
* @param unmountcb callback of unmount
|
|
5307
6746
|
*/
|
|
5308
6747
|
unmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
5309
|
-
|
|
5310
|
-
|
|
5311
|
-
|
|
5312
|
-
this.state = appStates.UNMOUNT;
|
|
5313
|
-
this.keepAliveState = null;
|
|
5314
|
-
this.keepAliveContainer = null;
|
|
6748
|
+
var _a;
|
|
6749
|
+
destroy = destroy || this.state === appStates.LOAD_FAILED;
|
|
6750
|
+
this.setAppState(appStates.UNMOUNT);
|
|
5315
6751
|
// result of unmount function
|
|
5316
|
-
let umdHookUnmountResult;
|
|
6752
|
+
let umdHookUnmountResult = null;
|
|
5317
6753
|
/**
|
|
5318
6754
|
* send an unmount event to the micro app or call umd unmount hook
|
|
5319
6755
|
* before the sandbox is cleared
|
|
5320
6756
|
*/
|
|
5321
|
-
|
|
5322
|
-
|
|
5323
|
-
|
|
5324
|
-
|
|
5325
|
-
|
|
5326
|
-
logError('an error occurred in the unmount function \n', this.name, e);
|
|
5327
|
-
}
|
|
6757
|
+
try {
|
|
6758
|
+
umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
|
|
6759
|
+
}
|
|
6760
|
+
catch (e) {
|
|
6761
|
+
logError('An error occurred in function unmount \n', this.name, e);
|
|
5328
6762
|
}
|
|
5329
|
-
// call window.onunmount of child app
|
|
5330
|
-
callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONUNMOUNT), this.name, `window.${microGlobalEvent.ONUNMOUNT}`);
|
|
5331
6763
|
// dispatch unmount event to micro app
|
|
5332
|
-
dispatchCustomEventToMicroApp('unmount'
|
|
6764
|
+
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
6765
|
+
// call window.onunmount of child app
|
|
6766
|
+
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
5333
6767
|
this.handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb);
|
|
5334
6768
|
}
|
|
5335
6769
|
/**
|
|
@@ -5341,19 +6775,17 @@ class CreateApp {
|
|
|
5341
6775
|
* @param unmountcb callback of unmount
|
|
5342
6776
|
*/
|
|
5343
6777
|
handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb) {
|
|
5344
|
-
const
|
|
6778
|
+
const nextAction = () => this.actionsForUnmount({
|
|
5345
6779
|
destroy,
|
|
5346
6780
|
clearData,
|
|
5347
6781
|
keepRouteState,
|
|
5348
6782
|
unmountcb,
|
|
5349
|
-
};
|
|
6783
|
+
});
|
|
5350
6784
|
if (isPromise(umdHookUnmountResult)) {
|
|
5351
|
-
umdHookUnmountResult
|
|
5352
|
-
.then(() => this.actionsForUnmount(unmountParam))
|
|
5353
|
-
.catch(() => this.actionsForUnmount(unmountParam));
|
|
6785
|
+
umdHookUnmountResult.then(nextAction).catch(nextAction);
|
|
5354
6786
|
}
|
|
5355
6787
|
else {
|
|
5356
|
-
|
|
6788
|
+
nextAction();
|
|
5357
6789
|
}
|
|
5358
6790
|
}
|
|
5359
6791
|
/**
|
|
@@ -5364,26 +6796,20 @@ class CreateApp {
|
|
|
5364
6796
|
* @param unmountcb callback of unmount
|
|
5365
6797
|
*/
|
|
5366
6798
|
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
|
|
5367
|
-
var _a
|
|
5368
|
-
if (destroy) {
|
|
5369
|
-
this.actionsForCompletelyDestroy();
|
|
5370
|
-
}
|
|
5371
|
-
else if (this.umdMode && this.container.childElementCount) {
|
|
6799
|
+
var _a;
|
|
6800
|
+
if (this.umdMode && this.container && !destroy) {
|
|
5372
6801
|
cloneContainer(this.container, this.source.html, false);
|
|
5373
6802
|
}
|
|
5374
|
-
if (this.umdMode) {
|
|
5375
|
-
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
|
|
5376
|
-
}
|
|
5377
6803
|
/**
|
|
5378
6804
|
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
5379
6805
|
* NOTE:
|
|
5380
6806
|
* 1. if destroy is true, clear route state
|
|
5381
6807
|
* 2. umd mode and keep-alive will not clear EventSource
|
|
5382
6808
|
*/
|
|
5383
|
-
(
|
|
6809
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop({
|
|
5384
6810
|
umdMode: this.umdMode,
|
|
5385
6811
|
keepRouteState: keepRouteState && !destroy,
|
|
5386
|
-
|
|
6812
|
+
destroy,
|
|
5387
6813
|
clearData: clearData || destroy,
|
|
5388
6814
|
});
|
|
5389
6815
|
if (!getActiveApps().length) {
|
|
@@ -5391,63 +6817,67 @@ class CreateApp {
|
|
|
5391
6817
|
}
|
|
5392
6818
|
// dispatch unmount event to base app
|
|
5393
6819
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
5394
|
-
this.
|
|
5395
|
-
unmountcb
|
|
6820
|
+
this.clearOptions(destroy);
|
|
6821
|
+
unmountcb === null || unmountcb === void 0 ? void 0 : unmountcb();
|
|
5396
6822
|
}
|
|
5397
|
-
|
|
6823
|
+
clearOptions(destroy) {
|
|
5398
6824
|
this.container.innerHTML = '';
|
|
5399
6825
|
this.container = null;
|
|
5400
6826
|
this.isPrerender = false;
|
|
5401
|
-
this.
|
|
6827
|
+
this.preRenderEvents = null;
|
|
6828
|
+
this.setKeepAliveState(null);
|
|
6829
|
+
// in iframe sandbox & default mode, delete the sandbox & iframeElement
|
|
6830
|
+
if (this.iframe && !this.umdMode)
|
|
6831
|
+
this.sandBox = null;
|
|
6832
|
+
if (destroy)
|
|
6833
|
+
this.actionsForCompletelyDestroy();
|
|
5402
6834
|
}
|
|
5403
6835
|
// actions for completely destroy
|
|
5404
6836
|
actionsForCompletelyDestroy() {
|
|
5405
|
-
|
|
5406
|
-
|
|
5407
|
-
}
|
|
6837
|
+
var _a, _b;
|
|
6838
|
+
(_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.deleteIframeElement) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
5408
6839
|
sourceCenter.script.deleteInlineInfo(this.source.scripts);
|
|
5409
6840
|
appInstanceMap.delete(this.name);
|
|
5410
6841
|
}
|
|
5411
6842
|
// hidden app when disconnectedCallback called with keep-alive
|
|
5412
6843
|
hiddenKeepAliveApp(callback) {
|
|
5413
|
-
var _a;
|
|
5414
|
-
|
|
5415
|
-
|
|
5416
|
-
|
|
5417
|
-
|
|
5418
|
-
|
|
5419
|
-
|
|
5420
|
-
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
6844
|
+
var _a, _b;
|
|
6845
|
+
this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_HIDDEN);
|
|
6846
|
+
/**
|
|
6847
|
+
* event should dispatch before clone node
|
|
6848
|
+
* dispatch afterHidden event to micro-app
|
|
6849
|
+
*/
|
|
6850
|
+
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
5421
6851
|
appState: 'afterhidden',
|
|
5422
6852
|
});
|
|
5423
6853
|
// dispatch afterHidden event to base app
|
|
5424
|
-
dispatchLifecyclesEvent(
|
|
6854
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
|
|
5425
6855
|
if (this.useMemoryRouter) {
|
|
5426
6856
|
// called after lifeCyclesEvent
|
|
5427
6857
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
5428
6858
|
}
|
|
5429
|
-
this.
|
|
5430
|
-
|
|
6859
|
+
this.container = cloneContainer(this.container, pureCreateElement('div'), false);
|
|
6860
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
|
|
6861
|
+
callback === null || callback === void 0 ? void 0 : callback();
|
|
5431
6862
|
}
|
|
5432
6863
|
// show app when connectedCallback called with keep-alive
|
|
5433
6864
|
showKeepAliveApp(container) {
|
|
5434
6865
|
var _a, _b;
|
|
5435
6866
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
5436
6867
|
// dispatch beforeShow event to micro-app
|
|
5437
|
-
dispatchCustomEventToMicroApp('appstate-change',
|
|
6868
|
+
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
5438
6869
|
appState: 'beforeshow',
|
|
5439
6870
|
});
|
|
5440
6871
|
// dispatch beforeShow event to base app
|
|
5441
6872
|
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
5442
|
-
|
|
5443
|
-
this.container = container;
|
|
5444
|
-
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
6873
|
+
this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
|
|
6874
|
+
this.container = cloneContainer(this.container, container, false);
|
|
5445
6875
|
if (this.useMemoryRouter) {
|
|
5446
6876
|
// called before lifeCyclesEvent
|
|
5447
6877
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
|
|
5448
6878
|
}
|
|
5449
6879
|
// dispatch afterShow event to micro-app
|
|
5450
|
-
dispatchCustomEventToMicroApp('appstate-change',
|
|
6880
|
+
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
5451
6881
|
appState: 'aftershow',
|
|
5452
6882
|
});
|
|
5453
6883
|
// dispatch afterShow event to base app
|
|
@@ -5460,48 +6890,71 @@ class CreateApp {
|
|
|
5460
6890
|
onerror(e) {
|
|
5461
6891
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
5462
6892
|
}
|
|
6893
|
+
/**
|
|
6894
|
+
* Scene:
|
|
6895
|
+
* 1. create app
|
|
6896
|
+
* 2. remount of default mode with iframe sandbox
|
|
6897
|
+
* In default mode with iframe sandbox, unmount app will delete iframeElement & sandBox, and create sandBox when mount again, used to solve the problem that module script cannot be execute when append it again
|
|
6898
|
+
*/
|
|
6899
|
+
createSandbox() {
|
|
6900
|
+
if (this.useSandbox && !this.sandBox) {
|
|
6901
|
+
if (this.iframe) {
|
|
6902
|
+
this.sandBox = new IframeSandbox(this.name, this.url);
|
|
6903
|
+
}
|
|
6904
|
+
else {
|
|
6905
|
+
this.sandBox = new WithSandBox(this.name, this.url);
|
|
6906
|
+
}
|
|
6907
|
+
}
|
|
6908
|
+
}
|
|
6909
|
+
// set app state
|
|
6910
|
+
setAppState(state) {
|
|
6911
|
+
this.state = state;
|
|
6912
|
+
}
|
|
5463
6913
|
// get app state
|
|
5464
6914
|
getAppState() {
|
|
5465
6915
|
return this.state;
|
|
5466
6916
|
}
|
|
6917
|
+
// set keep-alive state
|
|
6918
|
+
setKeepAliveState(state) {
|
|
6919
|
+
this.keepAliveState = state;
|
|
6920
|
+
}
|
|
5467
6921
|
// get keep-alive state
|
|
5468
6922
|
getKeepAliveState() {
|
|
5469
6923
|
return this.keepAliveState;
|
|
5470
6924
|
}
|
|
5471
6925
|
// get umd library, if it not exist, return empty object
|
|
5472
6926
|
getUmdLibraryHooks() {
|
|
5473
|
-
var _a, _b, _c, _d;
|
|
5474
6927
|
// after execScripts, the app maybe unmounted
|
|
5475
|
-
if (appStates.UNMOUNT !== this.state) {
|
|
5476
|
-
const
|
|
5477
|
-
|
|
5478
|
-
|
|
5479
|
-
|
|
6928
|
+
if (appStates.UNMOUNT !== this.state && this.sandBox) {
|
|
6929
|
+
const libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
6930
|
+
const proxyWindow = this.sandBox.proxyWindow;
|
|
6931
|
+
// compatible with pre versions
|
|
6932
|
+
if (isObject(proxyWindow[libraryName])) {
|
|
6933
|
+
return proxyWindow[libraryName];
|
|
5480
6934
|
}
|
|
5481
6935
|
return {
|
|
5482
|
-
mount:
|
|
5483
|
-
unmount:
|
|
6936
|
+
mount: proxyWindow.mount,
|
|
6937
|
+
unmount: proxyWindow.unmount,
|
|
5484
6938
|
};
|
|
5485
6939
|
}
|
|
5486
6940
|
return {};
|
|
5487
6941
|
}
|
|
5488
|
-
|
|
5489
|
-
var _a;
|
|
5490
|
-
|
|
5491
|
-
const listener = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow[eventName];
|
|
6942
|
+
getMicroAppGlobalHook(eventName) {
|
|
6943
|
+
var _a, _b;
|
|
6944
|
+
const listener = (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) === null || _b === void 0 ? void 0 : _b[eventName];
|
|
5492
6945
|
return isFunction(listener) ? listener : null;
|
|
5493
6946
|
}
|
|
5494
|
-
|
|
5495
|
-
|
|
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();
|
|
6947
|
+
querySelector(selectors) {
|
|
6948
|
+
return this.container ? globalEnv.rawElementQuerySelector.call(this.container, selectors) : null;
|
|
5504
6949
|
}
|
|
6950
|
+
querySelectorAll(selectors) {
|
|
6951
|
+
return this.container ? globalEnv.rawElementQuerySelectorAll.call(this.container, selectors) : [];
|
|
6952
|
+
}
|
|
6953
|
+
}
|
|
6954
|
+
// iframe route mode
|
|
6955
|
+
function isIframeSandbox(appName) {
|
|
6956
|
+
var _a, _b;
|
|
6957
|
+
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.iframe) !== null && _b !== void 0 ? _b : false;
|
|
5505
6958
|
}
|
|
5506
6959
|
|
|
5507
6960
|
/**
|
|
@@ -5530,12 +6983,14 @@ function defineElement(tagName) {
|
|
|
5530
6983
|
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
5531
6984
|
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
5532
6985
|
if (this.legalAttribute('name', formatAttrName) && this.legalAttribute('url', formatAttrUrl)) {
|
|
5533
|
-
const
|
|
5534
|
-
|
|
5535
|
-
|
|
5536
|
-
|
|
5537
|
-
|
|
5538
|
-
|
|
6986
|
+
const oldApp = appInstanceMap.get(formatAttrName);
|
|
6987
|
+
/**
|
|
6988
|
+
* If oldApp exist & appName is different, determine whether oldApp is running
|
|
6989
|
+
*/
|
|
6990
|
+
if (formatAttrName !== this.appName && oldApp) {
|
|
6991
|
+
if (oldApp.getAppState() !== appStates.UNMOUNT &&
|
|
6992
|
+
oldApp.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
6993
|
+
!oldApp.isPrefetch) {
|
|
5539
6994
|
this.setAttribute('name', this.appName);
|
|
5540
6995
|
return logError(`app name conflict, an app named ${formatAttrName} is running`);
|
|
5541
6996
|
}
|
|
@@ -5543,16 +6998,16 @@ function defineElement(tagName) {
|
|
|
5543
6998
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
5544
6999
|
if (formatAttrName === this.appName) {
|
|
5545
7000
|
this.handleUnmount(true, () => {
|
|
5546
|
-
this.actionsForAttributeChange(formatAttrName, formatAttrUrl,
|
|
7001
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
|
|
5547
7002
|
});
|
|
5548
7003
|
}
|
|
5549
7004
|
else if (this.getKeepAliveModeResult()) {
|
|
5550
7005
|
this.handleHiddenKeepAliveApp();
|
|
5551
|
-
this.actionsForAttributeChange(formatAttrName, formatAttrUrl,
|
|
7006
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
|
|
5552
7007
|
}
|
|
5553
7008
|
else {
|
|
5554
7009
|
this.handleUnmount(this.getDestroyCompatibleResult(), () => {
|
|
5555
|
-
this.actionsForAttributeChange(formatAttrName, formatAttrUrl,
|
|
7010
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
|
|
5556
7011
|
});
|
|
5557
7012
|
}
|
|
5558
7013
|
}
|
|
@@ -5684,37 +7139,35 @@ function defineElement(tagName) {
|
|
|
5684
7139
|
}
|
|
5685
7140
|
this.updateSsrUrl(this.appUrl);
|
|
5686
7141
|
if (appInstanceMap.has(this.appName)) {
|
|
5687
|
-
const
|
|
5688
|
-
const
|
|
5689
|
-
const
|
|
7142
|
+
const oldApp = appInstanceMap.get(this.appName);
|
|
7143
|
+
const oldAppUrl = oldApp.ssrUrl || oldApp.url;
|
|
7144
|
+
const targetUrl = this.ssrUrl || this.appUrl;
|
|
5690
7145
|
/**
|
|
5691
7146
|
* NOTE:
|
|
5692
7147
|
* 1. keep-alive don't care about ssrUrl
|
|
5693
7148
|
* 2. Even if the keep-alive app is pushed into the background, it is still active and cannot be replaced. Otherwise, it is difficult for developers to troubleshoot in case of conflict and will leave developers at a loss
|
|
5694
7149
|
* 3. When scopecss, useSandbox of prefetch app different from target app, delete prefetch app and create new one
|
|
5695
7150
|
*/
|
|
5696
|
-
if (
|
|
5697
|
-
|
|
5698
|
-
this.handleShowKeepAliveApp(
|
|
7151
|
+
if (oldApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
7152
|
+
oldApp.url === this.appUrl) {
|
|
7153
|
+
this.handleShowKeepAliveApp(oldApp);
|
|
5699
7154
|
}
|
|
5700
|
-
else if (
|
|
5701
|
-
(
|
|
5702
|
-
|
|
5703
|
-
this.handleAppMount(
|
|
7155
|
+
else if (oldAppUrl === targetUrl && (oldApp.getAppState() === appStates.UNMOUNT ||
|
|
7156
|
+
(oldApp.isPrefetch &&
|
|
7157
|
+
this.sameCoreOptions(oldApp)))) {
|
|
7158
|
+
this.handleAppMount(oldApp);
|
|
5704
7159
|
}
|
|
5705
|
-
else if (
|
|
5706
|
-
if ((process.env.NODE_ENV !== 'production') &&
|
|
5707
|
-
app.scopecss === this.isScopecss() &&
|
|
5708
|
-
app.useSandbox === this.isSandbox()) {
|
|
7160
|
+
else if (oldApp.isPrefetch || oldApp.getAppState() === appStates.UNMOUNT) {
|
|
7161
|
+
if ((process.env.NODE_ENV !== 'production') && this.sameCoreOptions(oldApp)) {
|
|
5709
7162
|
/**
|
|
5710
7163
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
5711
7164
|
*/
|
|
5712
|
-
logWarn(`the ${
|
|
7165
|
+
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${oldAppUrl} replaced by a new app with url: ${targetUrl}`, this.appName);
|
|
5713
7166
|
}
|
|
5714
7167
|
this.handleCreateApp();
|
|
5715
7168
|
}
|
|
5716
7169
|
else {
|
|
5717
|
-
logError(`app name conflict, an app named: ${this.appName} with url: ${
|
|
7170
|
+
logError(`app name conflict, an app named: ${this.appName} with url: ${oldAppUrl} is running`);
|
|
5718
7171
|
}
|
|
5719
7172
|
}
|
|
5720
7173
|
else {
|
|
@@ -5722,7 +7175,7 @@ function defineElement(tagName) {
|
|
|
5722
7175
|
}
|
|
5723
7176
|
}
|
|
5724
7177
|
// remount app or create app if attribute url or name change
|
|
5725
|
-
actionsForAttributeChange(formatAttrName, formatAttrUrl,
|
|
7178
|
+
actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp) {
|
|
5726
7179
|
var _a;
|
|
5727
7180
|
/**
|
|
5728
7181
|
* do not add judgment of formatAttrUrl === this.appUrl
|
|
@@ -5735,26 +7188,38 @@ function defineElement(tagName) {
|
|
|
5735
7188
|
this.setAttribute('name', this.appName);
|
|
5736
7189
|
}
|
|
5737
7190
|
/**
|
|
5738
|
-
* when
|
|
5739
|
-
* scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different,
|
|
5740
|
-
* scene2: if formatAttrName and this.appName are different:
|
|
7191
|
+
* when oldApp not null: this.appName === oldApp.name
|
|
7192
|
+
* scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, oldApp has been unmounted
|
|
7193
|
+
* scene2: if formatAttrName and this.appName are different: oldApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace oldApp
|
|
5741
7194
|
* scene3: url is different but ssrUrl is equal
|
|
5742
7195
|
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
5743
|
-
* scene5: if
|
|
7196
|
+
* scene5: if oldApp is KEEP_ALIVE_HIDDEN, name must different
|
|
5744
7197
|
*/
|
|
5745
|
-
if (
|
|
5746
|
-
if (
|
|
5747
|
-
if (
|
|
5748
|
-
this.handleShowKeepAliveApp(
|
|
7198
|
+
if (oldApp) {
|
|
7199
|
+
if (oldApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
7200
|
+
if (oldApp.url === this.appUrl) {
|
|
7201
|
+
this.handleShowKeepAliveApp(oldApp);
|
|
5749
7202
|
}
|
|
5750
7203
|
else {
|
|
5751
7204
|
// the hidden keep-alive app is still active
|
|
5752
7205
|
logError(`app name conflict, an app named ${this.appName} is running`);
|
|
5753
7206
|
}
|
|
7207
|
+
/**
|
|
7208
|
+
* TODO:
|
|
7209
|
+
* 1. oldApp必是unmountApp或preFetchApp,这里还应该考虑沙箱、iframe、样式隔离不一致的情况
|
|
7210
|
+
* 2. unmountApp要不要判断样式隔离、沙箱、iframe,然后彻底删除并再次渲染?(包括handleConnected里的处理,先不改?)
|
|
7211
|
+
* 推荐:if (
|
|
7212
|
+
* oldApp.url === this.appUrl &&
|
|
7213
|
+
* oldApp.ssrUrl === this.ssrUrl && (
|
|
7214
|
+
* oldApp.getAppState() === appStates.UNMOUNT ||
|
|
7215
|
+
* (oldApp.isPrefetch && this.sameCoreOptions(oldApp))
|
|
7216
|
+
* )
|
|
7217
|
+
* )
|
|
7218
|
+
*/
|
|
5754
7219
|
}
|
|
5755
|
-
else if (
|
|
7220
|
+
else if (oldApp.url === this.appUrl && oldApp.ssrUrl === this.ssrUrl) {
|
|
5756
7221
|
// mount app
|
|
5757
|
-
this.handleAppMount(
|
|
7222
|
+
this.handleAppMount(oldApp);
|
|
5758
7223
|
}
|
|
5759
7224
|
else {
|
|
5760
7225
|
this.handleCreateApp();
|
|
@@ -5778,24 +7243,39 @@ function defineElement(tagName) {
|
|
|
5778
7243
|
}
|
|
5779
7244
|
// create app instance
|
|
5780
7245
|
handleCreateApp() {
|
|
5781
|
-
|
|
7246
|
+
const createAppInstance = () => {
|
|
7247
|
+
var _a;
|
|
7248
|
+
return new CreateApp({
|
|
7249
|
+
name: this.appName,
|
|
7250
|
+
url: this.appUrl,
|
|
7251
|
+
scopecss: this.useScopecss(),
|
|
7252
|
+
useSandbox: this.useSandbox(),
|
|
7253
|
+
inline: this.getDisposeResult('inline'),
|
|
7254
|
+
iframe: this.getDisposeResult('iframe'),
|
|
7255
|
+
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
7256
|
+
ssrUrl: this.ssrUrl,
|
|
7257
|
+
});
|
|
7258
|
+
};
|
|
5782
7259
|
/**
|
|
5783
|
-
*
|
|
5784
|
-
*
|
|
7260
|
+
* Actions for destroy old app
|
|
7261
|
+
* If oldApp exist, it must be 3 scenes:
|
|
7262
|
+
* 1. oldApp is unmounted app (url is is different)
|
|
7263
|
+
* 2. oldApp is prefetch, not prerender (url, scopecss, useSandbox, iframe is different)
|
|
7264
|
+
* 3. oldApp is prerender (url, scopecss, useSandbox, iframe is different)
|
|
5785
7265
|
*/
|
|
5786
|
-
|
|
5787
|
-
|
|
7266
|
+
const oldApp = appInstanceMap.get(this.appName);
|
|
7267
|
+
if (oldApp) {
|
|
7268
|
+
if (oldApp.isPrerender) {
|
|
7269
|
+
this.handleUnmount(true, createAppInstance);
|
|
7270
|
+
}
|
|
7271
|
+
else {
|
|
7272
|
+
oldApp.actionsForCompletelyDestroy();
|
|
7273
|
+
createAppInstance();
|
|
7274
|
+
}
|
|
7275
|
+
}
|
|
7276
|
+
else {
|
|
7277
|
+
createAppInstance();
|
|
5788
7278
|
}
|
|
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
7279
|
}
|
|
5800
7280
|
/**
|
|
5801
7281
|
* mount app
|
|
@@ -5821,7 +7301,6 @@ function defineElement(tagName) {
|
|
|
5821
7301
|
baseroute: this.getBaseRouteCompatible(),
|
|
5822
7302
|
disablePatchRequest: this.getDisposeResult('disable-patch-request'),
|
|
5823
7303
|
fiber: this.getDisposeResult('fiber'),
|
|
5824
|
-
esmodule: this.getDisposeResult('esmodule'),
|
|
5825
7304
|
});
|
|
5826
7305
|
}
|
|
5827
7306
|
/**
|
|
@@ -5860,10 +7339,10 @@ function defineElement(tagName) {
|
|
|
5860
7339
|
* @param name Configuration item name
|
|
5861
7340
|
*/
|
|
5862
7341
|
getDisposeResult(name) {
|
|
5863
|
-
return (this.
|
|
7342
|
+
return (this.compatibleProperties(name) || !!microApp.options[name]) && this.compatibleDisableProperties(name);
|
|
5864
7343
|
}
|
|
5865
7344
|
// compatible of disableScopecss & disableSandbox
|
|
5866
|
-
|
|
7345
|
+
compatibleProperties(name) {
|
|
5867
7346
|
if (name === 'disable-scopecss') {
|
|
5868
7347
|
return this.hasAttribute('disable-scopecss') || this.hasAttribute('disableScopecss');
|
|
5869
7348
|
}
|
|
@@ -5873,7 +7352,7 @@ function defineElement(tagName) {
|
|
|
5873
7352
|
return this.hasAttribute(name);
|
|
5874
7353
|
}
|
|
5875
7354
|
// compatible of disableScopecss & disableSandbox
|
|
5876
|
-
|
|
7355
|
+
compatibleDisableProperties(name) {
|
|
5877
7356
|
if (name === 'disable-scopecss') {
|
|
5878
7357
|
return this.getAttribute('disable-scopecss') !== 'false' && this.getAttribute('disableScopecss') !== 'false';
|
|
5879
7358
|
}
|
|
@@ -5882,12 +7361,20 @@ function defineElement(tagName) {
|
|
|
5882
7361
|
}
|
|
5883
7362
|
return this.getAttribute(name) !== 'false';
|
|
5884
7363
|
}
|
|
5885
|
-
|
|
7364
|
+
useScopecss() {
|
|
5886
7365
|
return !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM'));
|
|
5887
7366
|
}
|
|
5888
|
-
|
|
7367
|
+
useSandbox() {
|
|
5889
7368
|
return !this.getDisposeResult('disable-sandbox');
|
|
5890
7369
|
}
|
|
7370
|
+
/**
|
|
7371
|
+
* Determine whether the core options of the existApp is consistent with the new one
|
|
7372
|
+
*/
|
|
7373
|
+
sameCoreOptions(app) {
|
|
7374
|
+
return (app.scopecss === this.useScopecss() &&
|
|
7375
|
+
app.useSandbox === this.useSandbox() &&
|
|
7376
|
+
app.iframe === this.getDisposeResult('iframe'));
|
|
7377
|
+
}
|
|
5891
7378
|
/**
|
|
5892
7379
|
* 2021-09-08
|
|
5893
7380
|
* get baseRoute
|
|
@@ -5972,7 +7459,7 @@ function defineElement(tagName) {
|
|
|
5972
7459
|
* {
|
|
5973
7460
|
* name: string,
|
|
5974
7461
|
* url: string,
|
|
5975
|
-
*
|
|
7462
|
+
* iframe: boolean,
|
|
5976
7463
|
* inline: boolean,
|
|
5977
7464
|
* 'disable-scopecss': boolean,
|
|
5978
7465
|
* 'disable-sandbox': boolean,
|
|
@@ -6036,7 +7523,7 @@ function preFetchAction(options) {
|
|
|
6036
7523
|
scopecss: !((_b = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss) !== null && _b !== void 0 ? _b : microApp.options['disable-scopecss']),
|
|
6037
7524
|
useSandbox: !((_d = (_c = options['disable-sandbox']) !== null && _c !== void 0 ? _c : options.disableSandbox) !== null && _d !== void 0 ? _d : microApp.options['disable-sandbox']),
|
|
6038
7525
|
inline: (_e = options.inline) !== null && _e !== void 0 ? _e : microApp.options.inline,
|
|
6039
|
-
|
|
7526
|
+
iframe: (_f = options.iframe) !== null && _f !== void 0 ? _f : microApp.options.iframe,
|
|
6040
7527
|
prefetchLevel: options.level && PREFETCH_LEVEL.includes(options.level) ? options.level : microApp.options.prefetchLevel && PREFETCH_LEVEL.includes(microApp.options.prefetchLevel) ? microApp.options.prefetchLevel : 2,
|
|
6041
7528
|
});
|
|
6042
7529
|
const oldOnload = app.onLoad;
|
|
@@ -6135,10 +7622,19 @@ function unmountApp(appName, options) {
|
|
|
6135
7622
|
return new Promise((resolve) => {
|
|
6136
7623
|
if (app) {
|
|
6137
7624
|
if (app.getAppState() === appStates.UNMOUNT || app.isPrefetch) {
|
|
6138
|
-
if (
|
|
6139
|
-
app.
|
|
7625
|
+
if (app.isPrerender) {
|
|
7626
|
+
app.unmount({
|
|
7627
|
+
destroy: !!(options === null || options === void 0 ? void 0 : options.destroy),
|
|
7628
|
+
clearData: !!(options === null || options === void 0 ? void 0 : options.clearData),
|
|
7629
|
+
keepRouteState: false,
|
|
7630
|
+
unmountcb: resolve.bind(null, true)
|
|
7631
|
+
});
|
|
7632
|
+
}
|
|
7633
|
+
else {
|
|
7634
|
+
if (options === null || options === void 0 ? void 0 : options.destroy)
|
|
7635
|
+
app.actionsForCompletelyDestroy();
|
|
7636
|
+
resolve(true);
|
|
6140
7637
|
}
|
|
6141
|
-
resolve(true);
|
|
6142
7638
|
}
|
|
6143
7639
|
else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
6144
7640
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
@@ -6188,7 +7684,7 @@ function unmountApp(appName, options) {
|
|
|
6188
7684
|
else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
|
|
6189
7685
|
const keepAliveAttrValue = container.getAttribute('keep-alive');
|
|
6190
7686
|
container.removeAttribute('keep-alive');
|
|
6191
|
-
let clearDataAttrValue;
|
|
7687
|
+
let clearDataAttrValue = null;
|
|
6192
7688
|
if (options.clearData) {
|
|
6193
7689
|
clearDataAttrValue = container.getAttribute('clear-data');
|
|
6194
7690
|
container.setAttribute('clear-data', 'true');
|
|
@@ -6198,7 +7694,7 @@ function unmountApp(appName, options) {
|
|
|
6198
7694
|
isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
|
|
6199
7695
|
}
|
|
6200
7696
|
else {
|
|
6201
|
-
let clearDataAttrValue;
|
|
7697
|
+
let clearDataAttrValue = null;
|
|
6202
7698
|
if (options === null || options === void 0 ? void 0 : options.clearData) {
|
|
6203
7699
|
clearDataAttrValue = container.getAttribute('clear-data');
|
|
6204
7700
|
container.setAttribute('clear-data', 'true');
|
|
@@ -6321,10 +7817,10 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
6321
7817
|
return logError(`${options.tagName} is invalid tagName`);
|
|
6322
7818
|
}
|
|
6323
7819
|
}
|
|
6324
|
-
|
|
7820
|
+
initGlobalEnv();
|
|
7821
|
+
if (globalEnv.rawWindow.customElements.get(this.tagName)) {
|
|
6325
7822
|
return logWarn(`element ${this.tagName} is already defined`);
|
|
6326
7823
|
}
|
|
6327
|
-
initGlobalEnv();
|
|
6328
7824
|
if (isPlainObject(options)) {
|
|
6329
7825
|
this.options = options;
|
|
6330
7826
|
options['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;
|