@micro-zoe/micro-app 1.0.0-alpha.9 → 1.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- const version = '1.0.0-alpha.9';
1
+ const version = '1.0.0-beta.0';
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,46 @@ function isShadowRoot(target) {
74
73
  return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
75
74
  }
76
75
  function isURL(target) {
77
- return target instanceof URL;
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
- return target instanceof Element;
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
- return target instanceof Node;
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';
84
116
  }
85
117
  // is ProxyDocument
86
118
  function isProxyDocument(target) {
@@ -323,6 +355,7 @@ function pureCreateElement(tagName, options) {
323
355
  function cloneContainer(origin, target, deep) {
324
356
  target.innerHTML = '';
325
357
  if (deep) {
358
+ // TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
326
359
  const clonedNode = origin.cloneNode(true);
327
360
  const fragment = document.createDocumentFragment();
328
361
  Array.from(clonedNode.childNodes).forEach((node) => {
@@ -335,6 +368,7 @@ function cloneContainer(origin, target, deep) {
335
368
  target.appendChild(node);
336
369
  });
337
370
  }
371
+ return target;
338
372
  }
339
373
  // is invalid key of querySelector
340
374
  function isInvalidQuerySelectorKey(key) {
@@ -500,12 +534,17 @@ function isInlineScript(address) {
500
534
  * @param appName app.name
501
535
  * @param args arguments
502
536
  */
503
- function callFnWithTryCatch(fn, appName, msgSuffix, ...args) {
537
+ function execMicroAppGlobalHook(fn, appName, hookName, ...args) {
504
538
  try {
505
539
  isFunction(fn) && fn(...args);
506
540
  }
507
541
  catch (e) {
508
- logError(`an error occurred in app ${appName} ${msgSuffix} \n`, null, e);
542
+ logError(`An error occurred in app ${appName} window.${hookName} \n`, null, e);
543
+ }
544
+ }
545
+ function clearDOM($dom) {
546
+ while ($dom === null || $dom === void 0 ? void 0 : $dom.firstChild) {
547
+ $dom.removeChild($dom.firstChild);
509
548
  }
510
549
  }
511
550
 
@@ -544,6 +583,11 @@ var microGlobalEvent;
544
583
  microGlobalEvent["ONMOUNT"] = "onmount";
545
584
  microGlobalEvent["ONUNMOUNT"] = "onunmount";
546
585
  })(microGlobalEvent || (microGlobalEvent = {}));
586
+ // custom event of child app
587
+ const microAppCustomEvent = [
588
+ 'unmount',
589
+ 'appstate-change',
590
+ ];
547
591
  // keep-alive status
548
592
  var keepAliveStates;
549
593
  (function (keepAliveStates) {
@@ -566,7 +610,6 @@ var MicroAppConfig;
566
610
  MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
567
611
  MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
568
612
  MicroAppConfig["CLEAR_DATA"] = "clear-data";
569
- MicroAppConfig["ESMODULE"] = "esmodule";
570
613
  MicroAppConfig["SSR"] = "ssr";
571
614
  MicroAppConfig["FIBER"] = "fiber";
572
615
  })(MicroAppConfig || (MicroAppConfig = {}));
@@ -1094,9 +1137,6 @@ function dispatchOnErrorEvent(element) {
1094
1137
  function createSourceCenter() {
1095
1138
  const linkList = new Map();
1096
1139
  const scriptList = new Map();
1097
- // setInterval(() => {
1098
- // console.log(linkList, scriptList)
1099
- // }, 10000);
1100
1140
  function createSourceHandler(targetList) {
1101
1141
  return {
1102
1142
  setInfo(address, info) {
@@ -1138,7 +1178,7 @@ function getExistParseCode(appName, prefix, linkInfo) {
1138
1178
  if (item !== appName) {
1139
1179
  const appSpaceData = appSpace[item];
1140
1180
  if (appSpaceData.parsedCode) {
1141
- return appSpaceData.parsedCode.replaceAll(new RegExp(createPrefix(item, true), 'g'), prefix);
1181
+ return appSpaceData.parsedCode.replace(new RegExp(createPrefix(item, true), 'g'), prefix);
1142
1182
  }
1143
1183
  }
1144
1184
  }
@@ -1224,18 +1264,18 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
1224
1264
  const linkInfo = sourceCenter.link.getInfo(address);
1225
1265
  return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
1226
1266
  });
1227
- const fiberLinkTasks = app.isPrefetch || app.fiber ? [] : null;
1267
+ const fiberLinkTasks = fiberStyleResult ? [] : null;
1228
1268
  promiseStream(fetchLinkPromise, (res) => {
1229
1269
  injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
1230
1270
  }, (err) => {
1231
1271
  logError(err, app.name);
1232
1272
  }, () => {
1233
- if (fiberLinkTasks) {
1234
- /**
1235
- * 1. If fiberLinkTasks is not null, fiberStyleResult is not null
1236
- * 2. Download link source while processing style
1237
- * 3. Process style first, and then process link
1238
- */
1273
+ /**
1274
+ * 1. If fiberStyleResult exist, fiberLinkTasks must exist
1275
+ * 2. Download link source while processing style
1276
+ * 3. Process style first, and then process link
1277
+ */
1278
+ if (fiberStyleResult) {
1239
1279
  fiberStyleResult.then(() => {
1240
1280
  fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
1241
1281
  serialExecFiberTasks(fiberLinkTasks);
@@ -1369,10 +1409,10 @@ class Adapter {
1369
1409
  'webpackHotUpdate',
1370
1410
  'Vue',
1371
1411
  ];
1372
- this.injectReactHRMProperty();
1412
+ this.injectReactHMRProperty();
1373
1413
  }
1374
1414
  // adapter for react
1375
- injectReactHRMProperty() {
1415
+ injectReactHMRProperty() {
1376
1416
  if ((process.env.NODE_ENV !== 'production')) {
1377
1417
  // react child in non-react env
1378
1418
  this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
@@ -1411,13 +1451,15 @@ function fixReactHMRConflict(app) {
1411
1451
  /**
1412
1452
  * reDefine parentNode of html
1413
1453
  * Scenes:
1414
- * 1. element-ui popover.js
1415
- * if (html.parentNode === document) ...
1454
+ * 1. element-ui@2/lib/utils/popper.js
1455
+ * var parent = element.parentNode;
1456
+ * // root is child app window
1457
+ * if (parent === root.document) ...
1416
1458
  */
1417
- function throttleDeferForParentNode(proxyDocument) {
1459
+ function throttleDeferForParentNode(microDocument) {
1418
1460
  const html = globalEnv.rawDocument.firstElementChild;
1419
- if (html && html.parentNode !== proxyDocument) {
1420
- setParentNode(html, proxyDocument);
1461
+ if ((html === null || html === void 0 ? void 0 : html.parentNode) === globalEnv.rawDocument) {
1462
+ setParentNode(html, microDocument);
1421
1463
  defer(() => {
1422
1464
  setParentNode(html, globalEnv.rawDocument);
1423
1465
  });
@@ -1437,6 +1479,64 @@ function setParentNode(target, value) {
1437
1479
  });
1438
1480
  }
1439
1481
  }
1482
+ // this events should be sent to the specified app
1483
+ const formatEventList = ['unmount', 'appstate-change'];
1484
+ /**
1485
+ * Format event name
1486
+ * @param eventName event name
1487
+ * @param appName app name
1488
+ */
1489
+ function formatEventName(eventName, appName) {
1490
+ var _a;
1491
+ if (!isIframeSandbox(appName) && (formatEventList.includes(eventName) ||
1492
+ ((eventName === 'popstate' || eventName === 'hashchange') && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.useMemoryRouter)))) {
1493
+ return `${eventName}-${appName}`;
1494
+ }
1495
+ return eventName;
1496
+ }
1497
+ /**
1498
+ * update dom tree of target dom
1499
+ * @param container target dom
1500
+ * @param appName app name
1501
+ */
1502
+ function patchElementTree(container, appName) {
1503
+ const children = Array.from(container.children);
1504
+ children.length && children.forEach((child) => {
1505
+ patchElementTree(child, appName);
1506
+ });
1507
+ for (const child of children) {
1508
+ updateElementInfo(child, appName);
1509
+ }
1510
+ }
1511
+ /**
1512
+ * rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
1513
+ * @param node target node
1514
+ * @param appName app name
1515
+ * @returns target node
1516
+ */
1517
+ function updateElementInfo(node, appName) {
1518
+ var _a, _b;
1519
+ const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
1520
+ if (proxyWindow && isNode(node) && !node.__MICRO_APP_NAME__) {
1521
+ // TODO: 测试baseURI和ownerDocument在with沙箱中是否正确
1522
+ rawDefineProperties(node, {
1523
+ baseURI: {
1524
+ configurable: true,
1525
+ get: () => proxyWindow.location.href,
1526
+ },
1527
+ ownerDocument: {
1528
+ configurable: true,
1529
+ get: () => proxyWindow.document,
1530
+ },
1531
+ __MICRO_APP_NAME__: {
1532
+ configurable: true,
1533
+ writable: true,
1534
+ value: appName,
1535
+ },
1536
+ });
1537
+ }
1538
+ return node;
1539
+ }
1440
1540
 
1441
1541
  // Record element and map element
1442
1542
  const dynamicElementInMicroAppMap = new WeakMap();
@@ -1447,7 +1547,7 @@ const dynamicElementInMicroAppMap = new WeakMap();
1447
1547
  * @param app app
1448
1548
  */
1449
1549
  function handleNewNode(parent, child, app) {
1450
- if (child instanceof HTMLStyleElement) {
1550
+ if (isStyleElement(child)) {
1451
1551
  if (child.hasAttribute('exclude')) {
1452
1552
  const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
1453
1553
  dynamicElementInMicroAppMap.set(child, replaceComment);
@@ -1458,7 +1558,7 @@ function handleNewNode(parent, child, app) {
1458
1558
  }
1459
1559
  return child;
1460
1560
  }
1461
- else if (child instanceof HTMLLinkElement) {
1561
+ else if (isLinkElement(child)) {
1462
1562
  if (child.hasAttribute('exclude') || checkExcludeUrl(child.getAttribute('href'), app.name)) {
1463
1563
  const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
1464
1564
  dynamicElementInMicroAppMap.set(child, linkReplaceComment);
@@ -1483,7 +1583,7 @@ function handleNewNode(parent, child, app) {
1483
1583
  }
1484
1584
  return child;
1485
1585
  }
1486
- else if (child instanceof HTMLScriptElement) {
1586
+ else if (isScriptElement(child)) {
1487
1587
  if (child.src &&
1488
1588
  isFunction(microApp.options.excludeAssetFilter) &&
1489
1589
  microApp.options.excludeAssetFilter(child.src)) {
@@ -1513,17 +1613,20 @@ function handleNewNode(parent, child, app) {
1513
1613
  * @param passiveChild second param of insertBefore and replaceChild
1514
1614
  */
1515
1615
  function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
1516
- const hijackParent = getHijackParent(parent, app);
1616
+ const hijackParent = getHijackParent(parent, targetChild, app);
1517
1617
  /**
1518
1618
  * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
1519
1619
  * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
1520
1620
  */
1521
1621
  if (hijackParent) {
1522
1622
  /**
1623
+ * Adapter for
1523
1624
  * WARNING:
1524
1625
  * Verifying that the parentNode of the targetChild points to document.body will cause other problems ?
1525
1626
  */
1526
- if (hijackParent.tagName === 'MICRO-APP-BODY' && rawMethod !== globalEnv.rawRemoveChild) {
1627
+ if (!isIframeSandbox(app.name) &&
1628
+ hijackParent.tagName === 'MICRO-APP-BODY' &&
1629
+ rawMethod !== globalEnv.rawRemoveChild) {
1527
1630
  const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
1528
1631
  if (!descriptor || descriptor.configurable) {
1529
1632
  rawDefineProperty(targetChild, 'parentNode', {
@@ -1553,7 +1656,7 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
1553
1656
  return targetChild;
1554
1657
  }
1555
1658
  if ((process.env.NODE_ENV !== 'production') &&
1556
- targetChild instanceof HTMLIFrameElement &&
1659
+ isIFrameElement(targetChild) &&
1557
1660
  rawMethod === globalEnv.rawAppendChild) {
1558
1661
  fixReactHMRConflict(app);
1559
1662
  }
@@ -1562,13 +1665,20 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
1562
1665
  return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
1563
1666
  }
1564
1667
  // head/body map to micro-app-head/micro-app-body
1565
- function getHijackParent(node, app) {
1566
- var _a, _b;
1567
- if (node === document.head) {
1568
- return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
1569
- }
1570
- if (node === document.body) {
1571
- return (_b = app === null || app === void 0 ? void 0 : app.container) === null || _b === void 0 ? void 0 : _b.querySelector('micro-app-body');
1668
+ function getHijackParent(parent, targetChild, app) {
1669
+ if (app) {
1670
+ if (parent === document.head) {
1671
+ if (app.iframe && isScriptElement(targetChild)) {
1672
+ return app.sandBox.microHead;
1673
+ }
1674
+ return app.querySelector('micro-app-head');
1675
+ }
1676
+ if (parent === document.body || parent === document.body.parentNode) {
1677
+ if (app.iframe && isScriptElement(targetChild)) {
1678
+ return app.sandBox.microBody;
1679
+ }
1680
+ return app.querySelector('micro-app-body');
1681
+ }
1572
1682
  }
1573
1683
  return null;
1574
1684
  }
@@ -1596,8 +1706,9 @@ function getMappingNode(node) {
1596
1706
  function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1597
1707
  const currentAppName = getCurrentAppName();
1598
1708
  if (isNode(newChild) &&
1709
+ !newChild.__PURE_ELEMENT__ &&
1599
1710
  (newChild.__MICRO_APP_NAME__ ||
1600
- (currentAppName && !newChild.__PURE_ELEMENT__))) {
1711
+ currentAppName)) {
1601
1712
  newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
1602
1713
  const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
1603
1714
  if (app === null || app === void 0 ? void 0 : app.container) {
@@ -1625,10 +1736,10 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1625
1736
  const app = appInstanceMap.get(currentAppName);
1626
1737
  if (app === null || app === void 0 ? void 0 : app.container) {
1627
1738
  if (parent === document.head) {
1628
- return rawMethod.call(app.container.querySelector('micro-app-head'), newChild);
1739
+ return rawMethod.call(app.querySelector('micro-app-head'), newChild);
1629
1740
  }
1630
1741
  else if (parent === document.body) {
1631
- return rawMethod.call(app.container.querySelector('micro-app-body'), newChild);
1742
+ return rawMethod.call(app.querySelector('micro-app-body'), newChild);
1632
1743
  }
1633
1744
  }
1634
1745
  }
@@ -1639,7 +1750,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1639
1750
  /**
1640
1751
  * Rewrite element prototype method
1641
1752
  */
1642
- function patchElementPrototypeMethods() {
1753
+ function patchElementAndDocument() {
1643
1754
  patchDocument();
1644
1755
  // prototype methods of add element👇
1645
1756
  Element.prototype.appendChild = function appendChild(newChild) {
@@ -1688,6 +1799,71 @@ function patchElementPrototypeMethods() {
1688
1799
  this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
1689
1800
  return clonedNode;
1690
1801
  };
1802
+ function getQueryTarget(node) {
1803
+ const currentAppName = getCurrentAppName();
1804
+ if ((node === document.body || node === document.head) && currentAppName) {
1805
+ const app = appInstanceMap.get(currentAppName);
1806
+ if (app === null || app === void 0 ? void 0 : app.container) {
1807
+ if (node === document.body) {
1808
+ return app.querySelector('micro-app-body');
1809
+ }
1810
+ else if (node === document.head) {
1811
+ return app.querySelector('micro-app-head');
1812
+ }
1813
+ }
1814
+ }
1815
+ return null;
1816
+ }
1817
+ Element.prototype.querySelector = function querySelector(selectors) {
1818
+ var _a;
1819
+ const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
1820
+ return globalEnv.rawElementQuerySelector.call(target, selectors);
1821
+ };
1822
+ Element.prototype.querySelectorAll = function querySelectorAll(selectors) {
1823
+ var _a;
1824
+ const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
1825
+ return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
1826
+ };
1827
+ rawDefineProperty(Element.prototype, 'innerHTML', {
1828
+ configurable: true,
1829
+ enumerable: true,
1830
+ get() {
1831
+ return globalEnv.rawInnerHTMLDesc.get.call(this);
1832
+ },
1833
+ set(code) {
1834
+ globalEnv.rawInnerHTMLDesc.set.call(this, code);
1835
+ const currentAppName = getCurrentAppName();
1836
+ Array.from(this.children).forEach((child) => {
1837
+ if (isElement(child) && currentAppName) {
1838
+ child.__MICRO_APP_NAME__ = currentAppName;
1839
+ }
1840
+ });
1841
+ }
1842
+ });
1843
+ // Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
1844
+ // rawDefineProperty(Node.prototype, 'parentNode', {
1845
+ // configurable: true,
1846
+ // enumerable: true,
1847
+ // get () {
1848
+ // const result = globalEnv.rawParentNodeDesc.get.call(this)
1849
+ // /**
1850
+ // * If parentNode is <micro-app-body>, return rawDocument.body
1851
+ // * Scenes:
1852
+ // * 1. element-ui@2/lib/utils/vue-popper.js
1853
+ // * if (this.popperElm.parentNode === document.body) ...
1854
+ // * WARNING:
1855
+ // * Will it cause other problems ?
1856
+ // * e.g. target.parentNode.remove(target)
1857
+ // * BUG:
1858
+ // * 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again )
1859
+ // */
1860
+ // if (result?.tagName === 'MICRO-APP-BODY' && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
1861
+ // return globalEnv.rawDocument.body
1862
+ // }
1863
+ // return result
1864
+ // },
1865
+ // set: undefined,
1866
+ // })
1691
1867
  }
1692
1868
  /**
1693
1869
  * Mark the newly created element in the micro application
@@ -1721,7 +1897,7 @@ function patchDocument() {
1721
1897
  };
1722
1898
  // query element👇
1723
1899
  function querySelector(selectors) {
1724
- var _a, _b, _c, _d;
1900
+ var _a, _b, _c;
1725
1901
  const _this = getBindTarget(this);
1726
1902
  const currentAppName = getCurrentAppName();
1727
1903
  if (!currentAppName ||
@@ -1732,10 +1908,10 @@ function patchDocument() {
1732
1908
  rawDocument !== _this) {
1733
1909
  return globalEnv.rawQuerySelector.call(_this, selectors);
1734
1910
  }
1735
- return (_d = (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.container) === null || _c === void 0 ? void 0 : _c.querySelector(selectors)) !== null && _d !== void 0 ? _d : null;
1911
+ return (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.querySelector(selectors)) !== null && _c !== void 0 ? _c : null;
1736
1912
  }
1737
1913
  function querySelectorAll(selectors) {
1738
- var _a, _b, _c, _d;
1914
+ var _a, _b, _c;
1739
1915
  const _this = getBindTarget(this);
1740
1916
  const currentAppName = getCurrentAppName();
1741
1917
  if (!currentAppName ||
@@ -1745,7 +1921,7 @@ function patchDocument() {
1745
1921
  rawDocument !== _this) {
1746
1922
  return globalEnv.rawQuerySelectorAll.call(_this, selectors);
1747
1923
  }
1748
- return (_d = (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.container) === null || _c === void 0 ? void 0 : _c.querySelectorAll(selectors)) !== null && _d !== void 0 ? _d : [];
1924
+ return (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.querySelectorAll(selectors)) !== null && _c !== void 0 ? _c : [];
1749
1925
  }
1750
1926
  rawRootDocument.prototype.querySelector = querySelector;
1751
1927
  rawRootDocument.prototype.querySelectorAll = querySelectorAll;
@@ -1833,7 +2009,7 @@ function patchSetAttribute() {
1833
2009
  const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
1834
2010
  if (appName &&
1835
2011
  appInstanceMap.has(appName) &&
1836
- (((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
2012
+ (((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
1837
2013
  (key === 'href' && /^link$/i.test(this.tagName)))) {
1838
2014
  const app = appInstanceMap.get(appName);
1839
2015
  value = CompletionPath(value, app.url);
@@ -1855,7 +2031,7 @@ function releasePatchDocument() {
1855
2031
  rawRootDocument.prototype.getElementsByName = globalEnv.rawGetElementsByName;
1856
2032
  }
1857
2033
  // release patch
1858
- function releasePatches() {
2034
+ function releasePatchElementAndDocument() {
1859
2035
  removeDomScope();
1860
2036
  releasePatchDocument();
1861
2037
  Element.prototype.appendChild = globalEnv.rawAppendChild;
@@ -1865,6 +2041,9 @@ function releasePatches() {
1865
2041
  Element.prototype.append = globalEnv.rawAppend;
1866
2042
  Element.prototype.prepend = globalEnv.rawPrepend;
1867
2043
  Element.prototype.cloneNode = globalEnv.rawCloneNode;
2044
+ Element.prototype.querySelector = globalEnv.rawElementQuerySelector;
2045
+ Element.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
2046
+ rawDefineProperty(Element.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
1868
2047
  }
1869
2048
  // exec when last child unmount
1870
2049
  function releasePatchSetAttribute() {
@@ -1883,16 +2062,21 @@ function rejectMicroAppStyle() {
1883
2062
  }
1884
2063
  }
1885
2064
 
1886
- const globalEnv = {};
2065
+ const globalEnv = {
2066
+ // mark current application as base application
2067
+ __MICRO_APP_BASE_APPLICATION__: true,
2068
+ // active sandbox count
2069
+ activeSandbox: 0,
2070
+ };
1887
2071
  /**
1888
2072
  * Note loop nesting
1889
2073
  * Only prototype or unique values can be put here
1890
2074
  */
1891
2075
  function initGlobalEnv() {
1892
2076
  if (isBrowser) {
1893
- const rawWindow = Function('return window')();
1894
- const rawDocument = Function('return document')();
1895
- const rawRootDocument = Function('return Document')();
2077
+ const rawWindow = window.rawWindow || Function('return window')();
2078
+ const rawDocument = window.rawDocument || Function('return document')();
2079
+ const rawRootDocument = rawWindow.Document || Function('return Document')();
1896
2080
  const supportModuleScript = isSupportModuleScript();
1897
2081
  /**
1898
2082
  * save patch raw methods
@@ -1906,9 +2090,14 @@ function initGlobalEnv() {
1906
2090
  const rawAppend = Element.prototype.append;
1907
2091
  const rawPrepend = Element.prototype.prepend;
1908
2092
  const rawCloneNode = Element.prototype.cloneNode;
2093
+ const rawElementQuerySelector = Element.prototype.querySelector;
2094
+ const rawElementQuerySelectorAll = Element.prototype.querySelectorAll;
2095
+ const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(Element.prototype, 'innerHTML');
2096
+ const rawParentNodeDesc = Object.getOwnPropertyDescriptor(Node.prototype, 'parentNode');
1909
2097
  const rawCreateElement = rawRootDocument.prototype.createElement;
1910
2098
  const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
1911
2099
  const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
2100
+ const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
1912
2101
  const rawQuerySelector = rawRootDocument.prototype.querySelector;
1913
2102
  const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
1914
2103
  const rawGetElementById = rawRootDocument.prototype.getElementById;
@@ -1926,18 +2115,19 @@ function initGlobalEnv() {
1926
2115
  * save effect raw methods
1927
2116
  * pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
1928
2117
  */
1929
- const rawWindowAddEventListener = rawWindow.addEventListener;
1930
- const rawWindowRemoveEventListener = rawWindow.removeEventListener;
1931
2118
  const rawSetInterval = rawWindow.setInterval;
1932
2119
  const rawSetTimeout = rawWindow.setTimeout;
1933
2120
  const rawClearInterval = rawWindow.clearInterval;
1934
2121
  const rawClearTimeout = rawWindow.clearTimeout;
1935
2122
  const rawPushState = rawWindow.history.pushState;
1936
2123
  const rawReplaceState = rawWindow.history.replaceState;
2124
+ const rawWindowAddEventListener = rawWindow.addEventListener;
2125
+ const rawWindowRemoveEventListener = rawWindow.removeEventListener;
1937
2126
  const rawDocumentAddEventListener = rawDocument.addEventListener;
1938
2127
  const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
1939
- // mark current application as base application
1940
- window.__MICRO_APP_BASE_APPLICATION__ = true;
2128
+ // TODO: 统一使用 EventTarget 去掉上面四个
2129
+ const rawAddEventListener = EventTarget.prototype.addEventListener;
2130
+ const rawRemoveEventListener = EventTarget.prototype.removeEventListener;
1941
2131
  assign(globalEnv, {
1942
2132
  // common global vars
1943
2133
  rawWindow,
@@ -1953,9 +2143,14 @@ function initGlobalEnv() {
1953
2143
  rawAppend,
1954
2144
  rawPrepend,
1955
2145
  rawCloneNode,
2146
+ rawElementQuerySelector,
2147
+ rawElementQuerySelectorAll,
2148
+ rawInnerHTMLDesc,
2149
+ rawParentNodeDesc,
1956
2150
  rawCreateElement,
1957
2151
  rawCreateElementNS,
1958
2152
  rawCreateDocumentFragment,
2153
+ rawCreateTextNode,
1959
2154
  rawQuerySelector,
1960
2155
  rawQuerySelectorAll,
1961
2156
  rawGetElementById,
@@ -1974,6 +2169,8 @@ function initGlobalEnv() {
1974
2169
  rawDocumentRemoveEventListener,
1975
2170
  rawPushState,
1976
2171
  rawReplaceState,
2172
+ rawAddEventListener,
2173
+ rawRemoveEventListener,
1977
2174
  });
1978
2175
  // global effect
1979
2176
  rejectMicroAppStyle();
@@ -1983,7 +2180,7 @@ function initGlobalEnv() {
1983
2180
  const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
1984
2181
  // whether use type='module' script
1985
2182
  function isTypeModule(app, scriptInfo) {
1986
- return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.esmodule);
2183
+ return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
1987
2184
  }
1988
2185
  // special script element
1989
2186
  function isSpecialScript(app, scriptInfo) {
@@ -2002,11 +2199,17 @@ function isInlineMode(app, scriptInfo) {
2002
2199
  return (app.inline ||
2003
2200
  scriptInfo.appSpace[app.name].inline ||
2004
2201
  isTypeModule(app, scriptInfo) ||
2005
- isSpecialScript(app, scriptInfo));
2202
+ isSpecialScript(app, scriptInfo) ||
2203
+ app.iframe);
2204
+ }
2205
+ // TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
2206
+ function getEffectWindow(app) {
2207
+ return app.iframe ? app.sandBox.microAppWindow : globalEnv.rawWindow;
2006
2208
  }
2007
2209
  // Convert string code to function
2008
- function code2Function(code) {
2009
- return new Function(code);
2210
+ function code2Function(app, code) {
2211
+ const targetWindow = getEffectWindow(app);
2212
+ return new targetWindow.Function(code);
2010
2213
  }
2011
2214
  /**
2012
2215
  * If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
@@ -2014,10 +2217,10 @@ function code2Function(code) {
2014
2217
  * @param scriptInfo scriptInfo of current address
2015
2218
  * @param currentCode pure code of current address
2016
2219
  */
2017
- function getExistParseResult(appName, scriptInfo, currentCode) {
2220
+ function getExistParseResult(app, scriptInfo, currentCode) {
2018
2221
  const appSpace = scriptInfo.appSpace;
2019
2222
  for (const item in appSpace) {
2020
- if (item !== appName) {
2223
+ if (item !== app.name) {
2021
2224
  const appSpaceData = appSpace[item];
2022
2225
  if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
2023
2226
  return appSpaceData.parsedFunction;
@@ -2030,7 +2233,7 @@ function getExistParseResult(appName, scriptInfo, currentCode) {
2030
2233
  * @returns parsedFunction
2031
2234
  */
2032
2235
  function getParsedFunction(app, scriptInfo, parsedCode) {
2033
- return getExistParseResult(app.name, scriptInfo, parsedCode) || code2Function(parsedCode);
2236
+ return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
2034
2237
  }
2035
2238
  // Prevent randomly created strings from repeating
2036
2239
  function getUniqueNonceSrc() {
@@ -2054,6 +2257,9 @@ function setConvertScriptAttr(convertScript, attrs) {
2054
2257
  function isWrapInSandBox(app, scriptInfo) {
2055
2258
  return app.useSandbox && !isTypeModule(app, scriptInfo);
2056
2259
  }
2260
+ function getSandboxType(app, scriptInfo) {
2261
+ return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
2262
+ }
2057
2263
  /**
2058
2264
  * Extract script elements
2059
2265
  * @param script script element
@@ -2062,6 +2268,7 @@ function isWrapInSandBox(app, scriptInfo) {
2062
2268
  * @param isDynamic dynamic insert
2063
2269
  */
2064
2270
  function extractScriptElement(script, parent, app, isDynamic = false) {
2271
+ var _a;
2065
2272
  let replaceComment = null;
2066
2273
  let src = script.getAttribute('src');
2067
2274
  if (src)
@@ -2073,6 +2280,10 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
2073
2280
  !scriptTypes.includes(script.type)) ||
2074
2281
  script.hasAttribute('ignore') ||
2075
2282
  checkIgnoreUrl(src, app.name)) {
2283
+ // 配置为忽略的脚本,清空 rawDocument.currentScript,避免被忽略的脚本内获取 currentScript 出错
2284
+ if ((_a = globalEnv.rawDocument) === null || _a === void 0 ? void 0 : _a.currentScript) {
2285
+ delete globalEnv.rawDocument.currentScript;
2286
+ }
2076
2287
  return null;
2077
2288
  }
2078
2289
  else if ((globalEnv.supportModuleScript && script.noModule) ||
@@ -2268,13 +2479,13 @@ function fetchScriptSuccess(address, scriptInfo, code, app) {
2268
2479
  */
2269
2480
  if (!appSpaceData.parsedCode) {
2270
2481
  appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
2271
- appSpaceData.wrapInSandBox = isWrapInSandBox(app, scriptInfo);
2482
+ appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
2272
2483
  if (!isInlineMode(app, scriptInfo)) {
2273
2484
  try {
2274
2485
  appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
2275
2486
  }
2276
2487
  catch (err) {
2277
- logWarn('Something went wrong while handling preloaded resources', app.name, '\n', err);
2488
+ logError('Something went wrong while handling preloaded resources', app.name, '\n', err);
2278
2489
  }
2279
2490
  }
2280
2491
  }
@@ -2295,7 +2506,8 @@ function execScripts(app, initHook) {
2295
2506
  const appSpaceData = scriptInfo.appSpace[app.name];
2296
2507
  // Notice the second render
2297
2508
  if (appSpaceData.defer || appSpaceData.async) {
2298
- if (scriptInfo.isExternal && !scriptInfo.code) {
2509
+ // TODO: defer和module彻底分开,不要混在一起
2510
+ if (scriptInfo.isExternal && !scriptInfo.code && !(app.iframe && appSpaceData.module)) {
2299
2511
  deferScriptPromise.push(fetchSource(address, app.name));
2300
2512
  }
2301
2513
  else {
@@ -2320,7 +2532,7 @@ function execScripts(app, initHook) {
2320
2532
  logError(err, app.name);
2321
2533
  }, () => {
2322
2534
  deferScriptInfo.forEach(([address, scriptInfo]) => {
2323
- if (scriptInfo.code) {
2535
+ if (isString(scriptInfo.code)) {
2324
2536
  injectFiberTask(fiberScriptTasks, () => {
2325
2537
  runScript(address, app, scriptInfo, initHook);
2326
2538
  !isTypeModule(app, scriptInfo) && initHook(false);
@@ -2364,20 +2576,19 @@ function execScripts(app, initHook) {
2364
2576
  * @param callback callback of module script
2365
2577
  */
2366
2578
  function runScript(address, app, scriptInfo, callback, replaceElement) {
2367
- var _a;
2368
2579
  try {
2369
2580
  actionsBeforeRunScript(app);
2370
2581
  const appSpaceData = scriptInfo.appSpace[app.name];
2371
- const wrapInSandBox = isWrapInSandBox(app, scriptInfo);
2582
+ const sandboxType = getSandboxType(app, scriptInfo);
2372
2583
  /**
2373
2584
  * NOTE:
2374
2585
  * 1. plugins and wrapCode will only be executed once
2375
2586
  * 2. if parsedCode not exist, parsedFunction is not exist
2376
2587
  * 3. if parsedCode exist, parsedFunction does not necessarily exist
2377
2588
  */
2378
- if (!appSpaceData.parsedCode || appSpaceData.wrapInSandBox !== wrapInSandBox) {
2589
+ if (!appSpaceData.parsedCode || appSpaceData.sandboxType !== sandboxType) {
2379
2590
  appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
2380
- appSpaceData.wrapInSandBox = wrapInSandBox;
2591
+ appSpaceData.sandboxType = sandboxType;
2381
2592
  appSpaceData.parsedFunction = null;
2382
2593
  }
2383
2594
  if (isInlineMode(app, scriptInfo)) {
@@ -2385,7 +2596,8 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
2385
2596
  runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
2386
2597
  if (!replaceElement) {
2387
2598
  // TEST IGNORE
2388
- (_a = app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-body').appendChild(scriptElement);
2599
+ const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
2600
+ parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
2389
2601
  }
2390
2602
  }
2391
2603
  else {
@@ -2417,7 +2629,7 @@ function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
2417
2629
  runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
2418
2630
  !isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
2419
2631
  };
2420
- if (scriptInfo.code) {
2632
+ if (scriptInfo.code || (app.iframe && scriptInfo.appSpace[app.name].module)) {
2421
2633
  defer(runDynamicScript);
2422
2634
  }
2423
2635
  else {
@@ -2464,6 +2676,9 @@ function runCode2InlineScript(address, code, module, scriptElement, attrs, callb
2464
2676
  scriptElement.setAttribute('type', 'module');
2465
2677
  if (callback) {
2466
2678
  callback.moduleCount && callback.moduleCount--;
2679
+ /**
2680
+ * module script will execute onload method only after it insert to document/iframe
2681
+ */
2467
2682
  scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
2468
2683
  }
2469
2684
  }
@@ -2478,7 +2693,7 @@ function runParsedFunction(app, scriptInfo) {
2478
2693
  if (!appSpaceData.parsedFunction) {
2479
2694
  appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
2480
2695
  }
2481
- appSpaceData.parsedFunction.call(window);
2696
+ appSpaceData.parsedFunction.call(getEffectWindow(app));
2482
2697
  }
2483
2698
  /**
2484
2699
  * bind js scope
@@ -2487,12 +2702,12 @@ function runParsedFunction(app, scriptInfo) {
2487
2702
  * @param scriptInfo source script info
2488
2703
  */
2489
2704
  function bindScope(address, app, code, scriptInfo) {
2490
- // TODO: cache
2705
+ // TODO: 1、cache 2、esm code is null
2491
2706
  if (isPlainObject(microApp.options.plugins)) {
2492
2707
  code = usePlugins(address, code, app.name, microApp.options.plugins);
2493
2708
  }
2494
2709
  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__);`;
2710
+ 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
2711
  }
2497
2712
  return code;
2498
2713
  }
@@ -2555,7 +2770,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2555
2770
  flatChildren(child, app, microAppHead, fiberStyleTasks);
2556
2771
  });
2557
2772
  for (const dom of children) {
2558
- if (dom instanceof HTMLLinkElement) {
2773
+ if (isLinkElement(dom)) {
2559
2774
  if (dom.hasAttribute('exclude') || checkExcludeUrl(dom.getAttribute('href'), app.name)) {
2560
2775
  parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
2561
2776
  }
@@ -2566,7 +2781,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2566
2781
  dom.setAttribute('href', CompletionPath(dom.getAttribute('href'), app.url));
2567
2782
  }
2568
2783
  }
2569
- else if (dom instanceof HTMLStyleElement) {
2784
+ else if (isStyleElement(dom)) {
2570
2785
  if (dom.hasAttribute('exclude')) {
2571
2786
  parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
2572
2787
  }
@@ -2574,10 +2789,10 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2574
2789
  injectFiberTask(fiberStyleTasks, () => scopedCSS(dom, app));
2575
2790
  }
2576
2791
  }
2577
- else if (dom instanceof HTMLScriptElement) {
2792
+ else if (isScriptElement(dom)) {
2578
2793
  extractScriptElement(dom, parent, app);
2579
2794
  }
2580
- else if (dom instanceof HTMLImageElement && dom.hasAttribute('src')) {
2795
+ else if (isImageElement(dom) && dom.hasAttribute('src')) {
2581
2796
  dom.setAttribute('src', CompletionPath(dom.getAttribute('src'), app.url));
2582
2797
  }
2583
2798
  /**
@@ -2600,8 +2815,8 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2600
2815
  */
2601
2816
  function extractSourceDom(htmlStr, app) {
2602
2817
  const wrapElement = getWrapElement(htmlStr);
2603
- const microAppHead = wrapElement.querySelector('micro-app-head');
2604
- const microAppBody = wrapElement.querySelector('micro-app-body');
2818
+ const microAppHead = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-head');
2819
+ const microAppBody = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-body');
2605
2820
  if (!microAppHead || !microAppBody) {
2606
2821
  const msg = `element ${microAppHead ? 'body' : 'head'} is missing`;
2607
2822
  app.onerror(new Error(msg));
@@ -2802,7 +3017,7 @@ const eventCenter = new EventCenter();
2802
3017
  * @param appName app.name
2803
3018
  * @param fromBaseApp is from base app
2804
3019
  */
2805
- function formatEventName(appName, fromBaseApp) {
3020
+ function createEventName(appName, fromBaseApp) {
2806
3021
  if (!isString(appName) || !appName)
2807
3022
  return '';
2808
3023
  return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`;
@@ -2881,7 +3096,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2881
3096
  * @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
2882
3097
  */
2883
3098
  addDataListener(appName, cb, autoTrigger) {
2884
- eventCenter.on(formatEventName(formatAppName(appName), false), cb, autoTrigger);
3099
+ eventCenter.on(createEventName(formatAppName(appName), false), cb, autoTrigger);
2885
3100
  }
2886
3101
  /**
2887
3102
  * remove listener
@@ -2889,7 +3104,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2889
3104
  * @param cb listener
2890
3105
  */
2891
3106
  removeDataListener(appName, cb) {
2892
- isFunction(cb) && eventCenter.off(formatEventName(formatAppName(appName), false), cb);
3107
+ isFunction(cb) && eventCenter.off(createEventName(formatAppName(appName), false), cb);
2893
3108
  }
2894
3109
  /**
2895
3110
  * get data from micro app or base app
@@ -2897,7 +3112,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2897
3112
  * @param fromBaseApp whether get data from base app, default is false
2898
3113
  */
2899
3114
  getData(appName, fromBaseApp = false) {
2900
- return eventCenter.getData(formatEventName(formatAppName(appName), fromBaseApp));
3115
+ return eventCenter.getData(createEventName(formatAppName(appName), fromBaseApp));
2901
3116
  }
2902
3117
  /**
2903
3118
  * Dispatch data to the specified micro app
@@ -2905,7 +3120,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2905
3120
  * @param data data
2906
3121
  */
2907
3122
  setData(appName, data, nextStep, force) {
2908
- eventCenter.dispatch(formatEventName(formatAppName(appName), true), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
3123
+ eventCenter.dispatch(createEventName(formatAppName(appName), true), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
2909
3124
  }
2910
3125
  forceSetData(appName, data, nextStep) {
2911
3126
  this.setData(appName, data, nextStep, true);
@@ -2916,14 +3131,14 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2916
3131
  * @param fromBaseApp whether clear data from child app, default is true
2917
3132
  */
2918
3133
  clearData(appName, fromBaseApp = true) {
2919
- eventCenter.clearData(formatEventName(formatAppName(appName), fromBaseApp));
3134
+ eventCenter.clearData(createEventName(formatAppName(appName), fromBaseApp));
2920
3135
  }
2921
3136
  /**
2922
3137
  * clear all listener for specified micro app
2923
3138
  * @param appName app.name
2924
3139
  */
2925
3140
  clearDataListener(appName) {
2926
- eventCenter.off(formatEventName(formatAppName(appName), false));
3141
+ eventCenter.off(createEventName(formatAppName(appName), false));
2927
3142
  }
2928
3143
  }
2929
3144
  // Event center for sub app
@@ -2940,20 +3155,20 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2940
3155
  */
2941
3156
  addDataListener(cb, autoTrigger) {
2942
3157
  cb.__AUTO_TRIGGER__ = autoTrigger;
2943
- eventCenter.on(formatEventName(this.appName, true), cb, autoTrigger);
3158
+ eventCenter.on(createEventName(this.appName, true), cb, autoTrigger);
2944
3159
  }
2945
3160
  /**
2946
3161
  * remove listener
2947
3162
  * @param cb listener
2948
3163
  */
2949
3164
  removeDataListener(cb) {
2950
- isFunction(cb) && eventCenter.off(formatEventName(this.appName, true), cb);
3165
+ isFunction(cb) && eventCenter.off(createEventName(this.appName, true), cb);
2951
3166
  }
2952
3167
  /**
2953
3168
  * get data from base app
2954
3169
  */
2955
3170
  getData(fromBaseApp = true) {
2956
- return eventCenter.getData(formatEventName(this.appName, fromBaseApp));
3171
+ return eventCenter.getData(createEventName(this.appName, fromBaseApp));
2957
3172
  }
2958
3173
  /**
2959
3174
  * dispatch data to base app
@@ -2961,12 +3176,12 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2961
3176
  */
2962
3177
  dispatch(data, nextStep, force) {
2963
3178
  removeDomScope();
2964
- eventCenter.dispatch(formatEventName(this.appName, false), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force, () => {
3179
+ eventCenter.dispatch(createEventName(this.appName, false), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force, () => {
2965
3180
  const app = appInstanceMap.get(this.appName);
2966
3181
  if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
2967
3182
  const event = new CustomEvent('datachange', {
2968
3183
  detail: {
2969
- data: eventCenter.getData(formatEventName(this.appName, false))
3184
+ data: eventCenter.getData(createEventName(this.appName, false))
2970
3185
  }
2971
3186
  });
2972
3187
  getRootContainer(app.container).dispatchEvent(event);
@@ -2981,33 +3196,35 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2981
3196
  * @param fromBaseApp whether clear data from base app, default is false
2982
3197
  */
2983
3198
  clearData(fromBaseApp = false) {
2984
- eventCenter.clearData(formatEventName(this.appName, fromBaseApp));
3199
+ eventCenter.clearData(createEventName(this.appName, fromBaseApp));
2985
3200
  }
2986
3201
  /**
2987
3202
  * clear all listeners
2988
3203
  */
2989
3204
  clearDataListener() {
2990
- eventCenter.off(formatEventName(this.appName, true));
3205
+ eventCenter.off(createEventName(this.appName, true));
2991
3206
  }
2992
3207
  }
2993
3208
  /**
2994
3209
  * Record UMD function before exec umdHookMount
2995
- * @param microAppEventCenter
3210
+ * NOTE: record maybe call twice when unmount prerender, keep-alive app manually with umd mode
3211
+ * @param microAppEventCenter instance of EventCenterForMicroApp
2996
3212
  */
2997
3213
  function recordDataCenterSnapshot(microAppEventCenter) {
2998
- const appName = microAppEventCenter.appName;
2999
- microAppEventCenter.umdDataListeners = { global: new Set(), normal: new Set() };
3000
- const globalEventInfo = eventCenter.eventList.get('global');
3001
- if (globalEventInfo) {
3002
- for (const cb of globalEventInfo.callbacks) {
3003
- if (appName === cb.__APP_NAME__) {
3004
- microAppEventCenter.umdDataListeners.global.add(cb);
3214
+ if (microAppEventCenter && !microAppEventCenter.umdDataListeners) {
3215
+ microAppEventCenter.umdDataListeners = { global: new Set(), normal: new Set() };
3216
+ const globalEventInfo = eventCenter.eventList.get('global');
3217
+ if (globalEventInfo) {
3218
+ for (const cb of globalEventInfo.callbacks) {
3219
+ if (microAppEventCenter.appName === cb.__APP_NAME__) {
3220
+ microAppEventCenter.umdDataListeners.global.add(cb);
3221
+ }
3005
3222
  }
3006
3223
  }
3007
- }
3008
- const subAppEventInfo = eventCenter.eventList.get(formatEventName(appName, true));
3009
- if (subAppEventInfo) {
3010
- microAppEventCenter.umdDataListeners.normal = new Set(subAppEventInfo.callbacks);
3224
+ const subAppEventInfo = eventCenter.eventList.get(createEventName(microAppEventCenter.appName, true));
3225
+ if (subAppEventInfo) {
3226
+ microAppEventCenter.umdDataListeners.normal = new Set(subAppEventInfo.callbacks);
3227
+ }
3011
3228
  }
3012
3229
  }
3013
3230
  /**
@@ -3015,13 +3232,24 @@ function recordDataCenterSnapshot(microAppEventCenter) {
3015
3232
  * @param microAppEventCenter instance of EventCenterForMicroApp
3016
3233
  */
3017
3234
  function rebuildDataCenterSnapshot(microAppEventCenter) {
3018
- for (const cb of microAppEventCenter.umdDataListeners.global) {
3019
- microAppEventCenter.addGlobalDataListener(cb, cb.__AUTO_TRIGGER__);
3020
- }
3021
- for (const cb of microAppEventCenter.umdDataListeners.normal) {
3022
- microAppEventCenter.addDataListener(cb, cb.__AUTO_TRIGGER__);
3235
+ // in withSandbox preRender mode with module script, umdDataListeners maybe undefined
3236
+ if (microAppEventCenter === null || microAppEventCenter === void 0 ? void 0 : microAppEventCenter.umdDataListeners) {
3237
+ for (const cb of microAppEventCenter.umdDataListeners.global) {
3238
+ microAppEventCenter.addGlobalDataListener(cb, cb.__AUTO_TRIGGER__);
3239
+ }
3240
+ for (const cb of microAppEventCenter.umdDataListeners.normal) {
3241
+ microAppEventCenter.addDataListener(cb, cb.__AUTO_TRIGGER__);
3242
+ }
3243
+ resetDataCenterSnapshot(microAppEventCenter);
3023
3244
  }
3024
3245
  }
3246
+ /**
3247
+ * delete umdDataListeners from microAppEventCenter
3248
+ * @param microAppEventCenter instance of EventCenterForMicroApp
3249
+ */
3250
+ function resetDataCenterSnapshot(microAppEventCenter) {
3251
+ delete microAppEventCenter.umdDataListeners;
3252
+ }
3025
3253
 
3026
3254
  // 管理 app 的单例
3027
3255
  class AppManager {
@@ -3084,12 +3312,12 @@ function isConstructorFunction(value) {
3084
3312
  return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
3085
3313
  }
3086
3314
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
3087
- function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
3088
- const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
3089
- if (value[cacheKey])
3090
- return value[cacheKey];
3091
- if (!isConstructorFunction(value) && !isBoundedFunction(value)) {
3092
- const bindRawObjectValue = value.bind(rawObject);
3315
+ function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
3316
+ if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
3317
+ const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
3318
+ if (value[cacheKey])
3319
+ return value[cacheKey];
3320
+ const bindRawObjectValue = value.bind(rawTarget);
3093
3321
  for (const key in value) {
3094
3322
  bindRawObjectValue[key] = value[key];
3095
3323
  }
@@ -3106,21 +3334,6 @@ function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
3106
3334
  return value;
3107
3335
  }
3108
3336
 
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
3337
  // document.onclick binding list, the binding function of each application is unique
3125
3338
  const documentClickListMap = new Map();
3126
3339
  let hasRewriteDocumentOnClick = false;
@@ -3231,7 +3444,7 @@ function effect(appName, microAppWindow) {
3231
3444
  const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
3232
3445
  // listener may be null, e.g test-passive
3233
3446
  microAppWindow.addEventListener = function (type, listener, options) {
3234
- type = formatEventName$1(type, appName);
3447
+ type = formatEventName(type, appName);
3235
3448
  const listenerList = eventListenerMap.get(type);
3236
3449
  if (listenerList) {
3237
3450
  listenerList.add(listener);
@@ -3243,7 +3456,7 @@ function effect(appName, microAppWindow) {
3243
3456
  rawWindowAddEventListener.call(rawWindow, type, listener, options);
3244
3457
  };
3245
3458
  microAppWindow.removeEventListener = function (type, listener, options) {
3246
- type = formatEventName$1(type, appName);
3459
+ type = formatEventName(type, appName);
3247
3460
  const listenerList = eventListenerMap.get(type);
3248
3461
  if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
3249
3462
  listenerList.delete(listener);
@@ -3270,39 +3483,32 @@ function effect(appName, microAppWindow) {
3270
3483
  };
3271
3484
  const sstWindowListenerMap = new Map();
3272
3485
  const sstDocumentListenerMap = new Map();
3273
- let sstIntervalIdMap = new Map();
3274
- let sstTimeoutIdMap = new Map();
3275
3486
  let sstOnClickHandler;
3276
- const clearSnapshotData = () => {
3487
+ // reset snapshot data
3488
+ const reset = () => {
3277
3489
  sstWindowListenerMap.clear();
3278
- sstIntervalIdMap.clear();
3279
- sstTimeoutIdMap.clear();
3280
3490
  sstDocumentListenerMap.clear();
3281
3491
  sstOnClickHandler = null;
3282
3492
  };
3283
3493
  /**
3284
- * record event and timer
3285
- * Scenes:
3286
- * 1. exec umdMountHook in umd mode
3287
- * 2. hidden keep-alive app
3288
- * 3. after init prerender app
3494
+ * NOTE:
3495
+ * 1. about timer(events & properties should record & rebuild at all modes, exclude default mode)
3496
+ * 2. record maybe call twice when unmount prerender, keep-alive app manually with umd mode
3497
+ * 4 modes: default-mode、umd-mode、prerender、keep-alive
3498
+ * Solution:
3499
+ * 1. default-mode(normal): clear events & timers, not record & rebuild anything
3500
+ * 2. umd-mode(normal): not clear timers, record & rebuild events
3501
+ * 3. prerender/keep-alive(default, umd): not clear timers, record & rebuild events
3289
3502
  */
3290
- const recordEffect = () => {
3503
+ const record = () => {
3291
3504
  // record window event
3292
3505
  eventListenerMap.forEach((listenerList, type) => {
3293
3506
  if (listenerList.size) {
3294
3507
  sstWindowListenerMap.set(type, new Set(listenerList));
3295
3508
  }
3296
3509
  });
3297
- // record timers
3298
- if (intervalIdMap.size) {
3299
- sstIntervalIdMap = new Map(intervalIdMap);
3300
- }
3301
- if (timeoutIdMap.size) {
3302
- sstTimeoutIdMap = new Map(timeoutIdMap);
3303
- }
3304
3510
  // record onclick handler
3305
- sstOnClickHandler = documentClickListMap.get(appName);
3511
+ sstOnClickHandler = sstOnClickHandler || documentClickListMap.get(appName);
3306
3512
  // record document event
3307
3513
  const documentAppListenersMap = documentEventListenerMap.get(appName);
3308
3514
  if (documentAppListenersMap) {
@@ -3314,20 +3520,13 @@ function effect(appName, microAppWindow) {
3314
3520
  }
3315
3521
  };
3316
3522
  // rebuild event and timer before remount app
3317
- const rebuildEffect = () => {
3523
+ const rebuild = () => {
3318
3524
  // rebuild window event
3319
3525
  sstWindowListenerMap.forEach((listenerList, type) => {
3320
3526
  for (const listener of listenerList) {
3321
3527
  microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
3322
3528
  }
3323
3529
  });
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
3530
  // rebuild onclick event
3332
3531
  sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
3333
3532
  /**
@@ -3341,10 +3540,10 @@ function effect(appName, microAppWindow) {
3341
3540
  }
3342
3541
  });
3343
3542
  removeDomScope();
3344
- clearSnapshotData();
3543
+ reset();
3345
3544
  };
3346
3545
  // release all event listener & interval & timeout when unmount app
3347
- const releaseEffect = () => {
3546
+ const release = ({ umdMode, isPrerender, keepAlive, destroy }) => {
3348
3547
  // Clear window binding events
3349
3548
  if (eventListenerMap.size) {
3350
3549
  eventListenerMap.forEach((listenerList, type) => {
@@ -3354,17 +3553,15 @@ function effect(appName, microAppWindow) {
3354
3553
  });
3355
3554
  eventListenerMap.clear();
3356
3555
  }
3357
- // Clear timers
3358
- if (intervalIdMap.size) {
3556
+ // default mode(not keep-alive or isPrerender)
3557
+ if ((!umdMode && !keepAlive && !isPrerender) || destroy) {
3359
3558
  intervalIdMap.forEach((_, intervalId) => {
3360
3559
  rawClearInterval.call(rawWindow, intervalId);
3361
3560
  });
3362
- intervalIdMap.clear();
3363
- }
3364
- if (timeoutIdMap.size) {
3365
3561
  timeoutIdMap.forEach((_, timeoutId) => {
3366
3562
  rawClearTimeout.call(rawWindow, timeoutId);
3367
3563
  });
3564
+ intervalIdMap.clear();
3368
3565
  timeoutIdMap.clear();
3369
3566
  }
3370
3567
  // Clear the function bound by micro application through document.onclick
@@ -3381,9 +3578,10 @@ function effect(appName, microAppWindow) {
3381
3578
  }
3382
3579
  };
3383
3580
  return {
3384
- recordEffect,
3385
- rebuildEffect,
3386
- releaseEffect,
3581
+ reset,
3582
+ record,
3583
+ rebuild,
3584
+ release,
3387
3585
  };
3388
3586
  }
3389
3587
 
@@ -3578,25 +3776,29 @@ function addHistoryListener(appName) {
3578
3776
  * 1. unmount app & hidden keep-alive app will not receive popstate event
3579
3777
  * 2. filter out onlyForBrowser
3580
3778
  */
3581
- if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName) &&
3779
+ if (getActiveApps({
3780
+ excludeHiddenApp: true,
3781
+ excludePreRender: true,
3782
+ }).includes(appName) &&
3582
3783
  !e.onlyForBrowser) {
3583
3784
  const microPath = getMicroPathFromURL(appName);
3584
3785
  const app = appInstanceMap.get(appName);
3585
3786
  const proxyWindow = app.sandBox.proxyWindow;
3787
+ const microAppWindow = app.sandBox.microAppWindow;
3586
3788
  let isHashChange = false;
3587
3789
  // for hashChangeEvent
3588
3790
  const oldHref = proxyWindow.location.href;
3589
3791
  // Do not attach micro state to url when microPath is empty
3590
3792
  if (microPath) {
3591
3793
  const oldHash = proxyWindow.location.hash;
3592
- updateMicroLocation(appName, microPath, proxyWindow.location);
3794
+ updateMicroLocation(appName, microPath, microAppWindow.location);
3593
3795
  isHashChange = proxyWindow.location.hash !== oldHash;
3594
3796
  }
3595
3797
  // dispatch formatted popStateEvent to child
3596
- dispatchPopStateEventToMicroApp(appName, proxyWindow);
3798
+ dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
3597
3799
  // dispatch formatted hashChangeEvent to child when hash change
3598
3800
  if (isHashChange)
3599
- dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref);
3801
+ dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
3600
3802
  // clear element scope before trigger event of next app
3601
3803
  removeDomScope();
3602
3804
  }
@@ -3612,10 +3814,9 @@ function addHistoryListener(appName) {
3612
3814
  * @param proxyWindow sandbox window
3613
3815
  * @param eventState history.state
3614
3816
  */
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) });
3817
+ function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
3618
3818
  /**
3819
+ * TODO: test
3619
3820
  * angular14 takes e.type as type judgment
3620
3821
  * when e.type is popstate-appName popstate event will be invalid
3621
3822
  */
@@ -3625,7 +3826,14 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
3625
3826
  // configurable: true,
3626
3827
  // enumerable: true,
3627
3828
  // })
3628
- globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
3829
+ // create PopStateEvent named popstate-appName with sub app state
3830
+ const newPopStateEvent = new PopStateEvent(formatEventName('popstate', appName), { state: getMicroState(appName) });
3831
+ if (isIframeSandbox(appName)) {
3832
+ microAppWindow.dispatchEvent(newPopStateEvent);
3833
+ }
3834
+ else {
3835
+ globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
3836
+ }
3629
3837
  // call function window.onpopstate if it exists
3630
3838
  isFunction(proxyWindow.onpopstate) && proxyWindow.onpopstate(newPopStateEvent);
3631
3839
  }
@@ -3635,12 +3843,17 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
3635
3843
  * @param proxyWindow sandbox window
3636
3844
  * @param oldHref old href
3637
3845
  */
3638
- function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
3639
- const newHashChangeEvent = new HashChangeEvent(formatEventName$1('hashchange', appName), {
3846
+ function dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref) {
3847
+ const newHashChangeEvent = new HashChangeEvent(formatEventName('hashchange', appName), {
3640
3848
  newURL: proxyWindow.location.href,
3641
3849
  oldURL: oldHref,
3642
3850
  });
3643
- globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
3851
+ if (isIframeSandbox(appName)) {
3852
+ microAppWindow.dispatchEvent(newHashChangeEvent);
3853
+ }
3854
+ else {
3855
+ globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
3856
+ }
3644
3857
  // call function window.onhashchange if it exists
3645
3858
  isFunction(proxyWindow.onhashchange) && proxyWindow.onhashchange(newHashChangeEvent);
3646
3859
  }
@@ -3692,22 +3905,26 @@ function createMicroHistory(appName, microLocation) {
3692
3905
  const rawHistory = globalEnv.rawWindow.history;
3693
3906
  function getMicroHistoryMethod(methodName) {
3694
3907
  return function (...rests) {
3908
+ var _a, _b, _c;
3909
+ // TODO: 测试iframe的URL兼容isURL的情况
3695
3910
  if (isString(rests[2]) || isURL(rests[2])) {
3696
3911
  const targetLocation = createURL(rests[2], microLocation.href);
3697
- if (targetLocation.origin === microLocation.origin) {
3698
- navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
3699
- const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3700
- if (targetFullPath !== microLocation.fullPath) {
3701
- updateMicroLocation(appName, targetFullPath, microLocation);
3702
- }
3703
- return void 0;
3912
+ const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3913
+ navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
3914
+ if (targetFullPath !== microLocation.fullPath) {
3915
+ updateMicroLocation(appName, targetFullPath, microLocation);
3704
3916
  }
3917
+ (_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
3918
+ }
3919
+ else {
3920
+ nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
3705
3921
  }
3706
- nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
3707
3922
  };
3708
3923
  }
3709
3924
  const pushState = getMicroHistoryMethod('pushState');
3710
3925
  const replaceState = getMicroHistoryMethod('replaceState');
3926
+ if (isIframeSandbox(appName))
3927
+ return { pushState, replaceState };
3711
3928
  return new Proxy(rawHistory, {
3712
3929
  get(target, key) {
3713
3930
  if (key === 'state') {
@@ -3719,8 +3936,7 @@ function createMicroHistory(appName, microLocation) {
3719
3936
  else if (key === 'replaceState') {
3720
3937
  return replaceState;
3721
3938
  }
3722
- const rawValue = Reflect.get(target, key);
3723
- return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'HISTORY') : rawValue;
3939
+ return bindFunctionToRawTarget(Reflect.get(target, key), target, 'HISTORY');
3724
3940
  },
3725
3941
  set(target, key, value) {
3726
3942
  Reflect.set(target, key, value);
@@ -3765,6 +3981,7 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
3765
3981
  if (isEffectiveApp(appName)) {
3766
3982
  const rawLocation = globalEnv.rawWindow.location;
3767
3983
  const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
3984
+ // oldHref use for hashChangeEvent of base app
3768
3985
  const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
3769
3986
  // navigate with native history method
3770
3987
  nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
@@ -3873,8 +4090,9 @@ function createRouterApi() {
3873
4090
  const microLocation = app.sandBox.proxyWindow.location;
3874
4091
  const targetLocation = createURL(to.path, microLocation.href);
3875
4092
  // Only get path data, even if the origin is different from microApp
4093
+ const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
3876
4094
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3877
- if (microLocation.fullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
4095
+ if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
3878
4096
  const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
3879
4097
  navigateWithRawHistory(appName, methodName, targetLocation, to.state);
3880
4098
  }
@@ -4023,8 +4241,7 @@ function createRouterApi() {
4023
4241
  baseRouterProxy = new Proxy(baseRouter, {
4024
4242
  get(target, key) {
4025
4243
  removeDomScope();
4026
- const rawValue = Reflect.get(target, key);
4027
- return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'BASEROUTER') : rawValue;
4244
+ return bindFunctionToRawTarget(Reflect.get(target, key), target, 'BASEROUTER');
4028
4245
  },
4029
4246
  set(target, key, value) {
4030
4247
  Reflect.set(target, key, value);
@@ -4052,9 +4269,118 @@ function createRouterApi() {
4052
4269
  }
4053
4270
  const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
4054
4271
 
4055
- const shadowLocationKeys = ['href', 'pathname', 'search', 'hash'];
4272
+ const escape2RawWindowKeys = [
4273
+ 'getComputedStyle',
4274
+ 'visualViewport',
4275
+ 'matchMedia',
4276
+ // 'DOMParser',
4277
+ 'ResizeObserver',
4278
+ 'IntersectionObserver',
4279
+ ];
4280
+ const escape2RawWindowRegExpKeys = [
4281
+ /animationFrame$/i,
4282
+ /mutationObserver$/i,
4283
+ /height$|width$/i,
4284
+ /offset$/i,
4285
+ // /event$/i,
4286
+ /^screen/i,
4287
+ /^scroll/i,
4288
+ /X$|Y$/,
4289
+ ];
4290
+ const scopeIframeWindowOnEvent = [
4291
+ 'onload',
4292
+ 'onbeforeunload',
4293
+ 'onunload',
4294
+ ];
4295
+ const scopeIframeWindowEvent = [
4296
+ 'hashchange',
4297
+ 'popstate',
4298
+ 'DOMContentLoaded',
4299
+ 'load',
4300
+ 'beforeunload',
4301
+ 'unload',
4302
+ ].concat(microAppCustomEvent);
4303
+ const scopeIframeDocumentEvent = [
4304
+ 'DOMContentLoaded',
4305
+ 'readystatechange',
4306
+ ];
4307
+ const scopeIframeDocumentOnEvent = [
4308
+ 'onreadystatechange',
4309
+ ];
4310
+ const uniqueDocumentElement = [
4311
+ 'body',
4312
+ 'head',
4313
+ 'html',
4314
+ 'title',
4315
+ ];
4316
+ const hijackMicroLocationKeys = [
4317
+ 'host',
4318
+ 'hostname',
4319
+ 'port',
4320
+ 'protocol',
4321
+ 'origin',
4322
+ ];
4323
+ // 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
4324
+ const proxy2RawDocOrShadowKeys = [
4325
+ 'childElementCount',
4326
+ 'children',
4327
+ 'firstElementChild',
4328
+ 'firstChild',
4329
+ 'lastElementChild',
4330
+ 'activeElement',
4331
+ 'fullscreenElement',
4332
+ 'pictureInPictureElement',
4333
+ 'pointerLockElement',
4334
+ 'styleSheets',
4335
+ ];
4336
+ // 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
4337
+ const proxy2RawDocOrShadowMethods = [
4338
+ 'append',
4339
+ 'contains',
4340
+ 'replaceChildren',
4341
+ 'getSelection',
4342
+ 'elementFromPoint',
4343
+ 'elementsFromPoint',
4344
+ 'getAnimations',
4345
+ ];
4346
+ // 直接代理到原生document上 (属性)
4347
+ const proxy2RawDocumentKeys = [
4348
+ 'characterSet',
4349
+ 'compatMode',
4350
+ 'contentType',
4351
+ 'designMode',
4352
+ 'dir',
4353
+ 'doctype',
4354
+ 'embeds',
4355
+ 'fullscreenEnabled',
4356
+ 'hidden',
4357
+ 'implementation',
4358
+ 'lastModified',
4359
+ 'pictureInPictureEnabled',
4360
+ 'plugins',
4361
+ 'readyState',
4362
+ 'referrer',
4363
+ 'visibilityState',
4364
+ 'fonts',
4365
+ ];
4366
+ // 直接代理到原生document上 (方法)
4367
+ const proxy2RawDocumentMethods = [
4368
+ 'execCommand',
4369
+ 'createRange',
4370
+ 'exitFullscreen',
4371
+ 'exitPictureInPicture',
4372
+ 'getElementsByTagNameNS',
4373
+ 'hasFocus',
4374
+ 'prepend',
4375
+ ];
4376
+ const globalPropertyList = [
4377
+ 'window',
4378
+ 'self',
4379
+ 'globalThis'
4380
+ ];
4381
+
4056
4382
  // origin is readonly, so we ignore when updateMicroLocation
4057
- const locationKeys = [...shadowLocationKeys, 'host', 'hostname', 'port', 'protocol', 'search'];
4383
+ const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
4058
4384
  // origin, fullPath is necessary for guardLocation
4059
4385
  const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
4060
4386
  /**
@@ -4062,19 +4388,27 @@ const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
4062
4388
  * MDN https://developer.mozilla.org/en-US/docs/Web/API/Location
4063
4389
  * @param appName app name
4064
4390
  * @param url app url
4391
+ * @param microAppWindow iframeWindow, iframe only
4392
+ * @param childStaticLocation real child location info, iframe only
4393
+ * @param browserHost host of browser, iframe only
4394
+ * @param childHost host of child app, iframe only
4065
4395
  */
4066
- function createMicroLocation(appName, url) {
4396
+ function createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
4067
4397
  const rawWindow = globalEnv.rawWindow;
4068
4398
  const rawLocation = rawWindow.location;
4069
- // microLocation is the location of child app, it is globally unique
4070
- const microLocation = createURL(url);
4071
- // shadowLocation is the current location information (href, pathname, search, hash)
4072
- const shadowLocation = {
4073
- href: microLocation.href,
4074
- pathname: microLocation.pathname,
4075
- search: microLocation.search,
4076
- hash: microLocation.hash,
4077
- };
4399
+ const isIframe = !!microAppWindow;
4400
+ /**
4401
+ * withLocation is microLocation for with sandbox
4402
+ * it is globally unique for child app
4403
+ */
4404
+ const withLocation = createURL(url);
4405
+ /**
4406
+ * In iframe, jump through raw iframeLocation will cause microAppWindow.location reset
4407
+ * So we get location dynamically
4408
+ */
4409
+ function getTarget() {
4410
+ return isIframe ? microAppWindow.location : withLocation;
4411
+ }
4078
4412
  /**
4079
4413
  * Common handler for href, assign, replace
4080
4414
  * It is mainly used to deal with special scenes about hash
@@ -4082,10 +4416,10 @@ function createMicroLocation(appName, url) {
4082
4416
  * @param methodName pushState/replaceState
4083
4417
  * @returns origin value or formatted value
4084
4418
  */
4085
- const commonHandler = (value, methodName) => {
4086
- const targetLocation = createURL(value, microLocation.href);
4419
+ function commonHandler(value, methodName) {
4420
+ const targetLocation = createURL(value, proxyLocation.href);
4087
4421
  // Even if the origin is the same, developers still have the possibility of want to jump to a new page
4088
- if (targetLocation.origin === microLocation.origin) {
4422
+ if (targetLocation.origin === proxyLocation.origin) {
4089
4423
  const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
4090
4424
  /**
4091
4425
  * change hash with location.href will not trigger the browser reload
@@ -4094,10 +4428,10 @@ function createMicroLocation(appName, url) {
4094
4428
  * 1. if child app only change hash, it should not trigger browser reload
4095
4429
  * 2. if address is same and has hash, it should not add route stack
4096
4430
  */
4097
- if (targetLocation.pathname === shadowLocation.pathname &&
4098
- targetLocation.search === shadowLocation.search) {
4431
+ if (targetLocation.pathname === proxyLocation.pathname &&
4432
+ targetLocation.search === proxyLocation.search) {
4099
4433
  let oldHref = null;
4100
- if (targetLocation.hash !== shadowLocation.hash) {
4434
+ if (targetLocation.hash !== proxyLocation.hash) {
4101
4435
  if (setMicroPathResult.isAttach2Hash)
4102
4436
  oldHref = rawLocation.href;
4103
4437
  nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
@@ -4106,35 +4440,22 @@ function createMicroLocation(appName, url) {
4106
4440
  dispatchNativeEvent(appName, false, oldHref);
4107
4441
  }
4108
4442
  else {
4109
- rawReload();
4443
+ reload();
4110
4444
  }
4111
4445
  return void 0;
4112
4446
  /**
4113
4447
  * when baseApp is hash router, address change of child can not reload browser
4114
- * so we imitate behavior of browser (reload)
4448
+ * so we imitate behavior of browser (reload) manually
4115
4449
  */
4116
4450
  }
4117
4451
  else if (setMicroPathResult.isAttach2Hash) {
4118
4452
  nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
4119
- rawReload();
4453
+ reload();
4120
4454
  return void 0;
4121
4455
  }
4122
- value = setMicroPathResult.fullPath;
4456
+ return setMicroPathResult.fullPath;
4123
4457
  }
4124
4458
  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
4459
  }
4139
4460
  /**
4140
4461
  * common handler for location.pathname & location.search
@@ -4144,7 +4465,7 @@ function createMicroLocation(appName, url) {
4144
4465
  function handleForPathNameAndSearch(targetPath, key) {
4145
4466
  const targetLocation = createURL(targetPath, url);
4146
4467
  // When the browser url has a hash value, the same pathname/search will not refresh browser
4147
- if (targetLocation[key] === shadowLocation[key] && shadowLocation.hash) {
4468
+ if (targetLocation[key] === proxyLocation[key] && proxyLocation.hash) {
4148
4469
  // The href has not changed, not need to dispatch hashchange event
4149
4470
  dispatchNativeEvent(appName, false);
4150
4471
  }
@@ -4155,58 +4476,96 @@ function createMicroLocation(appName, url) {
4155
4476
  * pathname: /path ==> /path#hash, /path ==> /path?query
4156
4477
  * search: ?query ==> ?query#hash
4157
4478
  */
4158
- nativeHistoryNavigate(appName, targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
4159
- rawReload();
4479
+ nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
4480
+ reload();
4160
4481
  }
4161
4482
  }
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
4483
  const createLocationMethod = (locationMethodName) => {
4196
4484
  return function (value) {
4197
4485
  if (isEffectiveApp(appName)) {
4198
4486
  const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
4199
- if (targetPath)
4200
- rawLocation[locationMethodName](targetPath);
4487
+ if (targetPath) {
4488
+ // Same as href, complete targetPath with browser origin in vite env
4489
+ rawLocation[locationMethodName](createURL(targetPath, rawLocation.origin).href);
4490
+ }
4201
4491
  }
4202
4492
  };
4203
4493
  };
4204
- return assign(microLocation, {
4205
- assign: createLocationMethod('assign'),
4206
- replace: createLocationMethod('replace'),
4207
- reload: (forcedReload) => rawLocation.reload(forcedReload),
4208
- shadowLocation,
4494
+ const assign = createLocationMethod('assign');
4495
+ const replace = createLocationMethod('replace');
4496
+ const reload = (forcedReload) => rawLocation.reload(forcedReload);
4497
+ rawDefineProperty(getTarget(), 'fullPath', {
4498
+ enumerable: true,
4499
+ configurable: true,
4500
+ get: () => proxyLocation.pathname + proxyLocation.search + proxyLocation.hash,
4501
+ });
4502
+ /**
4503
+ * location.assign/replace is readonly, cannot be proxy, so we use empty object as proxy target
4504
+ */
4505
+ const proxyLocation = new Proxy({}, {
4506
+ get: (_, key) => {
4507
+ const target = getTarget();
4508
+ if (isIframe) {
4509
+ // host hostname port protocol
4510
+ if (hijackMicroLocationKeys.includes(key)) {
4511
+ return childStaticLocation[key];
4512
+ }
4513
+ if (key === 'href') {
4514
+ // do not use target, because target may be deleted
4515
+ return target[key].replace(browserHost, childHost);
4516
+ }
4517
+ }
4518
+ if (key === 'assign')
4519
+ return assign;
4520
+ if (key === 'replace')
4521
+ return replace;
4522
+ if (key === 'reload')
4523
+ return reload;
4524
+ if (key === 'self')
4525
+ return target;
4526
+ return bindFunctionToRawTarget(Reflect.get(target, key), target, 'LOCATION');
4527
+ },
4528
+ set: (_, key, value) => {
4529
+ if (isEffectiveApp(appName)) {
4530
+ const target = getTarget();
4531
+ if (key === 'href') {
4532
+ const targetPath = commonHandler(value, 'pushState');
4533
+ /**
4534
+ * In vite, targetPath without origin will be completed with child origin
4535
+ * So we use browser origin to complete targetPath to avoid this problem
4536
+ * But, why child app can affect browser jump?
4537
+ * Guess(need check):
4538
+ * 1. vite records the origin when init
4539
+ * 2. listen for browser jump and automatically complete the address
4540
+ */
4541
+ if (targetPath) {
4542
+ rawLocation.href = createURL(targetPath, rawLocation.origin).href;
4543
+ }
4544
+ }
4545
+ else if (key === 'pathname') {
4546
+ const targetPath = ('/' + value).replace(/^\/+/, '/') + proxyLocation.search + proxyLocation.hash;
4547
+ handleForPathNameAndSearch(targetPath, 'pathname');
4548
+ }
4549
+ else if (key === 'search') {
4550
+ const targetPath = proxyLocation.pathname + ('?' + value).replace(/^\?+/, '?') + proxyLocation.hash;
4551
+ handleForPathNameAndSearch(targetPath, 'search');
4552
+ }
4553
+ else if (key === 'hash') {
4554
+ const targetPath = proxyLocation.pathname + proxyLocation.search + ('#' + value).replace(/^#+/, '#');
4555
+ const targetLocation = createURL(targetPath, url);
4556
+ // The same hash will not trigger popStateEvent
4557
+ if (targetLocation.hash !== proxyLocation.hash) {
4558
+ navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
4559
+ }
4560
+ }
4561
+ else {
4562
+ Reflect.set(target, key, value);
4563
+ }
4564
+ }
4565
+ return true;
4566
+ },
4209
4567
  });
4568
+ return proxyLocation;
4210
4569
  }
4211
4570
  /**
4212
4571
  * create guardLocation by microLocation, used for router guard
@@ -4238,17 +4597,17 @@ function autoTriggerNavigationGuard(appName, microLocation) {
4238
4597
  * @param type auto prevent
4239
4598
  */
4240
4599
  function updateMicroLocation(appName, path, microLocation, type) {
4241
- const newLocation = createURL(path, microLocation.href);
4600
+ var _a;
4242
4601
  // record old values of microLocation to `from`
4243
4602
  const from = createGuardLocation(appName, microLocation);
4244
- for (const key of locationKeys) {
4245
- if (shadowLocationKeys.includes(key)) {
4246
- // reference of shadowLocation
4247
- microLocation.shadowLocation[key] = newLocation[key];
4248
- }
4249
- else {
4250
- // @ts-ignore reference of microLocation
4251
- microLocation[key] = newLocation[key];
4603
+ const newLocation = createURL(path, microLocation.href);
4604
+ if (isIframeSandbox(appName)) {
4605
+ const microAppWindow = appInstanceMap.get(appName).sandBox.microAppWindow;
4606
+ (_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
4607
+ }
4608
+ else {
4609
+ for (const key of locationKeys) {
4610
+ microLocation.self[key] = newLocation[key];
4252
4611
  }
4253
4612
  }
4254
4613
  // update latest values of microLocation to `to`
@@ -4426,8 +4785,8 @@ function useMicroEventSource() {
4426
4785
  }
4427
4786
 
4428
4787
  const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
4429
- const globalPropertyList = ['window', 'self', 'globalThis'];
4430
- class SandBox {
4788
+ const globalPropertyList$1 = ['window', 'self', 'globalThis'];
4789
+ class WithSandBox {
4431
4790
  constructor(appName, url) {
4432
4791
  /**
4433
4792
  * Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
@@ -4478,18 +4837,21 @@ class SandBox {
4478
4837
  this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
4479
4838
  }
4480
4839
  /**
4481
- * 1. Prevent the key deleted during sandBox.stop after rewrite
4482
- * 2. Umd mode will not delete any keys during sandBox.stop
4483
- * 3. It must not be umd mode when call sandbox.start at the first time
4840
+ * Target: Ensure default mode action exactly same to first time when render again
4841
+ * 1. The following globalKey maybe modified when render, reset them when render again in default mode
4842
+ * 2. Umd mode will not delete any keys during sandBox.stop, ignore umd mode
4843
+ * 3. When sandbox.start called for the first time, it must be the default mode
4484
4844
  */
4485
4845
  if (!umdMode) {
4486
4846
  this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
4487
4847
  }
4488
- if (++SandBox.activeCount === 1) {
4848
+ if (++globalEnv.activeSandbox === 1) {
4849
+ patchElementAndDocument();
4850
+ patchHistory();
4851
+ }
4852
+ if (++WithSandBox.activeCount === 1) {
4489
4853
  effectDocumentEvent();
4490
- patchElementPrototypeMethods();
4491
4854
  initEnvOfNestedApp();
4492
- patchHistory();
4493
4855
  }
4494
4856
  fixBabelPolyfill6();
4495
4857
  }
@@ -4498,28 +4860,25 @@ class SandBox {
4498
4860
  * close sandbox and perform some clean up actions
4499
4861
  * @param umdMode is umd mode
4500
4862
  * @param keepRouteState prevent reset route
4501
- * @param clearEventSource clear MicroEventSource when destroy
4863
+ * @param destroy completely destroy, delete cache resources
4502
4864
  * @param clearData clear data from base app
4503
4865
  */
4504
- stop({ umdMode, keepRouteState, clearEventSource, clearData, }) {
4866
+ stop({ umdMode, keepRouteState, destroy, clearData, }) {
4505
4867
  if (this.active) {
4506
- // clear global event, timeout, data listener
4507
- this.releaseGlobalEffect(clearData);
4868
+ this.recordAndReleaseEffect({ clearData, destroy }, !umdMode || destroy);
4508
4869
  if (this.removeHistoryListener) {
4509
4870
  this.clearRouteState(keepRouteState);
4510
4871
  // release listener of popstate
4511
4872
  this.removeHistoryListener();
4512
4873
  }
4513
- if (clearEventSource) {
4514
- clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
4515
- }
4516
4874
  /**
4517
4875
  * NOTE:
4518
4876
  * 1. injectedKeys and escapeKeys must be placed at the back
4519
4877
  * 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
4520
4878
  * 3. umd mode will not delete global keys
4521
4879
  */
4522
- if (!umdMode) {
4880
+ if (!umdMode || destroy) {
4881
+ clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
4523
4882
  this.injectedKeys.forEach((key) => {
4524
4883
  Reflect.deleteProperty(this.microAppWindow, key);
4525
4884
  });
@@ -4529,30 +4888,47 @@ class SandBox {
4529
4888
  });
4530
4889
  this.escapeKeys.clear();
4531
4890
  }
4532
- if (--SandBox.activeCount === 0) {
4533
- releaseEffectDocumentEvent();
4534
- releasePatches();
4891
+ if (--globalEnv.activeSandbox === 0) {
4892
+ releasePatchElementAndDocument();
4535
4893
  releasePatchHistory();
4536
4894
  }
4895
+ if (--WithSandBox.activeCount === 0) {
4896
+ releaseEffectDocumentEvent();
4897
+ }
4537
4898
  this.active = false;
4538
4899
  }
4539
4900
  }
4540
4901
  /**
4541
- * clear global event, timeout, data listener
4902
+ * Record global effect and then release (effect: global event, timeout, data listener)
4542
4903
  * Scenes:
4543
- * 1. unmount of normal/umd app
4904
+ * 1. unmount of default/umd app
4544
4905
  * 2. hidden keep-alive app
4545
4906
  * 3. after init prerender app
4546
- * @param clearData clear data from base app
4907
+ * @param options {
4908
+ * @param clearData clear data from base app
4909
+ * @param isPrerender is prerender app
4910
+ * @param keepAlive is keep-alive app
4911
+ * }
4912
+ * @param preventRecord prevent record effect events
4547
4913
  */
4548
- releaseGlobalEffect(clearData = false) {
4549
- this.effectController.releaseEffect();
4550
- this.microAppWindow.microApp.clearDataListener();
4551
- this.microAppWindow.microApp.clearGlobalDataListener();
4552
- if (clearData) {
4553
- microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
4554
- this.microAppWindow.microApp.clearData();
4914
+ recordAndReleaseEffect(options, preventRecord = false) {
4915
+ if (preventRecord) {
4916
+ this.resetEffectSnapshot();
4555
4917
  }
4918
+ else {
4919
+ this.recordEffectSnapshot();
4920
+ }
4921
+ this.releaseGlobalEffect(options);
4922
+ }
4923
+ /**
4924
+ * reset effect snapshot data in default mode or destroy
4925
+ * Scenes:
4926
+ * 1. unmount hidden keep-alive app manually
4927
+ * 2. unmount prerender app manually
4928
+ */
4929
+ resetEffectSnapshot() {
4930
+ this.effectController.reset();
4931
+ resetDataCenterSnapshot(this.microAppWindow.microApp);
4556
4932
  }
4557
4933
  /**
4558
4934
  * record umd snapshot before the first execution of umdHookMount
@@ -4563,7 +4939,7 @@ class SandBox {
4563
4939
  */
4564
4940
  recordEffectSnapshot() {
4565
4941
  // this.microAppWindow.__MICRO_APP_UMD_MODE__ = true
4566
- this.effectController.recordEffect();
4942
+ this.effectController.record();
4567
4943
  recordDataCenterSnapshot(this.microAppWindow.microApp);
4568
4944
  // this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
4569
4945
  // this.injectedKeys.forEach((key: PropertyKey) => {
@@ -4575,12 +4951,34 @@ class SandBox {
4575
4951
  // this.recordUmdInjectedValues!.forEach((value: unknown, key: PropertyKey) => {
4576
4952
  // Reflect.set(this.proxyWindow, key, value)
4577
4953
  // })
4578
- this.effectController.rebuildEffect();
4954
+ this.effectController.rebuild();
4579
4955
  rebuildDataCenterSnapshot(this.microAppWindow.microApp);
4580
4956
  }
4581
- // set __MICRO_APP_PRE_RENDER__ state
4582
- setPreRenderState(state) {
4583
- this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
4957
+ /**
4958
+ * clear global event, timeout, data listener
4959
+ * Scenes:
4960
+ * 1. unmount of default/umd app
4961
+ * 2. hidden keep-alive app
4962
+ * 3. after init prerender app
4963
+ * @param clearData clear data from base app
4964
+ * @param isPrerender is prerender app
4965
+ * @param keepAlive is keep-alive app
4966
+ * @param destroy completely destroy
4967
+ */
4968
+ releaseGlobalEffect({ clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
4969
+ var _a, _b, _c;
4970
+ this.effectController.release({
4971
+ umdMode: this.proxyWindow.__MICRO_APP_UMD_MODE__,
4972
+ isPrerender,
4973
+ keepAlive,
4974
+ destroy,
4975
+ });
4976
+ (_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
4977
+ (_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
4978
+ if (clearData) {
4979
+ microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
4980
+ (_c = this.microAppWindow.microApp) === null || _c === void 0 ? void 0 : _c.clearData();
4981
+ }
4584
4982
  }
4585
4983
  /**
4586
4984
  * get scopeProperties and escapeProperties from plugins & adapter
@@ -4613,7 +5011,6 @@ class SandBox {
4613
5011
  createProxyWindow(appName) {
4614
5012
  const rawWindow = globalEnv.rawWindow;
4615
5013
  const descriptorTargetMap = new Map();
4616
- // window.xxx will trigger proxy
4617
5014
  return new Proxy(this.microAppWindow, {
4618
5015
  get: (target, key) => {
4619
5016
  throttleDeferForSetAppName(appName);
@@ -4621,11 +5018,14 @@ class SandBox {
4621
5018
  (isString(key) && /^__MICRO_APP_/.test(key)) ||
4622
5019
  this.scopeProperties.includes(key))
4623
5020
  return Reflect.get(target, key);
4624
- const rawValue = Reflect.get(rawWindow, key);
4625
- return isFunction(rawValue) ? bindFunctionToRawObject(rawWindow, rawValue) : rawValue;
5021
+ return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
4626
5022
  },
4627
5023
  set: (target, key, value) => {
4628
5024
  if (this.active) {
5025
+ /**
5026
+ * TODO:
5027
+ * 1、location域名相同,子应用内部跳转时的处理
5028
+ */
4629
5029
  if (this.adapter.escapeSetterKeyList.includes(key)) {
4630
5030
  Reflect.set(rawWindow, key, value);
4631
5031
  }
@@ -4646,15 +5046,15 @@ class SandBox {
4646
5046
  this.injectedKeys.add(key);
4647
5047
  }
4648
5048
  else {
5049
+ !Reflect.has(target, key) && this.injectedKeys.add(key);
4649
5050
  Reflect.set(target, key, value);
4650
- this.injectedKeys.add(key);
4651
5051
  }
4652
5052
  if ((this.escapeProperties.includes(key) ||
4653
5053
  (this.adapter.staticEscapeProperties.includes(key) &&
4654
5054
  !Reflect.has(rawWindow, key))) &&
4655
5055
  !this.scopeProperties.includes(key)) {
5056
+ !Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
4656
5057
  Reflect.set(rawWindow, key, value);
4657
- this.escapeKeys.add(key);
4658
5058
  }
4659
5059
  }
4660
5060
  return true;
@@ -4702,6 +5102,13 @@ class SandBox {
4702
5102
  },
4703
5103
  });
4704
5104
  }
5105
+ // set __MICRO_APP_PRE_RENDER__ state
5106
+ setPreRenderState(state) {
5107
+ this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
5108
+ }
5109
+ markUmdMode(state) {
5110
+ this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
5111
+ }
4705
5112
  /**
4706
5113
  * inject global properties to microAppWindow
4707
5114
  * @param microAppWindow micro window
@@ -4716,6 +5123,7 @@ class SandBox {
4716
5123
  microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
4717
5124
  microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
4718
5125
  microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
5126
+ microAppWindow.__MICRO_APP_UMD_MODE__ = false;
4719
5127
  microAppWindow.rawWindow = globalEnv.rawWindow;
4720
5128
  microAppWindow.rawDocument = globalEnv.rawDocument;
4721
5129
  microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
@@ -4760,7 +5168,7 @@ class SandBox {
4760
5168
  }
4761
5169
  rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
4762
5170
  rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
4763
- globalPropertyList.forEach((key) => {
5171
+ globalPropertyList$1.forEach((key) => {
4764
5172
  rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
4765
5173
  });
4766
5174
  }
@@ -4890,16 +5298,32 @@ class SandBox {
4890
5298
  });
4891
5299
  }
4892
5300
  initRouteState(defaultPage) {
4893
- initRouteStateWithURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location, defaultPage);
5301
+ initRouteStateWithURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location, defaultPage);
4894
5302
  }
4895
5303
  clearRouteState(keepRouteState) {
4896
- clearRouteStateFromURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__, this.proxyWindow.location, keepRouteState);
5304
+ clearRouteStateFromURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow.location, keepRouteState);
4897
5305
  }
4898
5306
  setRouteInfoForKeepAliveApp() {
4899
- updateBrowserURLWithLocation(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location);
5307
+ updateBrowserURLWithLocation(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location);
4900
5308
  }
4901
5309
  removeRouteInfoForKeepAliveApp() {
4902
- removeStateAndPathFromBrowser(this.proxyWindow.__MICRO_APP_NAME__);
5310
+ removeStateAndPathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__);
5311
+ }
5312
+ /**
5313
+ * Format all html elements when init
5314
+ * @param container micro app container
5315
+ */
5316
+ patchStaticElement(container) {
5317
+ patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
5318
+ }
5319
+ /**
5320
+ * action before exec scripts when mount
5321
+ * Actions:
5322
+ * 1. patch static elements from html
5323
+ * @param container micro app container
5324
+ */
5325
+ actionBeforeExecScripts(container) {
5326
+ this.patchStaticElement(container);
4903
5327
  }
4904
5328
  /**
4905
5329
  * Create new document and Document
@@ -4922,8 +5346,7 @@ class SandBox {
4922
5346
  return 'ProxyDocument';
4923
5347
  if (key === 'defaultView')
4924
5348
  return this.proxyWindow;
4925
- const rawValue = Reflect.get(target, key);
4926
- return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
5349
+ return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
4927
5350
  },
4928
5351
  set: (target, key, value) => {
4929
5352
  /**
@@ -4960,8 +5383,7 @@ class SandBox {
4960
5383
  Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
4961
5384
  get(target, key) {
4962
5385
  throttleDeferForSetAppName(appName);
4963
- const rawValue = Reflect.get(target, key);
4964
- return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
5386
+ return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
4965
5387
  },
4966
5388
  set(target, key, value) {
4967
5389
  Reflect.set(target, key, value);
@@ -4974,13 +5396,993 @@ class SandBox {
4974
5396
  };
4975
5397
  }
4976
5398
  }
4977
- SandBox.activeCount = 0; // number of active sandbox
5399
+ WithSandBox.activeCount = 0; // number of active sandbox
4978
5400
 
4979
- function formatEventInfo(event, element) {
4980
- Object.defineProperties(event, {
4981
- currentTarget: {
4982
- get() {
4983
- return element;
5401
+ function patchIframeRoute(appName, microAppWindow, childFullPath) {
5402
+ const microHistory = microAppWindow.history;
5403
+ microAppWindow.rawReplaceState = microHistory.replaceState;
5404
+ assign(microHistory, createMicroHistory(appName, microAppWindow.location));
5405
+ // exec updateMicroLocation after patch microHistory
5406
+ updateMicroLocation(appName, childFullPath, microAppWindow.location, 'prevent');
5407
+ }
5408
+
5409
+ function patchIframeWindow(appName, microAppWindow) {
5410
+ const rawWindow = globalEnv.rawWindow;
5411
+ escape2RawWindowKeys.forEach((key) => {
5412
+ microAppWindow[key] = bindFunctionToRawTarget(rawWindow[key], rawWindow);
5413
+ });
5414
+ Object.getOwnPropertyNames(microAppWindow)
5415
+ .filter((key) => {
5416
+ escape2RawWindowRegExpKeys.some((reg) => {
5417
+ if (reg.test(key) && key in microAppWindow.parent) {
5418
+ if (isFunction(rawWindow[key])) {
5419
+ microAppWindow[key] = bindFunctionToRawTarget(rawWindow[key], rawWindow);
5420
+ }
5421
+ else {
5422
+ const { configurable, enumerable } = Object.getOwnPropertyDescriptor(microAppWindow, key) || {
5423
+ configurable: true,
5424
+ enumerable: true,
5425
+ };
5426
+ if (configurable) {
5427
+ rawDefineProperty(microAppWindow, key, {
5428
+ configurable,
5429
+ enumerable,
5430
+ get: () => rawWindow[key],
5431
+ set: (value) => { rawWindow[key] = value; },
5432
+ });
5433
+ }
5434
+ }
5435
+ return true;
5436
+ }
5437
+ return false;
5438
+ });
5439
+ return /^on/.test(key) && !scopeIframeWindowOnEvent.includes(key);
5440
+ })
5441
+ .forEach((eventName) => {
5442
+ const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microAppWindow, eventName) || {
5443
+ enumerable: true,
5444
+ writable: true,
5445
+ };
5446
+ try {
5447
+ /**
5448
+ * 如果设置了iframeWindow上的这些on事件,处理函数会设置到原生window上,但this会绑定到iframeWindow
5449
+ * 获取这些值,则直接从原生window上取
5450
+ * 总结:这些on事件全部都代理到原生window上
5451
+ *
5452
+ * 问题:
5453
+ * 1、如果子应用没有设置,基座设置了on事件,子应用触发事件是会不会执行基座的函数?
5454
+ * 比如 基座定义了 window.onpopstate,子应用执行跳转会不会触发基座的onpopstate函数?
5455
+ *
5456
+ * 2、如果基座已经定义了 window.onpopstate,子应用定义会不会覆盖基座的?
5457
+ * 现在的逻辑看来,是会覆盖的,那么问题1就是 肯定的
5458
+ * TODO: 一些特殊事件onpopstate、onhashchange不代理,放在scopeIframeWindowOnEvent中
5459
+ */
5460
+ rawDefineProperty(microAppWindow, eventName, {
5461
+ enumerable,
5462
+ configurable: true,
5463
+ get: () => rawWindow[eventName],
5464
+ set: (writable !== null && writable !== void 0 ? writable : !!set) ? (value) => { rawWindow[eventName] = isFunction(value) ? value.bind(microAppWindow) : value; }
5465
+ : undefined,
5466
+ });
5467
+ }
5468
+ catch (e) {
5469
+ logWarn(e, appName);
5470
+ }
5471
+ });
5472
+ return windowEffect(microAppWindow);
5473
+ }
5474
+ function windowEffect(microAppWindow) {
5475
+ const { rawWindow, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
5476
+ const eventListenerMap = new Map();
5477
+ const sstWindowListenerMap = new Map();
5478
+ function getEventTarget(type) {
5479
+ return scopeIframeWindowEvent.includes(type) ? microAppWindow : rawWindow;
5480
+ }
5481
+ microAppWindow.addEventListener = function (type, listener, options) {
5482
+ const listenerList = eventListenerMap.get(type);
5483
+ if (listenerList) {
5484
+ listenerList.add(listener);
5485
+ }
5486
+ else {
5487
+ eventListenerMap.set(type, new Set([listener]));
5488
+ }
5489
+ listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
5490
+ rawAddEventListener.call(getEventTarget(type), type, listener, options);
5491
+ };
5492
+ microAppWindow.removeEventListener = function (type, listener, options) {
5493
+ const listenerList = eventListenerMap.get(type);
5494
+ if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
5495
+ listenerList.delete(listener);
5496
+ }
5497
+ rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
5498
+ };
5499
+ const reset = () => {
5500
+ sstWindowListenerMap.clear();
5501
+ };
5502
+ /**
5503
+ * NOTE:
5504
+ * 1. about timer(events & properties should record & rebuild at all modes, exclude default mode)
5505
+ * 2. record maybe call twice when unmount prerender, keep-alive app manually with umd mode
5506
+ * 4 modes: default-mode、umd-mode、prerender、keep-alive
5507
+ * Solution:
5508
+ * 1. default-mode(normal): clear events & timers, not record & rebuild anything
5509
+ * 2. umd-mode(normal): not clear timers, record & rebuild events
5510
+ * 3. prerender/keep-alive(default, umd): not clear timers, record & rebuild events
5511
+ *
5512
+ * TODO: 现在的 清除、记录和恢复操作分散的太零散,sandbox、create_app中都有分散,将代码再优化一下,集中处理
5513
+ */
5514
+ const record = () => {
5515
+ // record window event
5516
+ eventListenerMap.forEach((listenerList, type) => {
5517
+ if (listenerList.size) {
5518
+ sstWindowListenerMap.set(type, new Set(listenerList));
5519
+ }
5520
+ });
5521
+ };
5522
+ // rebuild event and timer before remount app
5523
+ const rebuild = () => {
5524
+ // rebuild window event
5525
+ sstWindowListenerMap.forEach((listenerList, type) => {
5526
+ for (const listener of listenerList) {
5527
+ microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
5528
+ }
5529
+ });
5530
+ reset();
5531
+ };
5532
+ const release = () => {
5533
+ // Clear window binding events
5534
+ if (eventListenerMap.size) {
5535
+ eventListenerMap.forEach((listenerList, type) => {
5536
+ for (const listener of listenerList) {
5537
+ rawRemoveEventListener.call(getEventTarget(type), type, listener);
5538
+ }
5539
+ });
5540
+ eventListenerMap.clear();
5541
+ }
5542
+ };
5543
+ return {
5544
+ reset,
5545
+ record,
5546
+ rebuild,
5547
+ release,
5548
+ };
5549
+ }
5550
+
5551
+ /**
5552
+ * TODO:
5553
+ * 1、shadowDOM
5554
+ * 2、重构
5555
+ */
5556
+ function patchIframeDocument(appName, microAppWindow, proxyLocation) {
5557
+ patchDocumentPrototype(appName, microAppWindow);
5558
+ patchDocumentProperties(appName, microAppWindow, proxyLocation);
5559
+ return documentEffect(appName, microAppWindow);
5560
+ }
5561
+ function patchDocumentPrototype(appName, microAppWindow) {
5562
+ const rawDocument = globalEnv.rawDocument;
5563
+ const microRootDocument = microAppWindow.Document;
5564
+ const microDocument = microAppWindow.document;
5565
+ microRootDocument.prototype.createElement = function createElement(tagName, options) {
5566
+ const element = globalEnv.rawCreateElement.call(this, tagName, options);
5567
+ return updateElementInfo(element, appName);
5568
+ };
5569
+ microRootDocument.prototype.createTextNode = function createTextNode(data) {
5570
+ const element = globalEnv.rawCreateTextNode.call(this, data);
5571
+ return updateElementInfo(element, appName);
5572
+ };
5573
+ function getDefaultRawTarget(target) {
5574
+ return microDocument !== target ? target : rawDocument;
5575
+ }
5576
+ // query element👇
5577
+ function querySelector(selectors) {
5578
+ var _a, _b;
5579
+ if (isUniqueElement(selectors) ||
5580
+ microDocument !== this) {
5581
+ const _this = getDefaultRawTarget(this);
5582
+ return globalEnv.rawQuerySelector.call(_this, selectors);
5583
+ }
5584
+ return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
5585
+ }
5586
+ function querySelectorAll(selectors) {
5587
+ var _a, _b;
5588
+ if (isUniqueElement(selectors) ||
5589
+ microDocument !== this) {
5590
+ const _this = getDefaultRawTarget(this);
5591
+ return globalEnv.rawQuerySelectorAll.call(_this, selectors);
5592
+ }
5593
+ return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
5594
+ }
5595
+ microRootDocument.prototype.querySelector = querySelector;
5596
+ microRootDocument.prototype.querySelectorAll = querySelectorAll;
5597
+ microRootDocument.prototype.getElementById = function getElementById(key) {
5598
+ const _this = getDefaultRawTarget(this);
5599
+ if (isInvalidQuerySelectorKey(key)) {
5600
+ return globalEnv.rawGetElementById.call(_this, key);
5601
+ }
5602
+ try {
5603
+ return querySelector.call(this, `#${key}`);
5604
+ }
5605
+ catch (_a) {
5606
+ return globalEnv.rawGetElementById.call(_this, key);
5607
+ }
5608
+ };
5609
+ microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
5610
+ const _this = getDefaultRawTarget(this);
5611
+ if (isInvalidQuerySelectorKey(key)) {
5612
+ return globalEnv.rawGetElementsByClassName.call(_this, key);
5613
+ }
5614
+ try {
5615
+ return querySelectorAll.call(this, `.${key}`);
5616
+ }
5617
+ catch (_a) {
5618
+ return globalEnv.rawGetElementsByClassName.call(_this, key);
5619
+ }
5620
+ };
5621
+ microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
5622
+ var _a;
5623
+ const _this = getDefaultRawTarget(this);
5624
+ if (isUniqueElement(key) ||
5625
+ isInvalidQuerySelectorKey(key) ||
5626
+ (!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
5627
+ return globalEnv.rawGetElementsByTagName.call(_this, key);
5628
+ }
5629
+ try {
5630
+ return querySelectorAll.call(this, key);
5631
+ }
5632
+ catch (_b) {
5633
+ return globalEnv.rawGetElementsByTagName.call(_this, key);
5634
+ }
5635
+ };
5636
+ microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
5637
+ const _this = getDefaultRawTarget(this);
5638
+ if (isInvalidQuerySelectorKey(key)) {
5639
+ return globalEnv.rawGetElementsByName.call(_this, key);
5640
+ }
5641
+ try {
5642
+ return querySelectorAll.call(this, `[name=${key}]`);
5643
+ }
5644
+ catch (_a) {
5645
+ return globalEnv.rawGetElementsByName.call(_this, key);
5646
+ }
5647
+ };
5648
+ }
5649
+ function patchDocumentProperties(appName, microAppWindow, proxyLocation) {
5650
+ const rawDocument = globalEnv.rawDocument;
5651
+ const microRootDocument = microAppWindow.Document;
5652
+ const microDocument = microAppWindow.document;
5653
+ const getCommonDescriptor = (key, getter) => {
5654
+ const { enumerable } = Object.getOwnPropertyDescriptor(microRootDocument.prototype, key) || {
5655
+ enumerable: true,
5656
+ writable: true,
5657
+ };
5658
+ return {
5659
+ configurable: true,
5660
+ enumerable,
5661
+ get: getter,
5662
+ };
5663
+ };
5664
+ const createDescriptors = () => {
5665
+ const result = {};
5666
+ const descList = [
5667
+ ['documentURI', () => proxyLocation.href],
5668
+ ['URL', () => proxyLocation.href],
5669
+ ['documentElement', () => rawDocument.documentElement],
5670
+ ['scrollingElement', () => rawDocument.scrollingElement],
5671
+ ['forms', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'form')],
5672
+ ['images', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'img')],
5673
+ ['links', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'a')],
5674
+ ];
5675
+ descList.forEach((desc) => {
5676
+ result[desc[0]] = getCommonDescriptor(desc[0], desc[1]);
5677
+ });
5678
+ // TODO: shadowDOM
5679
+ proxy2RawDocOrShadowKeys.forEach((key) => {
5680
+ result[key] = getCommonDescriptor(key, () => rawDocument[key]);
5681
+ });
5682
+ // TODO: shadowDOM
5683
+ proxy2RawDocOrShadowMethods.forEach((key) => {
5684
+ result[key] = getCommonDescriptor(key, () => bindFunctionToRawTarget(rawDocument[key], rawDocument, 'DOCUMENT'));
5685
+ });
5686
+ proxy2RawDocumentKeys.forEach((key) => {
5687
+ result[key] = getCommonDescriptor(key, () => rawDocument[key]);
5688
+ });
5689
+ proxy2RawDocumentMethods.forEach((key) => {
5690
+ result[key] = getCommonDescriptor(key, () => bindFunctionToRawTarget(rawDocument[key], rawDocument, 'DOCUMENT'));
5691
+ });
5692
+ return result;
5693
+ };
5694
+ rawDefineProperties(microRootDocument.prototype, createDescriptors());
5695
+ // head, body, html, title
5696
+ uniqueDocumentElement.forEach((tagName) => {
5697
+ rawDefineProperty(microDocument, tagName, {
5698
+ enumerable: true,
5699
+ configurable: true,
5700
+ get: () => rawDocument[tagName],
5701
+ set: undefined,
5702
+ });
5703
+ });
5704
+ }
5705
+ function documentEffect(appName, microAppWindow) {
5706
+ const documentEventListenerMap = new Map();
5707
+ const sstDocumentListenerMap = new Map();
5708
+ let onClickHandler = null;
5709
+ let sstOnClickHandler = null;
5710
+ const microRootDocument = microAppWindow.Document;
5711
+ const microDocument = microAppWindow.document;
5712
+ const { rawDocument, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
5713
+ function getEventTarget(type, bindTarget) {
5714
+ return scopeIframeDocumentEvent.includes(type) ? bindTarget : rawDocument;
5715
+ }
5716
+ microRootDocument.prototype.addEventListener = function (type, listener, options) {
5717
+ const handler = isFunction(listener) ? (listener.__MICRO_APP_BOUND_FUNCTION__ = listener.__MICRO_APP_BOUND_FUNCTION__ || listener.bind(this)) : listener;
5718
+ const appListenersMap = documentEventListenerMap.get(appName);
5719
+ if (appListenersMap) {
5720
+ const appListenerList = appListenersMap.get(type);
5721
+ if (appListenerList) {
5722
+ appListenerList.add(listener);
5723
+ }
5724
+ else {
5725
+ appListenersMap.set(type, new Set([listener]));
5726
+ }
5727
+ }
5728
+ else {
5729
+ documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
5730
+ }
5731
+ listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
5732
+ rawAddEventListener.call(getEventTarget(type, this), type, handler, options);
5733
+ };
5734
+ microRootDocument.prototype.removeEventListener = function (type, listener, options) {
5735
+ const appListenersMap = documentEventListenerMap.get(appName);
5736
+ if (appListenersMap) {
5737
+ const appListenerList = appListenersMap.get(type);
5738
+ if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
5739
+ appListenerList.delete(listener);
5740
+ }
5741
+ }
5742
+ const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
5743
+ rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
5744
+ };
5745
+ // 重新定义microRootDocument.prototype 上的on开头方法
5746
+ function createSetterHandler(eventName) {
5747
+ if (eventName === 'onclick') {
5748
+ return (value) => {
5749
+ if (isFunction(onClickHandler)) {
5750
+ rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
5751
+ }
5752
+ if (isFunction(value)) {
5753
+ onClickHandler = value.bind(microDocument);
5754
+ rawAddEventListener.call(rawDocument, 'click', onClickHandler, false);
5755
+ }
5756
+ else {
5757
+ onClickHandler = value;
5758
+ }
5759
+ };
5760
+ }
5761
+ return (value) => { rawDocument[eventName] = isFunction(value) ? value.bind(microDocument) : value; };
5762
+ }
5763
+ /**
5764
+ * TODO:
5765
+ * 1、直接代理到原生document是否正确
5766
+ * 2、shadowDOM
5767
+ */
5768
+ Object.getOwnPropertyNames(microRootDocument.prototype)
5769
+ .filter((key) => /^on/.test(key) && !scopeIframeDocumentOnEvent.includes(key))
5770
+ .forEach((eventName) => {
5771
+ const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microRootDocument.prototype, eventName) || {
5772
+ enumerable: true,
5773
+ writable: true,
5774
+ };
5775
+ try {
5776
+ rawDefineProperty(microRootDocument.prototype, eventName, {
5777
+ enumerable,
5778
+ configurable: true,
5779
+ get: () => {
5780
+ if (eventName === 'onclick')
5781
+ return onClickHandler;
5782
+ return rawDocument[eventName];
5783
+ },
5784
+ set: (writable !== null && writable !== void 0 ? writable : !!set) ? createSetterHandler(eventName) : undefined,
5785
+ });
5786
+ }
5787
+ catch (e) {
5788
+ logWarn(e, appName);
5789
+ }
5790
+ });
5791
+ const reset = () => {
5792
+ sstDocumentListenerMap.clear();
5793
+ sstOnClickHandler = null;
5794
+ };
5795
+ /**
5796
+ * record event
5797
+ * NOTE:
5798
+ * 1.record maybe call twice when unmount prerender, keep-alive app manually with umd mode
5799
+ * Scenes:
5800
+ * 1. exec umdMountHook in umd mode
5801
+ * 2. hidden keep-alive app
5802
+ * 3. after init prerender app
5803
+ */
5804
+ const record = () => {
5805
+ // record onclick handler
5806
+ sstOnClickHandler = sstOnClickHandler || onClickHandler;
5807
+ // record document event
5808
+ const documentAppListenersMap = documentEventListenerMap.get(appName);
5809
+ if (documentAppListenersMap) {
5810
+ documentAppListenersMap.forEach((listenerList, type) => {
5811
+ if (listenerList.size) {
5812
+ sstDocumentListenerMap.set(type, new Set(listenerList));
5813
+ }
5814
+ });
5815
+ }
5816
+ };
5817
+ // rebuild event and timer before remount app
5818
+ const rebuild = () => {
5819
+ // rebuild onclick event
5820
+ if (sstOnClickHandler)
5821
+ microDocument.onclick = sstOnClickHandler;
5822
+ sstDocumentListenerMap.forEach((listenerList, type) => {
5823
+ for (const listener of listenerList) {
5824
+ microDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
5825
+ }
5826
+ });
5827
+ reset();
5828
+ };
5829
+ const release = () => {
5830
+ // Clear the function bound by micro application through document.onclick
5831
+ if (isFunction(onClickHandler)) {
5832
+ rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
5833
+ onClickHandler = null;
5834
+ }
5835
+ // Clear document binding event
5836
+ const documentAppListenersMap = documentEventListenerMap.get(appName);
5837
+ if (documentAppListenersMap) {
5838
+ documentAppListenersMap.forEach((listenerList, type) => {
5839
+ for (const listener of listenerList) {
5840
+ rawRemoveEventListener.call(getEventTarget(type, microDocument), type, (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener);
5841
+ }
5842
+ });
5843
+ documentAppListenersMap.clear();
5844
+ }
5845
+ };
5846
+ return {
5847
+ reset,
5848
+ record,
5849
+ rebuild,
5850
+ release,
5851
+ };
5852
+ }
5853
+
5854
+ function patchIframeElement(appName, url, microAppWindow, iframeSandbox) {
5855
+ patchIframeNode(appName, microAppWindow, iframeSandbox);
5856
+ patchIframeAttribute(appName, url, microAppWindow);
5857
+ }
5858
+ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
5859
+ const microDocument = microAppWindow.document;
5860
+ const rawDocument = globalEnv.rawDocument;
5861
+ const microRootNode = microAppWindow.Node;
5862
+ const microRootElement = microAppWindow.Element;
5863
+ // const rawMicroGetRootNode = microRootNode.prototype.getRootNode
5864
+ const rawMicroAppendChild = microRootNode.prototype.appendChild;
5865
+ const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
5866
+ const rawMicroReplaceChild = microRootNode.prototype.replaceChild;
5867
+ const rawMicroCloneNode = microRootNode.prototype.cloneNode;
5868
+ const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
5869
+ const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
5870
+ const isPureNode = (target) => {
5871
+ return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
5872
+ };
5873
+ const getRawTarget = (target) => {
5874
+ if (target === iframeSandbox.microHead) {
5875
+ return rawDocument.head;
5876
+ }
5877
+ else if (target === iframeSandbox.microBody) {
5878
+ return rawDocument.body;
5879
+ }
5880
+ return target;
5881
+ };
5882
+ microRootNode.prototype.getRootNode = function getRootNode() {
5883
+ return microDocument;
5884
+ // TODO: 什么情况下返回原生document?
5885
+ // const rootNode = rawMicroGetRootNode.call(this, options)
5886
+ // if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
5887
+ // return rootNode
5888
+ };
5889
+ microRootNode.prototype.appendChild = function appendChild(node) {
5890
+ updateElementInfo(node, appName);
5891
+ // TODO:只有script才可以这样拦截,link、style不应该拦截
5892
+ if (isPureNode(node)) {
5893
+ return rawMicroAppendChild.call(this, node);
5894
+ }
5895
+ const _this = getRawTarget(this);
5896
+ if (_this !== this) {
5897
+ return _this.appendChild(node);
5898
+ }
5899
+ return rawMicroAppendChild.call(_this, node);
5900
+ };
5901
+ // TODO: 更多场景适配
5902
+ microRootNode.prototype.insertBefore = function insertBefore(node, child) {
5903
+ updateElementInfo(node, appName);
5904
+ if (isPureNode(node)) {
5905
+ return rawMicroInsertBefore.call(this, node, child);
5906
+ }
5907
+ const _this = getRawTarget(this);
5908
+ if (_this !== this) {
5909
+ if (child && !_this.contains(child)) {
5910
+ return _this.appendChild(node);
5911
+ }
5912
+ return _this.insertBefore(node, child);
5913
+ }
5914
+ return rawMicroInsertBefore.call(_this, node, child);
5915
+ };
5916
+ // TODO: 更多场景适配
5917
+ microRootNode.prototype.replaceChild = function replaceChild(node, child) {
5918
+ updateElementInfo(node, appName);
5919
+ if (isPureNode(node)) {
5920
+ return rawMicroReplaceChild.call(this, node, child);
5921
+ }
5922
+ const _this = getRawTarget(this);
5923
+ if (_this !== this) {
5924
+ if (child && !_this.contains(child)) {
5925
+ _this.appendChild(node);
5926
+ return child;
5927
+ }
5928
+ return _this.replaceChild(node, child);
5929
+ }
5930
+ return rawMicroReplaceChild.call(_this, node, child);
5931
+ };
5932
+ // patch cloneNode
5933
+ microRootNode.prototype.cloneNode = function cloneNode(deep) {
5934
+ const clonedNode = rawMicroCloneNode.call(this, deep);
5935
+ return updateElementInfo(clonedNode, appName);
5936
+ };
5937
+ rawDefineProperty(microRootElement.prototype, 'innerHTML', {
5938
+ configurable: true,
5939
+ enumerable: true,
5940
+ get() {
5941
+ return rawInnerHTMLDesc.get.call(this);
5942
+ },
5943
+ set(code) {
5944
+ rawInnerHTMLDesc.set.call(this, code);
5945
+ Array.from(this.children).forEach((child) => {
5946
+ if (isElement(child)) {
5947
+ updateElementInfo(child, appName);
5948
+ }
5949
+ });
5950
+ }
5951
+ });
5952
+ // patch parentNode
5953
+ rawDefineProperty(microRootNode.prototype, 'parentNode', {
5954
+ configurable: true,
5955
+ enumerable: true,
5956
+ get() {
5957
+ var _a;
5958
+ // set html.parentNode to microDocument
5959
+ throttleDeferForParentNode(microDocument);
5960
+ const result = rawParentNodeLDesc.get.call(this);
5961
+ /**
5962
+ * If parentNode is <micro-app-body>, return rawDocument.body
5963
+ * Scenes:
5964
+ * 1. element-ui@2/lib/utils/vue-popper.js
5965
+ * if (this.popperElm.parentNode === document.body) ...
5966
+ * WARNING:
5967
+ * Will it cause other problems ?
5968
+ * e.g. target.parentNode.remove(target)
5969
+ */
5970
+ if ((result === null || result === void 0 ? void 0 : result.tagName) === 'MICRO-APP-BODY' && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
5971
+ return rawDocument.body;
5972
+ }
5973
+ return result;
5974
+ },
5975
+ set: undefined,
5976
+ });
5977
+ // Adapt to new image(...) scene
5978
+ const ImageProxy = new Proxy(microAppWindow.Image, {
5979
+ construct(Target, args) {
5980
+ const elementImage = new Target(...args);
5981
+ updateElementInfo(elementImage, appName);
5982
+ return elementImage;
5983
+ },
5984
+ });
5985
+ rawDefineProperty(microAppWindow, 'Image', {
5986
+ configurable: true,
5987
+ writable: true,
5988
+ value: ImageProxy,
5989
+ });
5990
+ /**
5991
+ * TODO:
5992
+ * 1、append prepend
5993
+ * 2、cloneNode -- 完成
5994
+ * 3、innerHTML
5995
+ * 4、querySelector、querySelectorAll (head, body)
5996
+ * 5、Image -- 完成
5997
+ * 都是Element原型链上的方法
5998
+ */
5999
+ }
6000
+ function patchIframeAttribute(appName, url, microAppWindow) {
6001
+ const microRootElement = microAppWindow.Element;
6002
+ const rawMicroSetAttribute = microRootElement.prototype.setAttribute;
6003
+ microRootElement.prototype.setAttribute = function setAttribute(key, value) {
6004
+ if (((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
6005
+ (key === 'href' && /^link$/i.test(this.tagName))) {
6006
+ value = CompletionPath(value, url);
6007
+ }
6008
+ rawMicroSetAttribute.call(this, key, value);
6009
+ };
6010
+ const protoAttrList = [
6011
+ [microAppWindow.HTMLImageElement.prototype, 'src'],
6012
+ [microAppWindow.HTMLScriptElement.prototype, 'src'],
6013
+ [microAppWindow.HTMLLinkElement.prototype, 'href'],
6014
+ ];
6015
+ protoAttrList.forEach(([target, attr]) => {
6016
+ const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
6017
+ enumerable: true,
6018
+ configurable: true,
6019
+ };
6020
+ rawDefineProperty(target, attr, {
6021
+ enumerable,
6022
+ configurable,
6023
+ get: function () {
6024
+ return get === null || get === void 0 ? void 0 : get.call(this);
6025
+ },
6026
+ set: function (value) {
6027
+ set === null || set === void 0 ? void 0 : set.call(this, CompletionPath(value, url));
6028
+ },
6029
+ });
6030
+ });
6031
+ }
6032
+
6033
+ class IframeSandbox {
6034
+ constructor(appName, url) {
6035
+ this.active = false;
6036
+ // Properties that can be escape to rawWindow
6037
+ this.escapeProperties = [];
6038
+ // Properties escape to rawWindow, cleared when unmount
6039
+ this.escapeKeys = new Set();
6040
+ // TODO: 初始化和每次跳转时都要更新base的href
6041
+ this.updateIframeBase = () => {
6042
+ var _a;
6043
+ (_a = this.baseElement) === null || _a === void 0 ? void 0 : _a.setAttribute('href', this.proxyLocation.protocol + '//' + this.proxyLocation.host + this.proxyLocation.pathname);
6044
+ };
6045
+ const rawLocation = globalEnv.rawWindow.location;
6046
+ const browserHost = rawLocation.protocol + '//' + rawLocation.host;
6047
+ const childStaticLocation = new URL(url);
6048
+ const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
6049
+ const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
6050
+ this.deleteIframeElement = this.createIframeElement(appName, browserHost);
6051
+ this.microAppWindow = this.iframe.contentWindow;
6052
+ // TODO: 优化代码
6053
+ // exec before initStaticGlobalKeys
6054
+ this.createProxyLocation(appName, url, this.microAppWindow, childStaticLocation, browserHost, childHost);
6055
+ this.createProxyWindow(appName, this.microAppWindow);
6056
+ this.initStaticGlobalKeys(appName, url);
6057
+ // get escapeProperties from plugins
6058
+ this.getSpecialProperties(appName);
6059
+ this.patchIframe(this.microAppWindow, (resolve) => {
6060
+ this.createIframeTemplate(this.microAppWindow);
6061
+ patchIframeRoute(appName, this.microAppWindow, childFullPath);
6062
+ this.windowEffect = patchIframeWindow(appName, this.microAppWindow);
6063
+ this.documentEffect = patchIframeDocument(appName, this.microAppWindow, this.proxyLocation);
6064
+ patchIframeElement(appName, url, this.microAppWindow, this);
6065
+ resolve();
6066
+ });
6067
+ }
6068
+ /**
6069
+ * create iframe for sandbox
6070
+ * @param appName app name
6071
+ * @param browserHost browser origin
6072
+ * @returns release callback
6073
+ */
6074
+ createIframeElement(appName, browserHost) {
6075
+ this.iframe = pureCreateElement('iframe');
6076
+ const iframeAttrs = {
6077
+ src: browserHost,
6078
+ style: 'display: none',
6079
+ id: appName,
6080
+ };
6081
+ Object.keys(iframeAttrs).forEach((key) => this.iframe.setAttribute(key, iframeAttrs[key]));
6082
+ // effect action during construct
6083
+ globalEnv.rawDocument.body.appendChild(this.iframe);
6084
+ /**
6085
+ * If dom operated async when unmount, premature deletion of iframe will cause unexpected problems
6086
+ * e.g.
6087
+ * 1. antd: notification.destroy()
6088
+ * WARNING:
6089
+ * If async operation time is too long, defer cannot avoid the problem
6090
+ * TODO: more test
6091
+ */
6092
+ return () => defer(() => {
6093
+ var _a, _b;
6094
+ // default mode or destroy, iframe will be deleted when unmount
6095
+ (_b = (_a = this.iframe) === null || _a === void 0 ? void 0 : _a.parentNode) === null || _b === void 0 ? void 0 : _b.removeChild(this.iframe);
6096
+ this.iframe = null;
6097
+ });
6098
+ }
6099
+ start({ baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
6100
+ if (!this.active) {
6101
+ this.active = true;
6102
+ // TODO: 虚拟路由升级
6103
+ if (useMemoryRouter) {
6104
+ this.initRouteState(defaultPage);
6105
+ // unique listener of popstate event for sub app
6106
+ this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
6107
+ }
6108
+ else {
6109
+ this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
6110
+ }
6111
+ /**
6112
+ * create base element to iframe
6113
+ * WARNING: This will also affect a, image, link and script
6114
+ */
6115
+ if (!disablePatchRequest) {
6116
+ this.createIframeBase();
6117
+ }
6118
+ if (++globalEnv.activeSandbox === 1) {
6119
+ patchElementAndDocument();
6120
+ patchHistory();
6121
+ }
6122
+ if (++IframeSandbox.activeCount === 1) ;
6123
+ }
6124
+ }
6125
+ stop({ umdMode, keepRouteState, destroy, clearData, }) {
6126
+ if (this.active) {
6127
+ this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
6128
+ if (this.removeHistoryListener) {
6129
+ this.clearRouteState(keepRouteState);
6130
+ // release listener of popstate
6131
+ this.removeHistoryListener();
6132
+ }
6133
+ if (!umdMode || destroy) {
6134
+ this.deleteIframeElement();
6135
+ this.escapeKeys.forEach((key) => {
6136
+ Reflect.deleteProperty(globalEnv.rawWindow, key);
6137
+ });
6138
+ this.escapeKeys.clear();
6139
+ }
6140
+ if (--globalEnv.activeSandbox === 0) {
6141
+ releasePatchElementAndDocument();
6142
+ releasePatchHistory();
6143
+ }
6144
+ if (--IframeSandbox.activeCount === 0) ;
6145
+ this.active = false;
6146
+ }
6147
+ }
6148
+ /**
6149
+ * Record global effect and then release (effect: global event, timeout, data listener)
6150
+ * Scenes:
6151
+ * 1. unmount of default/umd app
6152
+ * 2. hidden keep-alive app
6153
+ * 3. after init prerender app
6154
+ * @param options {
6155
+ * @param clearData clear data from base app
6156
+ * @param isPrerender is prerender app
6157
+ * @param keepAlive is keep-alive app
6158
+ * }
6159
+ * @param preventRecord prevent record effect events (default or destroy)
6160
+ */
6161
+ recordAndReleaseEffect(options, preventRecord = false) {
6162
+ if (preventRecord) {
6163
+ this.resetEffectSnapshot();
6164
+ }
6165
+ else {
6166
+ this.recordEffectSnapshot();
6167
+ }
6168
+ this.releaseGlobalEffect(options);
6169
+ }
6170
+ /**
6171
+ * reset effect snapshot data in default mode or destroy
6172
+ * Scenes:
6173
+ * 1. unmount hidden keep-alive app manually
6174
+ * 2. unmount prerender app manually
6175
+ */
6176
+ resetEffectSnapshot() {
6177
+ this.windowEffect.reset();
6178
+ this.documentEffect.reset();
6179
+ resetDataCenterSnapshot(this.microAppWindow.microApp);
6180
+ }
6181
+ /**
6182
+ * record umd snapshot before the first execution of umdHookMount
6183
+ * Scenes:
6184
+ * 1. exec umdMountHook in umd mode
6185
+ * 2. hidden keep-alive app
6186
+ * 3. after init prerender app
6187
+ */
6188
+ recordEffectSnapshot() {
6189
+ this.windowEffect.record();
6190
+ this.documentEffect.record();
6191
+ recordDataCenterSnapshot(this.microAppWindow.microApp);
6192
+ }
6193
+ // rebuild umd snapshot before remount umd app
6194
+ rebuildEffectSnapshot() {
6195
+ this.windowEffect.rebuild();
6196
+ this.documentEffect.rebuild();
6197
+ rebuildDataCenterSnapshot(this.microAppWindow.microApp);
6198
+ }
6199
+ /**
6200
+ * clear global event, timeout, data listener
6201
+ * Scenes:
6202
+ * 1. unmount of normal/umd app
6203
+ * 2. hidden keep-alive app
6204
+ * 3. after init prerender app
6205
+ * @param clearData clear data from base app
6206
+ * @param isPrerender is prerender app
6207
+ * @param keepAlive is keep-alive app
6208
+ */
6209
+ releaseGlobalEffect({ clearData = false }) {
6210
+ var _a, _b, _c;
6211
+ this.windowEffect.release();
6212
+ this.documentEffect.release();
6213
+ (_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
6214
+ (_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
6215
+ if (clearData) {
6216
+ microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
6217
+ (_c = this.microAppWindow.microApp) === null || _c === void 0 ? void 0 : _c.clearData();
6218
+ }
6219
+ }
6220
+ // set __MICRO_APP_PRE_RENDER__ state
6221
+ setPreRenderState(state) {
6222
+ this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
6223
+ }
6224
+ markUmdMode(state) {
6225
+ this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
6226
+ }
6227
+ initStaticGlobalKeys(appName, url) {
6228
+ this.microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
6229
+ this.microAppWindow.__MICRO_APP_NAME__ = appName;
6230
+ this.microAppWindow.__MICRO_APP_URL__ = url;
6231
+ this.microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
6232
+ this.microAppWindow.__MICRO_APP_WINDOW__ = this.microAppWindow;
6233
+ this.microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
6234
+ this.microAppWindow.__MICRO_APP_UMD_MODE__ = false;
6235
+ this.microAppWindow.__MICRO_APP_SANDBOX__ = this;
6236
+ this.microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
6237
+ this.microAppWindow.rawWindow = globalEnv.rawWindow;
6238
+ this.microAppWindow.rawDocument = globalEnv.rawDocument;
6239
+ this.microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
6240
+ removeDomScope,
6241
+ pureCreateElement,
6242
+ location: this.proxyLocation,
6243
+ router,
6244
+ });
6245
+ }
6246
+ // TODO: RESTRUCTURE
6247
+ patchIframe(microAppWindow, cb) {
6248
+ this.sandboxReady = new Promise((resolve) => {
6249
+ (function iframeLocationReady() {
6250
+ setTimeout(() => {
6251
+ if (microAppWindow.location.href === 'about:blank') {
6252
+ iframeLocationReady();
6253
+ }
6254
+ else {
6255
+ /**
6256
+ * microAppWindow.document rebuild
6257
+ */
6258
+ microAppWindow.stop();
6259
+ cb(resolve);
6260
+ }
6261
+ }, 0);
6262
+ })();
6263
+ });
6264
+ }
6265
+ // TODO: RESTRUCTURE
6266
+ createIframeTemplate(microAppWindow) {
6267
+ const microDocument = microAppWindow.document;
6268
+ clearDOM(microDocument);
6269
+ const html = microDocument.createElement('html');
6270
+ html.innerHTML = '<head></head><body></body>';
6271
+ microDocument.appendChild(html);
6272
+ // 记录iframe原生body
6273
+ this.microBody = microDocument.body;
6274
+ this.microHead = microDocument.head;
6275
+ }
6276
+ /**
6277
+ * baseElement will complete the relative address of element according to the URL
6278
+ * e.g: a image link script fetch ajax EventSource
6279
+ */
6280
+ createIframeBase() {
6281
+ this.baseElement = pureCreateElement('base');
6282
+ this.updateIframeBase();
6283
+ this.microHead.appendChild(this.baseElement);
6284
+ }
6285
+ createProxyLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
6286
+ this.proxyLocation = createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
6287
+ }
6288
+ createProxyWindow(appName, microAppWindow) {
6289
+ const rawWindow = globalEnv.rawWindow;
6290
+ this.proxyWindow = new Proxy(microAppWindow, {
6291
+ get: (target, key) => {
6292
+ if (key === 'location') {
6293
+ return this.proxyLocation;
6294
+ }
6295
+ if (globalPropertyList.includes(key.toString())) {
6296
+ return this.proxyWindow;
6297
+ }
6298
+ return bindFunctionToRawTarget(Reflect.get(target, key), target);
6299
+ },
6300
+ set: (target, key, value) => {
6301
+ if (this.active) {
6302
+ /**
6303
+ * TODO:
6304
+ * 1、location域名相同,子应用内部跳转时的处理
6305
+ * 2、和with沙箱的变量相同,提取成公共数组
6306
+ */
6307
+ if (key === 'location') {
6308
+ return Reflect.set(rawWindow, key, value);
6309
+ }
6310
+ Reflect.set(target, key, value);
6311
+ if (this.escapeProperties.includes(key)) {
6312
+ !Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
6313
+ Reflect.set(rawWindow, key, value);
6314
+ }
6315
+ }
6316
+ return true;
6317
+ },
6318
+ has: (target, key) => key in target,
6319
+ deleteProperty: (target, key) => {
6320
+ if (Reflect.has(target, key)) {
6321
+ this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
6322
+ return Reflect.deleteProperty(target, key);
6323
+ }
6324
+ return true;
6325
+ },
6326
+ });
6327
+ }
6328
+ /**
6329
+ * get escapeProperties from plugins & adapter
6330
+ * @param appName app name
6331
+ */
6332
+ getSpecialProperties(appName) {
6333
+ var _a;
6334
+ if (isPlainObject(microApp.options.plugins)) {
6335
+ this.commonActionForSpecialProperties(microApp.options.plugins.global);
6336
+ this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
6337
+ }
6338
+ }
6339
+ // common action for global plugins and module plugins
6340
+ commonActionForSpecialProperties(plugins) {
6341
+ if (isArray(plugins)) {
6342
+ for (const plugin of plugins) {
6343
+ if (isPlainObject(plugin)) {
6344
+ if (isArray(plugin.escapeProperties)) {
6345
+ this.escapeProperties = this.escapeProperties.concat(plugin.escapeProperties);
6346
+ }
6347
+ }
6348
+ }
6349
+ }
6350
+ }
6351
+ initRouteState(defaultPage) {
6352
+ initRouteStateWithURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location, defaultPage);
6353
+ }
6354
+ clearRouteState(keepRouteState) {
6355
+ clearRouteStateFromURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow.location, keepRouteState);
6356
+ }
6357
+ setRouteInfoForKeepAliveApp() {
6358
+ updateBrowserURLWithLocation(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location);
6359
+ }
6360
+ removeRouteInfoForKeepAliveApp() {
6361
+ removeStateAndPathFromBrowser(this.microAppWindow.__MICRO_APP_NAME__);
6362
+ }
6363
+ /**
6364
+ * Format all html elements when init
6365
+ * @param container micro app container
6366
+ */
6367
+ patchStaticElement(container) {
6368
+ patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
6369
+ }
6370
+ /**
6371
+ * Actions:
6372
+ * 1. patch static elements from html
6373
+ * @param container micro app container
6374
+ */
6375
+ actionBeforeExecScripts(container) {
6376
+ this.patchStaticElement(container);
6377
+ }
6378
+ }
6379
+ IframeSandbox.activeCount = 0; // number of active sandbox
6380
+
6381
+ function formatEventInfo(event, element) {
6382
+ Object.defineProperties(event, {
6383
+ currentTarget: {
6384
+ get() {
6385
+ return element;
4984
6386
  }
4985
6387
  },
4986
6388
  target: {
@@ -5024,38 +6426,40 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
5024
6426
  }
5025
6427
  /**
5026
6428
  * Dispatch custom event to micro app
6429
+ * @param app app
5027
6430
  * @param eventName event name
5028
- * @param appName app name
5029
6431
  * @param detail event detail
5030
6432
  */
5031
- function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
5032
- const event = new CustomEvent(formatEventName$1(eventName, appName), {
6433
+ function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
6434
+ const event = new CustomEvent(formatEventName(eventName, app.name), {
5033
6435
  detail,
5034
6436
  });
5035
- window.dispatchEvent(event);
6437
+ const target = app.iframe ? app.sandBox.microAppWindow : window;
6438
+ target.dispatchEvent(event);
5036
6439
  }
5037
6440
 
5038
6441
  // micro app instances
5039
6442
  const appInstanceMap = new Map();
5040
6443
  class CreateApp {
5041
- constructor({ name, url, container, scopecss, useSandbox, inline, esmodule, ssrUrl, isPrefetch, prefetchLevel, }) {
6444
+ constructor({ name, url, container, scopecss, useSandbox, inline, iframe, ssrUrl, isPrefetch, prefetchLevel, }) {
5042
6445
  this.state = appStates.CREATED;
5043
6446
  this.keepAliveState = null;
5044
- this.keepAliveContainer = null;
5045
6447
  this.loadSourceLevel = 0;
5046
6448
  this.umdHookMount = null;
5047
6449
  this.umdHookUnmount = null;
5048
- this.libraryName = null;
5049
6450
  this.umdMode = false;
6451
+ // TODO: 类型优化,加上iframe沙箱
5050
6452
  this.sandBox = null;
5051
6453
  this.fiber = false;
5052
6454
  this.useMemoryRouter = true;
6455
+ appInstanceMap.set(name, this);
6456
+ // init actions
5053
6457
  this.name = name;
5054
6458
  this.url = url;
5055
6459
  this.useSandbox = useSandbox;
5056
6460
  this.scopecss = this.useSandbox && scopecss;
5057
6461
  this.inline = inline !== null && inline !== void 0 ? inline : false;
5058
- this.esmodule = esmodule !== null && esmodule !== void 0 ? esmodule : false;
6462
+ this.iframe = iframe !== null && iframe !== void 0 ? iframe : false;
5059
6463
  // not exist when prefetch 👇
5060
6464
  this.container = container !== null && container !== void 0 ? container : null;
5061
6465
  this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
@@ -5063,15 +6467,13 @@ class CreateApp {
5063
6467
  this.isPrefetch = isPrefetch !== null && isPrefetch !== void 0 ? isPrefetch : false;
5064
6468
  this.isPrerender = prefetchLevel === 3;
5065
6469
  this.prefetchLevel = prefetchLevel;
5066
- // init actions
5067
- appInstanceMap.set(this.name, this);
5068
6470
  this.source = { html: null, links: new Set(), scripts: new Set() };
5069
6471
  this.loadSourceCode();
5070
- this.useSandbox && (this.sandBox = new SandBox(name, url));
6472
+ this.createSandbox();
5071
6473
  }
5072
6474
  // Load resources
5073
6475
  loadSourceCode() {
5074
- this.state = appStates.LOADING;
6476
+ this.setAppState(appStates.LOADING);
5075
6477
  HTMLLoader.getInstance().run(this, extractSourceDom);
5076
6478
  }
5077
6479
  /**
@@ -5081,7 +6483,7 @@ class CreateApp {
5081
6483
  var _a;
5082
6484
  if (++this.loadSourceLevel === 2) {
5083
6485
  this.source.html = html;
5084
- this.state = appStates.LOADED;
6486
+ this.setAppState(appStates.LOADED);
5085
6487
  if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
5086
6488
  getRootContainer(this.container).mount(this);
5087
6489
  }
@@ -5092,7 +6494,7 @@ class CreateApp {
5092
6494
  * 1. fiber forced on
5093
6495
  * 2. only virtual router support
5094
6496
  *
5095
- * NOTE: (4P: not - update browser url, dispatch popstateEvent, reload window, dispatch lifecycle event)
6497
+ * NOTE: (Don't update browser url, dispatch popstateEvent, reload window, dispatch lifecycle event)
5096
6498
  * 1. pushState/replaceState in child can update microLocation, but will not attach router info to browser url
5097
6499
  * 2. prevent dispatch popstate/hashchange event to browser
5098
6500
  * 3. all navigation actions of location are invalid (In the future, we can consider update microLocation without trigger browser reload)
@@ -5112,7 +6514,6 @@ class CreateApp {
5112
6514
  useMemoryRouter: true,
5113
6515
  baseroute: '',
5114
6516
  fiber: true,
5115
- esmodule: this.esmodule,
5116
6517
  defaultPage: defaultPage !== null && defaultPage !== void 0 ? defaultPage : '',
5117
6518
  disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
5118
6519
  });
@@ -5127,7 +6528,7 @@ class CreateApp {
5127
6528
  this.loadSourceLevel = -1;
5128
6529
  if (appStates.UNMOUNT !== this.state) {
5129
6530
  this.onerror(e);
5130
- this.state = appStates.LOAD_FAILED;
6531
+ this.setAppState(appStates.LOAD_FAILED);
5131
6532
  }
5132
6533
  }
5133
6534
  /**
@@ -5139,150 +6540,151 @@ class CreateApp {
5139
6540
  * @param baseroute route prefix, default is ''
5140
6541
  * @param disablePatchRequest prevent rewrite request method of child app
5141
6542
  * @param fiber run js in fiber mode
5142
- * @param esmodule support type='module' script
5143
6543
  */
5144
- mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, esmodule, }) {
5145
- var _a, _b, _c, _d, _e, _f;
6544
+ mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, }) {
5146
6545
  if (this.loadSourceLevel !== 2) {
5147
6546
  /**
5148
- * unmount prefetch app when loading source, when mount again before loading end,
5149
- * isPrefetch & isPrerender will be reset, and this.container sill be null
5150
- * so we should set this.container
6547
+ * container cannot be null when load end
6548
+ * NOTE:
6549
+ * 1. render prefetch app before load end
6550
+ * 2. unmount prefetch app and mount again before load end
5151
6551
  */
5152
6552
  this.container = container;
5153
6553
  // mount before prerender exec mount (loading source), set isPrerender to false
5154
6554
  this.isPrerender = false;
5155
6555
  // reset app state to LOADING
5156
- this.state = appStates.LOADING;
6556
+ this.setAppState(appStates.LOADING);
5157
6557
  return;
5158
6558
  }
5159
- /**
5160
- * Mount app with prerender, this.container is empty
5161
- * When rendering again, identify prerender by this.container
5162
- * Transfer the contents of div to the <micro-app> tag
5163
- *
5164
- * Special scenes:
5165
- * 1. mount before prerender exec mount (loading source)
5166
- * 2. mount when prerender js executing
5167
- * 3. mount after prerender js exec end
5168
- *
5169
- * TODO: test shadowDOM
5170
- */
5171
- if (this.container instanceof HTMLDivElement &&
5172
- this.container.hasAttribute('prerender')) {
5173
- /**
5174
- * rebuild effect event of window, document, data center
5175
- * explain:
5176
- * 1. rebuild before exec mount, do nothing
5177
- * 2. rebuild when js executing, recovery recorded effect event, because prerender fiber mode
5178
- * 3. rebuild after js exec end, normal recovery effect event
5179
- */
5180
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
5181
- // current this.container is <div prerender='true'></div>
5182
- cloneContainer(this.container, container, false);
6559
+ this.createSandbox();
6560
+ const nextAction = () => {
6561
+ var _a, _b, _c, _d, _e, _f, _g;
5183
6562
  /**
5184
- * set this.container to <micro-app></micro-app>
5185
- * NOTE:
5186
- * must before exec this.preRenderEvent?.forEach((cb) => cb())
6563
+ * Special scenes:
6564
+ * 1. mount before prerender exec mount (loading source)
6565
+ * 2. mount when prerender js executing
6566
+ * 3. mount after prerender js exec end
6567
+ * 4. mount after prerender unmounted
6568
+ *
6569
+ * TODO: test shadowDOM
5187
6570
  */
5188
- this.container = container;
5189
- (_b = this.preRenderEvent) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
5190
- // reset isPrerender config
5191
- this.isPrerender = false;
5192
- this.preRenderEvent = undefined;
5193
- // attach router info to browser url
5194
- router.attachToURL(this.name);
5195
- return (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.setPreRenderState(false);
5196
- }
5197
- this.container = container;
5198
- this.inline = inline;
5199
- this.esmodule = esmodule;
5200
- this.fiber = fiber;
5201
- // use in sandbox/effect
5202
- this.useMemoryRouter = useMemoryRouter;
5203
- // this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
5204
- const dispatchBeforeMount = () => {
5205
- dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
5206
- };
5207
- if (this.isPrerender) {
5208
- ((_d = this.preRenderEvent) !== null && _d !== void 0 ? _d : (this.preRenderEvent = [])).push(dispatchBeforeMount);
5209
- }
5210
- else {
5211
- dispatchBeforeMount();
5212
- }
5213
- this.state = appStates.MOUNTING;
5214
- cloneContainer(this.source.html, this.container, !this.umdMode);
5215
- (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
5216
- umdMode: this.umdMode,
5217
- baseroute,
5218
- useMemoryRouter,
5219
- defaultPage,
5220
- disablePatchRequest,
5221
- });
5222
- let umdHookMountResult; // result of mount function
5223
- if (!this.umdMode) {
5224
- let hasDispatchMountedEvent = false;
5225
- // if all js are executed, param isFinished will be true
5226
- execScripts(this, (isFinished) => {
5227
- var _a;
6571
+ if (this.isPrerender &&
6572
+ isDivElement(this.container) &&
6573
+ this.container.hasAttribute('prerender')) {
6574
+ /**
6575
+ * rebuild effect event of window, document, data center
6576
+ * explain:
6577
+ * 1. rebuild before exec mount, do nothing
6578
+ * 2. rebuild when js executing, recovery recorded effect event, because prerender fiber mode
6579
+ * 3. rebuild after js exec end, normal recovery effect event
6580
+ */
6581
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
6582
+ // current this.container is <div prerender='true'></div>
6583
+ cloneContainer(this.container, container, false);
6584
+ /**
6585
+ * set this.container to <micro-app></micro-app>
6586
+ * NOTE:
6587
+ * must exec before this.preRenderEvents?.forEach((cb) => cb())
6588
+ */
6589
+ this.container = container;
6590
+ (_b = this.preRenderEvents) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
6591
+ // reset isPrerender config
6592
+ this.isPrerender = false;
6593
+ this.preRenderEvents = null;
6594
+ // attach router info to browser url
6595
+ router.attachToURL(this.name);
6596
+ (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.setPreRenderState(false);
6597
+ }
6598
+ else {
6599
+ this.container = container;
6600
+ this.inline = inline;
6601
+ this.fiber = fiber;
6602
+ // use in sandbox/effect
6603
+ this.useMemoryRouter = useMemoryRouter;
6604
+ // this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
6605
+ const dispatchBeforeMount = () => dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
6606
+ if (this.isPrerender) {
6607
+ ((_d = this.preRenderEvents) !== null && _d !== void 0 ? _d : (this.preRenderEvents = [])).push(dispatchBeforeMount);
6608
+ }
6609
+ else {
6610
+ dispatchBeforeMount();
6611
+ }
6612
+ this.setAppState(appStates.MOUNTING);
6613
+ // TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
6614
+ cloneContainer(this.source.html, this.container, !this.umdMode);
6615
+ (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
6616
+ umdMode: this.umdMode,
6617
+ baseroute,
6618
+ useMemoryRouter,
6619
+ defaultPage,
6620
+ disablePatchRequest,
6621
+ });
5228
6622
  if (!this.umdMode) {
5229
- const { mount, unmount } = this.getUmdLibraryHooks();
5230
- /**
5231
- * umdHookUnmount can works in non UMD mode
5232
- * register with window.unmount
5233
- */
5234
- this.umdHookUnmount = unmount;
5235
- // if mount & unmount is function, the sub app is umd mode
5236
- if (isFunction(mount) && isFunction(unmount)) {
5237
- this.umdHookMount = mount;
5238
- this.umdMode = true;
5239
- if (this.sandBox)
5240
- this.sandBox.proxyWindow.__MICRO_APP_UMD_MODE__ = true;
5241
- // this.sandBox?.recordEffectSnapshot()
5242
- try {
5243
- umdHookMountResult = this.umdHookMount(microApp.getData(this.name, true));
6623
+ // update element info of html
6624
+ (_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.actionBeforeExecScripts(this.container);
6625
+ // if all js are executed, param isFinished will be true
6626
+ execScripts(this, (isFinished) => {
6627
+ if (!this.umdMode) {
6628
+ const { mount, unmount } = this.getUmdLibraryHooks();
6629
+ /**
6630
+ * umdHookUnmount can works in default mode
6631
+ * register through window.unmount
6632
+ */
6633
+ this.umdHookUnmount = unmount;
6634
+ // if mount & unmount is function, the sub app is umd mode
6635
+ if (isFunction(mount) && isFunction(unmount)) {
6636
+ this.umdHookMount = mount;
6637
+ // sandbox must exist
6638
+ this.sandBox.markUmdMode(this.umdMode = true);
6639
+ try {
6640
+ this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
6641
+ }
6642
+ catch (e) {
6643
+ logError('An error occurred in function mount \n', this.name, e);
6644
+ }
6645
+ }
6646
+ else if (isFinished === true) {
6647
+ this.handleMounted();
6648
+ }
5244
6649
  }
5245
- catch (e) {
5246
- logError('an error occurred in the mount function \n', this.name, e);
5247
- }
5248
- }
6650
+ });
5249
6651
  }
5250
- if (!hasDispatchMountedEvent && (isFinished === true || this.umdMode)) {
5251
- hasDispatchMountedEvent = true;
5252
- const dispatchMounted = () => this.handleMounted(umdHookMountResult);
5253
- if (this.isPrerender) {
5254
- ((_a = this.preRenderEvent) !== null && _a !== void 0 ? _a : (this.preRenderEvent = [])).push(dispatchMounted);
5255
- this.recordAndReleaseEffect();
6652
+ else {
6653
+ (_g = this.sandBox) === null || _g === void 0 ? void 0 : _g.rebuildEffectSnapshot();
6654
+ try {
6655
+ this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
5256
6656
  }
5257
- else {
5258
- dispatchMounted();
6657
+ catch (e) {
6658
+ logError('An error occurred in function mount \n', this.name, e);
5259
6659
  }
5260
6660
  }
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
6661
  }
5271
- this.handleMounted(umdHookMountResult);
5272
- }
6662
+ };
6663
+ // TODO: any替换为iframe沙箱类型
6664
+ this.iframe ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
5273
6665
  }
5274
6666
  /**
5275
6667
  * handle for promise umdHookMount
5276
6668
  * @param umdHookMountResult result of umdHookMount
5277
6669
  */
5278
6670
  handleMounted(umdHookMountResult) {
5279
- if (isPromise(umdHookMountResult)) {
5280
- umdHookMountResult
5281
- .then(() => this.dispatchMountedEvent())
5282
- .catch((e) => this.onerror(e));
6671
+ var _a, _b;
6672
+ const dispatchAction = () => {
6673
+ if (isPromise(umdHookMountResult)) {
6674
+ umdHookMountResult
6675
+ .then(() => this.dispatchMountedEvent())
6676
+ .catch((e) => this.onerror(e));
6677
+ }
6678
+ else {
6679
+ this.dispatchMountedEvent();
6680
+ }
6681
+ };
6682
+ if (this.isPrerender) {
6683
+ (_a = this.preRenderEvents) === null || _a === void 0 ? void 0 : _a.push(dispatchAction);
6684
+ (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ isPrerender: true });
5283
6685
  }
5284
6686
  else {
5285
- this.dispatchMountedEvent();
6687
+ dispatchAction();
5286
6688
  }
5287
6689
  }
5288
6690
  /**
@@ -5290,9 +6692,9 @@ class CreateApp {
5290
6692
  */
5291
6693
  dispatchMountedEvent() {
5292
6694
  if (appStates.UNMOUNT !== this.state) {
5293
- this.state = appStates.MOUNTED;
6695
+ this.setAppState(appStates.MOUNTED);
5294
6696
  // call window.onmount of child app
5295
- callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONMOUNT), this.name, `window.${microGlobalEvent.ONMOUNT}`, microApp.getData(this.name, true));
6697
+ execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONMOUNT), this.name, microGlobalEvent.ONMOUNT, microApp.getData(this.name, true));
5296
6698
  // dispatch event mounted to parent
5297
6699
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
5298
6700
  }
@@ -5306,30 +6708,25 @@ class CreateApp {
5306
6708
  * @param unmountcb callback of unmount
5307
6709
  */
5308
6710
  unmount({ destroy, clearData, keepRouteState, unmountcb, }) {
5309
- if (this.state === appStates.LOAD_FAILED) {
5310
- destroy = true;
5311
- }
5312
- this.state = appStates.UNMOUNT;
5313
- this.keepAliveState = null;
5314
- this.keepAliveContainer = null;
6711
+ var _a;
6712
+ destroy = destroy || this.state === appStates.LOAD_FAILED;
6713
+ this.setAppState(appStates.UNMOUNT);
5315
6714
  // result of unmount function
5316
- let umdHookUnmountResult;
6715
+ let umdHookUnmountResult = null;
5317
6716
  /**
5318
6717
  * send an unmount event to the micro app or call umd unmount hook
5319
6718
  * before the sandbox is cleared
5320
6719
  */
5321
- if (isFunction(this.umdHookUnmount)) {
5322
- try {
5323
- umdHookUnmountResult = this.umdHookUnmount(microApp.getData(this.name, true));
5324
- }
5325
- catch (e) {
5326
- logError('an error occurred in the unmount function \n', this.name, e);
5327
- }
6720
+ try {
6721
+ umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
6722
+ }
6723
+ catch (e) {
6724
+ logError('An error occurred in function unmount \n', this.name, e);
5328
6725
  }
5329
- // call window.onunmount of child app
5330
- callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONUNMOUNT), this.name, `window.${microGlobalEvent.ONUNMOUNT}`);
5331
6726
  // dispatch unmount event to micro app
5332
- dispatchCustomEventToMicroApp('unmount', this.name);
6727
+ dispatchCustomEventToMicroApp(this, 'unmount');
6728
+ // call window.onunmount of child app
6729
+ execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
5333
6730
  this.handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb);
5334
6731
  }
5335
6732
  /**
@@ -5341,19 +6738,17 @@ class CreateApp {
5341
6738
  * @param unmountcb callback of unmount
5342
6739
  */
5343
6740
  handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb) {
5344
- const unmountParam = {
6741
+ const nextAction = () => this.actionsForUnmount({
5345
6742
  destroy,
5346
6743
  clearData,
5347
6744
  keepRouteState,
5348
6745
  unmountcb,
5349
- };
6746
+ });
5350
6747
  if (isPromise(umdHookUnmountResult)) {
5351
- umdHookUnmountResult
5352
- .then(() => this.actionsForUnmount(unmountParam))
5353
- .catch(() => this.actionsForUnmount(unmountParam));
6748
+ umdHookUnmountResult.then(nextAction).catch(nextAction);
5354
6749
  }
5355
6750
  else {
5356
- this.actionsForUnmount(unmountParam);
6751
+ nextAction();
5357
6752
  }
5358
6753
  }
5359
6754
  /**
@@ -5364,26 +6759,20 @@ class CreateApp {
5364
6759
  * @param unmountcb callback of unmount
5365
6760
  */
5366
6761
  actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
5367
- var _a, _b;
5368
- if (destroy) {
5369
- this.actionsForCompletelyDestroy();
5370
- }
5371
- else if (this.umdMode && this.container.childElementCount) {
6762
+ var _a;
6763
+ if (this.umdMode && this.container && !destroy) {
5372
6764
  cloneContainer(this.container, this.source.html, false);
5373
6765
  }
5374
- if (this.umdMode) {
5375
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
5376
- }
5377
6766
  /**
5378
6767
  * this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
5379
6768
  * NOTE:
5380
6769
  * 1. if destroy is true, clear route state
5381
6770
  * 2. umd mode and keep-alive will not clear EventSource
5382
6771
  */
5383
- (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop({
6772
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop({
5384
6773
  umdMode: this.umdMode,
5385
6774
  keepRouteState: keepRouteState && !destroy,
5386
- clearEventSource: !this.umdMode || destroy,
6775
+ destroy,
5387
6776
  clearData: clearData || destroy,
5388
6777
  });
5389
6778
  if (!getActiveApps().length) {
@@ -5391,63 +6780,67 @@ class CreateApp {
5391
6780
  }
5392
6781
  // dispatch unmount event to base app
5393
6782
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
5394
- this.resetConfig();
5395
- unmountcb && unmountcb();
6783
+ this.clearOptions(destroy);
6784
+ unmountcb === null || unmountcb === void 0 ? void 0 : unmountcb();
5396
6785
  }
5397
- resetConfig() {
6786
+ clearOptions(destroy) {
5398
6787
  this.container.innerHTML = '';
5399
6788
  this.container = null;
5400
6789
  this.isPrerender = false;
5401
- this.preRenderEvent = undefined;
6790
+ this.preRenderEvents = null;
6791
+ this.setKeepAliveState(null);
6792
+ // in iframe sandbox & default mode, delete the sandbox & iframeElement
6793
+ if (this.iframe && !this.umdMode)
6794
+ this.sandBox = null;
6795
+ if (destroy)
6796
+ this.actionsForCompletelyDestroy();
5402
6797
  }
5403
6798
  // actions for completely destroy
5404
6799
  actionsForCompletelyDestroy() {
5405
- if (!this.useSandbox && this.umdMode) {
5406
- delete window[this.libraryName];
5407
- }
6800
+ var _a, _b;
6801
+ (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.deleteIframeElement) === null || _b === void 0 ? void 0 : _b.call(_a);
5408
6802
  sourceCenter.script.deleteInlineInfo(this.source.scripts);
5409
6803
  appInstanceMap.delete(this.name);
5410
6804
  }
5411
6805
  // hidden app when disconnectedCallback called with keep-alive
5412
6806
  hiddenKeepAliveApp(callback) {
5413
- var _a;
5414
- const oldContainer = this.container;
5415
- cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
5416
- this.container = this.keepAliveContainer;
5417
- this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
5418
- // event should dispatch before clone node
5419
- // dispatch afterHidden event to micro-app
5420
- dispatchCustomEventToMicroApp('appstate-change', this.name, {
6807
+ var _a, _b;
6808
+ this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_HIDDEN);
6809
+ /**
6810
+ * event should dispatch before clone node
6811
+ * dispatch afterHidden event to micro-app
6812
+ */
6813
+ dispatchCustomEventToMicroApp(this, 'appstate-change', {
5421
6814
  appState: 'afterhidden',
5422
6815
  });
5423
6816
  // dispatch afterHidden event to base app
5424
- dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
6817
+ dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
5425
6818
  if (this.useMemoryRouter) {
5426
6819
  // called after lifeCyclesEvent
5427
6820
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
5428
6821
  }
5429
- this.recordAndReleaseEffect();
5430
- callback && callback();
6822
+ this.container = cloneContainer(this.container, pureCreateElement('div'), false);
6823
+ (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
6824
+ callback === null || callback === void 0 ? void 0 : callback();
5431
6825
  }
5432
6826
  // show app when connectedCallback called with keep-alive
5433
6827
  showKeepAliveApp(container) {
5434
6828
  var _a, _b;
5435
6829
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
5436
6830
  // dispatch beforeShow event to micro-app
5437
- dispatchCustomEventToMicroApp('appstate-change', this.name, {
6831
+ dispatchCustomEventToMicroApp(this, 'appstate-change', {
5438
6832
  appState: 'beforeshow',
5439
6833
  });
5440
6834
  // dispatch beforeShow event to base app
5441
6835
  dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
5442
- cloneContainer(this.container, container, false);
5443
- this.container = container;
5444
- this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
6836
+ this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
6837
+ this.container = cloneContainer(this.container, container, false);
5445
6838
  if (this.useMemoryRouter) {
5446
6839
  // called before lifeCyclesEvent
5447
6840
  (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
5448
6841
  }
5449
6842
  // dispatch afterShow event to micro-app
5450
- dispatchCustomEventToMicroApp('appstate-change', this.name, {
6843
+ dispatchCustomEventToMicroApp(this, 'appstate-change', {
5451
6844
  appState: 'aftershow',
5452
6845
  });
5453
6846
  // dispatch afterShow event to base app
@@ -5460,48 +6853,71 @@ class CreateApp {
5460
6853
  onerror(e) {
5461
6854
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
5462
6855
  }
6856
+ /**
6857
+ * Scene:
6858
+ * 1. create app
6859
+ * 2. remount of default mode with iframe sandbox
6860
+ * 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
6861
+ */
6862
+ createSandbox() {
6863
+ if (this.useSandbox && !this.sandBox) {
6864
+ if (this.iframe) {
6865
+ this.sandBox = new IframeSandbox(this.name, this.url);
6866
+ }
6867
+ else {
6868
+ this.sandBox = new WithSandBox(this.name, this.url);
6869
+ }
6870
+ }
6871
+ }
6872
+ // set app state
6873
+ setAppState(state) {
6874
+ this.state = state;
6875
+ }
5463
6876
  // get app state
5464
6877
  getAppState() {
5465
6878
  return this.state;
5466
6879
  }
6880
+ // set keep-alive state
6881
+ setKeepAliveState(state) {
6882
+ this.keepAliveState = state;
6883
+ }
5467
6884
  // get keep-alive state
5468
6885
  getKeepAliveState() {
5469
6886
  return this.keepAliveState;
5470
6887
  }
5471
6888
  // get umd library, if it not exist, return empty object
5472
6889
  getUmdLibraryHooks() {
5473
- var _a, _b, _c, _d;
5474
6890
  // after execScripts, the app maybe unmounted
5475
- if (appStates.UNMOUNT !== this.state) {
5476
- const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
5477
- this.libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
5478
- if (isObject(global[this.libraryName])) {
5479
- return global[this.libraryName];
6891
+ if (appStates.UNMOUNT !== this.state && this.sandBox) {
6892
+ const libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
6893
+ const proxyWindow = this.sandBox.proxyWindow;
6894
+ // compatible with pre versions
6895
+ if (isObject(proxyWindow[libraryName])) {
6896
+ return proxyWindow[libraryName];
5480
6897
  }
5481
6898
  return {
5482
- mount: (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.proxyWindow.mount,
5483
- unmount: (_d = this.sandBox) === null || _d === void 0 ? void 0 : _d.proxyWindow.unmount,
6899
+ mount: proxyWindow.mount,
6900
+ unmount: proxyWindow.unmount,
5484
6901
  };
5485
6902
  }
5486
6903
  return {};
5487
6904
  }
5488
- getGlobalEventListener(eventName) {
6905
+ getMicroAppGlobalHook(eventName) {
5489
6906
  var _a;
5490
- // @ts-ignore
5491
- const listener = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow[eventName];
6907
+ const listener = ((_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow)[eventName];
5492
6908
  return isFunction(listener) ? listener : null;
5493
6909
  }
5494
- /**
5495
- * Record global effect and then release (effect: global event, timeout, data listener)
5496
- * Scenes:
5497
- * 1. hidden keep-alive app
5498
- * 2. after init prerender app
5499
- */
5500
- recordAndReleaseEffect() {
5501
- var _a, _b;
5502
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
5503
- (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.releaseGlobalEffect();
6910
+ querySelector(selectors) {
6911
+ return this.container ? globalEnv.rawElementQuerySelector.call(this.container, selectors) : null;
5504
6912
  }
6913
+ querySelectorAll(selectors) {
6914
+ return this.container ? globalEnv.rawElementQuerySelectorAll.call(this.container, selectors) : [];
6915
+ }
6916
+ }
6917
+ // iframe route mode
6918
+ function isIframeSandbox(appName) {
6919
+ var _a, _b;
6920
+ return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.iframe) !== null && _b !== void 0 ? _b : false;
5505
6921
  }
5506
6922
 
5507
6923
  /**
@@ -5530,12 +6946,14 @@ function defineElement(tagName) {
5530
6946
  const formatAttrName = formatAppName(this.getAttribute('name'));
5531
6947
  const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
5532
6948
  if (this.legalAttribute('name', formatAttrName) && this.legalAttribute('url', formatAttrUrl)) {
5533
- const existApp = appInstanceMap.get(formatAttrName);
5534
- if (formatAttrName !== this.appName && existApp) {
5535
- // handling of cached and non-prefetch apps
5536
- if (appStates.UNMOUNT !== existApp.getAppState() &&
5537
- keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
5538
- !existApp.isPrefetch) {
6949
+ const oldApp = appInstanceMap.get(formatAttrName);
6950
+ /**
6951
+ * If oldApp exist & appName is different, determine whether oldApp is running
6952
+ */
6953
+ if (formatAttrName !== this.appName && oldApp) {
6954
+ if (oldApp.getAppState() !== appStates.UNMOUNT &&
6955
+ oldApp.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN &&
6956
+ !oldApp.isPrefetch) {
5539
6957
  this.setAttribute('name', this.appName);
5540
6958
  return logError(`app name conflict, an app named ${formatAttrName} is running`);
5541
6959
  }
@@ -5543,16 +6961,16 @@ function defineElement(tagName) {
5543
6961
  if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
5544
6962
  if (formatAttrName === this.appName) {
5545
6963
  this.handleUnmount(true, () => {
5546
- this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
6964
+ this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
5547
6965
  });
5548
6966
  }
5549
6967
  else if (this.getKeepAliveModeResult()) {
5550
6968
  this.handleHiddenKeepAliveApp();
5551
- this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
6969
+ this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
5552
6970
  }
5553
6971
  else {
5554
6972
  this.handleUnmount(this.getDestroyCompatibleResult(), () => {
5555
- this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
6973
+ this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
5556
6974
  });
5557
6975
  }
5558
6976
  }
@@ -5684,37 +7102,35 @@ function defineElement(tagName) {
5684
7102
  }
5685
7103
  this.updateSsrUrl(this.appUrl);
5686
7104
  if (appInstanceMap.has(this.appName)) {
5687
- const app = appInstanceMap.get(this.appName);
5688
- const existAppUrl = app.ssrUrl || app.url;
5689
- const targetAppUrl = this.ssrUrl || this.appUrl;
7105
+ const oldApp = appInstanceMap.get(this.appName);
7106
+ const oldAppUrl = oldApp.ssrUrl || oldApp.url;
7107
+ const targetUrl = this.ssrUrl || this.appUrl;
5690
7108
  /**
5691
7109
  * NOTE:
5692
7110
  * 1. keep-alive don't care about ssrUrl
5693
7111
  * 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
7112
  * 3. When scopecss, useSandbox of prefetch app different from target app, delete prefetch app and create new one
5695
7113
  */
5696
- if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
5697
- app.url === this.appUrl) {
5698
- this.handleShowKeepAliveApp(app);
7114
+ if (oldApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
7115
+ oldApp.url === this.appUrl) {
7116
+ this.handleShowKeepAliveApp(oldApp);
5699
7117
  }
5700
- else if (existAppUrl === targetAppUrl && (app.getAppState() === appStates.UNMOUNT ||
5701
- (app.isPrefetch && (app.scopecss === this.isScopecss() &&
5702
- app.useSandbox === this.isSandbox())))) {
5703
- this.handleAppMount(app);
7118
+ else if (oldAppUrl === targetUrl && (oldApp.getAppState() === appStates.UNMOUNT ||
7119
+ (oldApp.isPrefetch &&
7120
+ this.sameCoreOptions(oldApp)))) {
7121
+ this.handleAppMount(oldApp);
5704
7122
  }
5705
- else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
5706
- if ((process.env.NODE_ENV !== 'production') &&
5707
- app.scopecss === this.isScopecss() &&
5708
- app.useSandbox === this.isSandbox()) {
7123
+ else if (oldApp.isPrefetch || oldApp.getAppState() === appStates.UNMOUNT) {
7124
+ if ((process.env.NODE_ENV !== 'production') && this.sameCoreOptions(oldApp)) {
5709
7125
  /**
5710
7126
  * url is different & old app is unmounted or prefetch, create new app to replace old one
5711
7127
  */
5712
- logWarn(`the ${app.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${existAppUrl} replaced by a new app with url: ${targetAppUrl}`, this.appName);
7128
+ logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${oldAppUrl} replaced by a new app with url: ${targetUrl}`, this.appName);
5713
7129
  }
5714
7130
  this.handleCreateApp();
5715
7131
  }
5716
7132
  else {
5717
- logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running`);
7133
+ logError(`app name conflict, an app named: ${this.appName} with url: ${oldAppUrl} is running`);
5718
7134
  }
5719
7135
  }
5720
7136
  else {
@@ -5722,7 +7138,7 @@ function defineElement(tagName) {
5722
7138
  }
5723
7139
  }
5724
7140
  // remount app or create app if attribute url or name change
5725
- actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
7141
+ actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp) {
5726
7142
  var _a;
5727
7143
  /**
5728
7144
  * do not add judgment of formatAttrUrl === this.appUrl
@@ -5735,26 +7151,38 @@ function defineElement(tagName) {
5735
7151
  this.setAttribute('name', this.appName);
5736
7152
  }
5737
7153
  /**
5738
- * when existApp not null: this.appName === existApp.name
5739
- * scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, existApp has been unmounted
5740
- * scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
7154
+ * when oldApp not null: this.appName === oldApp.name
7155
+ * scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, oldApp has been unmounted
7156
+ * 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
7157
  * scene3: url is different but ssrUrl is equal
5742
7158
  * scene4: url is equal but ssrUrl is different, if url is equal, name must different
5743
- * scene5: if existApp is KEEP_ALIVE_HIDDEN, name must different
7159
+ * scene5: if oldApp is KEEP_ALIVE_HIDDEN, name must different
5744
7160
  */
5745
- if (existApp) {
5746
- if (existApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
5747
- if (existApp.url === this.appUrl) {
5748
- this.handleShowKeepAliveApp(existApp);
7161
+ if (oldApp) {
7162
+ if (oldApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
7163
+ if (oldApp.url === this.appUrl) {
7164
+ this.handleShowKeepAliveApp(oldApp);
5749
7165
  }
5750
7166
  else {
5751
7167
  // the hidden keep-alive app is still active
5752
7168
  logError(`app name conflict, an app named ${this.appName} is running`);
5753
7169
  }
7170
+ /**
7171
+ * TODO:
7172
+ * 1. oldApp必是unmountApp或preFetchApp,这里还应该考虑沙箱、iframe、样式隔离不一致的情况
7173
+ * 2. unmountApp要不要判断样式隔离、沙箱、iframe,然后彻底删除并再次渲染?(包括handleConnected里的处理,先不改?)
7174
+ * 推荐:if (
7175
+ * oldApp.url === this.appUrl &&
7176
+ * oldApp.ssrUrl === this.ssrUrl && (
7177
+ * oldApp.getAppState() === appStates.UNMOUNT ||
7178
+ * (oldApp.isPrefetch && this.sameCoreOptions(oldApp))
7179
+ * )
7180
+ * )
7181
+ */
5754
7182
  }
5755
- else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
7183
+ else if (oldApp.url === this.appUrl && oldApp.ssrUrl === this.ssrUrl) {
5756
7184
  // mount app
5757
- this.handleAppMount(existApp);
7185
+ this.handleAppMount(oldApp);
5758
7186
  }
5759
7187
  else {
5760
7188
  this.handleCreateApp();
@@ -5778,24 +7206,39 @@ function defineElement(tagName) {
5778
7206
  }
5779
7207
  // create app instance
5780
7208
  handleCreateApp() {
5781
- var _a;
7209
+ const createAppInstance = () => {
7210
+ var _a;
7211
+ return new CreateApp({
7212
+ name: this.appName,
7213
+ url: this.appUrl,
7214
+ scopecss: this.useScopecss(),
7215
+ useSandbox: this.useSandbox(),
7216
+ inline: this.getDisposeResult('inline'),
7217
+ iframe: this.getDisposeResult('iframe'),
7218
+ container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
7219
+ ssrUrl: this.ssrUrl,
7220
+ });
7221
+ };
5782
7222
  /**
5783
- * actions for destroy old app
5784
- * fix of unmounted umd app with disableSandbox
7223
+ * Actions for destroy old app
7224
+ * If oldApp exist, it must be 3 scenes:
7225
+ * 1. oldApp is unmounted app (url is is different)
7226
+ * 2. oldApp is prefetch, not prerender (url, scopecss, useSandbox, iframe is different)
7227
+ * 3. oldApp is prerender (url, scopecss, useSandbox, iframe is different)
5785
7228
  */
5786
- if (appInstanceMap.has(this.appName)) {
5787
- appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
7229
+ const oldApp = appInstanceMap.get(this.appName);
7230
+ if (oldApp) {
7231
+ if (oldApp.isPrerender) {
7232
+ this.handleUnmount(true, createAppInstance);
7233
+ }
7234
+ else {
7235
+ oldApp.actionsForCompletelyDestroy();
7236
+ createAppInstance();
7237
+ }
7238
+ }
7239
+ else {
7240
+ createAppInstance();
5788
7241
  }
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
7242
  }
5800
7243
  /**
5801
7244
  * mount app
@@ -5821,7 +7264,6 @@ function defineElement(tagName) {
5821
7264
  baseroute: this.getBaseRouteCompatible(),
5822
7265
  disablePatchRequest: this.getDisposeResult('disable-patch-request'),
5823
7266
  fiber: this.getDisposeResult('fiber'),
5824
- esmodule: this.getDisposeResult('esmodule'),
5825
7267
  });
5826
7268
  }
5827
7269
  /**
@@ -5860,10 +7302,10 @@ function defineElement(tagName) {
5860
7302
  * @param name Configuration item name
5861
7303
  */
5862
7304
  getDisposeResult(name) {
5863
- return (this.compatibleSpecialProperties(name) || !!microApp.options[name]) && this.compatibleDisableSpecialProperties(name);
7305
+ return (this.compatibleProperties(name) || !!microApp.options[name]) && this.compatibleDisableProperties(name);
5864
7306
  }
5865
7307
  // compatible of disableScopecss & disableSandbox
5866
- compatibleSpecialProperties(name) {
7308
+ compatibleProperties(name) {
5867
7309
  if (name === 'disable-scopecss') {
5868
7310
  return this.hasAttribute('disable-scopecss') || this.hasAttribute('disableScopecss');
5869
7311
  }
@@ -5873,7 +7315,7 @@ function defineElement(tagName) {
5873
7315
  return this.hasAttribute(name);
5874
7316
  }
5875
7317
  // compatible of disableScopecss & disableSandbox
5876
- compatibleDisableSpecialProperties(name) {
7318
+ compatibleDisableProperties(name) {
5877
7319
  if (name === 'disable-scopecss') {
5878
7320
  return this.getAttribute('disable-scopecss') !== 'false' && this.getAttribute('disableScopecss') !== 'false';
5879
7321
  }
@@ -5882,12 +7324,20 @@ function defineElement(tagName) {
5882
7324
  }
5883
7325
  return this.getAttribute(name) !== 'false';
5884
7326
  }
5885
- isScopecss() {
7327
+ useScopecss() {
5886
7328
  return !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM'));
5887
7329
  }
5888
- isSandbox() {
7330
+ useSandbox() {
5889
7331
  return !this.getDisposeResult('disable-sandbox');
5890
7332
  }
7333
+ /**
7334
+ * Determine whether the core options of the existApp is consistent with the new one
7335
+ */
7336
+ sameCoreOptions(app) {
7337
+ return (app.scopecss === this.useScopecss() &&
7338
+ app.useSandbox === this.useSandbox() &&
7339
+ app.iframe === this.getDisposeResult('iframe'));
7340
+ }
5891
7341
  /**
5892
7342
  * 2021-09-08
5893
7343
  * get baseRoute
@@ -5972,7 +7422,7 @@ function defineElement(tagName) {
5972
7422
  * {
5973
7423
  * name: string,
5974
7424
  * url: string,
5975
- * esmodule: boolean,
7425
+ * iframe: boolean,
5976
7426
  * inline: boolean,
5977
7427
  * 'disable-scopecss': boolean,
5978
7428
  * 'disable-sandbox': boolean,
@@ -6036,7 +7486,7 @@ function preFetchAction(options) {
6036
7486
  scopecss: !((_b = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss) !== null && _b !== void 0 ? _b : microApp.options['disable-scopecss']),
6037
7487
  useSandbox: !((_d = (_c = options['disable-sandbox']) !== null && _c !== void 0 ? _c : options.disableSandbox) !== null && _d !== void 0 ? _d : microApp.options['disable-sandbox']),
6038
7488
  inline: (_e = options.inline) !== null && _e !== void 0 ? _e : microApp.options.inline,
6039
- esmodule: (_f = options.esmodule) !== null && _f !== void 0 ? _f : microApp.options.esmodule,
7489
+ iframe: (_f = options.iframe) !== null && _f !== void 0 ? _f : microApp.options.iframe,
6040
7490
  prefetchLevel: options.level && PREFETCH_LEVEL.includes(options.level) ? options.level : microApp.options.prefetchLevel && PREFETCH_LEVEL.includes(microApp.options.prefetchLevel) ? microApp.options.prefetchLevel : 2,
6041
7491
  });
6042
7492
  const oldOnload = app.onLoad;
@@ -6135,10 +7585,19 @@ function unmountApp(appName, options) {
6135
7585
  return new Promise((resolve) => {
6136
7586
  if (app) {
6137
7587
  if (app.getAppState() === appStates.UNMOUNT || app.isPrefetch) {
6138
- if (options === null || options === void 0 ? void 0 : options.destroy) {
6139
- app.actionsForCompletelyDestroy();
7588
+ if (app.isPrerender) {
7589
+ app.unmount({
7590
+ destroy: !!(options === null || options === void 0 ? void 0 : options.destroy),
7591
+ clearData: !!(options === null || options === void 0 ? void 0 : options.clearData),
7592
+ keepRouteState: false,
7593
+ unmountcb: resolve.bind(null, true)
7594
+ });
7595
+ }
7596
+ else {
7597
+ if (options === null || options === void 0 ? void 0 : options.destroy)
7598
+ app.actionsForCompletelyDestroy();
7599
+ resolve(true);
6140
7600
  }
6141
- resolve(true);
6142
7601
  }
6143
7602
  else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
6144
7603
  if (options === null || options === void 0 ? void 0 : options.destroy) {
@@ -6188,7 +7647,7 @@ function unmountApp(appName, options) {
6188
7647
  else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
6189
7648
  const keepAliveAttrValue = container.getAttribute('keep-alive');
6190
7649
  container.removeAttribute('keep-alive');
6191
- let clearDataAttrValue;
7650
+ let clearDataAttrValue = null;
6192
7651
  if (options.clearData) {
6193
7652
  clearDataAttrValue = container.getAttribute('clear-data');
6194
7653
  container.setAttribute('clear-data', 'true');
@@ -6198,7 +7657,7 @@ function unmountApp(appName, options) {
6198
7657
  isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
6199
7658
  }
6200
7659
  else {
6201
- let clearDataAttrValue;
7660
+ let clearDataAttrValue = null;
6202
7661
  if (options === null || options === void 0 ? void 0 : options.clearData) {
6203
7662
  clearDataAttrValue = container.getAttribute('clear-data');
6204
7663
  container.setAttribute('clear-data', 'true');
@@ -6321,10 +7780,10 @@ class MicroApp extends EventCenterForBaseApp {
6321
7780
  return logError(`${options.tagName} is invalid tagName`);
6322
7781
  }
6323
7782
  }
6324
- if (window.customElements.get(this.tagName)) {
7783
+ initGlobalEnv();
7784
+ if (globalEnv.rawWindow.customElements.get(this.tagName)) {
6325
7785
  return logWarn(`element ${this.tagName} is already defined`);
6326
7786
  }
6327
- initGlobalEnv();
6328
7787
  if (isPlainObject(options)) {
6329
7788
  this.options = options;
6330
7789
  options['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;