@micro-zoe/micro-app 1.0.0-alpha.8 → 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.8';
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) {
@@ -344,7 +378,8 @@ function isInvalidQuerySelectorKey(key) {
344
378
  function isUniqueElement(key) {
345
379
  return (/^body$/i.test(key) ||
346
380
  /^head$/i.test(key) ||
347
- /^html$/i.test(key));
381
+ /^html$/i.test(key) ||
382
+ /^title$/i.test(key));
348
383
  }
349
384
  /**
350
385
  * get micro-app element
@@ -499,12 +534,17 @@ function isInlineScript(address) {
499
534
  * @param appName app.name
500
535
  * @param args arguments
501
536
  */
502
- function callFnWithTryCatch(fn, appName, msgSuffix, ...args) {
537
+ function execMicroAppGlobalHook(fn, appName, hookName, ...args) {
503
538
  try {
504
539
  isFunction(fn) && fn(...args);
505
540
  }
506
541
  catch (e) {
507
- 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);
508
548
  }
509
549
  }
510
550
 
@@ -543,6 +583,11 @@ var microGlobalEvent;
543
583
  microGlobalEvent["ONMOUNT"] = "onmount";
544
584
  microGlobalEvent["ONUNMOUNT"] = "onunmount";
545
585
  })(microGlobalEvent || (microGlobalEvent = {}));
586
+ // custom event of child app
587
+ const microAppCustomEvent = [
588
+ 'unmount',
589
+ 'appstate-change',
590
+ ];
546
591
  // keep-alive status
547
592
  var keepAliveStates;
548
593
  (function (keepAliveStates) {
@@ -565,7 +610,6 @@ var MicroAppConfig;
565
610
  MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
566
611
  MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
567
612
  MicroAppConfig["CLEAR_DATA"] = "clear-data";
568
- MicroAppConfig["ESMODULE"] = "esmodule";
569
613
  MicroAppConfig["SSR"] = "ssr";
570
614
  MicroAppConfig["FIBER"] = "fiber";
571
615
  })(MicroAppConfig || (MicroAppConfig = {}));
@@ -578,7 +622,7 @@ const PREFETCH_LEVEL = [1, 2, 3];
578
622
  * NOTE:
579
623
  * 1. Do not add fetch, XMLHttpRequest, EventSource
580
624
  */
581
- const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
625
+ const globalKeyToBeCached = 'window,self,globalThis,document,Document,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
582
626
 
583
627
  /**
584
628
  * fetch source of html, js, css
@@ -1093,9 +1137,6 @@ function dispatchOnErrorEvent(element) {
1093
1137
  function createSourceCenter() {
1094
1138
  const linkList = new Map();
1095
1139
  const scriptList = new Map();
1096
- // setInterval(() => {
1097
- // console.log(linkList, scriptList)
1098
- // }, 10000);
1099
1140
  function createSourceHandler(targetList) {
1100
1141
  return {
1101
1142
  setInfo(address, info) {
@@ -1137,7 +1178,7 @@ function getExistParseCode(appName, prefix, linkInfo) {
1137
1178
  if (item !== appName) {
1138
1179
  const appSpaceData = appSpace[item];
1139
1180
  if (appSpaceData.parsedCode) {
1140
- return appSpaceData.parsedCode.replaceAll(new RegExp(createPrefix(item, true), 'g'), prefix);
1181
+ return appSpaceData.parsedCode.replace(new RegExp(createPrefix(item, true), 'g'), prefix);
1141
1182
  }
1142
1183
  }
1143
1184
  }
@@ -1223,18 +1264,18 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
1223
1264
  const linkInfo = sourceCenter.link.getInfo(address);
1224
1265
  return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
1225
1266
  });
1226
- const fiberLinkTasks = app.isPrefetch || app.fiber ? [] : null;
1267
+ const fiberLinkTasks = fiberStyleResult ? [] : null;
1227
1268
  promiseStream(fetchLinkPromise, (res) => {
1228
1269
  injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
1229
1270
  }, (err) => {
1230
1271
  logError(err, app.name);
1231
1272
  }, () => {
1232
- if (fiberLinkTasks) {
1233
- /**
1234
- * 1. If fiberLinkTasks is not null, fiberStyleResult is not null
1235
- * 2. Download link source while processing style
1236
- * 3. Process style first, and then process link
1237
- */
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) {
1238
1279
  fiberStyleResult.then(() => {
1239
1280
  fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
1240
1281
  serialExecFiberTasks(fiberLinkTasks);
@@ -1368,10 +1409,10 @@ class Adapter {
1368
1409
  'webpackHotUpdate',
1369
1410
  'Vue',
1370
1411
  ];
1371
- this.injectReactHRMProperty();
1412
+ this.injectReactHMRProperty();
1372
1413
  }
1373
1414
  // adapter for react
1374
- injectReactHRMProperty() {
1415
+ injectReactHMRProperty() {
1375
1416
  if ((process.env.NODE_ENV !== 'production')) {
1376
1417
  // react child in non-react env
1377
1418
  this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
@@ -1410,13 +1451,15 @@ function fixReactHMRConflict(app) {
1410
1451
  /**
1411
1452
  * reDefine parentNode of html
1412
1453
  * Scenes:
1413
- * 1. element-ui popover.js
1414
- * 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) ...
1415
1458
  */
1416
- function throttleDeferForParentNode(proxyDocument) {
1459
+ function throttleDeferForParentNode(microDocument) {
1417
1460
  const html = globalEnv.rawDocument.firstElementChild;
1418
- if (html && html.parentNode !== proxyDocument) {
1419
- setParentNode(html, proxyDocument);
1461
+ if ((html === null || html === void 0 ? void 0 : html.parentNode) === globalEnv.rawDocument) {
1462
+ setParentNode(html, microDocument);
1420
1463
  defer(() => {
1421
1464
  setParentNode(html, globalEnv.rawDocument);
1422
1465
  });
@@ -1436,6 +1479,64 @@ function setParentNode(target, value) {
1436
1479
  });
1437
1480
  }
1438
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
+ }
1439
1540
 
1440
1541
  // Record element and map element
1441
1542
  const dynamicElementInMicroAppMap = new WeakMap();
@@ -1446,7 +1547,7 @@ const dynamicElementInMicroAppMap = new WeakMap();
1446
1547
  * @param app app
1447
1548
  */
1448
1549
  function handleNewNode(parent, child, app) {
1449
- if (child instanceof HTMLStyleElement) {
1550
+ if (isStyleElement(child)) {
1450
1551
  if (child.hasAttribute('exclude')) {
1451
1552
  const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
1452
1553
  dynamicElementInMicroAppMap.set(child, replaceComment);
@@ -1457,7 +1558,7 @@ function handleNewNode(parent, child, app) {
1457
1558
  }
1458
1559
  return child;
1459
1560
  }
1460
- else if (child instanceof HTMLLinkElement) {
1561
+ else if (isLinkElement(child)) {
1461
1562
  if (child.hasAttribute('exclude') || checkExcludeUrl(child.getAttribute('href'), app.name)) {
1462
1563
  const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
1463
1564
  dynamicElementInMicroAppMap.set(child, linkReplaceComment);
@@ -1482,7 +1583,7 @@ function handleNewNode(parent, child, app) {
1482
1583
  }
1483
1584
  return child;
1484
1585
  }
1485
- else if (child instanceof HTMLScriptElement) {
1586
+ else if (isScriptElement(child)) {
1486
1587
  if (child.src &&
1487
1588
  isFunction(microApp.options.excludeAssetFilter) &&
1488
1589
  microApp.options.excludeAssetFilter(child.src)) {
@@ -1512,17 +1613,20 @@ function handleNewNode(parent, child, app) {
1512
1613
  * @param passiveChild second param of insertBefore and replaceChild
1513
1614
  */
1514
1615
  function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
1515
- const hijackParent = getHijackParent(parent, app);
1616
+ const hijackParent = getHijackParent(parent, targetChild, app);
1516
1617
  /**
1517
1618
  * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
1518
1619
  * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
1519
1620
  */
1520
1621
  if (hijackParent) {
1521
1622
  /**
1623
+ * Adapter for
1522
1624
  * WARNING:
1523
1625
  * Verifying that the parentNode of the targetChild points to document.body will cause other problems ?
1524
1626
  */
1525
- if (hijackParent.tagName === 'MICRO-APP-BODY' && rawMethod !== globalEnv.rawRemoveChild) {
1627
+ if (!isIframeSandbox(app.name) &&
1628
+ hijackParent.tagName === 'MICRO-APP-BODY' &&
1629
+ rawMethod !== globalEnv.rawRemoveChild) {
1526
1630
  const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
1527
1631
  if (!descriptor || descriptor.configurable) {
1528
1632
  rawDefineProperty(targetChild, 'parentNode', {
@@ -1552,7 +1656,7 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
1552
1656
  return targetChild;
1553
1657
  }
1554
1658
  if ((process.env.NODE_ENV !== 'production') &&
1555
- targetChild instanceof HTMLIFrameElement &&
1659
+ isIFrameElement(targetChild) &&
1556
1660
  rawMethod === globalEnv.rawAppendChild) {
1557
1661
  fixReactHMRConflict(app);
1558
1662
  }
@@ -1561,13 +1665,20 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
1561
1665
  return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
1562
1666
  }
1563
1667
  // head/body map to micro-app-head/micro-app-body
1564
- function getHijackParent(node, app) {
1565
- var _a, _b;
1566
- if (node === document.head) {
1567
- return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
1568
- }
1569
- if (node === document.body) {
1570
- 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
+ }
1571
1682
  }
1572
1683
  return null;
1573
1684
  }
@@ -1595,8 +1706,9 @@ function getMappingNode(node) {
1595
1706
  function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1596
1707
  const currentAppName = getCurrentAppName();
1597
1708
  if (isNode(newChild) &&
1709
+ !newChild.__PURE_ELEMENT__ &&
1598
1710
  (newChild.__MICRO_APP_NAME__ ||
1599
- (currentAppName && !newChild.__PURE_ELEMENT__))) {
1711
+ currentAppName)) {
1600
1712
  newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
1601
1713
  const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
1602
1714
  if (app === null || app === void 0 ? void 0 : app.container) {
@@ -1624,10 +1736,10 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1624
1736
  const app = appInstanceMap.get(currentAppName);
1625
1737
  if (app === null || app === void 0 ? void 0 : app.container) {
1626
1738
  if (parent === document.head) {
1627
- return rawMethod.call(app.container.querySelector('micro-app-head'), newChild);
1739
+ return rawMethod.call(app.querySelector('micro-app-head'), newChild);
1628
1740
  }
1629
1741
  else if (parent === document.body) {
1630
- return rawMethod.call(app.container.querySelector('micro-app-body'), newChild);
1742
+ return rawMethod.call(app.querySelector('micro-app-body'), newChild);
1631
1743
  }
1632
1744
  }
1633
1745
  }
@@ -1638,7 +1750,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1638
1750
  /**
1639
1751
  * Rewrite element prototype method
1640
1752
  */
1641
- function patchElementPrototypeMethods() {
1753
+ function patchElementAndDocument() {
1642
1754
  patchDocument();
1643
1755
  // prototype methods of add element👇
1644
1756
  Element.prototype.appendChild = function appendChild(newChild) {
@@ -1687,6 +1799,71 @@ function patchElementPrototypeMethods() {
1687
1799
  this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
1688
1800
  return clonedNode;
1689
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
+ // })
1690
1867
  }
1691
1868
  /**
1692
1869
  * Mark the newly created element in the micro application
@@ -1720,7 +1897,7 @@ function patchDocument() {
1720
1897
  };
1721
1898
  // query element👇
1722
1899
  function querySelector(selectors) {
1723
- var _a, _b, _c, _d;
1900
+ var _a, _b, _c;
1724
1901
  const _this = getBindTarget(this);
1725
1902
  const currentAppName = getCurrentAppName();
1726
1903
  if (!currentAppName ||
@@ -1731,10 +1908,10 @@ function patchDocument() {
1731
1908
  rawDocument !== _this) {
1732
1909
  return globalEnv.rawQuerySelector.call(_this, selectors);
1733
1910
  }
1734
- 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;
1735
1912
  }
1736
1913
  function querySelectorAll(selectors) {
1737
- var _a, _b, _c, _d;
1914
+ var _a, _b, _c;
1738
1915
  const _this = getBindTarget(this);
1739
1916
  const currentAppName = getCurrentAppName();
1740
1917
  if (!currentAppName ||
@@ -1744,7 +1921,7 @@ function patchDocument() {
1744
1921
  rawDocument !== _this) {
1745
1922
  return globalEnv.rawQuerySelectorAll.call(_this, selectors);
1746
1923
  }
1747
- 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 : [];
1748
1925
  }
1749
1926
  rawRootDocument.prototype.querySelector = querySelector;
1750
1927
  rawRootDocument.prototype.querySelectorAll = querySelectorAll;
@@ -1832,7 +2009,7 @@ function patchSetAttribute() {
1832
2009
  const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
1833
2010
  if (appName &&
1834
2011
  appInstanceMap.has(appName) &&
1835
- (((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)) ||
1836
2013
  (key === 'href' && /^link$/i.test(this.tagName)))) {
1837
2014
  const app = appInstanceMap.get(appName);
1838
2015
  value = CompletionPath(value, app.url);
@@ -1854,7 +2031,7 @@ function releasePatchDocument() {
1854
2031
  rawRootDocument.prototype.getElementsByName = globalEnv.rawGetElementsByName;
1855
2032
  }
1856
2033
  // release patch
1857
- function releasePatches() {
2034
+ function releasePatchElementAndDocument() {
1858
2035
  removeDomScope();
1859
2036
  releasePatchDocument();
1860
2037
  Element.prototype.appendChild = globalEnv.rawAppendChild;
@@ -1864,6 +2041,9 @@ function releasePatches() {
1864
2041
  Element.prototype.append = globalEnv.rawAppend;
1865
2042
  Element.prototype.prepend = globalEnv.rawPrepend;
1866
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);
1867
2047
  }
1868
2048
  // exec when last child unmount
1869
2049
  function releasePatchSetAttribute() {
@@ -1882,16 +2062,21 @@ function rejectMicroAppStyle() {
1882
2062
  }
1883
2063
  }
1884
2064
 
1885
- 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
+ };
1886
2071
  /**
1887
2072
  * Note loop nesting
1888
2073
  * Only prototype or unique values can be put here
1889
2074
  */
1890
2075
  function initGlobalEnv() {
1891
2076
  if (isBrowser) {
1892
- const rawWindow = Function('return window')();
1893
- const rawDocument = Function('return document')();
1894
- 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')();
1895
2080
  const supportModuleScript = isSupportModuleScript();
1896
2081
  /**
1897
2082
  * save patch raw methods
@@ -1905,9 +2090,14 @@ function initGlobalEnv() {
1905
2090
  const rawAppend = Element.prototype.append;
1906
2091
  const rawPrepend = Element.prototype.prepend;
1907
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');
1908
2097
  const rawCreateElement = rawRootDocument.prototype.createElement;
1909
2098
  const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
1910
2099
  const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
2100
+ const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
1911
2101
  const rawQuerySelector = rawRootDocument.prototype.querySelector;
1912
2102
  const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
1913
2103
  const rawGetElementById = rawRootDocument.prototype.getElementById;
@@ -1925,18 +2115,19 @@ function initGlobalEnv() {
1925
2115
  * save effect raw methods
1926
2116
  * pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
1927
2117
  */
1928
- const rawWindowAddEventListener = rawWindow.addEventListener;
1929
- const rawWindowRemoveEventListener = rawWindow.removeEventListener;
1930
2118
  const rawSetInterval = rawWindow.setInterval;
1931
2119
  const rawSetTimeout = rawWindow.setTimeout;
1932
2120
  const rawClearInterval = rawWindow.clearInterval;
1933
2121
  const rawClearTimeout = rawWindow.clearTimeout;
1934
2122
  const rawPushState = rawWindow.history.pushState;
1935
2123
  const rawReplaceState = rawWindow.history.replaceState;
2124
+ const rawWindowAddEventListener = rawWindow.addEventListener;
2125
+ const rawWindowRemoveEventListener = rawWindow.removeEventListener;
1936
2126
  const rawDocumentAddEventListener = rawDocument.addEventListener;
1937
2127
  const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
1938
- // mark current application as base application
1939
- window.__MICRO_APP_BASE_APPLICATION__ = true;
2128
+ // TODO: 统一使用 EventTarget 去掉上面四个
2129
+ const rawAddEventListener = EventTarget.prototype.addEventListener;
2130
+ const rawRemoveEventListener = EventTarget.prototype.removeEventListener;
1940
2131
  assign(globalEnv, {
1941
2132
  // common global vars
1942
2133
  rawWindow,
@@ -1952,9 +2143,14 @@ function initGlobalEnv() {
1952
2143
  rawAppend,
1953
2144
  rawPrepend,
1954
2145
  rawCloneNode,
2146
+ rawElementQuerySelector,
2147
+ rawElementQuerySelectorAll,
2148
+ rawInnerHTMLDesc,
2149
+ rawParentNodeDesc,
1955
2150
  rawCreateElement,
1956
2151
  rawCreateElementNS,
1957
2152
  rawCreateDocumentFragment,
2153
+ rawCreateTextNode,
1958
2154
  rawQuerySelector,
1959
2155
  rawQuerySelectorAll,
1960
2156
  rawGetElementById,
@@ -1973,6 +2169,8 @@ function initGlobalEnv() {
1973
2169
  rawDocumentRemoveEventListener,
1974
2170
  rawPushState,
1975
2171
  rawReplaceState,
2172
+ rawAddEventListener,
2173
+ rawRemoveEventListener,
1976
2174
  });
1977
2175
  // global effect
1978
2176
  rejectMicroAppStyle();
@@ -1982,7 +2180,7 @@ function initGlobalEnv() {
1982
2180
  const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
1983
2181
  // whether use type='module' script
1984
2182
  function isTypeModule(app, scriptInfo) {
1985
- return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.esmodule);
2183
+ return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
1986
2184
  }
1987
2185
  // special script element
1988
2186
  function isSpecialScript(app, scriptInfo) {
@@ -2001,11 +2199,17 @@ function isInlineMode(app, scriptInfo) {
2001
2199
  return (app.inline ||
2002
2200
  scriptInfo.appSpace[app.name].inline ||
2003
2201
  isTypeModule(app, scriptInfo) ||
2004
- 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;
2005
2208
  }
2006
2209
  // Convert string code to function
2007
- function code2Function(code) {
2008
- return new Function(code);
2210
+ function code2Function(app, code) {
2211
+ const targetWindow = getEffectWindow(app);
2212
+ return new targetWindow.Function(code);
2009
2213
  }
2010
2214
  /**
2011
2215
  * If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
@@ -2013,10 +2217,10 @@ function code2Function(code) {
2013
2217
  * @param scriptInfo scriptInfo of current address
2014
2218
  * @param currentCode pure code of current address
2015
2219
  */
2016
- function getExistParseResult(appName, scriptInfo, currentCode) {
2220
+ function getExistParseResult(app, scriptInfo, currentCode) {
2017
2221
  const appSpace = scriptInfo.appSpace;
2018
2222
  for (const item in appSpace) {
2019
- if (item !== appName) {
2223
+ if (item !== app.name) {
2020
2224
  const appSpaceData = appSpace[item];
2021
2225
  if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
2022
2226
  return appSpaceData.parsedFunction;
@@ -2029,7 +2233,7 @@ function getExistParseResult(appName, scriptInfo, currentCode) {
2029
2233
  * @returns parsedFunction
2030
2234
  */
2031
2235
  function getParsedFunction(app, scriptInfo, parsedCode) {
2032
- return getExistParseResult(app.name, scriptInfo, parsedCode) || code2Function(parsedCode);
2236
+ return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
2033
2237
  }
2034
2238
  // Prevent randomly created strings from repeating
2035
2239
  function getUniqueNonceSrc() {
@@ -2053,6 +2257,9 @@ function setConvertScriptAttr(convertScript, attrs) {
2053
2257
  function isWrapInSandBox(app, scriptInfo) {
2054
2258
  return app.useSandbox && !isTypeModule(app, scriptInfo);
2055
2259
  }
2260
+ function getSandboxType(app, scriptInfo) {
2261
+ return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
2262
+ }
2056
2263
  /**
2057
2264
  * Extract script elements
2058
2265
  * @param script script element
@@ -2061,6 +2268,7 @@ function isWrapInSandBox(app, scriptInfo) {
2061
2268
  * @param isDynamic dynamic insert
2062
2269
  */
2063
2270
  function extractScriptElement(script, parent, app, isDynamic = false) {
2271
+ var _a;
2064
2272
  let replaceComment = null;
2065
2273
  let src = script.getAttribute('src');
2066
2274
  if (src)
@@ -2072,6 +2280,10 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
2072
2280
  !scriptTypes.includes(script.type)) ||
2073
2281
  script.hasAttribute('ignore') ||
2074
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
+ }
2075
2287
  return null;
2076
2288
  }
2077
2289
  else if ((globalEnv.supportModuleScript && script.noModule) ||
@@ -2267,13 +2479,13 @@ function fetchScriptSuccess(address, scriptInfo, code, app) {
2267
2479
  */
2268
2480
  if (!appSpaceData.parsedCode) {
2269
2481
  appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
2270
- appSpaceData.wrapInSandBox = isWrapInSandBox(app, scriptInfo);
2482
+ appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
2271
2483
  if (!isInlineMode(app, scriptInfo)) {
2272
2484
  try {
2273
2485
  appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
2274
2486
  }
2275
2487
  catch (err) {
2276
- 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);
2277
2489
  }
2278
2490
  }
2279
2491
  }
@@ -2294,7 +2506,8 @@ function execScripts(app, initHook) {
2294
2506
  const appSpaceData = scriptInfo.appSpace[app.name];
2295
2507
  // Notice the second render
2296
2508
  if (appSpaceData.defer || appSpaceData.async) {
2297
- if (scriptInfo.isExternal && !scriptInfo.code) {
2509
+ // TODO: defer和module彻底分开,不要混在一起
2510
+ if (scriptInfo.isExternal && !scriptInfo.code && !(app.iframe && appSpaceData.module)) {
2298
2511
  deferScriptPromise.push(fetchSource(address, app.name));
2299
2512
  }
2300
2513
  else {
@@ -2319,7 +2532,7 @@ function execScripts(app, initHook) {
2319
2532
  logError(err, app.name);
2320
2533
  }, () => {
2321
2534
  deferScriptInfo.forEach(([address, scriptInfo]) => {
2322
- if (scriptInfo.code) {
2535
+ if (isString(scriptInfo.code)) {
2323
2536
  injectFiberTask(fiberScriptTasks, () => {
2324
2537
  runScript(address, app, scriptInfo, initHook);
2325
2538
  !isTypeModule(app, scriptInfo) && initHook(false);
@@ -2363,20 +2576,19 @@ function execScripts(app, initHook) {
2363
2576
  * @param callback callback of module script
2364
2577
  */
2365
2578
  function runScript(address, app, scriptInfo, callback, replaceElement) {
2366
- var _a;
2367
2579
  try {
2368
2580
  actionsBeforeRunScript(app);
2369
2581
  const appSpaceData = scriptInfo.appSpace[app.name];
2370
- const wrapInSandBox = isWrapInSandBox(app, scriptInfo);
2582
+ const sandboxType = getSandboxType(app, scriptInfo);
2371
2583
  /**
2372
2584
  * NOTE:
2373
2585
  * 1. plugins and wrapCode will only be executed once
2374
2586
  * 2. if parsedCode not exist, parsedFunction is not exist
2375
2587
  * 3. if parsedCode exist, parsedFunction does not necessarily exist
2376
2588
  */
2377
- if (!appSpaceData.parsedCode || appSpaceData.wrapInSandBox !== wrapInSandBox) {
2589
+ if (!appSpaceData.parsedCode || appSpaceData.sandboxType !== sandboxType) {
2378
2590
  appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
2379
- appSpaceData.wrapInSandBox = wrapInSandBox;
2591
+ appSpaceData.sandboxType = sandboxType;
2380
2592
  appSpaceData.parsedFunction = null;
2381
2593
  }
2382
2594
  if (isInlineMode(app, scriptInfo)) {
@@ -2384,7 +2596,8 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
2384
2596
  runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
2385
2597
  if (!replaceElement) {
2386
2598
  // TEST IGNORE
2387
- (_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);
2388
2601
  }
2389
2602
  }
2390
2603
  else {
@@ -2416,7 +2629,7 @@ function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
2416
2629
  runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
2417
2630
  !isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
2418
2631
  };
2419
- if (scriptInfo.code) {
2632
+ if (scriptInfo.code || (app.iframe && scriptInfo.appSpace[app.name].module)) {
2420
2633
  defer(runDynamicScript);
2421
2634
  }
2422
2635
  else {
@@ -2463,6 +2676,9 @@ function runCode2InlineScript(address, code, module, scriptElement, attrs, callb
2463
2676
  scriptElement.setAttribute('type', 'module');
2464
2677
  if (callback) {
2465
2678
  callback.moduleCount && callback.moduleCount--;
2679
+ /**
2680
+ * module script will execute onload method only after it insert to document/iframe
2681
+ */
2466
2682
  scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
2467
2683
  }
2468
2684
  }
@@ -2477,7 +2693,7 @@ function runParsedFunction(app, scriptInfo) {
2477
2693
  if (!appSpaceData.parsedFunction) {
2478
2694
  appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
2479
2695
  }
2480
- appSpaceData.parsedFunction.call(window);
2696
+ appSpaceData.parsedFunction.call(getEffectWindow(app));
2481
2697
  }
2482
2698
  /**
2483
2699
  * bind js scope
@@ -2486,12 +2702,12 @@ function runParsedFunction(app, scriptInfo) {
2486
2702
  * @param scriptInfo source script info
2487
2703
  */
2488
2704
  function bindScope(address, app, code, scriptInfo) {
2489
- // TODO: cache
2705
+ // TODO: 1、cache 2、esm code is null
2490
2706
  if (isPlainObject(microApp.options.plugins)) {
2491
2707
  code = usePlugins(address, code, app.name, microApp.options.plugins);
2492
2708
  }
2493
2709
  if (isWrapInSandBox(app, scriptInfo)) {
2494
- 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__);`;
2495
2711
  }
2496
2712
  return code;
2497
2713
  }
@@ -2554,7 +2770,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2554
2770
  flatChildren(child, app, microAppHead, fiberStyleTasks);
2555
2771
  });
2556
2772
  for (const dom of children) {
2557
- if (dom instanceof HTMLLinkElement) {
2773
+ if (isLinkElement(dom)) {
2558
2774
  if (dom.hasAttribute('exclude') || checkExcludeUrl(dom.getAttribute('href'), app.name)) {
2559
2775
  parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
2560
2776
  }
@@ -2565,7 +2781,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2565
2781
  dom.setAttribute('href', CompletionPath(dom.getAttribute('href'), app.url));
2566
2782
  }
2567
2783
  }
2568
- else if (dom instanceof HTMLStyleElement) {
2784
+ else if (isStyleElement(dom)) {
2569
2785
  if (dom.hasAttribute('exclude')) {
2570
2786
  parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
2571
2787
  }
@@ -2573,15 +2789,23 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2573
2789
  injectFiberTask(fiberStyleTasks, () => scopedCSS(dom, app));
2574
2790
  }
2575
2791
  }
2576
- else if (dom instanceof HTMLScriptElement) {
2792
+ else if (isScriptElement(dom)) {
2577
2793
  extractScriptElement(dom, parent, app);
2578
2794
  }
2579
- else if (dom instanceof HTMLMetaElement || dom instanceof HTMLTitleElement) {
2580
- parent.removeChild(dom);
2581
- }
2582
- else if (dom instanceof HTMLImageElement && dom.hasAttribute('src')) {
2795
+ else if (isImageElement(dom) && dom.hasAttribute('src')) {
2583
2796
  dom.setAttribute('src', CompletionPath(dom.getAttribute('src'), app.url));
2584
2797
  }
2798
+ /**
2799
+ * Don't remove meta and title, they have some special scenes
2800
+ * e.g.
2801
+ * document.querySelector('meta[name="viewport"]') // for flexible
2802
+ * document.querySelector('meta[name="baseurl"]').baseurl // for api request
2803
+ *
2804
+ * Title point to main app title, child app title used to be compatible with some special scenes
2805
+ */
2806
+ // else if (dom instanceof HTMLMetaElement || dom instanceof HTMLTitleElement) {
2807
+ // parent.removeChild(dom)
2808
+ // }
2585
2809
  }
2586
2810
  }
2587
2811
  /**
@@ -2591,8 +2815,8 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2591
2815
  */
2592
2816
  function extractSourceDom(htmlStr, app) {
2593
2817
  const wrapElement = getWrapElement(htmlStr);
2594
- const microAppHead = wrapElement.querySelector('micro-app-head');
2595
- 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');
2596
2820
  if (!microAppHead || !microAppBody) {
2597
2821
  const msg = `element ${microAppHead ? 'body' : 'head'} is missing`;
2598
2822
  app.onerror(new Error(msg));
@@ -2793,7 +3017,7 @@ const eventCenter = new EventCenter();
2793
3017
  * @param appName app.name
2794
3018
  * @param fromBaseApp is from base app
2795
3019
  */
2796
- function formatEventName(appName, fromBaseApp) {
3020
+ function createEventName(appName, fromBaseApp) {
2797
3021
  if (!isString(appName) || !appName)
2798
3022
  return '';
2799
3023
  return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`;
@@ -2872,7 +3096,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2872
3096
  * @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
2873
3097
  */
2874
3098
  addDataListener(appName, cb, autoTrigger) {
2875
- eventCenter.on(formatEventName(formatAppName(appName), false), cb, autoTrigger);
3099
+ eventCenter.on(createEventName(formatAppName(appName), false), cb, autoTrigger);
2876
3100
  }
2877
3101
  /**
2878
3102
  * remove listener
@@ -2880,7 +3104,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2880
3104
  * @param cb listener
2881
3105
  */
2882
3106
  removeDataListener(appName, cb) {
2883
- isFunction(cb) && eventCenter.off(formatEventName(formatAppName(appName), false), cb);
3107
+ isFunction(cb) && eventCenter.off(createEventName(formatAppName(appName), false), cb);
2884
3108
  }
2885
3109
  /**
2886
3110
  * get data from micro app or base app
@@ -2888,7 +3112,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2888
3112
  * @param fromBaseApp whether get data from base app, default is false
2889
3113
  */
2890
3114
  getData(appName, fromBaseApp = false) {
2891
- return eventCenter.getData(formatEventName(formatAppName(appName), fromBaseApp));
3115
+ return eventCenter.getData(createEventName(formatAppName(appName), fromBaseApp));
2892
3116
  }
2893
3117
  /**
2894
3118
  * Dispatch data to the specified micro app
@@ -2896,7 +3120,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2896
3120
  * @param data data
2897
3121
  */
2898
3122
  setData(appName, data, nextStep, force) {
2899
- 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);
2900
3124
  }
2901
3125
  forceSetData(appName, data, nextStep) {
2902
3126
  this.setData(appName, data, nextStep, true);
@@ -2907,14 +3131,14 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2907
3131
  * @param fromBaseApp whether clear data from child app, default is true
2908
3132
  */
2909
3133
  clearData(appName, fromBaseApp = true) {
2910
- eventCenter.clearData(formatEventName(formatAppName(appName), fromBaseApp));
3134
+ eventCenter.clearData(createEventName(formatAppName(appName), fromBaseApp));
2911
3135
  }
2912
3136
  /**
2913
3137
  * clear all listener for specified micro app
2914
3138
  * @param appName app.name
2915
3139
  */
2916
3140
  clearDataListener(appName) {
2917
- eventCenter.off(formatEventName(formatAppName(appName), false));
3141
+ eventCenter.off(createEventName(formatAppName(appName), false));
2918
3142
  }
2919
3143
  }
2920
3144
  // Event center for sub app
@@ -2931,20 +3155,20 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2931
3155
  */
2932
3156
  addDataListener(cb, autoTrigger) {
2933
3157
  cb.__AUTO_TRIGGER__ = autoTrigger;
2934
- eventCenter.on(formatEventName(this.appName, true), cb, autoTrigger);
3158
+ eventCenter.on(createEventName(this.appName, true), cb, autoTrigger);
2935
3159
  }
2936
3160
  /**
2937
3161
  * remove listener
2938
3162
  * @param cb listener
2939
3163
  */
2940
3164
  removeDataListener(cb) {
2941
- isFunction(cb) && eventCenter.off(formatEventName(this.appName, true), cb);
3165
+ isFunction(cb) && eventCenter.off(createEventName(this.appName, true), cb);
2942
3166
  }
2943
3167
  /**
2944
3168
  * get data from base app
2945
3169
  */
2946
3170
  getData(fromBaseApp = true) {
2947
- return eventCenter.getData(formatEventName(this.appName, fromBaseApp));
3171
+ return eventCenter.getData(createEventName(this.appName, fromBaseApp));
2948
3172
  }
2949
3173
  /**
2950
3174
  * dispatch data to base app
@@ -2952,12 +3176,12 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2952
3176
  */
2953
3177
  dispatch(data, nextStep, force) {
2954
3178
  removeDomScope();
2955
- 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, () => {
2956
3180
  const app = appInstanceMap.get(this.appName);
2957
3181
  if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
2958
3182
  const event = new CustomEvent('datachange', {
2959
3183
  detail: {
2960
- data: eventCenter.getData(formatEventName(this.appName, false))
3184
+ data: eventCenter.getData(createEventName(this.appName, false))
2961
3185
  }
2962
3186
  });
2963
3187
  getRootContainer(app.container).dispatchEvent(event);
@@ -2972,33 +3196,35 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2972
3196
  * @param fromBaseApp whether clear data from base app, default is false
2973
3197
  */
2974
3198
  clearData(fromBaseApp = false) {
2975
- eventCenter.clearData(formatEventName(this.appName, fromBaseApp));
3199
+ eventCenter.clearData(createEventName(this.appName, fromBaseApp));
2976
3200
  }
2977
3201
  /**
2978
3202
  * clear all listeners
2979
3203
  */
2980
3204
  clearDataListener() {
2981
- eventCenter.off(formatEventName(this.appName, true));
3205
+ eventCenter.off(createEventName(this.appName, true));
2982
3206
  }
2983
3207
  }
2984
3208
  /**
2985
3209
  * Record UMD function before exec umdHookMount
2986
- * @param microAppEventCenter
3210
+ * NOTE: record maybe call twice when unmount prerender, keep-alive app manually with umd mode
3211
+ * @param microAppEventCenter instance of EventCenterForMicroApp
2987
3212
  */
2988
3213
  function recordDataCenterSnapshot(microAppEventCenter) {
2989
- const appName = microAppEventCenter.appName;
2990
- microAppEventCenter.umdDataListeners = { global: new Set(), normal: new Set() };
2991
- const globalEventInfo = eventCenter.eventList.get('global');
2992
- if (globalEventInfo) {
2993
- for (const cb of globalEventInfo.callbacks) {
2994
- if (appName === cb.__APP_NAME__) {
2995
- 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
+ }
2996
3222
  }
2997
3223
  }
2998
- }
2999
- const subAppEventInfo = eventCenter.eventList.get(formatEventName(appName, true));
3000
- if (subAppEventInfo) {
3001
- 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
+ }
3002
3228
  }
3003
3229
  }
3004
3230
  /**
@@ -3006,13 +3232,24 @@ function recordDataCenterSnapshot(microAppEventCenter) {
3006
3232
  * @param microAppEventCenter instance of EventCenterForMicroApp
3007
3233
  */
3008
3234
  function rebuildDataCenterSnapshot(microAppEventCenter) {
3009
- for (const cb of microAppEventCenter.umdDataListeners.global) {
3010
- microAppEventCenter.addGlobalDataListener(cb, cb.__AUTO_TRIGGER__);
3011
- }
3012
- for (const cb of microAppEventCenter.umdDataListeners.normal) {
3013
- 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);
3014
3244
  }
3015
3245
  }
3246
+ /**
3247
+ * delete umdDataListeners from microAppEventCenter
3248
+ * @param microAppEventCenter instance of EventCenterForMicroApp
3249
+ */
3250
+ function resetDataCenterSnapshot(microAppEventCenter) {
3251
+ delete microAppEventCenter.umdDataListeners;
3252
+ }
3016
3253
 
3017
3254
  // 管理 app 的单例
3018
3255
  class AppManager {
@@ -3075,12 +3312,12 @@ function isConstructorFunction(value) {
3075
3312
  return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
3076
3313
  }
3077
3314
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
3078
- function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
3079
- const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
3080
- if (value[cacheKey])
3081
- return value[cacheKey];
3082
- if (!isConstructorFunction(value) && !isBoundedFunction(value)) {
3083
- 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);
3084
3321
  for (const key in value) {
3085
3322
  bindRawObjectValue[key] = value[key];
3086
3323
  }
@@ -3097,21 +3334,6 @@ function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
3097
3334
  return value;
3098
3335
  }
3099
3336
 
3100
- // this events should be sent to the specified app
3101
- const formatEventList = ['unmount', 'appstate-change'];
3102
- /**
3103
- * Format event name
3104
- * @param eventName event name
3105
- * @param appName app name
3106
- */
3107
- function formatEventName$1(eventName, appName) {
3108
- var _a;
3109
- if (formatEventList.includes(eventName) ||
3110
- ((eventName === 'popstate' || eventName === 'hashchange') && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.useMemoryRouter))) {
3111
- return `${eventName}-${appName}`;
3112
- }
3113
- return eventName;
3114
- }
3115
3337
  // document.onclick binding list, the binding function of each application is unique
3116
3338
  const documentClickListMap = new Map();
3117
3339
  let hasRewriteDocumentOnClick = false;
@@ -3222,7 +3444,7 @@ function effect(appName, microAppWindow) {
3222
3444
  const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
3223
3445
  // listener may be null, e.g test-passive
3224
3446
  microAppWindow.addEventListener = function (type, listener, options) {
3225
- type = formatEventName$1(type, appName);
3447
+ type = formatEventName(type, appName);
3226
3448
  const listenerList = eventListenerMap.get(type);
3227
3449
  if (listenerList) {
3228
3450
  listenerList.add(listener);
@@ -3234,7 +3456,7 @@ function effect(appName, microAppWindow) {
3234
3456
  rawWindowAddEventListener.call(rawWindow, type, listener, options);
3235
3457
  };
3236
3458
  microAppWindow.removeEventListener = function (type, listener, options) {
3237
- type = formatEventName$1(type, appName);
3459
+ type = formatEventName(type, appName);
3238
3460
  const listenerList = eventListenerMap.get(type);
3239
3461
  if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
3240
3462
  listenerList.delete(listener);
@@ -3261,39 +3483,32 @@ function effect(appName, microAppWindow) {
3261
3483
  };
3262
3484
  const sstWindowListenerMap = new Map();
3263
3485
  const sstDocumentListenerMap = new Map();
3264
- let sstIntervalIdMap = new Map();
3265
- let sstTimeoutIdMap = new Map();
3266
3486
  let sstOnClickHandler;
3267
- const clearSnapshotData = () => {
3487
+ // reset snapshot data
3488
+ const reset = () => {
3268
3489
  sstWindowListenerMap.clear();
3269
- sstIntervalIdMap.clear();
3270
- sstTimeoutIdMap.clear();
3271
3490
  sstDocumentListenerMap.clear();
3272
3491
  sstOnClickHandler = null;
3273
3492
  };
3274
3493
  /**
3275
- * record event and timer
3276
- * Scenes:
3277
- * 1. exec umdMountHook in umd mode
3278
- * 2. hidden keep-alive app
3279
- * 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
3280
3502
  */
3281
- const recordEffect = () => {
3503
+ const record = () => {
3282
3504
  // record window event
3283
3505
  eventListenerMap.forEach((listenerList, type) => {
3284
3506
  if (listenerList.size) {
3285
3507
  sstWindowListenerMap.set(type, new Set(listenerList));
3286
3508
  }
3287
3509
  });
3288
- // record timers
3289
- if (intervalIdMap.size) {
3290
- sstIntervalIdMap = new Map(intervalIdMap);
3291
- }
3292
- if (timeoutIdMap.size) {
3293
- sstTimeoutIdMap = new Map(timeoutIdMap);
3294
- }
3295
3510
  // record onclick handler
3296
- sstOnClickHandler = documentClickListMap.get(appName);
3511
+ sstOnClickHandler = sstOnClickHandler || documentClickListMap.get(appName);
3297
3512
  // record document event
3298
3513
  const documentAppListenersMap = documentEventListenerMap.get(appName);
3299
3514
  if (documentAppListenersMap) {
@@ -3305,20 +3520,13 @@ function effect(appName, microAppWindow) {
3305
3520
  }
3306
3521
  };
3307
3522
  // rebuild event and timer before remount app
3308
- const rebuildEffect = () => {
3523
+ const rebuild = () => {
3309
3524
  // rebuild window event
3310
3525
  sstWindowListenerMap.forEach((listenerList, type) => {
3311
3526
  for (const listener of listenerList) {
3312
3527
  microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
3313
3528
  }
3314
3529
  });
3315
- // rebuild timer
3316
- sstIntervalIdMap.forEach((info) => {
3317
- microAppWindow.setInterval(info.handler, info.timeout, ...info.args);
3318
- });
3319
- sstTimeoutIdMap.forEach((info) => {
3320
- microAppWindow.setTimeout(info.handler, info.timeout, ...info.args);
3321
- });
3322
3530
  // rebuild onclick event
3323
3531
  sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
3324
3532
  /**
@@ -3332,10 +3540,10 @@ function effect(appName, microAppWindow) {
3332
3540
  }
3333
3541
  });
3334
3542
  removeDomScope();
3335
- clearSnapshotData();
3543
+ reset();
3336
3544
  };
3337
3545
  // release all event listener & interval & timeout when unmount app
3338
- const releaseEffect = () => {
3546
+ const release = ({ umdMode, isPrerender, keepAlive, destroy }) => {
3339
3547
  // Clear window binding events
3340
3548
  if (eventListenerMap.size) {
3341
3549
  eventListenerMap.forEach((listenerList, type) => {
@@ -3345,17 +3553,15 @@ function effect(appName, microAppWindow) {
3345
3553
  });
3346
3554
  eventListenerMap.clear();
3347
3555
  }
3348
- // Clear timers
3349
- if (intervalIdMap.size) {
3556
+ // default mode(not keep-alive or isPrerender)
3557
+ if ((!umdMode && !keepAlive && !isPrerender) || destroy) {
3350
3558
  intervalIdMap.forEach((_, intervalId) => {
3351
3559
  rawClearInterval.call(rawWindow, intervalId);
3352
3560
  });
3353
- intervalIdMap.clear();
3354
- }
3355
- if (timeoutIdMap.size) {
3356
3561
  timeoutIdMap.forEach((_, timeoutId) => {
3357
3562
  rawClearTimeout.call(rawWindow, timeoutId);
3358
3563
  });
3564
+ intervalIdMap.clear();
3359
3565
  timeoutIdMap.clear();
3360
3566
  }
3361
3567
  // Clear the function bound by micro application through document.onclick
@@ -3372,9 +3578,10 @@ function effect(appName, microAppWindow) {
3372
3578
  }
3373
3579
  };
3374
3580
  return {
3375
- recordEffect,
3376
- rebuildEffect,
3377
- releaseEffect,
3581
+ reset,
3582
+ record,
3583
+ rebuild,
3584
+ release,
3378
3585
  };
3379
3586
  }
3380
3587
 
@@ -3569,25 +3776,29 @@ function addHistoryListener(appName) {
3569
3776
  * 1. unmount app & hidden keep-alive app will not receive popstate event
3570
3777
  * 2. filter out onlyForBrowser
3571
3778
  */
3572
- if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName) &&
3779
+ if (getActiveApps({
3780
+ excludeHiddenApp: true,
3781
+ excludePreRender: true,
3782
+ }).includes(appName) &&
3573
3783
  !e.onlyForBrowser) {
3574
3784
  const microPath = getMicroPathFromURL(appName);
3575
3785
  const app = appInstanceMap.get(appName);
3576
3786
  const proxyWindow = app.sandBox.proxyWindow;
3787
+ const microAppWindow = app.sandBox.microAppWindow;
3577
3788
  let isHashChange = false;
3578
3789
  // for hashChangeEvent
3579
3790
  const oldHref = proxyWindow.location.href;
3580
3791
  // Do not attach micro state to url when microPath is empty
3581
3792
  if (microPath) {
3582
3793
  const oldHash = proxyWindow.location.hash;
3583
- updateMicroLocation(appName, microPath, proxyWindow.location);
3794
+ updateMicroLocation(appName, microPath, microAppWindow.location);
3584
3795
  isHashChange = proxyWindow.location.hash !== oldHash;
3585
3796
  }
3586
3797
  // dispatch formatted popStateEvent to child
3587
- dispatchPopStateEventToMicroApp(appName, proxyWindow);
3798
+ dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
3588
3799
  // dispatch formatted hashChangeEvent to child when hash change
3589
3800
  if (isHashChange)
3590
- dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref);
3801
+ dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
3591
3802
  // clear element scope before trigger event of next app
3592
3803
  removeDomScope();
3593
3804
  }
@@ -3603,10 +3814,9 @@ function addHistoryListener(appName) {
3603
3814
  * @param proxyWindow sandbox window
3604
3815
  * @param eventState history.state
3605
3816
  */
3606
- function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
3607
- // create PopStateEvent named popstate-appName with sub app state
3608
- const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName) });
3817
+ function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
3609
3818
  /**
3819
+ * TODO: test
3610
3820
  * angular14 takes e.type as type judgment
3611
3821
  * when e.type is popstate-appName popstate event will be invalid
3612
3822
  */
@@ -3616,7 +3826,14 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
3616
3826
  // configurable: true,
3617
3827
  // enumerable: true,
3618
3828
  // })
3619
- 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
+ }
3620
3837
  // call function window.onpopstate if it exists
3621
3838
  isFunction(proxyWindow.onpopstate) && proxyWindow.onpopstate(newPopStateEvent);
3622
3839
  }
@@ -3626,12 +3843,17 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
3626
3843
  * @param proxyWindow sandbox window
3627
3844
  * @param oldHref old href
3628
3845
  */
3629
- function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
3630
- const newHashChangeEvent = new HashChangeEvent(formatEventName$1('hashchange', appName), {
3846
+ function dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref) {
3847
+ const newHashChangeEvent = new HashChangeEvent(formatEventName('hashchange', appName), {
3631
3848
  newURL: proxyWindow.location.href,
3632
3849
  oldURL: oldHref,
3633
3850
  });
3634
- globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
3851
+ if (isIframeSandbox(appName)) {
3852
+ microAppWindow.dispatchEvent(newHashChangeEvent);
3853
+ }
3854
+ else {
3855
+ globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
3856
+ }
3635
3857
  // call function window.onhashchange if it exists
3636
3858
  isFunction(proxyWindow.onhashchange) && proxyWindow.onhashchange(newHashChangeEvent);
3637
3859
  }
@@ -3683,22 +3905,26 @@ function createMicroHistory(appName, microLocation) {
3683
3905
  const rawHistory = globalEnv.rawWindow.history;
3684
3906
  function getMicroHistoryMethod(methodName) {
3685
3907
  return function (...rests) {
3908
+ var _a, _b, _c;
3909
+ // TODO: 测试iframe的URL兼容isURL的情况
3686
3910
  if (isString(rests[2]) || isURL(rests[2])) {
3687
3911
  const targetLocation = createURL(rests[2], microLocation.href);
3688
- if (targetLocation.origin === microLocation.origin) {
3689
- navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
3690
- const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3691
- if (targetFullPath !== microLocation.fullPath) {
3692
- updateMicroLocation(appName, targetFullPath, microLocation);
3693
- }
3694
- 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);
3695
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]);
3696
3921
  }
3697
- nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
3698
3922
  };
3699
3923
  }
3700
3924
  const pushState = getMicroHistoryMethod('pushState');
3701
3925
  const replaceState = getMicroHistoryMethod('replaceState');
3926
+ if (isIframeSandbox(appName))
3927
+ return { pushState, replaceState };
3702
3928
  return new Proxy(rawHistory, {
3703
3929
  get(target, key) {
3704
3930
  if (key === 'state') {
@@ -3710,8 +3936,7 @@ function createMicroHistory(appName, microLocation) {
3710
3936
  else if (key === 'replaceState') {
3711
3937
  return replaceState;
3712
3938
  }
3713
- const rawValue = Reflect.get(target, key);
3714
- return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'HISTORY') : rawValue;
3939
+ return bindFunctionToRawTarget(Reflect.get(target, key), target, 'HISTORY');
3715
3940
  },
3716
3941
  set(target, key, value) {
3717
3942
  Reflect.set(target, key, value);
@@ -3756,6 +3981,7 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
3756
3981
  if (isEffectiveApp(appName)) {
3757
3982
  const rawLocation = globalEnv.rawWindow.location;
3758
3983
  const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
3984
+ // oldHref use for hashChangeEvent of base app
3759
3985
  const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
3760
3986
  // navigate with native history method
3761
3987
  nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
@@ -3864,8 +4090,9 @@ function createRouterApi() {
3864
4090
  const microLocation = app.sandBox.proxyWindow.location;
3865
4091
  const targetLocation = createURL(to.path, microLocation.href);
3866
4092
  // Only get path data, even if the origin is different from microApp
4093
+ const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
3867
4094
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3868
- if (microLocation.fullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
4095
+ if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
3869
4096
  const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
3870
4097
  navigateWithRawHistory(appName, methodName, targetLocation, to.state);
3871
4098
  }
@@ -4014,8 +4241,7 @@ function createRouterApi() {
4014
4241
  baseRouterProxy = new Proxy(baseRouter, {
4015
4242
  get(target, key) {
4016
4243
  removeDomScope();
4017
- const rawValue = Reflect.get(target, key);
4018
- return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'BASEROUTER') : rawValue;
4244
+ return bindFunctionToRawTarget(Reflect.get(target, key), target, 'BASEROUTER');
4019
4245
  },
4020
4246
  set(target, key, value) {
4021
4247
  Reflect.set(target, key, value);
@@ -4043,9 +4269,118 @@ function createRouterApi() {
4043
4269
  }
4044
4270
  const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
4045
4271
 
4046
- 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
+
4047
4382
  // origin is readonly, so we ignore when updateMicroLocation
4048
- const locationKeys = [...shadowLocationKeys, 'host', 'hostname', 'port', 'protocol', 'search'];
4383
+ const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
4049
4384
  // origin, fullPath is necessary for guardLocation
4050
4385
  const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
4051
4386
  /**
@@ -4053,19 +4388,27 @@ const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
4053
4388
  * MDN https://developer.mozilla.org/en-US/docs/Web/API/Location
4054
4389
  * @param appName app name
4055
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
4056
4395
  */
4057
- function createMicroLocation(appName, url) {
4396
+ function createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
4058
4397
  const rawWindow = globalEnv.rawWindow;
4059
4398
  const rawLocation = rawWindow.location;
4060
- // microLocation is the location of child app, it is globally unique
4061
- const microLocation = createURL(url);
4062
- // shadowLocation is the current location information (href, pathname, search, hash)
4063
- const shadowLocation = {
4064
- href: microLocation.href,
4065
- pathname: microLocation.pathname,
4066
- search: microLocation.search,
4067
- hash: microLocation.hash,
4068
- };
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
+ }
4069
4412
  /**
4070
4413
  * Common handler for href, assign, replace
4071
4414
  * It is mainly used to deal with special scenes about hash
@@ -4073,10 +4416,10 @@ function createMicroLocation(appName, url) {
4073
4416
  * @param methodName pushState/replaceState
4074
4417
  * @returns origin value or formatted value
4075
4418
  */
4076
- const commonHandler = (value, methodName) => {
4077
- const targetLocation = createURL(value, microLocation.href);
4419
+ function commonHandler(value, methodName) {
4420
+ const targetLocation = createURL(value, proxyLocation.href);
4078
4421
  // Even if the origin is the same, developers still have the possibility of want to jump to a new page
4079
- if (targetLocation.origin === microLocation.origin) {
4422
+ if (targetLocation.origin === proxyLocation.origin) {
4080
4423
  const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
4081
4424
  /**
4082
4425
  * change hash with location.href will not trigger the browser reload
@@ -4085,10 +4428,10 @@ function createMicroLocation(appName, url) {
4085
4428
  * 1. if child app only change hash, it should not trigger browser reload
4086
4429
  * 2. if address is same and has hash, it should not add route stack
4087
4430
  */
4088
- if (targetLocation.pathname === shadowLocation.pathname &&
4089
- targetLocation.search === shadowLocation.search) {
4431
+ if (targetLocation.pathname === proxyLocation.pathname &&
4432
+ targetLocation.search === proxyLocation.search) {
4090
4433
  let oldHref = null;
4091
- if (targetLocation.hash !== shadowLocation.hash) {
4434
+ if (targetLocation.hash !== proxyLocation.hash) {
4092
4435
  if (setMicroPathResult.isAttach2Hash)
4093
4436
  oldHref = rawLocation.href;
4094
4437
  nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
@@ -4097,35 +4440,22 @@ function createMicroLocation(appName, url) {
4097
4440
  dispatchNativeEvent(appName, false, oldHref);
4098
4441
  }
4099
4442
  else {
4100
- rawReload();
4443
+ reload();
4101
4444
  }
4102
4445
  return void 0;
4103
4446
  /**
4104
4447
  * when baseApp is hash router, address change of child can not reload browser
4105
- * so we imitate behavior of browser (reload)
4448
+ * so we imitate behavior of browser (reload) manually
4106
4449
  */
4107
4450
  }
4108
4451
  else if (setMicroPathResult.isAttach2Hash) {
4109
4452
  nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
4110
- rawReload();
4453
+ reload();
4111
4454
  return void 0;
4112
4455
  }
4113
- value = setMicroPathResult.fullPath;
4456
+ return setMicroPathResult.fullPath;
4114
4457
  }
4115
4458
  return value;
4116
- };
4117
- /**
4118
- * create location PropertyDescriptor (href, pathname, search, hash)
4119
- * @param key property name
4120
- * @param setter setter of location property
4121
- */
4122
- function createPropertyDescriptor(getter, setter) {
4123
- return {
4124
- enumerable: true,
4125
- configurable: true,
4126
- get: getter,
4127
- set: setter,
4128
- };
4129
4459
  }
4130
4460
  /**
4131
4461
  * common handler for location.pathname & location.search
@@ -4135,7 +4465,7 @@ function createMicroLocation(appName, url) {
4135
4465
  function handleForPathNameAndSearch(targetPath, key) {
4136
4466
  const targetLocation = createURL(targetPath, url);
4137
4467
  // When the browser url has a hash value, the same pathname/search will not refresh browser
4138
- if (targetLocation[key] === shadowLocation[key] && shadowLocation.hash) {
4468
+ if (targetLocation[key] === proxyLocation[key] && proxyLocation.hash) {
4139
4469
  // The href has not changed, not need to dispatch hashchange event
4140
4470
  dispatchNativeEvent(appName, false);
4141
4471
  }
@@ -4146,58 +4476,96 @@ function createMicroLocation(appName, url) {
4146
4476
  * pathname: /path ==> /path#hash, /path ==> /path?query
4147
4477
  * search: ?query ==> ?query#hash
4148
4478
  */
4149
- nativeHistoryNavigate(appName, targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
4150
- rawReload();
4479
+ nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
4480
+ reload();
4151
4481
  }
4152
4482
  }
4153
- function rawReload() {
4154
- isEffectiveApp(appName) && rawLocation.reload();
4155
- }
4156
- /**
4157
- * Special processing for four keys: href, pathname, search and hash
4158
- * They take values from shadowLocation, and require special operations when assigning values
4159
- */
4160
- rawDefineProperties(microLocation, {
4161
- href: createPropertyDescriptor(() => shadowLocation.href, (value) => {
4162
- if (isEffectiveApp(appName)) {
4163
- const targetPath = commonHandler(value, 'pushState');
4164
- if (targetPath)
4165
- rawLocation.href = targetPath;
4166
- }
4167
- }),
4168
- pathname: createPropertyDescriptor(() => shadowLocation.pathname, (value) => {
4169
- const targetPath = ('/' + value).replace(/^\/+/, '/') + shadowLocation.search + shadowLocation.hash;
4170
- handleForPathNameAndSearch(targetPath, 'pathname');
4171
- }),
4172
- search: createPropertyDescriptor(() => shadowLocation.search, (value) => {
4173
- const targetPath = shadowLocation.pathname + ('?' + value).replace(/^\?+/, '?') + shadowLocation.hash;
4174
- handleForPathNameAndSearch(targetPath, 'search');
4175
- }),
4176
- hash: createPropertyDescriptor(() => shadowLocation.hash, (value) => {
4177
- const targetPath = shadowLocation.pathname + shadowLocation.search + ('#' + value).replace(/^#+/, '#');
4178
- const targetLocation = createURL(targetPath, url);
4179
- // The same hash will not trigger popStateEvent
4180
- if (targetLocation.hash !== shadowLocation.hash) {
4181
- navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
4182
- }
4183
- }),
4184
- fullPath: createPropertyDescriptor(() => shadowLocation.pathname + shadowLocation.search + shadowLocation.hash, noop),
4185
- });
4186
4483
  const createLocationMethod = (locationMethodName) => {
4187
4484
  return function (value) {
4188
4485
  if (isEffectiveApp(appName)) {
4189
4486
  const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
4190
- if (targetPath)
4191
- 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
+ }
4192
4491
  }
4193
4492
  };
4194
4493
  };
4195
- return assign(microLocation, {
4196
- assign: createLocationMethod('assign'),
4197
- replace: createLocationMethod('replace'),
4198
- reload: (forcedReload) => rawLocation.reload(forcedReload),
4199
- 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
+ },
4200
4567
  });
4568
+ return proxyLocation;
4201
4569
  }
4202
4570
  /**
4203
4571
  * create guardLocation by microLocation, used for router guard
@@ -4229,17 +4597,17 @@ function autoTriggerNavigationGuard(appName, microLocation) {
4229
4597
  * @param type auto prevent
4230
4598
  */
4231
4599
  function updateMicroLocation(appName, path, microLocation, type) {
4232
- const newLocation = createURL(path, microLocation.href);
4600
+ var _a;
4233
4601
  // record old values of microLocation to `from`
4234
4602
  const from = createGuardLocation(appName, microLocation);
4235
- for (const key of locationKeys) {
4236
- if (shadowLocationKeys.includes(key)) {
4237
- // reference of shadowLocation
4238
- microLocation.shadowLocation[key] = newLocation[key];
4239
- }
4240
- else {
4241
- // @ts-ignore reference of microLocation
4242
- 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];
4243
4611
  }
4244
4612
  }
4245
4613
  // update latest values of microLocation to `to`
@@ -4335,8 +4703,6 @@ function createMicroFetch(url, target) {
4335
4703
  * When fetch rewrite by baseApp, domScope still active when exec rawWindow.fetch
4336
4704
  * If baseApp operate dom in fetch, it will cause error
4337
4705
  * The same for XMLHttpRequest, EventSource
4338
- * e.g.
4339
- * baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
4340
4706
  */
4341
4707
  removeDomScope();
4342
4708
  return rawFetch.call(globalEnv.rawWindow, input, init, ...rests);
@@ -4419,8 +4785,8 @@ function useMicroEventSource() {
4419
4785
  }
4420
4786
 
4421
4787
  const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
4422
- const globalPropertyList = ['window', 'self', 'globalThis'];
4423
- class SandBox {
4788
+ const globalPropertyList$1 = ['window', 'self', 'globalThis'];
4789
+ class WithSandBox {
4424
4790
  constructor(appName, url) {
4425
4791
  /**
4426
4792
  * Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
@@ -4471,17 +4837,21 @@ class SandBox {
4471
4837
  this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
4472
4838
  }
4473
4839
  /**
4474
- * 1. prevent the key deleted during sandBox.stop after rewrite
4475
- * 2. umd mode will not delete any keys during sandBox.stop
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
4476
4844
  */
4477
4845
  if (!umdMode) {
4478
4846
  this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
4479
4847
  }
4480
- if (++SandBox.activeCount === 1) {
4848
+ if (++globalEnv.activeSandbox === 1) {
4849
+ patchElementAndDocument();
4850
+ patchHistory();
4851
+ }
4852
+ if (++WithSandBox.activeCount === 1) {
4481
4853
  effectDocumentEvent();
4482
- patchElementPrototypeMethods();
4483
4854
  initEnvOfNestedApp();
4484
- patchHistory();
4485
4855
  }
4486
4856
  fixBabelPolyfill6();
4487
4857
  }
@@ -4490,28 +4860,25 @@ class SandBox {
4490
4860
  * close sandbox and perform some clean up actions
4491
4861
  * @param umdMode is umd mode
4492
4862
  * @param keepRouteState prevent reset route
4493
- * @param clearEventSource clear MicroEventSource when destroy
4863
+ * @param destroy completely destroy, delete cache resources
4494
4864
  * @param clearData clear data from base app
4495
4865
  */
4496
- stop({ umdMode, keepRouteState, clearEventSource, clearData, }) {
4866
+ stop({ umdMode, keepRouteState, destroy, clearData, }) {
4497
4867
  if (this.active) {
4498
- // clear global event, timeout, data listener
4499
- this.releaseGlobalEffect(clearData);
4868
+ this.recordAndReleaseEffect({ clearData, destroy }, !umdMode || destroy);
4500
4869
  if (this.removeHistoryListener) {
4501
4870
  this.clearRouteState(keepRouteState);
4502
4871
  // release listener of popstate
4503
4872
  this.removeHistoryListener();
4504
4873
  }
4505
- if (clearEventSource) {
4506
- clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
4507
- }
4508
4874
  /**
4509
4875
  * NOTE:
4510
4876
  * 1. injectedKeys and escapeKeys must be placed at the back
4511
4877
  * 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
4512
4878
  * 3. umd mode will not delete global keys
4513
4879
  */
4514
- if (!umdMode) {
4880
+ if (!umdMode || destroy) {
4881
+ clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
4515
4882
  this.injectedKeys.forEach((key) => {
4516
4883
  Reflect.deleteProperty(this.microAppWindow, key);
4517
4884
  });
@@ -4521,30 +4888,47 @@ class SandBox {
4521
4888
  });
4522
4889
  this.escapeKeys.clear();
4523
4890
  }
4524
- if (--SandBox.activeCount === 0) {
4525
- releaseEffectDocumentEvent();
4526
- releasePatches();
4891
+ if (--globalEnv.activeSandbox === 0) {
4892
+ releasePatchElementAndDocument();
4527
4893
  releasePatchHistory();
4528
4894
  }
4895
+ if (--WithSandBox.activeCount === 0) {
4896
+ releaseEffectDocumentEvent();
4897
+ }
4529
4898
  this.active = false;
4530
4899
  }
4531
4900
  }
4532
4901
  /**
4533
- * clear global event, timeout, data listener
4902
+ * Record global effect and then release (effect: global event, timeout, data listener)
4534
4903
  * Scenes:
4535
- * 1. unmount of normal/umd app
4904
+ * 1. unmount of default/umd app
4536
4905
  * 2. hidden keep-alive app
4537
4906
  * 3. after init prerender app
4538
- * @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
4539
4913
  */
4540
- releaseGlobalEffect(clearData = false) {
4541
- this.effectController.releaseEffect();
4542
- this.microAppWindow.microApp.clearDataListener();
4543
- this.microAppWindow.microApp.clearGlobalDataListener();
4544
- if (clearData) {
4545
- microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
4546
- this.microAppWindow.microApp.clearData();
4914
+ recordAndReleaseEffect(options, preventRecord = false) {
4915
+ if (preventRecord) {
4916
+ this.resetEffectSnapshot();
4917
+ }
4918
+ else {
4919
+ this.recordEffectSnapshot();
4547
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);
4548
4932
  }
4549
4933
  /**
4550
4934
  * record umd snapshot before the first execution of umdHookMount
@@ -4555,7 +4939,7 @@ class SandBox {
4555
4939
  */
4556
4940
  recordEffectSnapshot() {
4557
4941
  // this.microAppWindow.__MICRO_APP_UMD_MODE__ = true
4558
- this.effectController.recordEffect();
4942
+ this.effectController.record();
4559
4943
  recordDataCenterSnapshot(this.microAppWindow.microApp);
4560
4944
  // this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
4561
4945
  // this.injectedKeys.forEach((key: PropertyKey) => {
@@ -4567,12 +4951,34 @@ class SandBox {
4567
4951
  // this.recordUmdInjectedValues!.forEach((value: unknown, key: PropertyKey) => {
4568
4952
  // Reflect.set(this.proxyWindow, key, value)
4569
4953
  // })
4570
- this.effectController.rebuildEffect();
4954
+ this.effectController.rebuild();
4571
4955
  rebuildDataCenterSnapshot(this.microAppWindow.microApp);
4572
4956
  }
4573
- // set __MICRO_APP_PRE_RENDER__ state
4574
- setPreRenderState(state) {
4575
- 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
+ }
4576
4982
  }
4577
4983
  /**
4578
4984
  * get scopeProperties and escapeProperties from plugins & adapter
@@ -4605,7 +5011,6 @@ class SandBox {
4605
5011
  createProxyWindow(appName) {
4606
5012
  const rawWindow = globalEnv.rawWindow;
4607
5013
  const descriptorTargetMap = new Map();
4608
- // window.xxx will trigger proxy
4609
5014
  return new Proxy(this.microAppWindow, {
4610
5015
  get: (target, key) => {
4611
5016
  throttleDeferForSetAppName(appName);
@@ -4613,11 +5018,14 @@ class SandBox {
4613
5018
  (isString(key) && /^__MICRO_APP_/.test(key)) ||
4614
5019
  this.scopeProperties.includes(key))
4615
5020
  return Reflect.get(target, key);
4616
- const rawValue = Reflect.get(rawWindow, key);
4617
- return isFunction(rawValue) ? bindFunctionToRawObject(rawWindow, rawValue) : rawValue;
5021
+ return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
4618
5022
  },
4619
5023
  set: (target, key, value) => {
4620
5024
  if (this.active) {
5025
+ /**
5026
+ * TODO:
5027
+ * 1、location域名相同,子应用内部跳转时的处理
5028
+ */
4621
5029
  if (this.adapter.escapeSetterKeyList.includes(key)) {
4622
5030
  Reflect.set(rawWindow, key, value);
4623
5031
  }
@@ -4638,15 +5046,15 @@ class SandBox {
4638
5046
  this.injectedKeys.add(key);
4639
5047
  }
4640
5048
  else {
5049
+ !Reflect.has(target, key) && this.injectedKeys.add(key);
4641
5050
  Reflect.set(target, key, value);
4642
- this.injectedKeys.add(key);
4643
5051
  }
4644
5052
  if ((this.escapeProperties.includes(key) ||
4645
5053
  (this.adapter.staticEscapeProperties.includes(key) &&
4646
5054
  !Reflect.has(rawWindow, key))) &&
4647
5055
  !this.scopeProperties.includes(key)) {
5056
+ !Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
4648
5057
  Reflect.set(rawWindow, key, value);
4649
- this.escapeKeys.add(key);
4650
5058
  }
4651
5059
  }
4652
5060
  return true;
@@ -4694,6 +5102,13 @@ class SandBox {
4694
5102
  },
4695
5103
  });
4696
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
+ }
4697
5112
  /**
4698
5113
  * inject global properties to microAppWindow
4699
5114
  * @param microAppWindow micro window
@@ -4708,6 +5123,7 @@ class SandBox {
4708
5123
  microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
4709
5124
  microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
4710
5125
  microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
5126
+ microAppWindow.__MICRO_APP_UMD_MODE__ = false;
4711
5127
  microAppWindow.rawWindow = globalEnv.rawWindow;
4712
5128
  microAppWindow.rawDocument = globalEnv.rawDocument;
4713
5129
  microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
@@ -4725,7 +5141,6 @@ class SandBox {
4725
5141
  configurable: false,
4726
5142
  enumerable: true,
4727
5143
  get() {
4728
- throttleDeferForSetAppName(appName);
4729
5144
  // return globalEnv.rawDocument
4730
5145
  return proxyDocument;
4731
5146
  },
@@ -4734,7 +5149,6 @@ class SandBox {
4734
5149
  configurable: false,
4735
5150
  enumerable: false,
4736
5151
  get() {
4737
- throttleDeferForSetAppName(appName);
4738
5152
  // return globalEnv.rawRootDocument
4739
5153
  return MicroDocument;
4740
5154
  },
@@ -4754,7 +5168,7 @@ class SandBox {
4754
5168
  }
4755
5169
  rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
4756
5170
  rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
4757
- globalPropertyList.forEach((key) => {
5171
+ globalPropertyList$1.forEach((key) => {
4758
5172
  rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
4759
5173
  });
4760
5174
  }
@@ -4780,6 +5194,7 @@ class SandBox {
4780
5194
  this.setHijackProperty(microAppWindow, appName);
4781
5195
  if (!disablePatchRequest)
4782
5196
  this.patchRequestApi(microAppWindow, appName, url);
5197
+ this.setScopeProperties(microAppWindow);
4783
5198
  }
4784
5199
  // set hijack Properties to microAppWindow
4785
5200
  setHijackProperty(microAppWindow, appName) {
@@ -4847,9 +5262,21 @@ class SandBox {
4847
5262
  },
4848
5263
  });
4849
5264
  }
4850
- // set location & history for memory router
4851
- setMicroAppRouter(microAppWindow, appName, url) {
4852
- const { microLocation, microHistory } = createMicroRouter(appName, url);
5265
+ /**
5266
+ * Init scope keys to microAppWindow, prevent fall to rawWindow from with(microAppWindow)
5267
+ * like: if (!xxx) {}
5268
+ * NOTE:
5269
+ * 1. Symbol.unscopables cannot affect undefined keys
5270
+ * 2. Doesn't use for window.xxx because it fall to proxyWindow
5271
+ */
5272
+ setScopeProperties(microAppWindow) {
5273
+ this.scopeProperties.forEach((key) => {
5274
+ Reflect.set(microAppWindow, key, microAppWindow[key]);
5275
+ });
5276
+ }
5277
+ // set location & history for memory router
5278
+ setMicroAppRouter(microAppWindow, appName, url) {
5279
+ const { microLocation, microHistory } = createMicroRouter(appName, url);
4853
5280
  rawDefineProperties(microAppWindow, {
4854
5281
  location: {
4855
5282
  configurable: false,
@@ -4871,91 +5298,1085 @@ class SandBox {
4871
5298
  });
4872
5299
  }
4873
5300
  initRouteState(defaultPage) {
4874
- initRouteStateWithURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location, defaultPage);
5301
+ initRouteStateWithURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location, defaultPage);
5302
+ }
5303
+ clearRouteState(keepRouteState) {
5304
+ clearRouteStateFromURL(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow.location, keepRouteState);
5305
+ }
5306
+ setRouteInfoForKeepAliveApp() {
5307
+ updateBrowserURLWithLocation(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.location);
5308
+ }
5309
+ removeRouteInfoForKeepAliveApp() {
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);
5327
+ }
5328
+ /**
5329
+ * Create new document and Document
5330
+ */
5331
+ createProxyDocument(appName) {
5332
+ const rawDocument = globalEnv.rawDocument;
5333
+ const rawRootDocument = globalEnv.rawRootDocument;
5334
+ const createElement = function (tagName, options) {
5335
+ const element = globalEnv.rawCreateElement.call(rawDocument, tagName, options);
5336
+ element.__MICRO_APP_NAME__ = appName;
5337
+ return element;
5338
+ };
5339
+ const proxyDocument = new Proxy(rawDocument, {
5340
+ get: (target, key) => {
5341
+ throttleDeferForSetAppName(appName);
5342
+ throttleDeferForParentNode(proxyDocument);
5343
+ if (key === 'createElement')
5344
+ return createElement;
5345
+ if (key === Symbol.toStringTag)
5346
+ return 'ProxyDocument';
5347
+ if (key === 'defaultView')
5348
+ return this.proxyWindow;
5349
+ return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
5350
+ },
5351
+ set: (target, key, value) => {
5352
+ /**
5353
+ * 1. Fix TypeError: Illegal invocation when set document.title
5354
+ * 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
5355
+ */
5356
+ Reflect.set(target, key, value);
5357
+ return true;
5358
+ }
5359
+ });
5360
+ class MicroDocument {
5361
+ static [Symbol.hasInstance](target) {
5362
+ let proto = target;
5363
+ while (proto = Object.getPrototypeOf(proto)) {
5364
+ if (proto === MicroDocument.prototype) {
5365
+ return true;
5366
+ }
5367
+ }
5368
+ return (target === proxyDocument ||
5369
+ target instanceof rawRootDocument);
5370
+ }
5371
+ }
5372
+ /**
5373
+ * TIP:
5374
+ * 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
5375
+ * 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
5376
+ * e.g.
5377
+ * class B extends A {}
5378
+ * B.__proto__ === A // true
5379
+ * B.prototype.__proto__ === A.prototype // true
5380
+ */
5381
+ Object.setPrototypeOf(MicroDocument, rawRootDocument);
5382
+ // Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
5383
+ Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
5384
+ get(target, key) {
5385
+ throttleDeferForSetAppName(appName);
5386
+ return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
5387
+ },
5388
+ set(target, key, value) {
5389
+ Reflect.set(target, key, value);
5390
+ return true;
5391
+ }
5392
+ }));
5393
+ return {
5394
+ proxyDocument,
5395
+ MicroDocument,
5396
+ };
5397
+ }
5398
+ }
5399
+ WithSandBox.activeCount = 0; // number of active sandbox
5400
+
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;
4875
6223
  }
4876
- clearRouteState(keepRouteState) {
4877
- clearRouteStateFromURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__, this.proxyWindow.location, keepRouteState);
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
+ });
4878
6245
  }
4879
- setRouteInfoForKeepAliveApp() {
4880
- updateBrowserURLWithLocation(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location);
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
+ });
4881
6264
  }
4882
- removeRouteInfoForKeepAliveApp() {
4883
- removeStateAndPathFromBrowser(this.proxyWindow.__MICRO_APP_NAME__);
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;
4884
6275
  }
4885
6276
  /**
4886
- * Create new document and Document
6277
+ * baseElement will complete the relative address of element according to the URL
6278
+ * e.g: a image link script fetch ajax EventSource
4887
6279
  */
4888
- createProxyDocument(appName) {
4889
- const rawDocument = globalEnv.rawDocument;
4890
- const rawRootDocument = globalEnv.rawRootDocument;
4891
- const createElement = function (tagName, options) {
4892
- const element = globalEnv.rawCreateElement.call(rawDocument, tagName, options);
4893
- element.__MICRO_APP_NAME__ = appName;
4894
- return element;
4895
- };
4896
- const proxyDocument = new Proxy(rawDocument, {
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, {
4897
6291
  get: (target, key) => {
4898
- throttleDeferForSetAppName(appName);
4899
- throttleDeferForParentNode(proxyDocument);
4900
- if (key === 'createElement')
4901
- return createElement;
4902
- if (key === Symbol.toStringTag)
4903
- return 'ProxyDocument';
4904
- if (key === 'defaultView')
6292
+ if (key === 'location') {
6293
+ return this.proxyLocation;
6294
+ }
6295
+ if (globalPropertyList.includes(key.toString())) {
4905
6296
  return this.proxyWindow;
4906
- const rawValue = Reflect.get(target, key);
4907
- return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
6297
+ }
6298
+ return bindFunctionToRawTarget(Reflect.get(target, key), target);
4908
6299
  },
4909
6300
  set: (target, key, value) => {
4910
- // Fix TypeError: Illegal invocation when set document.title
4911
- Reflect.set(target, key, value);
4912
- /**
4913
- * If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
4914
- */
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
+ }
4915
6316
  return true;
4916
- }
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
+ },
4917
6326
  });
4918
- class MicroDocument {
4919
- static [Symbol.hasInstance](target) {
4920
- let proto = target;
4921
- while (proto = Object.getPrototypeOf(proto)) {
4922
- if (proto === MicroDocument.prototype) {
4923
- return true;
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);
4924
6346
  }
4925
6347
  }
4926
- return (target === proxyDocument ||
4927
- target instanceof rawRootDocument);
4928
6348
  }
4929
6349
  }
4930
- /**
4931
- * TIP:
4932
- * 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
4933
- * 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
4934
- * e.g.
4935
- * class B extends A {}
4936
- * B.__proto__ === A // true
4937
- * B.prototype.__proto__ === A.prototype // true
4938
- */
4939
- Object.setPrototypeOf(MicroDocument, rawRootDocument);
4940
- // Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
4941
- Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
4942
- get(target, key) {
4943
- throttleDeferForSetAppName(appName);
4944
- const rawValue = Reflect.get(target, key);
4945
- return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
4946
- },
4947
- set(target, key, value) {
4948
- Reflect.set(target, key, value);
4949
- return true;
4950
- }
4951
- }));
4952
- return {
4953
- proxyDocument,
4954
- MicroDocument,
4955
- };
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);
4956
6377
  }
4957
6378
  }
4958
- SandBox.activeCount = 0; // number of active sandbox
6379
+ IframeSandbox.activeCount = 0; // number of active sandbox
4959
6380
 
4960
6381
  function formatEventInfo(event, element) {
4961
6382
  Object.defineProperties(event, {
@@ -5005,38 +6426,40 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
5005
6426
  }
5006
6427
  /**
5007
6428
  * Dispatch custom event to micro app
6429
+ * @param app app
5008
6430
  * @param eventName event name
5009
- * @param appName app name
5010
6431
  * @param detail event detail
5011
6432
  */
5012
- function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
5013
- const event = new CustomEvent(formatEventName$1(eventName, appName), {
6433
+ function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
6434
+ const event = new CustomEvent(formatEventName(eventName, app.name), {
5014
6435
  detail,
5015
6436
  });
5016
- window.dispatchEvent(event);
6437
+ const target = app.iframe ? app.sandBox.microAppWindow : window;
6438
+ target.dispatchEvent(event);
5017
6439
  }
5018
6440
 
5019
6441
  // micro app instances
5020
6442
  const appInstanceMap = new Map();
5021
6443
  class CreateApp {
5022
- constructor({ name, url, container, scopecss, useSandbox, inline, esmodule, ssrUrl, isPrefetch, prefetchLevel, }) {
6444
+ constructor({ name, url, container, scopecss, useSandbox, inline, iframe, ssrUrl, isPrefetch, prefetchLevel, }) {
5023
6445
  this.state = appStates.CREATED;
5024
6446
  this.keepAliveState = null;
5025
- this.keepAliveContainer = null;
5026
6447
  this.loadSourceLevel = 0;
5027
6448
  this.umdHookMount = null;
5028
6449
  this.umdHookUnmount = null;
5029
- this.libraryName = null;
5030
6450
  this.umdMode = false;
6451
+ // TODO: 类型优化,加上iframe沙箱
5031
6452
  this.sandBox = null;
5032
6453
  this.fiber = false;
5033
6454
  this.useMemoryRouter = true;
6455
+ appInstanceMap.set(name, this);
6456
+ // init actions
5034
6457
  this.name = name;
5035
6458
  this.url = url;
5036
6459
  this.useSandbox = useSandbox;
5037
6460
  this.scopecss = this.useSandbox && scopecss;
5038
6461
  this.inline = inline !== null && inline !== void 0 ? inline : false;
5039
- this.esmodule = esmodule !== null && esmodule !== void 0 ? esmodule : false;
6462
+ this.iframe = iframe !== null && iframe !== void 0 ? iframe : false;
5040
6463
  // not exist when prefetch 👇
5041
6464
  this.container = container !== null && container !== void 0 ? container : null;
5042
6465
  this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
@@ -5044,15 +6467,13 @@ class CreateApp {
5044
6467
  this.isPrefetch = isPrefetch !== null && isPrefetch !== void 0 ? isPrefetch : false;
5045
6468
  this.isPrerender = prefetchLevel === 3;
5046
6469
  this.prefetchLevel = prefetchLevel;
5047
- // init actions
5048
- appInstanceMap.set(this.name, this);
5049
6470
  this.source = { html: null, links: new Set(), scripts: new Set() };
5050
6471
  this.loadSourceCode();
5051
- this.useSandbox && (this.sandBox = new SandBox(name, url));
6472
+ this.createSandbox();
5052
6473
  }
5053
6474
  // Load resources
5054
6475
  loadSourceCode() {
5055
- this.state = appStates.LOADING;
6476
+ this.setAppState(appStates.LOADING);
5056
6477
  HTMLLoader.getInstance().run(this, extractSourceDom);
5057
6478
  }
5058
6479
  /**
@@ -5062,7 +6483,7 @@ class CreateApp {
5062
6483
  var _a;
5063
6484
  if (++this.loadSourceLevel === 2) {
5064
6485
  this.source.html = html;
5065
- this.state = appStates.LOADED;
6486
+ this.setAppState(appStates.LOADED);
5066
6487
  if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
5067
6488
  getRootContainer(this.container).mount(this);
5068
6489
  }
@@ -5073,7 +6494,7 @@ class CreateApp {
5073
6494
  * 1. fiber forced on
5074
6495
  * 2. only virtual router support
5075
6496
  *
5076
- * 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)
5077
6498
  * 1. pushState/replaceState in child can update microLocation, but will not attach router info to browser url
5078
6499
  * 2. prevent dispatch popstate/hashchange event to browser
5079
6500
  * 3. all navigation actions of location are invalid (In the future, we can consider update microLocation without trigger browser reload)
@@ -5093,7 +6514,6 @@ class CreateApp {
5093
6514
  useMemoryRouter: true,
5094
6515
  baseroute: '',
5095
6516
  fiber: true,
5096
- esmodule: this.esmodule,
5097
6517
  defaultPage: defaultPage !== null && defaultPage !== void 0 ? defaultPage : '',
5098
6518
  disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
5099
6519
  });
@@ -5108,7 +6528,7 @@ class CreateApp {
5108
6528
  this.loadSourceLevel = -1;
5109
6529
  if (appStates.UNMOUNT !== this.state) {
5110
6530
  this.onerror(e);
5111
- this.state = appStates.LOAD_FAILED;
6531
+ this.setAppState(appStates.LOAD_FAILED);
5112
6532
  }
5113
6533
  }
5114
6534
  /**
@@ -5120,150 +6540,151 @@ class CreateApp {
5120
6540
  * @param baseroute route prefix, default is ''
5121
6541
  * @param disablePatchRequest prevent rewrite request method of child app
5122
6542
  * @param fiber run js in fiber mode
5123
- * @param esmodule support type='module' script
5124
6543
  */
5125
- mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, esmodule, }) {
5126
- var _a, _b, _c, _d, _e, _f;
6544
+ mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, }) {
5127
6545
  if (this.loadSourceLevel !== 2) {
5128
6546
  /**
5129
- * unmount prefetch app when loading source, when mount again before loading end,
5130
- * isPrefetch & isPrerender will be reset, and this.container sill be null
5131
- * 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
5132
6551
  */
5133
6552
  this.container = container;
5134
6553
  // mount before prerender exec mount (loading source), set isPrerender to false
5135
6554
  this.isPrerender = false;
5136
6555
  // reset app state to LOADING
5137
- this.state = appStates.LOADING;
6556
+ this.setAppState(appStates.LOADING);
5138
6557
  return;
5139
6558
  }
5140
- /**
5141
- * Mount app with prerender, this.container is empty
5142
- * When rendering again, identify prerender by this.container
5143
- * Transfer the contents of div to the <micro-app> tag
5144
- *
5145
- * Special scenes:
5146
- * 1. mount before prerender exec mount (loading source)
5147
- * 2. mount when prerender js executing
5148
- * 3. mount after prerender js exec end
5149
- *
5150
- * TODO: test shadowDOM
5151
- */
5152
- if (this.container instanceof HTMLDivElement &&
5153
- this.container.hasAttribute('prerender')) {
5154
- /**
5155
- * rebuild effect event of window, document, data center
5156
- * explain:
5157
- * 1. rebuild before exec mount, do nothing
5158
- * 2. rebuild when js executing, recovery recorded effect event, because prerender fiber mode
5159
- * 3. rebuild after js exec end, normal recovery effect event
5160
- */
5161
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
5162
- // current this.container is <div prerender='true'></div>
5163
- cloneContainer(this.container, container, false);
6559
+ this.createSandbox();
6560
+ const nextAction = () => {
6561
+ var _a, _b, _c, _d, _e, _f, _g;
5164
6562
  /**
5165
- * set this.container to <micro-app></micro-app>
5166
- * NOTE:
5167
- * 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
5168
6570
  */
5169
- this.container = container;
5170
- (_b = this.preRenderEvent) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
5171
- // reset isPrerender config
5172
- this.isPrerender = false;
5173
- this.preRenderEvent = undefined;
5174
- // attach router info to browser url
5175
- router.attachToURL(this.name);
5176
- return (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.setPreRenderState(false);
5177
- }
5178
- this.container = container;
5179
- this.inline = inline;
5180
- this.esmodule = esmodule;
5181
- this.fiber = fiber;
5182
- // use in sandbox/effect
5183
- this.useMemoryRouter = useMemoryRouter;
5184
- // this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
5185
- const dispatchBeforeMount = () => {
5186
- dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
5187
- };
5188
- if (this.isPrerender) {
5189
- ((_d = this.preRenderEvent) !== null && _d !== void 0 ? _d : (this.preRenderEvent = [])).push(dispatchBeforeMount);
5190
- }
5191
- else {
5192
- dispatchBeforeMount();
5193
- }
5194
- this.state = appStates.MOUNTING;
5195
- cloneContainer(this.source.html, this.container, !this.umdMode);
5196
- (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
5197
- umdMode: this.umdMode,
5198
- baseroute,
5199
- useMemoryRouter,
5200
- defaultPage,
5201
- disablePatchRequest,
5202
- });
5203
- let umdHookMountResult; // result of mount function
5204
- if (!this.umdMode) {
5205
- let hasDispatchMountedEvent = false;
5206
- // if all js are executed, param isFinished will be true
5207
- execScripts(this, (isFinished) => {
5208
- 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
+ });
5209
6622
  if (!this.umdMode) {
5210
- const { mount, unmount } = this.getUmdLibraryHooks();
5211
- /**
5212
- * umdHookUnmount can works in non UMD mode
5213
- * register with window.unmount
5214
- */
5215
- this.umdHookUnmount = unmount;
5216
- // if mount & unmount is function, the sub app is umd mode
5217
- if (isFunction(mount) && isFunction(unmount)) {
5218
- this.umdHookMount = mount;
5219
- this.umdMode = true;
5220
- if (this.sandBox)
5221
- this.sandBox.proxyWindow.__MICRO_APP_UMD_MODE__ = true;
5222
- // this.sandBox?.recordEffectSnapshot()
5223
- try {
5224
- umdHookMountResult = this.umdHookMount(microApp.getData(this.name, true));
5225
- }
5226
- catch (e) {
5227
- logError('an error occurred in the mount function \n', this.name, e);
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
+ }
5228
6649
  }
5229
- }
6650
+ });
5230
6651
  }
5231
- if (!hasDispatchMountedEvent && (isFinished === true || this.umdMode)) {
5232
- hasDispatchMountedEvent = true;
5233
- const dispatchMounted = () => this.handleMounted(umdHookMountResult);
5234
- if (this.isPrerender) {
5235
- ((_a = this.preRenderEvent) !== null && _a !== void 0 ? _a : (this.preRenderEvent = [])).push(dispatchMounted);
5236
- 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)));
5237
6656
  }
5238
- else {
5239
- dispatchMounted();
6657
+ catch (e) {
6658
+ logError('An error occurred in function mount \n', this.name, e);
5240
6659
  }
5241
6660
  }
5242
- });
5243
- }
5244
- else {
5245
- (_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.rebuildEffectSnapshot();
5246
- try {
5247
- umdHookMountResult = this.umdHookMount();
5248
6661
  }
5249
- catch (e) {
5250
- logError('an error occurred in the mount function \n', this.name, e);
5251
- }
5252
- this.handleMounted(umdHookMountResult);
5253
- }
6662
+ };
6663
+ // TODO: any替换为iframe沙箱类型
6664
+ this.iframe ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
5254
6665
  }
5255
6666
  /**
5256
6667
  * handle for promise umdHookMount
5257
6668
  * @param umdHookMountResult result of umdHookMount
5258
6669
  */
5259
6670
  handleMounted(umdHookMountResult) {
5260
- if (isPromise(umdHookMountResult)) {
5261
- umdHookMountResult
5262
- .then(() => this.dispatchMountedEvent())
5263
- .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 });
5264
6685
  }
5265
6686
  else {
5266
- this.dispatchMountedEvent();
6687
+ dispatchAction();
5267
6688
  }
5268
6689
  }
5269
6690
  /**
@@ -5271,9 +6692,9 @@ class CreateApp {
5271
6692
  */
5272
6693
  dispatchMountedEvent() {
5273
6694
  if (appStates.UNMOUNT !== this.state) {
5274
- this.state = appStates.MOUNTED;
6695
+ this.setAppState(appStates.MOUNTED);
5275
6696
  // call window.onmount of child app
5276
- 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));
5277
6698
  // dispatch event mounted to parent
5278
6699
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
5279
6700
  }
@@ -5287,30 +6708,25 @@ class CreateApp {
5287
6708
  * @param unmountcb callback of unmount
5288
6709
  */
5289
6710
  unmount({ destroy, clearData, keepRouteState, unmountcb, }) {
5290
- if (this.state === appStates.LOAD_FAILED) {
5291
- destroy = true;
5292
- }
5293
- this.state = appStates.UNMOUNT;
5294
- this.keepAliveState = null;
5295
- this.keepAliveContainer = null;
6711
+ var _a;
6712
+ destroy = destroy || this.state === appStates.LOAD_FAILED;
6713
+ this.setAppState(appStates.UNMOUNT);
5296
6714
  // result of unmount function
5297
- let umdHookUnmountResult;
6715
+ let umdHookUnmountResult = null;
5298
6716
  /**
5299
6717
  * send an unmount event to the micro app or call umd unmount hook
5300
6718
  * before the sandbox is cleared
5301
6719
  */
5302
- if (isFunction(this.umdHookUnmount)) {
5303
- try {
5304
- umdHookUnmountResult = this.umdHookUnmount(microApp.getData(this.name, true));
5305
- }
5306
- catch (e) {
5307
- logError('an error occurred in the unmount function \n', this.name, e);
5308
- }
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);
5309
6725
  }
5310
- // call window.onunmount of child app
5311
- callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONUNMOUNT), this.name, `window.${microGlobalEvent.ONUNMOUNT}`);
5312
6726
  // dispatch unmount event to micro app
5313
- 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);
5314
6730
  this.handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb);
5315
6731
  }
5316
6732
  /**
@@ -5322,19 +6738,17 @@ class CreateApp {
5322
6738
  * @param unmountcb callback of unmount
5323
6739
  */
5324
6740
  handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb) {
5325
- const unmountParam = {
6741
+ const nextAction = () => this.actionsForUnmount({
5326
6742
  destroy,
5327
6743
  clearData,
5328
6744
  keepRouteState,
5329
6745
  unmountcb,
5330
- };
6746
+ });
5331
6747
  if (isPromise(umdHookUnmountResult)) {
5332
- umdHookUnmountResult
5333
- .then(() => this.actionsForUnmount(unmountParam))
5334
- .catch(() => this.actionsForUnmount(unmountParam));
6748
+ umdHookUnmountResult.then(nextAction).catch(nextAction);
5335
6749
  }
5336
6750
  else {
5337
- this.actionsForUnmount(unmountParam);
6751
+ nextAction();
5338
6752
  }
5339
6753
  }
5340
6754
  /**
@@ -5345,26 +6759,20 @@ class CreateApp {
5345
6759
  * @param unmountcb callback of unmount
5346
6760
  */
5347
6761
  actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
5348
- var _a, _b;
5349
- if (destroy) {
5350
- this.actionsForCompletelyDestroy();
5351
- }
5352
- else if (this.umdMode && this.container.childElementCount) {
6762
+ var _a;
6763
+ if (this.umdMode && this.container && !destroy) {
5353
6764
  cloneContainer(this.container, this.source.html, false);
5354
6765
  }
5355
- if (this.umdMode) {
5356
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
5357
- }
5358
6766
  /**
5359
6767
  * this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
5360
6768
  * NOTE:
5361
6769
  * 1. if destroy is true, clear route state
5362
6770
  * 2. umd mode and keep-alive will not clear EventSource
5363
6771
  */
5364
- (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop({
6772
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop({
5365
6773
  umdMode: this.umdMode,
5366
6774
  keepRouteState: keepRouteState && !destroy,
5367
- clearEventSource: !this.umdMode || destroy,
6775
+ destroy,
5368
6776
  clearData: clearData || destroy,
5369
6777
  });
5370
6778
  if (!getActiveApps().length) {
@@ -5372,59 +6780,67 @@ class CreateApp {
5372
6780
  }
5373
6781
  // dispatch unmount event to base app
5374
6782
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
5375
- this.resetConfig();
5376
- unmountcb && unmountcb();
6783
+ this.clearOptions(destroy);
6784
+ unmountcb === null || unmountcb === void 0 ? void 0 : unmountcb();
5377
6785
  }
5378
- resetConfig() {
6786
+ clearOptions(destroy) {
5379
6787
  this.container.innerHTML = '';
5380
6788
  this.container = null;
5381
6789
  this.isPrerender = false;
5382
- 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();
5383
6797
  }
5384
6798
  // actions for completely destroy
5385
6799
  actionsForCompletelyDestroy() {
5386
- if (!this.useSandbox && this.umdMode) {
5387
- delete window[this.libraryName];
5388
- }
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);
5389
6802
  sourceCenter.script.deleteInlineInfo(this.source.scripts);
5390
6803
  appInstanceMap.delete(this.name);
5391
6804
  }
5392
6805
  // hidden app when disconnectedCallback called with keep-alive
5393
6806
  hiddenKeepAliveApp(callback) {
5394
- var _a;
5395
- const oldContainer = this.container;
5396
- cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
5397
- this.container = this.keepAliveContainer;
5398
- this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
5399
- // event should dispatch before clone node
5400
- // dispatch afterHidden event to micro-app
5401
- 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', {
5402
6814
  appState: 'afterhidden',
5403
6815
  });
5404
6816
  // dispatch afterHidden event to base app
5405
- dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
5406
- // called after lifeCyclesEvent
5407
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
5408
- this.recordAndReleaseEffect();
5409
- callback && callback();
6817
+ dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
6818
+ if (this.useMemoryRouter) {
6819
+ // called after lifeCyclesEvent
6820
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
6821
+ }
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();
5410
6825
  }
5411
6826
  // show app when connectedCallback called with keep-alive
5412
6827
  showKeepAliveApp(container) {
5413
6828
  var _a, _b;
5414
6829
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
5415
6830
  // dispatch beforeShow event to micro-app
5416
- dispatchCustomEventToMicroApp('appstate-change', this.name, {
6831
+ dispatchCustomEventToMicroApp(this, 'appstate-change', {
5417
6832
  appState: 'beforeshow',
5418
6833
  });
5419
6834
  // dispatch beforeShow event to base app
5420
6835
  dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
5421
- cloneContainer(this.container, container, false);
5422
- this.container = container;
5423
- this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
5424
- // called before lifeCyclesEvent
5425
- (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
6836
+ this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
6837
+ this.container = cloneContainer(this.container, container, false);
6838
+ if (this.useMemoryRouter) {
6839
+ // called before lifeCyclesEvent
6840
+ (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
6841
+ }
5426
6842
  // dispatch afterShow event to micro-app
5427
- dispatchCustomEventToMicroApp('appstate-change', this.name, {
6843
+ dispatchCustomEventToMicroApp(this, 'appstate-change', {
5428
6844
  appState: 'aftershow',
5429
6845
  });
5430
6846
  // dispatch afterShow event to base app
@@ -5437,49 +6853,72 @@ class CreateApp {
5437
6853
  onerror(e) {
5438
6854
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
5439
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
+ }
5440
6876
  // get app state
5441
6877
  getAppState() {
5442
6878
  return this.state;
5443
6879
  }
6880
+ // set keep-alive state
6881
+ setKeepAliveState(state) {
6882
+ this.keepAliveState = state;
6883
+ }
5444
6884
  // get keep-alive state
5445
6885
  getKeepAliveState() {
5446
6886
  return this.keepAliveState;
5447
6887
  }
5448
6888
  // get umd library, if it not exist, return empty object
5449
6889
  getUmdLibraryHooks() {
5450
- var _a, _b, _c, _d;
5451
6890
  // after execScripts, the app maybe unmounted
5452
- if (appStates.UNMOUNT !== this.state) {
5453
- const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
5454
- this.libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
5455
- if (isObject(global[this.libraryName])) {
5456
- 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];
5457
6897
  }
5458
6898
  return {
5459
- mount: (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.proxyWindow.mount,
5460
- unmount: (_d = this.sandBox) === null || _d === void 0 ? void 0 : _d.proxyWindow.unmount,
6899
+ mount: proxyWindow.mount,
6900
+ unmount: proxyWindow.unmount,
5461
6901
  };
5462
6902
  }
5463
6903
  return {};
5464
6904
  }
5465
- getGlobalEventListener(eventName) {
6905
+ getMicroAppGlobalHook(eventName) {
5466
6906
  var _a;
5467
- // @ts-ignore
5468
- 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];
5469
6908
  return isFunction(listener) ? listener : null;
5470
6909
  }
5471
- /**
5472
- * Record global effect and then release (effect: global event, timeout, data listener)
5473
- * Scenes:
5474
- * 1. hidden keep-alive app
5475
- * 2. after init prerender app
5476
- */
5477
- recordAndReleaseEffect() {
5478
- var _a, _b;
5479
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
5480
- (_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;
6912
+ }
6913
+ querySelectorAll(selectors) {
6914
+ return this.container ? globalEnv.rawElementQuerySelectorAll.call(this.container, selectors) : [];
5481
6915
  }
5482
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;
6921
+ }
5483
6922
 
5484
6923
  /**
5485
6924
  * define element
@@ -5507,12 +6946,14 @@ function defineElement(tagName) {
5507
6946
  const formatAttrName = formatAppName(this.getAttribute('name'));
5508
6947
  const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
5509
6948
  if (this.legalAttribute('name', formatAttrName) && this.legalAttribute('url', formatAttrUrl)) {
5510
- const existApp = appInstanceMap.get(formatAttrName);
5511
- if (formatAttrName !== this.appName && existApp) {
5512
- // handling of cached and non-prefetch apps
5513
- if (appStates.UNMOUNT !== existApp.getAppState() &&
5514
- keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
5515
- !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) {
5516
6957
  this.setAttribute('name', this.appName);
5517
6958
  return logError(`app name conflict, an app named ${formatAttrName} is running`);
5518
6959
  }
@@ -5520,16 +6961,16 @@ function defineElement(tagName) {
5520
6961
  if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
5521
6962
  if (formatAttrName === this.appName) {
5522
6963
  this.handleUnmount(true, () => {
5523
- this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
6964
+ this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
5524
6965
  });
5525
6966
  }
5526
6967
  else if (this.getKeepAliveModeResult()) {
5527
6968
  this.handleHiddenKeepAliveApp();
5528
- this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
6969
+ this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
5529
6970
  }
5530
6971
  else {
5531
6972
  this.handleUnmount(this.getDestroyCompatibleResult(), () => {
5532
- this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
6973
+ this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
5533
6974
  });
5534
6975
  }
5535
6976
  }
@@ -5561,10 +7002,16 @@ function defineElement(tagName) {
5561
7002
  * In some special scenes, such as vue's keep-alive, the micro-app will be inserted and deleted twice in an instant
5562
7003
  * So we execute the mount method async and record connectState to prevent repeated rendering
5563
7004
  */
7005
+ const effectiveApp = this.appName && this.appUrl;
5564
7006
  defer(() => {
5565
7007
  if (this.connectStateMap.get(cacheCount)) {
5566
7008
  dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED);
5567
- this.handleConnected();
7009
+ /**
7010
+ * If insert micro-app element without name or url, and set them in next action like angular,
7011
+ * handleConnected will be executed twice, causing the app render repeatedly,
7012
+ * so we only execute handleConnected() if url and name exist when connectedCallback
7013
+ */
7014
+ effectiveApp && this.handleConnected();
5568
7015
  }
5569
7016
  });
5570
7017
  }
@@ -5655,37 +7102,35 @@ function defineElement(tagName) {
5655
7102
  }
5656
7103
  this.updateSsrUrl(this.appUrl);
5657
7104
  if (appInstanceMap.has(this.appName)) {
5658
- const app = appInstanceMap.get(this.appName);
5659
- const existAppUrl = app.ssrUrl || app.url;
5660
- 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;
5661
7108
  /**
5662
7109
  * NOTE:
5663
7110
  * 1. keep-alive don't care about ssrUrl
5664
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
5665
7112
  * 3. When scopecss, useSandbox of prefetch app different from target app, delete prefetch app and create new one
5666
7113
  */
5667
- if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
5668
- app.url === this.appUrl) {
5669
- this.handleShowKeepAliveApp(app);
7114
+ if (oldApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
7115
+ oldApp.url === this.appUrl) {
7116
+ this.handleShowKeepAliveApp(oldApp);
5670
7117
  }
5671
- else if (existAppUrl === targetAppUrl && (app.getAppState() === appStates.UNMOUNT ||
5672
- (app.isPrefetch && (app.scopecss === this.isScopecss() &&
5673
- app.useSandbox === this.isSandbox())))) {
5674
- this.handleAppMount(app);
7118
+ else if (oldAppUrl === targetUrl && (oldApp.getAppState() === appStates.UNMOUNT ||
7119
+ (oldApp.isPrefetch &&
7120
+ this.sameCoreOptions(oldApp)))) {
7121
+ this.handleAppMount(oldApp);
5675
7122
  }
5676
- else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
5677
- if ((process.env.NODE_ENV !== 'production') &&
5678
- app.scopecss === this.isScopecss() &&
5679
- app.useSandbox === this.isSandbox()) {
7123
+ else if (oldApp.isPrefetch || oldApp.getAppState() === appStates.UNMOUNT) {
7124
+ if ((process.env.NODE_ENV !== 'production') && this.sameCoreOptions(oldApp)) {
5680
7125
  /**
5681
7126
  * url is different & old app is unmounted or prefetch, create new app to replace old one
5682
7127
  */
5683
- 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);
5684
7129
  }
5685
7130
  this.handleCreateApp();
5686
7131
  }
5687
7132
  else {
5688
- 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`);
5689
7134
  }
5690
7135
  }
5691
7136
  else {
@@ -5693,7 +7138,7 @@ function defineElement(tagName) {
5693
7138
  }
5694
7139
  }
5695
7140
  // remount app or create app if attribute url or name change
5696
- actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
7141
+ actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp) {
5697
7142
  var _a;
5698
7143
  /**
5699
7144
  * do not add judgment of formatAttrUrl === this.appUrl
@@ -5706,26 +7151,38 @@ function defineElement(tagName) {
5706
7151
  this.setAttribute('name', this.appName);
5707
7152
  }
5708
7153
  /**
5709
- * when existApp not null: this.appName === existApp.name
5710
- * scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, existApp has been unmounted
5711
- * 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
5712
7157
  * scene3: url is different but ssrUrl is equal
5713
7158
  * scene4: url is equal but ssrUrl is different, if url is equal, name must different
5714
- * scene5: if existApp is KEEP_ALIVE_HIDDEN, name must different
7159
+ * scene5: if oldApp is KEEP_ALIVE_HIDDEN, name must different
5715
7160
  */
5716
- if (existApp) {
5717
- if (existApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
5718
- if (existApp.url === this.appUrl) {
5719
- this.handleShowKeepAliveApp(existApp);
7161
+ if (oldApp) {
7162
+ if (oldApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
7163
+ if (oldApp.url === this.appUrl) {
7164
+ this.handleShowKeepAliveApp(oldApp);
5720
7165
  }
5721
7166
  else {
5722
7167
  // the hidden keep-alive app is still active
5723
7168
  logError(`app name conflict, an app named ${this.appName} is running`);
5724
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
+ */
5725
7182
  }
5726
- else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
7183
+ else if (oldApp.url === this.appUrl && oldApp.ssrUrl === this.ssrUrl) {
5727
7184
  // mount app
5728
- this.handleAppMount(existApp);
7185
+ this.handleAppMount(oldApp);
5729
7186
  }
5730
7187
  else {
5731
7188
  this.handleCreateApp();
@@ -5749,24 +7206,39 @@ function defineElement(tagName) {
5749
7206
  }
5750
7207
  // create app instance
5751
7208
  handleCreateApp() {
5752
- 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
+ };
5753
7222
  /**
5754
- * actions for destroy old app
5755
- * 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)
5756
7228
  */
5757
- if (appInstanceMap.has(this.appName)) {
5758
- 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();
5759
7241
  }
5760
- new CreateApp({
5761
- name: this.appName,
5762
- url: this.appUrl,
5763
- scopecss: this.isScopecss(),
5764
- useSandbox: this.isSandbox(),
5765
- inline: this.getDisposeResult('inline'),
5766
- esmodule: this.getDisposeResult('esmodule'),
5767
- container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
5768
- ssrUrl: this.ssrUrl,
5769
- });
5770
7242
  }
5771
7243
  /**
5772
7244
  * mount app
@@ -5792,7 +7264,6 @@ function defineElement(tagName) {
5792
7264
  baseroute: this.getBaseRouteCompatible(),
5793
7265
  disablePatchRequest: this.getDisposeResult('disable-patch-request'),
5794
7266
  fiber: this.getDisposeResult('fiber'),
5795
- esmodule: this.getDisposeResult('esmodule'),
5796
7267
  });
5797
7268
  }
5798
7269
  /**
@@ -5831,10 +7302,10 @@ function defineElement(tagName) {
5831
7302
  * @param name Configuration item name
5832
7303
  */
5833
7304
  getDisposeResult(name) {
5834
- return (this.compatibleSpecialProperties(name) || !!microApp.options[name]) && this.compatibleDisableSpecialProperties(name);
7305
+ return (this.compatibleProperties(name) || !!microApp.options[name]) && this.compatibleDisableProperties(name);
5835
7306
  }
5836
7307
  // compatible of disableScopecss & disableSandbox
5837
- compatibleSpecialProperties(name) {
7308
+ compatibleProperties(name) {
5838
7309
  if (name === 'disable-scopecss') {
5839
7310
  return this.hasAttribute('disable-scopecss') || this.hasAttribute('disableScopecss');
5840
7311
  }
@@ -5844,7 +7315,7 @@ function defineElement(tagName) {
5844
7315
  return this.hasAttribute(name);
5845
7316
  }
5846
7317
  // compatible of disableScopecss & disableSandbox
5847
- compatibleDisableSpecialProperties(name) {
7318
+ compatibleDisableProperties(name) {
5848
7319
  if (name === 'disable-scopecss') {
5849
7320
  return this.getAttribute('disable-scopecss') !== 'false' && this.getAttribute('disableScopecss') !== 'false';
5850
7321
  }
@@ -5853,12 +7324,20 @@ function defineElement(tagName) {
5853
7324
  }
5854
7325
  return this.getAttribute(name) !== 'false';
5855
7326
  }
5856
- isScopecss() {
7327
+ useScopecss() {
5857
7328
  return !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM'));
5858
7329
  }
5859
- isSandbox() {
7330
+ useSandbox() {
5860
7331
  return !this.getDisposeResult('disable-sandbox');
5861
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
+ }
5862
7341
  /**
5863
7342
  * 2021-09-08
5864
7343
  * get baseRoute
@@ -5943,23 +7422,32 @@ function defineElement(tagName) {
5943
7422
  * {
5944
7423
  * name: string,
5945
7424
  * url: string,
5946
- * disableScopecss?: boolean,
5947
- * disableSandbox?: boolean,
5948
- * disableMemoryRouter?: boolean,
7425
+ * iframe: boolean,
7426
+ * inline: boolean,
7427
+ * 'disable-scopecss': boolean,
7428
+ * 'disable-sandbox': boolean,
7429
+ * level: number,
7430
+ * 'default-page': string,
7431
+ * 'disable-patch-request': boolean,
5949
7432
  * },
5950
7433
  * ...
5951
7434
  * ])
5952
7435
  * Note:
5953
- * 1: preFetch is asynchronous and is performed only when the browser is idle
5954
- * 2: disableScopecss, disableSandbox, disableMemoryRouter must be same with micro-app element, if conflict, the one who executes first shall prevail
5955
- * @param apps micro apps
7436
+ * 1: preFetch is async and is performed only when the browser is idle
7437
+ * 2: options of prefetch preferably match the config of the micro-app element, although this is not required
7438
+ * @param apps micro app options
7439
+ * @param delay delay time
5956
7440
  */
5957
7441
  function preFetch(apps, delay) {
5958
7442
  if (!isBrowser) {
5959
7443
  return logError('preFetch is only supported in browser environment');
5960
7444
  }
5961
7445
  requestIdleCallback(() => {
5962
- const delayTime = delay !== null && delay !== void 0 ? delay : microApp.options.prefetchDelay;
7446
+ const delayTime = isNumber(delay) ? delay : microApp.options.prefetchDelay;
7447
+ /**
7448
+ * TODO: remove setTimeout
7449
+ * Is there a better way?
7450
+ */
5963
7451
  setTimeout(() => {
5964
7452
  // releasePrefetchEffect()
5965
7453
  preFetchInSerial(apps);
@@ -5998,7 +7486,7 @@ function preFetchAction(options) {
5998
7486
  scopecss: !((_b = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss) !== null && _b !== void 0 ? _b : microApp.options['disable-scopecss']),
5999
7487
  useSandbox: !((_d = (_c = options['disable-sandbox']) !== null && _c !== void 0 ? _c : options.disableSandbox) !== null && _d !== void 0 ? _d : microApp.options['disable-sandbox']),
6000
7488
  inline: (_e = options.inline) !== null && _e !== void 0 ? _e : microApp.options.inline,
6001
- 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,
6002
7490
  prefetchLevel: options.level && PREFETCH_LEVEL.includes(options.level) ? options.level : microApp.options.prefetchLevel && PREFETCH_LEVEL.includes(microApp.options.prefetchLevel) ? microApp.options.prefetchLevel : 2,
6003
7491
  });
6004
7492
  const oldOnload = app.onLoad;
@@ -6097,10 +7585,19 @@ function unmountApp(appName, options) {
6097
7585
  return new Promise((resolve) => {
6098
7586
  if (app) {
6099
7587
  if (app.getAppState() === appStates.UNMOUNT || app.isPrefetch) {
6100
- if (options === null || options === void 0 ? void 0 : options.destroy) {
6101
- 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);
6102
7600
  }
6103
- resolve(true);
6104
7601
  }
6105
7602
  else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
6106
7603
  if (options === null || options === void 0 ? void 0 : options.destroy) {
@@ -6150,7 +7647,7 @@ function unmountApp(appName, options) {
6150
7647
  else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
6151
7648
  const keepAliveAttrValue = container.getAttribute('keep-alive');
6152
7649
  container.removeAttribute('keep-alive');
6153
- let clearDataAttrValue;
7650
+ let clearDataAttrValue = null;
6154
7651
  if (options.clearData) {
6155
7652
  clearDataAttrValue = container.getAttribute('clear-data');
6156
7653
  container.setAttribute('clear-data', 'true');
@@ -6160,7 +7657,7 @@ function unmountApp(appName, options) {
6160
7657
  isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
6161
7658
  }
6162
7659
  else {
6163
- let clearDataAttrValue;
7660
+ let clearDataAttrValue = null;
6164
7661
  if (options === null || options === void 0 ? void 0 : options.clearData) {
6165
7662
  clearDataAttrValue = container.getAttribute('clear-data');
6166
7663
  container.setAttribute('clear-data', 'true');
@@ -6283,10 +7780,10 @@ class MicroApp extends EventCenterForBaseApp {
6283
7780
  return logError(`${options.tagName} is invalid tagName`);
6284
7781
  }
6285
7782
  }
6286
- if (window.customElements.get(this.tagName)) {
7783
+ initGlobalEnv();
7784
+ if (globalEnv.rawWindow.customElements.get(this.tagName)) {
6287
7785
  return logWarn(`element ${this.tagName} is already defined`);
6288
7786
  }
6289
- initGlobalEnv();
6290
7787
  if (isPlainObject(options)) {
6291
7788
  this.options = options;
6292
7789
  options['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;