@micro-zoe/micro-app 1.0.0-alpha.1 → 1.0.0-alpha.4

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.1';
1
+ const version = '1.0.0-alpha.4';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -41,6 +41,10 @@ function isFunction(target) {
41
41
  function isPlainObject(target) {
42
42
  return toString.call(target) === '[object Object]';
43
43
  }
44
+ // is Object
45
+ function isObject(target) {
46
+ return typeof target === 'object';
47
+ }
44
48
  // is Promise
45
49
  function isPromise(target) {
46
50
  return toString.call(target) === '[object Promise]';
@@ -49,6 +53,18 @@ function isPromise(target) {
49
53
  function isBoundFunction(target) {
50
54
  return isFunction(target) && target.name.indexOf('bound ') === 0 && !target.hasOwnProperty('prototype');
51
55
  }
56
+ // is constructor function
57
+ function isConstructor(target) {
58
+ var _a;
59
+ if (isFunction(target)) {
60
+ const targetStr = target.toString();
61
+ return (((_a = target.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === target &&
62
+ Object.getOwnPropertyNames(target.prototype).length > 1) ||
63
+ /^function\s+[A-Z]/.test(targetStr) ||
64
+ /^class\s+/.test(targetStr);
65
+ }
66
+ return false;
67
+ }
52
68
  // is ShadowRoot
53
69
  function isShadowRoot(target) {
54
70
  return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
@@ -56,6 +72,10 @@ function isShadowRoot(target) {
56
72
  function isURL(target) {
57
73
  return target instanceof URL;
58
74
  }
75
+ // is ProxyDocument
76
+ function isProxyDocument(target) {
77
+ return toString.call(target) === '[object ProxyDocument]';
78
+ }
59
79
  /**
60
80
  * format error log
61
81
  * @param msg message
@@ -270,6 +290,7 @@ function pureCreateElement(tagName, options) {
270
290
  const element = document.createElement(tagName, options);
271
291
  if (element.__MICRO_APP_NAME__)
272
292
  delete element.__MICRO_APP_NAME__;
293
+ element.__PURE_ELEMENT__ = true;
273
294
  return element;
274
295
  }
275
296
  /**
@@ -465,14 +486,82 @@ const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,
465
486
  * @param config fetch options
466
487
  */
467
488
  function fetchSource(url, appName = null, options = {}) {
489
+ /**
490
+ * When child navigate to new async page, click event will scope dom to child and then fetch new source
491
+ * this may cause error when fetch rewrite by baseApp
492
+ * e.g.
493
+ * baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
494
+ */
495
+ removeDomScope();
468
496
  if (isFunction(microApp.fetch)) {
469
497
  return microApp.fetch(url, options, appName);
470
498
  }
471
- return fetch(url, options).then((res) => {
499
+ // Don’t use globalEnv.rawWindow.fetch, will cause sgm-2.8.0.js throw error in nest app
500
+ return window.fetch(url, options).then((res) => {
472
501
  return res.text();
473
502
  });
474
503
  }
475
504
 
505
+ class HTMLLoader {
506
+ static getInstance() {
507
+ if (!this.instance) {
508
+ this.instance = new HTMLLoader();
509
+ }
510
+ return this.instance;
511
+ }
512
+ /**
513
+ * run logic of load and format html
514
+ * @param successCb success callback
515
+ * @param errorCb error callback, type: (err: Error, meetFetchErr: boolean) => void
516
+ */
517
+ run(app, successCb) {
518
+ const appName = app.name;
519
+ const htmlUrl = app.ssrUrl || app.url;
520
+ fetchSource(htmlUrl, appName, { cache: 'no-cache' }).then((htmlStr) => {
521
+ if (!htmlStr) {
522
+ const msg = 'html is empty, please check in detail';
523
+ app.onerror(new Error(msg));
524
+ return logError(msg, appName);
525
+ }
526
+ htmlStr = this.formatHTML(htmlUrl, htmlStr, appName);
527
+ successCb(htmlStr, app);
528
+ }).catch((e) => {
529
+ logError(`Failed to fetch data from ${app.url}, micro-app stop rendering`, appName, e);
530
+ app.onLoadError(e);
531
+ });
532
+ }
533
+ formatHTML(htmlUrl, htmlStr, appName) {
534
+ return this.processHtml(htmlUrl, htmlStr, appName, microApp.plugins)
535
+ .replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
536
+ return match
537
+ .replace(/<head/i, '<micro-app-head')
538
+ .replace(/<\/head>/i, '</micro-app-head>');
539
+ })
540
+ .replace(/<body[^>]*>[\s\S]*?<\/body>/i, (match) => {
541
+ return match
542
+ .replace(/<body/i, '<micro-app-body')
543
+ .replace(/<\/body>/i, '</micro-app-body>');
544
+ });
545
+ }
546
+ processHtml(url, code, appName, plugins) {
547
+ var _a;
548
+ if (!plugins)
549
+ return code;
550
+ const mergedPlugins = [];
551
+ plugins.global && mergedPlugins.push(...plugins.global);
552
+ ((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]) && mergedPlugins.push(...plugins.modules[appName]);
553
+ if (mergedPlugins.length > 0) {
554
+ return mergedPlugins.reduce((preCode, plugin) => {
555
+ if (isPlainObject(plugin) && isFunction(plugin.processHtml)) {
556
+ return plugin.processHtml(preCode, url, plugin.options);
557
+ }
558
+ return preCode;
559
+ }, code);
560
+ }
561
+ return code;
562
+ }
563
+ }
564
+
476
565
  // common reg
477
566
  const rootSelectorREG = /(^|\s+)(html|:root)(?=[\s>~[.#:]+|$)/;
478
567
  const bodySelectorREG = /(^|\s+)((html[\s>~]+body)|body)(?=[\s>~[.#:]+|$)/;
@@ -551,7 +640,7 @@ class CSSParser {
551
640
  return true;
552
641
  }
553
642
  formatSelector(skip) {
554
- const m = this.commonMatch(/^([^{]+)/, skip);
643
+ const m = this.commonMatch(/^[^{]+/, skip);
555
644
  if (!m)
556
645
  return false;
557
646
  return m[0].replace(/(^|,[\n\s]*)([^,]+)/g, (_, separator, selector) => {
@@ -631,7 +720,7 @@ class CSSParser {
631
720
  keyframesRule() {
632
721
  if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
633
722
  return false;
634
- if (!this.commonMatch(/^([-\w]+)\s*/))
723
+ if (!this.commonMatch(/^[^{]+/))
635
724
  return parseError('@keyframes missing name', this.linkPath);
636
725
  this.matchComments();
637
726
  if (!this.matchOpenBrace())
@@ -783,7 +872,7 @@ class CSSParser {
783
872
  }
784
873
  // splice string
785
874
  recordResult(strFragment) {
786
- // Firefox is slow when string contain special characters, see https://github.com/micro-zoe/micro-app/issues/256
875
+ // Firefox performance degradation when string contain special characters, see https://github.com/micro-zoe/micro-app/issues/256
787
876
  if (isFireFox()) {
788
877
  this.result += encodeURIComponent(strFragment);
789
878
  }
@@ -1071,6 +1160,27 @@ function fixReactHMRConflict(app) {
1071
1160
  }
1072
1161
  }
1073
1162
  }
1163
+ /**
1164
+ * reDefine parentNode of html
1165
+ * Scenes:
1166
+ * 1. element-ui popover.js
1167
+ * if (html.parentNode === document) ...
1168
+ */
1169
+ function throttleDeferForParentNode(proxyDocument) {
1170
+ const html = globalEnv.rawDocument.firstElementChild;
1171
+ if (html && html.parentNode !== proxyDocument) {
1172
+ setRootParentNode(html, proxyDocument);
1173
+ defer(() => {
1174
+ setRootParentNode(html, globalEnv.rawDocument);
1175
+ });
1176
+ }
1177
+ }
1178
+ function setRootParentNode(root, value) {
1179
+ Object.defineProperty(root, 'parentNode', {
1180
+ value,
1181
+ configurable: true,
1182
+ });
1183
+ }
1074
1184
 
1075
1185
  // Record element and map element
1076
1186
  const dynamicElementInMicroAppMap = new WeakMap();
@@ -1093,12 +1203,12 @@ function handleNewNode(parent, child, app) {
1093
1203
  return child;
1094
1204
  }
1095
1205
  else if (child instanceof HTMLLinkElement) {
1096
- if (child.hasAttribute('exclude')) {
1206
+ if (child.hasAttribute('exclude') || checkExcludeUrl(child.getAttribute('href'), app.name)) {
1097
1207
  const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
1098
1208
  dynamicElementInMicroAppMap.set(child, linkReplaceComment);
1099
1209
  return linkReplaceComment;
1100
1210
  }
1101
- else if (child.hasAttribute('ignore')) {
1211
+ else if (child.hasAttribute('ignore') || checkIgnoreUrl(child.getAttribute('href'), app.name)) {
1102
1212
  return child;
1103
1213
  }
1104
1214
  const { url, info, replaceComment } = extractLinkFromHtml(child, parent, app, true);
@@ -1208,20 +1318,35 @@ function getMappingNode(node) {
1208
1318
  * @param rawMethod method
1209
1319
  */
1210
1320
  function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1211
- if (newChild === null || newChild === void 0 ? void 0 : newChild.__MICRO_APP_NAME__) {
1321
+ const currentAppName = getCurrentAppName();
1322
+ if (newChild instanceof Node &&
1323
+ (newChild.__MICRO_APP_NAME__ ||
1324
+ (currentAppName && !newChild.__PURE_ELEMENT__))) {
1325
+ newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
1212
1326
  const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
1213
1327
  if (app === null || app === void 0 ? void 0 : app.container) {
1328
+ if (newChild instanceof Element) {
1329
+ if (/^(img|script)$/i.test(newChild.tagName)) {
1330
+ if (newChild.hasAttribute('src')) {
1331
+ globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
1332
+ }
1333
+ if (newChild.hasAttribute('srcset')) {
1334
+ globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
1335
+ }
1336
+ }
1337
+ else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
1338
+ globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
1339
+ }
1340
+ }
1214
1341
  return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(parent, newChild, app), passiveChild && getMappingNode(passiveChild));
1215
1342
  }
1216
1343
  else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
1217
1344
  return rawMethod.call(parent, newChild);
1218
1345
  }
1219
- return rawMethod.call(parent, newChild, passiveChild);
1220
1346
  }
1221
1347
  else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
1222
- const appName = getCurrentAppName();
1223
- if (!(newChild instanceof Node) && appName) {
1224
- const app = appInstanceMap.get(appName);
1348
+ if (!(newChild instanceof Node) && currentAppName) {
1349
+ const app = appInstanceMap.get(currentAppName);
1225
1350
  if (app === null || app === void 0 ? void 0 : app.container) {
1226
1351
  if (parent === document.head) {
1227
1352
  return rawMethod.call(app.container.querySelector('micro-app-head'), newChild);
@@ -1267,12 +1392,18 @@ function patchElementPrototypeMethods() {
1267
1392
  };
1268
1393
  // prototype methods of delete element👇
1269
1394
  Element.prototype.removeChild = function removeChild(oldChild) {
1395
+ var _a;
1270
1396
  if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
1271
1397
  const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
1272
1398
  if (app === null || app === void 0 ? void 0 : app.container) {
1273
1399
  return invokePrototypeMethod(app, globalEnv.rawRemoveChild, this, getMappingNode(oldChild));
1274
1400
  }
1275
- return globalEnv.rawRemoveChild.call(this, oldChild);
1401
+ try {
1402
+ return globalEnv.rawRemoveChild.call(this, oldChild);
1403
+ }
1404
+ catch (_b) {
1405
+ return (_a = oldChild === null || oldChild === void 0 ? void 0 : oldChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(oldChild);
1406
+ }
1276
1407
  }
1277
1408
  return globalEnv.rawRemoveChild.call(this, oldChild);
1278
1409
  };
@@ -1288,109 +1419,120 @@ function patchElementPrototypeMethods() {
1288
1419
  * @param element new element
1289
1420
  */
1290
1421
  function markElement(element) {
1291
- const appName = getCurrentAppName();
1292
- if (appName)
1293
- element.__MICRO_APP_NAME__ = appName;
1422
+ const currentAppName = getCurrentAppName();
1423
+ if (currentAppName)
1424
+ element.__MICRO_APP_NAME__ = currentAppName;
1294
1425
  return element;
1295
1426
  }
1296
1427
  // methods of document
1297
1428
  function patchDocument() {
1298
1429
  const rawDocument = globalEnv.rawDocument;
1430
+ const rawRootDocument = globalEnv.rawRootDocument;
1431
+ function getBindTarget(target) {
1432
+ return isProxyDocument(target) ? rawDocument : target;
1433
+ }
1299
1434
  // create element 👇
1300
- Document.prototype.createElement = function createElement(tagName, options) {
1301
- const element = globalEnv.rawCreateElement.call(this, tagName, options);
1435
+ rawRootDocument.prototype.createElement = function createElement(tagName, options) {
1436
+ const element = globalEnv.rawCreateElement.call(getBindTarget(this), tagName, options);
1302
1437
  return markElement(element);
1303
1438
  };
1304
- Document.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
1305
- const element = globalEnv.rawCreateElementNS.call(this, namespaceURI, name, options);
1439
+ rawRootDocument.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
1440
+ const element = globalEnv.rawCreateElementNS.call(getBindTarget(this), namespaceURI, name, options);
1306
1441
  return markElement(element);
1307
1442
  };
1308
- Document.prototype.createDocumentFragment = function createDocumentFragment() {
1309
- const element = globalEnv.rawCreateDocumentFragment.call(this);
1443
+ rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
1444
+ const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
1310
1445
  return markElement(element);
1311
1446
  };
1312
1447
  // query element👇
1313
1448
  function querySelector(selectors) {
1314
1449
  var _a, _b, _c, _d;
1315
- const appName = getCurrentAppName();
1316
- if (!appName ||
1317
- !((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) ||
1450
+ const _this = getBindTarget(this);
1451
+ const currentAppName = getCurrentAppName();
1452
+ if (!currentAppName ||
1453
+ !((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
1318
1454
  !selectors ||
1319
1455
  isUniqueElement(selectors) ||
1320
1456
  // see https://github.com/micro-zoe/micro-app/issues/56
1321
- rawDocument !== this) {
1322
- return globalEnv.rawQuerySelector.call(this, selectors);
1457
+ rawDocument !== _this) {
1458
+ return globalEnv.rawQuerySelector.call(_this, selectors);
1323
1459
  }
1324
- return (_d = (_c = (_b = appInstanceMap.get(appName)) === null || _b === void 0 ? void 0 : _b.container) === null || _c === void 0 ? void 0 : _c.querySelector(selectors)) !== null && _d !== void 0 ? _d : null;
1460
+ 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;
1325
1461
  }
1326
1462
  function querySelectorAll(selectors) {
1327
1463
  var _a, _b, _c, _d;
1328
- const appName = getCurrentAppName();
1329
- if (!appName ||
1330
- !((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) ||
1464
+ const _this = getBindTarget(this);
1465
+ const currentAppName = getCurrentAppName();
1466
+ if (!currentAppName ||
1467
+ !((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
1331
1468
  !selectors ||
1332
1469
  isUniqueElement(selectors) ||
1333
- rawDocument !== this) {
1334
- return globalEnv.rawQuerySelectorAll.call(this, selectors);
1470
+ rawDocument !== _this) {
1471
+ return globalEnv.rawQuerySelectorAll.call(_this, selectors);
1335
1472
  }
1336
- return (_d = (_c = (_b = appInstanceMap.get(appName)) === null || _b === void 0 ? void 0 : _b.container) === null || _c === void 0 ? void 0 : _c.querySelectorAll(selectors)) !== null && _d !== void 0 ? _d : [];
1473
+ 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 : [];
1337
1474
  }
1338
- Document.prototype.querySelector = querySelector;
1339
- Document.prototype.querySelectorAll = querySelectorAll;
1340
- Document.prototype.getElementById = function getElementById(key) {
1475
+ rawRootDocument.prototype.querySelector = querySelector;
1476
+ rawRootDocument.prototype.querySelectorAll = querySelectorAll;
1477
+ rawRootDocument.prototype.getElementById = function getElementById(key) {
1478
+ const _this = getBindTarget(this);
1341
1479
  if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) {
1342
- return globalEnv.rawGetElementById.call(this, key);
1480
+ return globalEnv.rawGetElementById.call(_this, key);
1343
1481
  }
1344
1482
  try {
1345
- return querySelector.call(this, `#${key}`);
1483
+ return querySelector.call(_this, `#${key}`);
1346
1484
  }
1347
1485
  catch (_a) {
1348
- return globalEnv.rawGetElementById.call(this, key);
1486
+ return globalEnv.rawGetElementById.call(_this, key);
1349
1487
  }
1350
1488
  };
1351
- Document.prototype.getElementsByClassName = function getElementsByClassName(key) {
1489
+ rawRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
1490
+ const _this = getBindTarget(this);
1352
1491
  if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) {
1353
- return globalEnv.rawGetElementsByClassName.call(this, key);
1492
+ return globalEnv.rawGetElementsByClassName.call(_this, key);
1354
1493
  }
1355
1494
  try {
1356
- return querySelectorAll.call(this, `.${key}`);
1495
+ return querySelectorAll.call(_this, `.${key}`);
1357
1496
  }
1358
1497
  catch (_a) {
1359
- return globalEnv.rawGetElementsByClassName.call(this, key);
1498
+ return globalEnv.rawGetElementsByClassName.call(_this, key);
1360
1499
  }
1361
1500
  };
1362
- Document.prototype.getElementsByTagName = function getElementsByTagName(key) {
1501
+ rawRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
1363
1502
  var _a;
1364
- const appName = getCurrentAppName();
1365
- if (!appName ||
1503
+ const _this = getBindTarget(this);
1504
+ const currentAppName = getCurrentAppName();
1505
+ if (!currentAppName ||
1366
1506
  isUniqueElement(key) ||
1367
1507
  isInvalidQuerySelectorKey(key) ||
1368
- (!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
1369
- return globalEnv.rawGetElementsByTagName.call(this, key);
1508
+ (!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
1509
+ return globalEnv.rawGetElementsByTagName.call(_this, key);
1370
1510
  }
1371
1511
  try {
1372
- return querySelectorAll.call(this, key);
1512
+ return querySelectorAll.call(_this, key);
1373
1513
  }
1374
1514
  catch (_b) {
1375
- return globalEnv.rawGetElementsByTagName.call(this, key);
1515
+ return globalEnv.rawGetElementsByTagName.call(_this, key);
1376
1516
  }
1377
1517
  };
1378
- Document.prototype.getElementsByName = function getElementsByName(key) {
1518
+ rawRootDocument.prototype.getElementsByName = function getElementsByName(key) {
1519
+ const _this = getBindTarget(this);
1379
1520
  if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) {
1380
- return globalEnv.rawGetElementsByName.call(this, key);
1521
+ return globalEnv.rawGetElementsByName.call(_this, key);
1381
1522
  }
1382
1523
  try {
1383
- return querySelectorAll.call(this, `[name=${key}]`);
1524
+ return querySelectorAll.call(_this, `[name=${key}]`);
1384
1525
  }
1385
1526
  catch (_a) {
1386
- return globalEnv.rawGetElementsByName.call(this, key);
1527
+ return globalEnv.rawGetElementsByName.call(_this, key);
1387
1528
  }
1388
1529
  };
1389
1530
  }
1390
1531
  /**
1391
1532
  * patchSetAttribute is different from other patch
1392
- * it not dependent on sandbox
1393
- * it should exec when micro-app first created & release when all app unmounted
1533
+ * NOTE:
1534
+ * 1. it not dependent on sandbox
1535
+ * 2. it should exec when first micro-app-element created & release when all app unmounted
1394
1536
  */
1395
1537
  let hasRewriteSetAttribute = false;
1396
1538
  function patchSetAttribute() {
@@ -1401,9 +1543,9 @@ function patchSetAttribute() {
1401
1543
  if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
1402
1544
  if (isPlainObject(value)) {
1403
1545
  const cloneValue = {};
1404
- Object.getOwnPropertyNames(value).forEach((key) => {
1405
- if (!(isString(key) && key.indexOf('__') === 0)) {
1406
- cloneValue[key] = value[key];
1546
+ Object.getOwnPropertyNames(value).forEach((ownKey) => {
1547
+ if (!(isString(ownKey) && ownKey.indexOf('__') === 0)) {
1548
+ cloneValue[ownKey] = value[ownKey];
1407
1549
  }
1408
1550
  });
1409
1551
  this.data = cloneValue;
@@ -1412,36 +1554,34 @@ function patchSetAttribute() {
1412
1554
  logWarn('property data must be an object', this.getAttribute('name'));
1413
1555
  }
1414
1556
  }
1415
- else if ((((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
1416
- (key === 'href' && /^link$/i.test(this.tagName))) &&
1417
- this.__MICRO_APP_NAME__ &&
1418
- appInstanceMap.has(this.__MICRO_APP_NAME__)) {
1419
- const app = appInstanceMap.get(this.__MICRO_APP_NAME__);
1420
- globalEnv.rawSetAttribute.call(this, key, CompletionPath(value, app.url));
1421
- }
1422
1557
  else {
1558
+ const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
1559
+ if (appName &&
1560
+ appInstanceMap.has(appName) &&
1561
+ (((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
1562
+ (key === 'href' && /^link$/i.test(this.tagName)))) {
1563
+ const app = appInstanceMap.get(appName);
1564
+ value = CompletionPath(value, app.url);
1565
+ }
1423
1566
  globalEnv.rawSetAttribute.call(this, key, value);
1424
1567
  }
1425
1568
  };
1426
1569
  }
1427
- function releasePatchSetAttribute() {
1428
- hasRewriteSetAttribute = false;
1429
- Element.prototype.setAttribute = globalEnv.rawSetAttribute;
1430
- }
1431
1570
  function releasePatchDocument() {
1432
- Document.prototype.createElement = globalEnv.rawCreateElement;
1433
- Document.prototype.createElementNS = globalEnv.rawCreateElementNS;
1434
- Document.prototype.createDocumentFragment = globalEnv.rawCreateDocumentFragment;
1435
- Document.prototype.querySelector = globalEnv.rawQuerySelector;
1436
- Document.prototype.querySelectorAll = globalEnv.rawQuerySelectorAll;
1437
- Document.prototype.getElementById = globalEnv.rawGetElementById;
1438
- Document.prototype.getElementsByClassName = globalEnv.rawGetElementsByClassName;
1439
- Document.prototype.getElementsByTagName = globalEnv.rawGetElementsByTagName;
1440
- Document.prototype.getElementsByName = globalEnv.rawGetElementsByName;
1571
+ const rawRootDocument = globalEnv.rawRootDocument;
1572
+ rawRootDocument.prototype.createElement = globalEnv.rawCreateElement;
1573
+ rawRootDocument.prototype.createElementNS = globalEnv.rawCreateElementNS;
1574
+ rawRootDocument.prototype.createDocumentFragment = globalEnv.rawCreateDocumentFragment;
1575
+ rawRootDocument.prototype.querySelector = globalEnv.rawQuerySelector;
1576
+ rawRootDocument.prototype.querySelectorAll = globalEnv.rawQuerySelectorAll;
1577
+ rawRootDocument.prototype.getElementById = globalEnv.rawGetElementById;
1578
+ rawRootDocument.prototype.getElementsByClassName = globalEnv.rawGetElementsByClassName;
1579
+ rawRootDocument.prototype.getElementsByTagName = globalEnv.rawGetElementsByTagName;
1580
+ rawRootDocument.prototype.getElementsByName = globalEnv.rawGetElementsByName;
1441
1581
  }
1442
1582
  // release patch
1443
1583
  function releasePatches() {
1444
- setCurrentAppName(null);
1584
+ removeDomScope();
1445
1585
  releasePatchDocument();
1446
1586
  Element.prototype.appendChild = globalEnv.rawAppendChild;
1447
1587
  Element.prototype.insertBefore = globalEnv.rawInsertBefore;
@@ -1451,6 +1591,11 @@ function releasePatches() {
1451
1591
  Element.prototype.prepend = globalEnv.rawPrepend;
1452
1592
  Element.prototype.cloneNode = globalEnv.rawCloneNode;
1453
1593
  }
1594
+ // exec when last child unmount
1595
+ function releasePatchSetAttribute() {
1596
+ hasRewriteSetAttribute = false;
1597
+ Element.prototype.setAttribute = globalEnv.rawSetAttribute;
1598
+ }
1454
1599
  // Set the style of micro-app-head and micro-app-body
1455
1600
  let hasRejectMicroAppStyle = false;
1456
1601
  function rejectMicroAppStyle() {
@@ -1470,6 +1615,10 @@ const globalEnv = {};
1470
1615
  */
1471
1616
  function initGlobalEnv() {
1472
1617
  if (isBrowser) {
1618
+ const rawWindow = Function('return window')();
1619
+ const rawDocument = Function('return document')();
1620
+ const rawRootDocument = Function('return Document')();
1621
+ const supportModuleScript = isSupportModuleScript();
1473
1622
  /**
1474
1623
  * save patch raw methods
1475
1624
  * pay attention to this binding
@@ -1482,15 +1631,15 @@ function initGlobalEnv() {
1482
1631
  const rawAppend = Element.prototype.append;
1483
1632
  const rawPrepend = Element.prototype.prepend;
1484
1633
  const rawCloneNode = Element.prototype.cloneNode;
1485
- const rawCreateElement = Document.prototype.createElement;
1486
- const rawCreateElementNS = Document.prototype.createElementNS;
1487
- const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
1488
- const rawQuerySelector = Document.prototype.querySelector;
1489
- const rawQuerySelectorAll = Document.prototype.querySelectorAll;
1490
- const rawGetElementById = Document.prototype.getElementById;
1491
- const rawGetElementsByClassName = Document.prototype.getElementsByClassName;
1492
- const rawGetElementsByTagName = Document.prototype.getElementsByTagName;
1493
- const rawGetElementsByName = Document.prototype.getElementsByName;
1634
+ const rawCreateElement = rawRootDocument.prototype.createElement;
1635
+ const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
1636
+ const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
1637
+ const rawQuerySelector = rawRootDocument.prototype.querySelector;
1638
+ const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
1639
+ const rawGetElementById = rawRootDocument.prototype.getElementById;
1640
+ const rawGetElementsByClassName = rawRootDocument.prototype.getElementsByClassName;
1641
+ const rawGetElementsByTagName = rawRootDocument.prototype.getElementsByTagName;
1642
+ const rawGetElementsByName = rawRootDocument.prototype.getElementsByName;
1494
1643
  const ImageProxy = new Proxy(Image, {
1495
1644
  construct(Target, args) {
1496
1645
  const elementImage = new Target(...args);
@@ -1498,9 +1647,6 @@ function initGlobalEnv() {
1498
1647
  return elementImage;
1499
1648
  },
1500
1649
  });
1501
- const rawWindow = Function('return window')();
1502
- const rawDocument = Function('return document')();
1503
- const supportModuleScript = isSupportModuleScript();
1504
1650
  /**
1505
1651
  * save effect raw methods
1506
1652
  * pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
@@ -1511,11 +1657,18 @@ function initGlobalEnv() {
1511
1657
  const rawSetTimeout = rawWindow.setTimeout;
1512
1658
  const rawClearInterval = rawWindow.clearInterval;
1513
1659
  const rawClearTimeout = rawWindow.clearTimeout;
1660
+ const rawPushState = rawWindow.history.pushState;
1661
+ const rawReplaceState = rawWindow.history.replaceState;
1514
1662
  const rawDocumentAddEventListener = rawDocument.addEventListener;
1515
1663
  const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
1516
1664
  // mark current application as base application
1517
1665
  window.__MICRO_APP_BASE_APPLICATION__ = true;
1518
1666
  assign(globalEnv, {
1667
+ // common global vars
1668
+ rawWindow,
1669
+ rawDocument,
1670
+ rawRootDocument,
1671
+ supportModuleScript,
1519
1672
  // source/patch
1520
1673
  rawSetAttribute,
1521
1674
  rawAppendChild,
@@ -1535,10 +1688,6 @@ function initGlobalEnv() {
1535
1688
  rawGetElementsByTagName,
1536
1689
  rawGetElementsByName,
1537
1690
  ImageProxy,
1538
- // common global vars
1539
- rawWindow,
1540
- rawDocument,
1541
- supportModuleScript,
1542
1691
  // sandbox/effect
1543
1692
  rawWindowAddEventListener,
1544
1693
  rawWindowRemoveEventListener,
@@ -1548,6 +1697,8 @@ function initGlobalEnv() {
1548
1697
  rawClearTimeout,
1549
1698
  rawDocumentAddEventListener,
1550
1699
  rawDocumentRemoveEventListener,
1700
+ rawPushState,
1701
+ rawReplaceState,
1551
1702
  });
1552
1703
  // global effect
1553
1704
  rejectMicroAppStyle();
@@ -1566,11 +1717,14 @@ const globalScripts = new Map();
1566
1717
  function extractScriptElement(script, parent, app, isDynamic = false) {
1567
1718
  let replaceComment = null;
1568
1719
  let src = script.getAttribute('src');
1569
- if (script.hasAttribute('exclude')) {
1720
+ if (src) {
1721
+ src = CompletionPath(src, app.url);
1722
+ }
1723
+ if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
1570
1724
  replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
1571
1725
  }
1572
- else if ((script.type && !['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module'].includes(script.type)) ||
1573
- script.hasAttribute('ignore')) {
1726
+ else if ((script.type && !['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'].includes(script.type)) ||
1727
+ script.hasAttribute('ignore') || checkIgnoreUrl(src, app.name)) {
1574
1728
  return null;
1575
1729
  }
1576
1730
  else if ((globalEnv.supportModuleScript && script.noModule) ||
@@ -1578,7 +1732,6 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
1578
1732
  replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
1579
1733
  }
1580
1734
  else if (src) { // remote script
1581
- src = CompletionPath(src, app.url);
1582
1735
  const info = {
1583
1736
  code: '',
1584
1737
  isExternal: true,
@@ -1628,6 +1781,46 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
1628
1781
  return parent.replaceChild(replaceComment, script);
1629
1782
  }
1630
1783
  }
1784
+ /**
1785
+ * get assets plugins
1786
+ * @param appName app name
1787
+ */
1788
+ function getAssetsPlugins(appName) {
1789
+ var _a, _b, _c;
1790
+ const globalPlugins = ((_a = microApp.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
1791
+ const modulePlugins = ((_c = (_b = microApp.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
1792
+ return [...globalPlugins, ...modulePlugins];
1793
+ }
1794
+ /**
1795
+ * whether the url needs to be excluded
1796
+ * @param url css or js link
1797
+ * @param plugins microApp plugins
1798
+ */
1799
+ function checkExcludeUrl(url, appName) {
1800
+ if (!url)
1801
+ return false;
1802
+ const plugins = getAssetsPlugins(appName) || [];
1803
+ return plugins.some(plugin => {
1804
+ if (!plugin.excludeChecker)
1805
+ return false;
1806
+ return plugin.excludeChecker(url);
1807
+ });
1808
+ }
1809
+ /**
1810
+ * whether the url needs to be ignore
1811
+ * @param url css or js link
1812
+ * @param plugins microApp plugins
1813
+ */
1814
+ function checkIgnoreUrl(url, appName) {
1815
+ if (!url)
1816
+ return false;
1817
+ const plugins = getAssetsPlugins(appName) || [];
1818
+ return plugins.some(plugin => {
1819
+ if (!plugin.ignoreChecker)
1820
+ return false;
1821
+ return plugin.ignoreChecker(url);
1822
+ });
1823
+ }
1631
1824
  /**
1632
1825
  * Get remote resources of script
1633
1826
  * @param wrapElement htmlDom
@@ -1768,6 +1961,13 @@ function runDynamicRemoteScript(url, info, app, originScript) {
1768
1961
  if (app.source.scripts.has(url)) {
1769
1962
  const existInfo = app.source.scripts.get(url);
1770
1963
  !existInfo.module && defer(dispatchScriptOnLoadEvent);
1964
+ /**
1965
+ * TODO: 这里要改,当script初始化时动态创建远程script时,初次渲染和二次渲染的顺序不一致,会导致错误
1966
+ * 1、url不存在缓存,初始化的时候肯定是要异步请求,那么执行顺序就会靠后,至少落后于html自带的script
1967
+ * 2、url存在缓存,那么二次渲染的时候这里会同步执行,就会先于html自带的script执行
1968
+ * 3、测试一下,初次渲染和二次渲染时,onload的执行时机,是在js执行完成,还是执行之前
1969
+ * 4、将上述问题做成注释,方便后续阅读和理解
1970
+ */
1771
1971
  return runScript(url, app, existInfo, true, dispatchScriptOnLoadEvent);
1772
1972
  }
1773
1973
  if (globalScripts.has(url)) {
@@ -1800,7 +2000,7 @@ function runDynamicRemoteScript(url, info, app, originScript) {
1800
2000
  catch (e) {
1801
2001
  console.error(`[micro-app from runDynamicScript] app ${app.name}: `, e, url);
1802
2002
  }
1803
- !info.module && dispatchOnLoadEvent(originScript);
2003
+ !info.module && dispatchScriptOnLoadEvent();
1804
2004
  }).catch((err) => {
1805
2005
  logError(err, app.name);
1806
2006
  dispatchOnErrorEvent(originScript);
@@ -1848,6 +2048,7 @@ function runCode2Function(code, info) {
1848
2048
  * @param info source script info
1849
2049
  */
1850
2050
  function bindScope(url, app, code, info) {
2051
+ // TODO: 增加缓存机制
1851
2052
  if (isPlainObject(microApp.plugins)) {
1852
2053
  code = usePlugins(url, code, app.name, microApp.plugins, info);
1853
2054
  }
@@ -1904,10 +2105,10 @@ function flatChildren(parent, app, microAppHead) {
1904
2105
  });
1905
2106
  for (const dom of children) {
1906
2107
  if (dom instanceof HTMLLinkElement) {
1907
- if (dom.hasAttribute('exclude')) {
2108
+ if (dom.hasAttribute('exclude') || checkExcludeUrl(dom.getAttribute('href'), app.name)) {
1908
2109
  parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
1909
2110
  }
1910
- else if (!dom.hasAttribute('ignore')) {
2111
+ else if (!(dom.hasAttribute('ignore') || checkIgnoreUrl(dom.getAttribute('href'), app.name))) {
1911
2112
  extractLinkFromHtml(dom, parent, app);
1912
2113
  }
1913
2114
  else if (dom.hasAttribute('href')) {
@@ -1961,34 +2162,6 @@ function extractSourceDom(htmlStr, app) {
1961
2162
  app.onLoad(wrapElement);
1962
2163
  }
1963
2164
  }
1964
- /**
1965
- * Get and format html
1966
- * @param app app
1967
- */
1968
- function extractHtml(app) {
1969
- fetchSource(app.ssrUrl || app.url, app.name, { cache: 'no-cache' }).then((htmlStr) => {
1970
- if (!htmlStr) {
1971
- const msg = 'html is empty, please check in detail';
1972
- app.onerror(new Error(msg));
1973
- return logError(msg, app.name);
1974
- }
1975
- htmlStr = htmlStr
1976
- .replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
1977
- return match
1978
- .replace(/<head/i, '<micro-app-head')
1979
- .replace(/<\/head>/i, '</micro-app-head>');
1980
- })
1981
- .replace(/<body[^>]*>[\s\S]*?<\/body>/i, (match) => {
1982
- return match
1983
- .replace(/<body/i, '<micro-app-body')
1984
- .replace(/<\/body>/i, '</micro-app-body>');
1985
- });
1986
- extractSourceDom(htmlStr, app);
1987
- }).catch((e) => {
1988
- logError(`Failed to fetch data from ${app.url}, micro-app stop rendering`, app.name, e);
1989
- app.onLoadError(e);
1990
- });
1991
- }
1992
2165
 
1993
2166
  class EventCenter {
1994
2167
  constructor() {
@@ -2271,12 +2444,39 @@ function rebuildDataCenterSnapshot(microAppEventCenter) {
2271
2444
  }
2272
2445
  }
2273
2446
 
2447
+ // 管理 app 的单例
2448
+ class AppManager {
2449
+ constructor() {
2450
+ // Todo: appInstanceMap 由 AppManager 来创建,不再由 create_app 管理
2451
+ this.appInstanceMap = appInstanceMap;
2452
+ }
2453
+ static getInstance() {
2454
+ if (!this.instance) {
2455
+ this.instance = new AppManager();
2456
+ }
2457
+ return this.instance;
2458
+ }
2459
+ get(appName) {
2460
+ return this.appInstanceMap.get(appName);
2461
+ }
2462
+ set(appName, app) {
2463
+ this.appInstanceMap.set(appName, app);
2464
+ }
2465
+ getAll() {
2466
+ return Array.from(this.appInstanceMap.values());
2467
+ }
2468
+ clear() {
2469
+ this.appInstanceMap.clear();
2470
+ }
2471
+ }
2472
+
2274
2473
  function unmountNestedApp() {
2275
- appInstanceMap.forEach(app => {
2474
+ releaseUnmountOfNestedApp();
2475
+ AppManager.getInstance().getAll().forEach(app => {
2276
2476
  // @ts-ignore
2277
2477
  app.container && getRootContainer(app.container).disconnectedCallback();
2278
2478
  });
2279
- !window.__MICRO_APP_UMD_MODE__ && appInstanceMap.clear();
2479
+ !window.__MICRO_APP_UMD_MODE__ && AppManager.getInstance().clear();
2280
2480
  }
2281
2481
  // release listener
2282
2482
  function releaseUnmountOfNestedApp() {
@@ -2286,7 +2486,7 @@ function releaseUnmountOfNestedApp() {
2286
2486
  }
2287
2487
  // if micro-app run in micro application, delete all next generation application when unmount event received
2288
2488
  // unmount event will auto release by sandbox
2289
- function listenUmountOfNestedApp() {
2489
+ function initEnvOfNestedApp() {
2290
2490
  if (window.__MICRO_APP_ENVIRONMENT__) {
2291
2491
  releaseUnmountOfNestedApp();
2292
2492
  window.addEventListener('unmount', unmountNestedApp, false);
@@ -2299,35 +2499,30 @@ function isBoundedFunction(value) {
2299
2499
  return value.__MICRO_APP_IS_BOUND_FUNCTION__;
2300
2500
  return value.__MICRO_APP_IS_BOUND_FUNCTION__ = isBoundFunction(value);
2301
2501
  }
2302
- function isConstructor(value) {
2303
- var _a;
2502
+ function isConstructorFunction(value) {
2304
2503
  if (isBoolean(value.__MICRO_APP_IS_CONSTRUCTOR__))
2305
2504
  return value.__MICRO_APP_IS_CONSTRUCTOR__;
2306
- const valueStr = value.toString();
2307
- const result = (((_a = value.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === value &&
2308
- Object.getOwnPropertyNames(value.prototype).length > 1) ||
2309
- /^function\s+[A-Z]/.test(valueStr) ||
2310
- /^class\s+/.test(valueStr);
2311
- return value.__MICRO_APP_IS_CONSTRUCTOR__ = result;
2505
+ return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
2312
2506
  }
2313
2507
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
2314
- function bindFunctionToRawWindow(rawWindow, value) {
2315
- if (value.__MICRO_APP_BOUND_WINDOW_FUNCTION__)
2316
- return value.__MICRO_APP_BOUND_WINDOW_FUNCTION__;
2317
- if (!isConstructor(value) && !isBoundedFunction(value)) {
2318
- const bindRawWindowValue = value.bind(rawWindow);
2508
+ function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
2509
+ const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
2510
+ if (value[cacheKey])
2511
+ return value[cacheKey];
2512
+ if (!isConstructorFunction(value) && !isBoundedFunction(value)) {
2513
+ const bindRawObjectValue = value.bind(rawObject);
2319
2514
  for (const key in value) {
2320
- bindRawWindowValue[key] = value[key];
2515
+ bindRawObjectValue[key] = value[key];
2321
2516
  }
2322
2517
  if (value.hasOwnProperty('prototype')) {
2323
- rawDefineProperty(bindRawWindowValue, 'prototype', {
2518
+ rawDefineProperty(bindRawObjectValue, 'prototype', {
2324
2519
  value: value.prototype,
2325
2520
  configurable: true,
2326
2521
  enumerable: false,
2327
2522
  writable: true,
2328
2523
  });
2329
2524
  }
2330
- return value.__MICRO_APP_BOUND_WINDOW_FUNCTION__ = bindRawWindowValue;
2525
+ return value[cacheKey] = bindRawObjectValue;
2331
2526
  }
2332
2527
  return value;
2333
2528
  }
@@ -2493,6 +2688,13 @@ function effect(appName, microAppWindow) {
2493
2688
  let umdIntervalIdMap = new Map();
2494
2689
  let umdTimeoutIdMap = new Map();
2495
2690
  let umdOnClickHandler;
2691
+ const clearUmdSnapshotData = () => {
2692
+ umdWindowListenerMap.clear();
2693
+ umdIntervalIdMap.clear();
2694
+ umdTimeoutIdMap.clear();
2695
+ umdDocumentListenerMap.clear();
2696
+ umdOnClickHandler = null;
2697
+ };
2496
2698
  // record event and timer before exec umdMountHook
2497
2699
  const recordUmdEffect = () => {
2498
2700
  // record window event
@@ -2538,13 +2740,12 @@ function effect(appName, microAppWindow) {
2538
2740
  // rebuild onclick event
2539
2741
  umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
2540
2742
  // rebuild document event
2541
- setCurrentAppName(appName);
2542
2743
  umdDocumentListenerMap.forEach((listenerList, type) => {
2543
2744
  for (const listener of listenerList) {
2544
2745
  document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
2545
2746
  }
2546
2747
  });
2547
- setCurrentAppName(null);
2748
+ clearUmdSnapshotData();
2548
2749
  };
2549
2750
  // release all event listener & interval & timeout when unmount app
2550
2751
  const releaseEffect = () => {
@@ -2591,7 +2792,8 @@ function effect(appName, microAppWindow) {
2591
2792
  }
2592
2793
 
2593
2794
  // set micro app state to origin state
2594
- function setMicroState(appName, rawState, microState) {
2795
+ function setMicroState(appName, microState) {
2796
+ const rawState = globalEnv.rawWindow.history.state;
2595
2797
  const additionalState = {
2596
2798
  microAppState: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.microAppState, {
2597
2799
  [appName]: microState
@@ -2614,9 +2816,9 @@ function removeMicroState(appName, rawState) {
2614
2816
  return assign({}, rawState);
2615
2817
  }
2616
2818
  // get micro app state form origin state
2617
- function getMicroState(appName, state) {
2618
- var _a;
2619
- return ((_a = state === null || state === void 0 ? void 0 : state.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
2819
+ function getMicroState(appName) {
2820
+ var _a, _b;
2821
+ return ((_b = (_a = globalEnv.rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.microAppState) === null || _b === void 0 ? void 0 : _b[appName]) || null;
2620
2822
  }
2621
2823
  const ENC_AD_RE = /&/g; // %M1
2622
2824
  const ENC_EQ_RE = /=/g; // %M2
@@ -2641,7 +2843,8 @@ function commonDecode(path) {
2641
2843
  }
2642
2844
  // 格式化query参数key,防止与原有参数的冲突
2643
2845
  function formatQueryAppName(appName) {
2644
- return `app-${appName}`;
2846
+ // return `app-${appName}`
2847
+ return appName;
2645
2848
  }
2646
2849
  // 根据浏览器url参数,获取当前子应用的path
2647
2850
  function getMicroPathFromURL(appName) {
@@ -2746,7 +2949,10 @@ function addHistoryListener(appName) {
2746
2949
  const rawWindow = globalEnv.rawWindow;
2747
2950
  // handle popstate event and distribute to child app
2748
2951
  const popStateHandler = (e) => {
2749
- // exclude hidden keep-alive app
2952
+ /**
2953
+ * 1. unmount app & hidden keep-alive app will not receive popstate event
2954
+ * 2. filter out onlyForBrowser
2955
+ */
2750
2956
  if (getActiveApps(true).includes(appName) && !e.onlyForBrowser) {
2751
2957
  const microPath = getMicroPathFromURL(appName);
2752
2958
  const app = appInstanceMap.get(appName);
@@ -2761,7 +2967,7 @@ function addHistoryListener(appName) {
2761
2967
  isHashChange = proxyWindow.location.hash !== oldHash;
2762
2968
  }
2763
2969
  // dispatch formatted popStateEvent to child
2764
- dispatchPopStateEventToMicroApp(appName, proxyWindow, rawWindow.history.state);
2970
+ dispatchPopStateEventToMicroApp(appName, proxyWindow);
2765
2971
  // dispatch formatted hashChangeEvent to child when hash change
2766
2972
  if (isHashChange)
2767
2973
  dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref);
@@ -2780,9 +2986,9 @@ function addHistoryListener(appName) {
2780
2986
  * @param proxyWindow sandbox window
2781
2987
  * @param eventState history.state
2782
2988
  */
2783
- function dispatchPopStateEventToMicroApp(appName, proxyWindow, eventState) {
2989
+ function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
2784
2990
  // create PopStateEvent named popstate-appName with sub app state
2785
- const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName, eventState) });
2991
+ const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName) });
2786
2992
  globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
2787
2993
  // call function window.onpopstate if it exists
2788
2994
  typeof proxyWindow.onpopstate === 'function' && proxyWindow.onpopstate(newPopStateEvent);
@@ -2847,37 +3053,44 @@ function createMicroHistory(appName, microLocation) {
2847
3053
  const rawHistory = globalEnv.rawWindow.history;
2848
3054
  function getMicroHistoryMethod(methodName) {
2849
3055
  return function (...rests) {
2850
- if ((methodName === 'pushState' || methodName === 'replaceState') &&
2851
- (isString(rests[2]) || isURL(rests[2]))) {
3056
+ if (isString(rests[2]) || isURL(rests[2])) {
2852
3057
  const targetLocation = createURL(rests[2], microLocation.href);
2853
3058
  if (targetLocation.origin === microLocation.origin) {
2854
- navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rawHistory.state, rests[0]), rests[1]);
3059
+ navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
2855
3060
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
2856
3061
  if (targetFullPath !== microLocation.fullPath) {
2857
3062
  updateMicroLocation(appName, targetFullPath, microLocation);
2858
3063
  }
3064
+ return void 0;
2859
3065
  }
2860
- else {
2861
- rawHistory[methodName].apply(rawHistory, rests);
2862
- }
2863
- }
2864
- else {
2865
- rawHistory[methodName].apply(rawHistory, rests);
2866
3066
  }
3067
+ nativeHistoryNavigate(methodName, rests[2], rests[0], rests[1]);
2867
3068
  };
2868
3069
  }
3070
+ const pushState = getMicroHistoryMethod('pushState');
3071
+ const replaceState = getMicroHistoryMethod('replaceState');
2869
3072
  return new Proxy(rawHistory, {
2870
3073
  get(target, key) {
2871
3074
  if (key === 'state') {
2872
- return getMicroState(appName, rawHistory.state);
3075
+ return getMicroState(appName);
3076
+ }
3077
+ else if (key === 'pushState') {
3078
+ return pushState;
2873
3079
  }
2874
- else if (isFunction(Reflect.get(target, key))) {
2875
- return getMicroHistoryMethod(key);
3080
+ else if (key === 'replaceState') {
3081
+ return replaceState;
2876
3082
  }
2877
- return Reflect.get(target, key);
3083
+ const rawValue = Reflect.get(target, key);
3084
+ return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'HISTORY') : rawValue;
2878
3085
  },
2879
3086
  set(target, key, value) {
2880
- return Reflect.set(target, key, value);
3087
+ Reflect.set(target, key, value);
3088
+ /**
3089
+ * If the set() method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
3090
+ * e.g. history.state = {}
3091
+ * TypeError: 'set' on proxy: trap returned falsish for property 'state'
3092
+ */
3093
+ return true;
2881
3094
  }
2882
3095
  });
2883
3096
  }
@@ -2889,12 +3102,13 @@ function createMicroHistory(appName, microLocation) {
2889
3102
  * @param title history.title, default is ''
2890
3103
  */
2891
3104
  function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
2892
- globalEnv.rawWindow.history[methodName](state, title, fullPath);
3105
+ const method = methodName === 'pushState' ? globalEnv.rawPushState : globalEnv.rawReplaceState;
3106
+ method.call(globalEnv.rawWindow.history, state, title, fullPath);
2893
3107
  }
2894
3108
  /**
2895
3109
  * Navigate to new path, and dispatch native popStateEvent/hashChangeEvent to browser
2896
3110
  * Use scenes:
2897
- * 1. mount/unmount through updateBrowserURL with limited popstateEvent
3111
+ * 1. mount/unmount through attachRouteToBrowserURL with limited popstateEvent
2898
3112
  * 2. proxyHistory.pushState/replaceState with limited popstateEvent
2899
3113
  * 3. api microApp.router.push/replace
2900
3114
  * 4. proxyLocation.hash = xxx
@@ -2914,19 +3128,20 @@ function navigateWithNativeEvent(methodName, result, onlyForBrowser, state, titl
2914
3128
  dispatchNativeEvent(onlyForBrowser, oldHref);
2915
3129
  }
2916
3130
  /**
2917
- * update browser url when mount/unmount/hidden/show
3131
+ * update browser url when mount/unmount/hidden/show/attachToURL/attachAllToURL
3132
+ * just attach microRoute info to browser, dispatch event to base app(exclude child)
2918
3133
  * @param result result of add/remove microApp path on browser url
2919
3134
  * @param state history.state
2920
3135
  */
2921
- function updateBrowserURL(result, state) {
3136
+ function attachRouteToBrowserURL(result, state) {
2922
3137
  navigateWithNativeEvent('replaceState', result, true, state);
2923
3138
  }
2924
3139
  /**
2925
3140
  * When path is same, keep the microAppState in history.state
2926
- * Fix bug of missing microAppState in next.js & angular
3141
+ * Fix bug of missing microAppState when base app is next.js or angular
2927
3142
  * @param method history.pushState/replaceState
2928
3143
  */
2929
- function patchHistoryState(method) {
3144
+ function reWriteHistoryMethod(method) {
2930
3145
  const rawWindow = globalEnv.rawWindow;
2931
3146
  return function (...rests) {
2932
3147
  var _a;
@@ -2942,22 +3157,38 @@ function patchHistoryState(method) {
2942
3157
  }
2943
3158
  }
2944
3159
  method.apply(rawWindow.history, rests);
3160
+ /**
3161
+ * Attach child router info to browser url when base app navigate with pushState/replaceState
3162
+ * NOTE:
3163
+ * 1. Exec after apply pushState/replaceState
3164
+ * 2. Unable to catch when base app navigate with location
3165
+ * 3. When in nest app, rawPushState/rawReplaceState has been modified by parent
3166
+ * 4.
3167
+ */
3168
+ getActiveApps(true).forEach(appName => {
3169
+ const app = appInstanceMap.get(appName);
3170
+ if (app.sandBox && app.useMemoryRouter && !getMicroPathFromURL(appName)) {
3171
+ attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
3172
+ }
3173
+ });
3174
+ // fix bug for nest app
3175
+ removeDomScope();
2945
3176
  };
2946
3177
  }
2947
- let isReWriteHistoryState = false;
2948
3178
  /**
2949
3179
  * rewrite history.pushState/replaceState
2950
3180
  * used to fix the problem that the microAppState maybe missing when mainApp navigate to same path
2951
3181
  * e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
2952
3182
  */
2953
- function rewriteHistoryState() {
2954
- // filter nest app
2955
- if (!isReWriteHistoryState && !window.__MICRO_APP_ENVIRONMENT__) {
2956
- isReWriteHistoryState = true;
2957
- const rawWindow = globalEnv.rawWindow;
2958
- rawWindow.history.pushState = patchHistoryState(rawWindow.history.pushState);
2959
- rawWindow.history.replaceState = patchHistoryState(rawWindow.history.replaceState);
2960
- }
3183
+ function patchHistory() {
3184
+ const rawWindow = globalEnv.rawWindow;
3185
+ rawWindow.history.pushState = reWriteHistoryMethod(globalEnv.rawPushState);
3186
+ rawWindow.history.replaceState = reWriteHistoryMethod(globalEnv.rawReplaceState);
3187
+ }
3188
+ function releasePatchHistory() {
3189
+ const rawWindow = globalEnv.rawWindow;
3190
+ rawWindow.history.pushState = globalEnv.rawPushState;
3191
+ rawWindow.history.replaceState = globalEnv.rawReplaceState;
2961
3192
  }
2962
3193
 
2963
3194
  function createRouterApi() {
@@ -2969,7 +3200,7 @@ function createRouterApi() {
2969
3200
  * @param state to.state
2970
3201
  */
2971
3202
  function navigateWithRawHistory(appName, methodName, targetLocation, state) {
2972
- navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, globalEnv.rawWindow.history.state, state !== null && state !== void 0 ? state : null));
3203
+ navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
2973
3204
  // clear element scope after navigate
2974
3205
  removeDomScope();
2975
3206
  }
@@ -2984,11 +3215,11 @@ function createRouterApi() {
2984
3215
  function createNavigationMethod(replace) {
2985
3216
  return function (to) {
2986
3217
  const appName = formatAppName(to.name);
2987
- // console.log(3333333, appInstanceMap.get(appName))
2988
3218
  if (appName && isString(to.path)) {
2989
3219
  const app = appInstanceMap.get(appName);
2990
- if (app && !app.sandBox)
2991
- return logError(`navigation failed, sandBox of app ${appName} is closed`);
3220
+ if (app && (!app.sandBox || !app.useMemoryRouter)) {
3221
+ return logError(`navigation failed, memory router of app ${appName} is closed`);
3222
+ }
2992
3223
  // active apps, include hidden keep-alive app
2993
3224
  if (getActiveApps().includes(appName)) {
2994
3225
  const microLocation = app.sandBox.proxyWindow.location;
@@ -3031,7 +3262,7 @@ function createRouterApi() {
3031
3262
  * NOTE:
3032
3263
  * 1. Modify browser url first, and then run guards,
3033
3264
  * consistent with the browser forward & back button
3034
- * 2. Note the element binding
3265
+ * 2. Prevent the element binding
3035
3266
  * @param appName app name
3036
3267
  * @param to target location
3037
3268
  * @param from old location
@@ -3065,43 +3296,102 @@ function createRouterApi() {
3065
3296
  function clearRouterWhenUnmount(appName) {
3066
3297
  router.current.delete(appName);
3067
3298
  }
3068
- // defaultPage data
3069
- const defaultPageRecord = useMapRecord();
3070
3299
  /**
3071
- * defaultPage只在子应用初始化时生效,且优先级比浏览器上的子应用路由地址低
3300
+ * NOTE:
3301
+ * 1. sandbox not open
3302
+ * 2. useMemoryRouter is false
3303
+ */
3304
+ function commonHandlerForAttachToURL(appName) {
3305
+ const app = appInstanceMap.get(appName);
3306
+ if (app.sandBox && app.useMemoryRouter) {
3307
+ attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
3308
+ }
3309
+ }
3310
+ /**
3311
+ * Attach specified active app router info to browser url
3072
3312
  * @param appName app name
3073
- * @param path page path
3074
3313
  */
3075
- function setDefaultPage(appName, path) {
3314
+ function attachToURL(appName) {
3076
3315
  appName = formatAppName(appName);
3077
- if (!appName)
3078
- return noopFalse;
3079
- return defaultPageRecord.add(appName, path);
3316
+ if (appName && getActiveApps().includes(appName)) {
3317
+ commonHandlerForAttachToURL(appName);
3318
+ }
3080
3319
  }
3081
- function removeDefaultPage(appName) {
3082
- appName = formatAppName(appName);
3083
- if (!appName)
3084
- return false;
3085
- return defaultPageRecord.delete(appName);
3320
+ /**
3321
+ * Attach all active app router info to browser url
3322
+ * exclude hidden keep-alive app
3323
+ */
3324
+ function attachAllToURL(includeHiddenApp = false) {
3325
+ getActiveApps(!includeHiddenApp).forEach(appName => commonHandlerForAttachToURL(appName));
3326
+ }
3327
+ function createDefaultPageApi() {
3328
+ // defaultPage data
3329
+ const defaultPageRecord = useMapRecord();
3330
+ /**
3331
+ * defaultPage only effect when mount, and has lower priority than query on browser url
3332
+ * SetDefaultPageOptions {
3333
+ * @param name app name
3334
+ * @param path page path
3335
+ * }
3336
+ */
3337
+ function setDefaultPage(options) {
3338
+ const appName = formatAppName(options.name);
3339
+ if (!appName || !options.path) {
3340
+ if (process.env.NODE_ENV !== 'production') {
3341
+ if (!appName) {
3342
+ logWarn(`setDefaultPage: invalid appName "${appName}"`);
3343
+ }
3344
+ else {
3345
+ logWarn('setDefaultPage: path is required');
3346
+ }
3347
+ }
3348
+ return noopFalse;
3349
+ }
3350
+ return defaultPageRecord.add(appName, options.path);
3351
+ }
3352
+ function removeDefaultPage(appName) {
3353
+ appName = formatAppName(appName);
3354
+ if (!appName)
3355
+ return false;
3356
+ return defaultPageRecord.delete(appName);
3357
+ }
3358
+ return {
3359
+ setDefaultPage,
3360
+ removeDefaultPage,
3361
+ getDefaultPage: defaultPageRecord.get,
3362
+ };
3363
+ }
3364
+ function createBaseRouterApi() {
3365
+ /**
3366
+ * Record base app router, let child app control base app navigation
3367
+ */
3368
+ let baseRouterProxy = null;
3369
+ function setBaseAppRouter(baseRouter) {
3370
+ if (isObject(baseRouter)) {
3371
+ baseRouterProxy = new Proxy(baseRouter, {
3372
+ get(target, key) {
3373
+ removeDomScope();
3374
+ const rawValue = Reflect.get(target, key);
3375
+ return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'BASEROUTER') : rawValue;
3376
+ },
3377
+ set(target, key, value) {
3378
+ Reflect.set(target, key, value);
3379
+ return true;
3380
+ }
3381
+ });
3382
+ }
3383
+ else if (process.env.NODE_ENV !== 'production') {
3384
+ logWarn('setBaseAppRouter: Invalid base router');
3385
+ }
3386
+ }
3387
+ return {
3388
+ setBaseAppRouter,
3389
+ getBaseAppRouter: () => baseRouterProxy,
3390
+ };
3086
3391
  }
3087
3392
  // Router API for developer
3088
- const router = {
3089
- current: new Map(),
3090
- encode: encodeMicroPath,
3091
- decode: decodeMicroPath,
3092
- push: createNavigationMethod(false),
3093
- replace: createNavigationMethod(true),
3094
- go: createRawHistoryMethod('go'),
3095
- back: createRawHistoryMethod('back'),
3096
- forward: createRawHistoryMethod('forward'),
3097
- beforeEach: beforeGuards.add,
3098
- afterEach: afterGuards.add,
3099
- // attachToURL: 将指定的子应用路由信息添加到浏览器地址上
3100
- // attachAllToURL: 将所有正在运行的子应用路由信息添加到浏览器地址上
3101
- setDefaultPage,
3102
- removeDefaultPage,
3103
- getDefaultPage: defaultPageRecord.get,
3104
- };
3393
+ const router = Object.assign(Object.assign({ current: new Map(), encode: encodeMicroPath, decode: decodeMicroPath, push: createNavigationMethod(false), replace: createNavigationMethod(true), go: createRawHistoryMethod('go'), back: createRawHistoryMethod('back'), forward: createRawHistoryMethod('forward'), beforeEach: beforeGuards.add, afterEach: afterGuards.add, attachToURL,
3394
+ attachAllToURL }, createDefaultPageApi()), createBaseRouterApi());
3105
3395
  return {
3106
3396
  router,
3107
3397
  executeNavigationGuard,
@@ -3115,56 +3405,6 @@ const shadowLocationKeys = ['href', 'pathname', 'search', 'hash'];
3115
3405
  const locationKeys = [...shadowLocationKeys, 'host', 'hostname', 'port', 'protocol', 'search'];
3116
3406
  // origin, fullPath is necessary for guardLocation
3117
3407
  const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
3118
- /**
3119
- * create guardLocation by microLocation, used for router guard
3120
- */
3121
- function createGuardLocation(appName, microLocation) {
3122
- const guardLocation = assign({ name: appName }, microLocation);
3123
- // The prototype values on the URL needs to be manually transferred
3124
- for (const key of guardLocationKeys)
3125
- guardLocation[key] = microLocation[key];
3126
- return guardLocation;
3127
- }
3128
- // for updateBrowserURLWithLocation when initial
3129
- function autoTriggerNavigationGuard(appName, microLocation) {
3130
- executeNavigationGuard(appName, createGuardLocation(appName, microLocation), createGuardLocation(appName, microLocation));
3131
- }
3132
- /**
3133
- * The following scenes will trigger location update:
3134
- * 1. pushState/replaceState
3135
- * 2. popStateEvent
3136
- * 3. query on browser url when init sub app
3137
- * 4. set defaultPage when when init sub app
3138
- * NOTE:
3139
- * 1. update browser URL first, and then update microLocation
3140
- * 2. the same fullPath will not trigger router guards
3141
- * @param appName app name
3142
- * @param path target path
3143
- * @param base base url
3144
- * @param microLocation micro app location
3145
- * @param type auto prevent
3146
- */
3147
- function updateMicroLocation(appName, path, microLocation, type) {
3148
- const newLocation = createURL(path, microLocation.href);
3149
- // record old values of microLocation to `from`
3150
- const from = createGuardLocation(appName, microLocation);
3151
- for (const key of locationKeys) {
3152
- if (shadowLocationKeys.includes(key)) {
3153
- // reference of shadowLocation
3154
- microLocation.shadowLocation[key] = newLocation[key];
3155
- }
3156
- else {
3157
- // @ts-ignore reference of microLocation
3158
- microLocation[key] = newLocation[key];
3159
- }
3160
- }
3161
- // update latest values of microLocation to `to`
3162
- const to = createGuardLocation(appName, microLocation);
3163
- // The hook called only when fullPath changed
3164
- if (type === 'auto' || (from.fullPath !== to.fullPath && type !== 'prevent')) {
3165
- executeNavigationGuard(appName, to, from);
3166
- }
3167
- }
3168
3408
  /**
3169
3409
  * Create location for microApp, each microApp has only one location object, it is a reference type
3170
3410
  * MDN https://developer.mozilla.org/en-US/docs/Web/API/Location
@@ -3309,6 +3549,56 @@ function createMicroLocation(appName, url) {
3309
3549
  shadowLocation,
3310
3550
  });
3311
3551
  }
3552
+ /**
3553
+ * create guardLocation by microLocation, used for router guard
3554
+ */
3555
+ function createGuardLocation(appName, microLocation) {
3556
+ const guardLocation = assign({ name: appName }, microLocation);
3557
+ // The prototype values on the URL needs to be manually transferred
3558
+ for (const key of guardLocationKeys)
3559
+ guardLocation[key] = microLocation[key];
3560
+ return guardLocation;
3561
+ }
3562
+ // for updateBrowserURLWithLocation when initial
3563
+ function autoTriggerNavigationGuard(appName, microLocation) {
3564
+ executeNavigationGuard(appName, createGuardLocation(appName, microLocation), createGuardLocation(appName, microLocation));
3565
+ }
3566
+ /**
3567
+ * The following scenes will trigger location update:
3568
+ * 1. pushState/replaceState
3569
+ * 2. popStateEvent
3570
+ * 3. query on browser url when init sub app
3571
+ * 4. set defaultPage when when init sub app
3572
+ * NOTE:
3573
+ * 1. update browser URL first, and then update microLocation
3574
+ * 2. the same fullPath will not trigger router guards
3575
+ * @param appName app name
3576
+ * @param path target path
3577
+ * @param base base url
3578
+ * @param microLocation micro app location
3579
+ * @param type auto prevent
3580
+ */
3581
+ function updateMicroLocation(appName, path, microLocation, type) {
3582
+ const newLocation = createURL(path, microLocation.href);
3583
+ // record old values of microLocation to `from`
3584
+ const from = createGuardLocation(appName, microLocation);
3585
+ for (const key of locationKeys) {
3586
+ if (shadowLocationKeys.includes(key)) {
3587
+ // reference of shadowLocation
3588
+ microLocation.shadowLocation[key] = newLocation[key];
3589
+ }
3590
+ else {
3591
+ // @ts-ignore reference of microLocation
3592
+ microLocation[key] = newLocation[key];
3593
+ }
3594
+ }
3595
+ // update latest values of microLocation to `to`
3596
+ const to = createGuardLocation(appName, microLocation);
3597
+ // The hook called only when fullPath changed
3598
+ if (type === 'auto' || (from.fullPath !== to.fullPath && type !== 'prevent')) {
3599
+ executeNavigationGuard(appName, to, from);
3600
+ }
3601
+ }
3312
3602
 
3313
3603
  /**
3314
3604
  * The router system has two operations: read and write
@@ -3318,7 +3608,6 @@ function createMicroLocation(appName, url) {
3318
3608
  * @returns MicroRouter
3319
3609
  */
3320
3610
  function createMicroRouter(appName, url) {
3321
- rewriteHistoryState();
3322
3611
  const microLocation = createMicroLocation(appName, url);
3323
3612
  return {
3324
3613
  microLocation,
@@ -3344,7 +3633,7 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
3344
3633
  if (defaultPage)
3345
3634
  updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
3346
3635
  // attach microApp route info to browser URL
3347
- updateBrowserURL(setMicroPathToURL(appName, microLocation), setMicroState(appName, globalEnv.rawWindow.history.state, null));
3636
+ attachRouteToBrowserURL(setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
3348
3637
  // trigger guards after change browser URL
3349
3638
  autoTriggerNavigationGuard(appName, microLocation);
3350
3639
  }
@@ -3368,7 +3657,7 @@ function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
3368
3657
  * called on sandbox.stop or hidden of keep-alive app
3369
3658
  */
3370
3659
  function removeStateAndPathFromBrowser(appName) {
3371
- updateBrowserURL(removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
3660
+ attachRouteToBrowserURL(removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
3372
3661
  }
3373
3662
 
3374
3663
  /**
@@ -3380,13 +3669,21 @@ function removeStateAndPathFromBrowser(appName) {
3380
3669
  * @param target proxy target
3381
3670
  */
3382
3671
  function createMicroFetch(url, target) {
3383
- if (!isUndefined(target) && !isFunction(target))
3384
- return target;
3385
- const rawFetch = target || globalEnv.rawWindow.fetch;
3672
+ const rawFetch = !isUndefined(target) ? target : globalEnv.rawWindow.fetch;
3673
+ if (!isFunction(rawFetch))
3674
+ return rawFetch;
3386
3675
  return function microFetch(input, init, ...rests) {
3387
3676
  if (isString(input) || isURL(input)) {
3388
3677
  input = createURL(input, url).toString();
3389
3678
  }
3679
+ /**
3680
+ * When fetch rewrite by baseApp, domScope still active when exec rawWindow.fetch
3681
+ * If baseApp operate dom in fetch, it will cause error
3682
+ * The same for XMLHttpRequest, EventSource
3683
+ * e.g.
3684
+ * baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
3685
+ */
3686
+ removeDomScope();
3390
3687
  return rawFetch.call(globalEnv.rawWindow, input, init, ...rests);
3391
3688
  };
3392
3689
  }
@@ -3397,14 +3694,15 @@ function createMicroFetch(url, target) {
3397
3694
  * @param target proxy target
3398
3695
  */
3399
3696
  function createMicroXMLHttpRequest(url, target) {
3400
- if (!isUndefined(target) && !isFunction(target))
3401
- return target;
3402
- const rawXMLHttpRequest = target || globalEnv.rawWindow.XMLHttpRequest;
3697
+ const rawXMLHttpRequest = !isUndefined(target) ? target : globalEnv.rawWindow.XMLHttpRequest;
3698
+ if (!isConstructor(rawXMLHttpRequest))
3699
+ return rawXMLHttpRequest;
3403
3700
  return class MicroXMLHttpRequest extends rawXMLHttpRequest {
3404
3701
  open(method, reqUrl, ...rests) {
3405
3702
  if ((isString(reqUrl) && !/^f(ile|tp):\/\//.test(reqUrl)) || isURL(reqUrl)) {
3406
3703
  reqUrl = createURL(reqUrl, url).toString();
3407
3704
  }
3705
+ removeDomScope();
3408
3706
  super.open(method, reqUrl, ...rests);
3409
3707
  }
3410
3708
  };
@@ -3420,14 +3718,15 @@ function useMicroEventSource() {
3420
3718
  * @param target proxy target
3421
3719
  */
3422
3720
  function createMicroEventSource(appName, url, target) {
3423
- if (!isUndefined(target) && !isFunction(target))
3424
- return target;
3425
- const rawEventSource = target || globalEnv.rawWindow.EventSource;
3721
+ const rawEventSource = !isUndefined(target) ? target : globalEnv.rawWindow.EventSource;
3722
+ if (!isConstructor(rawEventSource))
3723
+ return rawEventSource;
3426
3724
  return class MicroEventSource extends rawEventSource {
3427
3725
  constructor(eventSourceUrl, eventSourceInitDict, ...rests) {
3428
3726
  if (isString(eventSourceUrl) || isURL(eventSourceUrl)) {
3429
3727
  eventSourceUrl = createURL(eventSourceUrl, url).toString();
3430
3728
  }
3729
+ removeDomScope();
3431
3730
  super(eventSourceUrl, eventSourceInitDict, ...rests);
3432
3731
  if (eventSourceMap) {
3433
3732
  const eventSourceList = eventSourceMap.get(appName);
@@ -3479,6 +3778,8 @@ class SandBox {
3479
3778
  this.injectedKeys = new Set();
3480
3779
  // Properties escape to rawWindow, cleared when unmount
3481
3780
  this.escapeKeys = new Set();
3781
+ // record injected values before the first execution of umdHookMount and rebuild before remount umd app
3782
+ // private recordUmdInjectedValues?: Map<PropertyKey, unknown>
3482
3783
  // sandbox state
3483
3784
  this.active = false;
3484
3785
  this.microAppWindow = {}; // Proxy target
@@ -3492,7 +3793,8 @@ class SandBox {
3492
3793
  // inject global properties
3493
3794
  this.initStaticGlobalKeys(this.microAppWindow, appName, url, useMemoryRouter);
3494
3795
  }
3495
- start(baseRoute, useMemoryRouter = true, defaultPage = '') {
3796
+ // TODO: 重构
3797
+ start(umdMode = false, baseRoute = '', useMemoryRouter = true, defaultPage = '', disablePatchRequest = false) {
3496
3798
  if (!this.active) {
3497
3799
  this.active = true;
3498
3800
  if (useMemoryRouter) {
@@ -3503,17 +3805,23 @@ class SandBox {
3503
3805
  else {
3504
3806
  this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseRoute;
3505
3807
  }
3506
- // prevent the key deleted during sandBox.stop after rewrite
3507
- this.initGlobalKeysWhenStart(this.microAppWindow, this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__);
3808
+ /**
3809
+ * 1. prevent the key deleted during sandBox.stop after rewrite
3810
+ * 2. umd mode will not delete any keys during sandBox.stop
3811
+ */
3812
+ if (!umdMode) {
3813
+ this.initGlobalKeysWhenStart(this.microAppWindow, this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__, disablePatchRequest);
3814
+ }
3508
3815
  if (++SandBox.activeCount === 1) {
3509
3816
  effectDocumentEvent();
3510
3817
  patchElementPrototypeMethods();
3511
- listenUmountOfNestedApp();
3818
+ initEnvOfNestedApp();
3819
+ patchHistory();
3512
3820
  }
3513
3821
  fixBabelPolyfill6();
3514
3822
  }
3515
3823
  }
3516
- stop(keepRouteState, clearEventSource) {
3824
+ stop(umdMode, keepRouteState, clearEventSource) {
3517
3825
  if (this.active) {
3518
3826
  this.releaseEffect();
3519
3827
  this.microAppWindow.microApp.clearDataListener();
@@ -3530,37 +3838,41 @@ class SandBox {
3530
3838
  * NOTE:
3531
3839
  * 1. injectedKeys and escapeKeys must be placed at the back
3532
3840
  * 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
3841
+ * 3. umd mode will not delete global keys
3533
3842
  */
3534
- this.injectedKeys.forEach((key) => {
3535
- Reflect.deleteProperty(this.microAppWindow, key);
3536
- });
3537
- this.injectedKeys.clear();
3538
- this.escapeKeys.forEach((key) => {
3539
- Reflect.deleteProperty(globalEnv.rawWindow, key);
3540
- });
3541
- this.escapeKeys.clear();
3843
+ if (!umdMode) {
3844
+ this.injectedKeys.forEach((key) => {
3845
+ Reflect.deleteProperty(this.microAppWindow, key);
3846
+ });
3847
+ this.injectedKeys.clear();
3848
+ this.escapeKeys.forEach((key) => {
3849
+ Reflect.deleteProperty(globalEnv.rawWindow, key);
3850
+ });
3851
+ this.escapeKeys.clear();
3852
+ }
3542
3853
  if (--SandBox.activeCount === 0) {
3543
3854
  releaseEffectDocumentEvent();
3544
3855
  releasePatches();
3856
+ releasePatchHistory();
3545
3857
  }
3546
3858
  this.active = false;
3547
3859
  }
3548
3860
  }
3549
3861
  // record umd snapshot before the first execution of umdHookMount
3550
3862
  recordUmdSnapshot() {
3551
- this.microAppWindow.__MICRO_APP_UMD_MODE__ = true;
3863
+ // this.microAppWindow.__MICRO_APP_UMD_MODE__ = true
3552
3864
  this.recordUmdEffect();
3553
3865
  recordDataCenterSnapshot(this.microAppWindow.microApp);
3554
- this.recordUmdInjectedValues = new Map();
3555
- this.injectedKeys.forEach((key) => {
3556
- this.recordUmdInjectedValues.set(key, Reflect.get(this.microAppWindow, key));
3557
- });
3866
+ // this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
3867
+ // this.injectedKeys.forEach((key: PropertyKey) => {
3868
+ // this.recordUmdInjectedValues!.set(key, Reflect.get(this.microAppWindow, key))
3869
+ // })
3558
3870
  }
3559
3871
  // rebuild umd snapshot before remount umd app
3560
3872
  rebuildUmdSnapshot() {
3561
- this.recordUmdInjectedValues.forEach((value, key) => {
3562
- Reflect.set(this.proxyWindow, key, value);
3563
- });
3873
+ // this.recordUmdInjectedValues!.forEach((value: unknown, key: PropertyKey) => {
3874
+ // Reflect.set(this.proxyWindow, key, value)
3875
+ // })
3564
3876
  this.rebuildUmdEffect();
3565
3877
  rebuildDataCenterSnapshot(this.microAppWindow.microApp);
3566
3878
  }
@@ -3604,7 +3916,7 @@ class SandBox {
3604
3916
  this.scopeProperties.includes(key))
3605
3917
  return Reflect.get(target, key);
3606
3918
  const rawValue = Reflect.get(rawWindow, key);
3607
- return isFunction(rawValue) ? bindFunctionToRawWindow(rawWindow, rawValue) : rawValue;
3919
+ return isFunction(rawValue) ? bindFunctionToRawObject(rawWindow, rawValue) : rawValue;
3608
3920
  },
3609
3921
  set: (target, key, value) => {
3610
3922
  if (this.active) {
@@ -3704,20 +4016,33 @@ class SandBox {
3704
4016
  pureCreateElement,
3705
4017
  router,
3706
4018
  });
4019
+ this.setProxyDocument(microAppWindow, appName);
3707
4020
  this.setMappingPropertiesWithRawDescriptor(microAppWindow);
3708
4021
  if (useMemoryRouter)
3709
4022
  this.setMicroAppRouter(microAppWindow, appName, url);
3710
4023
  }
3711
- /**
3712
- * init global properties of microAppWindow when exec sandBox.start
3713
- * @param microAppWindow micro window
3714
- * @param appName app name
3715
- * @param url app url
3716
- */
3717
- initGlobalKeysWhenStart(microAppWindow, appName, url) {
3718
- microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
3719
- this.setHijackProperties(microAppWindow, appName);
3720
- this.patchHijackRequest(microAppWindow, appName, url);
4024
+ setProxyDocument(microAppWindow, appName) {
4025
+ const { proxyDocument, MicroDocument } = this.createProxyDocument(appName);
4026
+ rawDefineProperties(microAppWindow, {
4027
+ document: {
4028
+ configurable: false,
4029
+ enumerable: true,
4030
+ get() {
4031
+ throttleDeferForSetAppName(appName);
4032
+ // return globalEnv.rawDocument
4033
+ return proxyDocument;
4034
+ },
4035
+ },
4036
+ Document: {
4037
+ configurable: false,
4038
+ enumerable: false,
4039
+ get() {
4040
+ throttleDeferForSetAppName(appName);
4041
+ // return globalEnv.rawRootDocument
4042
+ return MicroDocument;
4043
+ },
4044
+ }
4045
+ });
3721
4046
  }
3722
4047
  // properties associated with the native window
3723
4048
  setMappingPropertiesWithRawDescriptor(microAppWindow) {
@@ -3746,18 +4071,23 @@ class SandBox {
3746
4071
  };
3747
4072
  return descriptor;
3748
4073
  }
4074
+ /**
4075
+ * init global properties of microAppWindow when exec sandBox.start
4076
+ * @param microAppWindow micro window
4077
+ * @param appName app name
4078
+ * @param url app url
4079
+ * @param disablePatchRequest prevent rewrite request method of child app
4080
+ */
4081
+ initGlobalKeysWhenStart(microAppWindow, appName, url, disablePatchRequest) {
4082
+ microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
4083
+ this.setHijackProperty(microAppWindow, appName);
4084
+ if (!disablePatchRequest)
4085
+ this.patchRequestApi(microAppWindow, appName, url);
4086
+ }
3749
4087
  // set hijack Properties to microAppWindow
3750
- setHijackProperties(microAppWindow, appName) {
4088
+ setHijackProperty(microAppWindow, appName) {
3751
4089
  let modifiedEval, modifiedImage;
3752
4090
  rawDefineProperties(microAppWindow, {
3753
- document: {
3754
- configurable: true,
3755
- enumerable: true,
3756
- get() {
3757
- throttleDeferForSetAppName(appName);
3758
- return globalEnv.rawDocument;
3759
- },
3760
- },
3761
4091
  eval: {
3762
4092
  configurable: true,
3763
4093
  enumerable: false,
@@ -3783,7 +4113,7 @@ class SandBox {
3783
4113
  });
3784
4114
  }
3785
4115
  // rewrite fetch, XMLHttpRequest, EventSource
3786
- patchHijackRequest(microAppWindow, appName, url) {
4116
+ patchRequestApi(microAppWindow, appName, url) {
3787
4117
  let microFetch = createMicroFetch(url);
3788
4118
  let microXMLHttpRequest = createMicroXMLHttpRequest(url);
3789
4119
  let microEventSource = createMicroEventSource(appName, url);
@@ -3855,6 +4185,76 @@ class SandBox {
3855
4185
  removeRouteInfoForKeepAliveApp() {
3856
4186
  removeStateAndPathFromBrowser(this.proxyWindow.__MICRO_APP_NAME__);
3857
4187
  }
4188
+ /**
4189
+ * Create new document and Document
4190
+ */
4191
+ createProxyDocument(appName) {
4192
+ const rawDocument = globalEnv.rawDocument;
4193
+ const rawRootDocument = globalEnv.rawRootDocument;
4194
+ const createElement = function (tagName, options) {
4195
+ const element = globalEnv.rawCreateElement.call(rawDocument, tagName, options);
4196
+ element.__MICRO_APP_NAME__ = appName;
4197
+ return element;
4198
+ };
4199
+ const proxyDocument = new Proxy(rawDocument, {
4200
+ get(target, key) {
4201
+ throttleDeferForSetAppName(appName);
4202
+ throttleDeferForParentNode(proxyDocument);
4203
+ if (key === 'createElement')
4204
+ return createElement;
4205
+ if (key === Symbol.toStringTag)
4206
+ return 'ProxyDocument';
4207
+ const rawValue = Reflect.get(target, key);
4208
+ return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
4209
+ },
4210
+ set(target, key, value) {
4211
+ // Fix TypeError: Illegal invocation when set document.title
4212
+ Reflect.set(target, key, value);
4213
+ /**
4214
+ * If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
4215
+ */
4216
+ return true;
4217
+ }
4218
+ });
4219
+ class MicroDocument {
4220
+ static [Symbol.hasInstance](target) {
4221
+ let proto = target;
4222
+ while (proto = Object.getPrototypeOf(proto)) {
4223
+ if (proto === MicroDocument.prototype) {
4224
+ return true;
4225
+ }
4226
+ }
4227
+ return (target === proxyDocument ||
4228
+ target instanceof rawRootDocument);
4229
+ }
4230
+ }
4231
+ /**
4232
+ * TIP:
4233
+ * 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
4234
+ * 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
4235
+ * e.g.
4236
+ * class B extends A {}
4237
+ * B.__proto__ === A // true
4238
+ * B.prototype.__proto__ === A.prototype // true
4239
+ */
4240
+ Object.setPrototypeOf(MicroDocument, rawRootDocument);
4241
+ // Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
4242
+ Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
4243
+ get(target, key) {
4244
+ throttleDeferForSetAppName(appName);
4245
+ const rawValue = Reflect.get(target, key);
4246
+ return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
4247
+ },
4248
+ set(target, key, value) {
4249
+ Reflect.set(target, key, value);
4250
+ return true;
4251
+ }
4252
+ }));
4253
+ return {
4254
+ proxyDocument,
4255
+ MicroDocument,
4256
+ };
4257
+ }
3858
4258
  }
3859
4259
  SandBox.activeCount = 0; // number of active sandbox
3860
4260
 
@@ -3922,7 +4322,7 @@ function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
3922
4322
  // micro app instances
3923
4323
  const appInstanceMap = new Map();
3924
4324
  class CreateApp {
3925
- constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, useMemoryRouter, baseroute, keepRouteState, defaultPage, }) {
4325
+ constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, useMemoryRouter, baseroute, keepRouteState, hiddenRouter, defaultPage, disablePatchRequest, }) {
3926
4326
  this.state = appStates.CREATED;
3927
4327
  this.keepAliveState = null;
3928
4328
  this.keepAliveContainer = null;
@@ -3935,18 +4335,20 @@ class CreateApp {
3935
4335
  this.prefetchResolve = null;
3936
4336
  this.container = null;
3937
4337
  this.sandBox = null;
3938
- this.container = container !== null && container !== void 0 ? container : null;
3939
- this.inline = inline !== null && inline !== void 0 ? inline : false;
3940
- this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : '';
3941
- this.keepRouteState = keepRouteState !== null && keepRouteState !== void 0 ? keepRouteState : false;
3942
- this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
3943
- // optional during init👆
3944
4338
  this.name = name;
3945
4339
  this.url = url;
3946
4340
  this.useSandbox = useSandbox;
3947
4341
  this.scopecss = this.useSandbox && scopecss;
3948
4342
  this.useMemoryRouter = this.useSandbox && useMemoryRouter;
4343
+ // optional during init base on prefetch 👇
4344
+ this.container = container !== null && container !== void 0 ? container : null;
4345
+ this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
4346
+ this.inline = inline !== null && inline !== void 0 ? inline : false;
4347
+ this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : '';
4348
+ this.keepRouteState = keepRouteState !== null && keepRouteState !== void 0 ? keepRouteState : false;
4349
+ this.hiddenRouter = hiddenRouter !== null && hiddenRouter !== void 0 ? hiddenRouter : false;
3949
4350
  this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : '';
4351
+ this.disablePatchRequest = disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false;
3950
4352
  this.source = {
3951
4353
  links: new Map(),
3952
4354
  scripts: new Map(),
@@ -3957,7 +4359,7 @@ class CreateApp {
3957
4359
  // Load resources
3958
4360
  loadSourceCode() {
3959
4361
  this.state = appStates.LOADING;
3960
- extractHtml(this);
4362
+ HTMLLoader.getInstance().run(this, extractSourceDom);
3961
4363
  }
3962
4364
  /**
3963
4365
  * When resource is loaded, mount app if it is not prefetch or unmount
@@ -3997,17 +4399,17 @@ class CreateApp {
3997
4399
  * @param inline js runs in inline mode
3998
4400
  * @param baseroute route prefix, default is ''
3999
4401
  * @param keepRouteState keep route state when unmount, default is false
4402
+ * @param disablePatchRequest prevent rewrite request method of child app
4000
4403
  */
4001
- mount(container, inline, baseroute, keepRouteState, defaultPage) {
4404
+ mount(container, inline, baseroute, keepRouteState, defaultPage, hiddenRouter, disablePatchRequest) {
4002
4405
  var _a, _b, _c;
4003
- if (isBoolean(inline))
4004
- this.inline = inline;
4005
- // keepRouteState effective on unmount
4006
- if (isBoolean(keepRouteState))
4007
- this.keepRouteState = keepRouteState;
4406
+ this.inline = inline !== null && inline !== void 0 ? inline : this.inline;
4407
+ this.keepRouteState = keepRouteState !== null && keepRouteState !== void 0 ? keepRouteState : this.keepRouteState;
4008
4408
  this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
4009
4409
  this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
4010
4410
  this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : this.defaultPage;
4411
+ this.hiddenRouter = hiddenRouter !== null && hiddenRouter !== void 0 ? hiddenRouter : this.hiddenRouter;
4412
+ this.disablePatchRequest = disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : this.disablePatchRequest;
4011
4413
  if (this.loadSourceLevel !== 2) {
4012
4414
  this.state = appStates.LOADING;
4013
4415
  return;
@@ -4015,13 +4417,12 @@ class CreateApp {
4015
4417
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
4016
4418
  this.state = appStates.MOUNTING;
4017
4419
  cloneContainer(this.source.html, this.container, !this.umdMode);
4018
- (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute, this.useMemoryRouter, this.defaultPage);
4420
+ (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.umdMode, this.baseroute, this.useMemoryRouter, this.defaultPage, this.disablePatchRequest);
4019
4421
  let umdHookMountResult; // result of mount function
4020
4422
  if (!this.umdMode) {
4021
4423
  let hasDispatchMountedEvent = false;
4022
4424
  // if all js are executed, param isFinished will be true
4023
4425
  execScripts(this.source.scripts, this, (isFinished) => {
4024
- var _a;
4025
4426
  if (!this.umdMode) {
4026
4427
  const { mount, unmount } = this.getUmdLibraryHooks();
4027
4428
  // if mount & unmount is function, the sub app is umd mode
@@ -4029,7 +4430,9 @@ class CreateApp {
4029
4430
  this.umdHookMount = mount;
4030
4431
  this.umdHookUnmount = unmount;
4031
4432
  this.umdMode = true;
4032
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordUmdSnapshot();
4433
+ if (this.sandBox)
4434
+ this.sandBox.proxyWindow.__MICRO_APP_UMD_MODE__ = true;
4435
+ // this.sandBox?.recordUmdSnapshot()
4033
4436
  try {
4034
4437
  umdHookMountResult = this.umdHookMount();
4035
4438
  }
@@ -4131,20 +4534,23 @@ class CreateApp {
4131
4534
  * @param unmountcb callback of unmount
4132
4535
  */
4133
4536
  actionsForUnmount(destroy, unmountcb) {
4134
- var _a;
4537
+ var _a, _b;
4135
4538
  if (destroy) {
4136
4539
  this.actionsForCompletelyDestroy();
4137
4540
  }
4138
4541
  else if (this.umdMode && this.container.childElementCount) {
4139
4542
  cloneContainer(this.container, this.source.html, false);
4140
4543
  }
4544
+ if (this.umdMode) {
4545
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordUmdSnapshot();
4546
+ }
4141
4547
  /**
4142
4548
  * this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
4143
4549
  * NOTE:
4144
4550
  * 1. if destroy is true, clear route state
4145
4551
  * 2. umd mode and keep-alive will not clear EventSource
4146
4552
  */
4147
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop(this.keepRouteState && !destroy, !this.umdMode || destroy);
4553
+ (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop(this.umdMode, this.keepRouteState && !destroy, !this.umdMode || destroy);
4148
4554
  if (!getActiveApps().length) {
4149
4555
  releasePatchSetAttribute();
4150
4556
  }
@@ -4282,6 +4688,7 @@ function defineElement(tagName) {
4282
4688
  this.setAttribute('name', this.appName);
4283
4689
  }
4284
4690
  };
4691
+ // patchSetAttribute hijiack data attribute, it needs exec first
4285
4692
  patchSetAttribute();
4286
4693
  }
4287
4694
  static get observedAttributes() {
@@ -4458,7 +4865,7 @@ function defineElement(tagName) {
4458
4865
  app.isPrefetch = false;
4459
4866
  defer(() => {
4460
4867
  var _a;
4461
- return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible(), this.getDisposeResult('keep-router-state'), this.getDefaultPageValue());
4868
+ return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible(), this.getDisposeResult('keep-router-state'), this.getDefaultPageValue(), this.getDisposeResult('hidden-router'), this.getDisposeResult('disable-patch-request'));
4462
4869
  });
4463
4870
  }
4464
4871
  // create app instance
@@ -4477,12 +4884,14 @@ function defineElement(tagName) {
4477
4884
  ssrUrl: this.ssrUrl,
4478
4885
  container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
4479
4886
  inline: this.getDisposeResult('inline'),
4480
- scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')),
4481
- useSandbox: !this.getDisposeResult('disableSandbox'),
4887
+ scopecss: !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM')),
4888
+ useSandbox: !this.getDisposeResult('disable-sandbox'),
4482
4889
  useMemoryRouter: !this.getDisposeResult('disable-memory-router'),
4483
4890
  baseroute: this.getBaseRouteCompatible(),
4484
4891
  keepRouteState: this.getDisposeResult('keep-router-state'),
4485
4892
  defaultPage: this.getDefaultPageValue(),
4893
+ hiddenRouter: this.getDisposeResult('hidden-router'),
4894
+ disablePatchRequest: this.getDisposeResult('disable-patch-request'),
4486
4895
  });
4487
4896
  appInstanceMap.set(this.appName, instance);
4488
4897
  }
@@ -4517,25 +4926,25 @@ function defineElement(tagName) {
4517
4926
  */
4518
4927
  getDisposeResult(name) {
4519
4928
  // @ts-ignore
4520
- return (this.compatibleSpecialProperties(name) || microApp[name]) && this.compatibleDisableSpecialProperties(name);
4929
+ return (this.compatibleSpecialProperties(name) || !!microApp[name]) && this.compatibleDisableSpecialProperties(name);
4521
4930
  }
4522
4931
  // compatible of disableScopecss & disableSandbox
4523
4932
  compatibleSpecialProperties(name) {
4524
- if (name === 'disableScopecss') {
4525
- return this.hasAttribute('disableScopecss') || this.hasAttribute('disable-scopecss');
4933
+ if (name === 'disable-scopecss') {
4934
+ return this.hasAttribute('disable-scopecss') || this.hasAttribute('disableScopecss');
4526
4935
  }
4527
- else if (name === 'disableSandbox') {
4528
- return this.hasAttribute('disableSandbox') || this.hasAttribute('disable-sandbox');
4936
+ else if (name === 'disable-sandbox') {
4937
+ return this.hasAttribute('disable-sandbox') || this.hasAttribute('disableSandbox');
4529
4938
  }
4530
4939
  return this.hasAttribute(name);
4531
4940
  }
4532
4941
  // compatible of disableScopecss & disableSandbox
4533
4942
  compatibleDisableSpecialProperties(name) {
4534
- if (name === 'disableScopecss') {
4535
- return this.getAttribute('disableScopecss') !== 'false' && this.getAttribute('disable-scopecss') !== 'false';
4943
+ if (name === 'disable-scopecss') {
4944
+ return this.getAttribute('disable-scopecss') !== 'false' && this.getAttribute('disableScopecss') !== 'false';
4536
4945
  }
4537
- else if (name === 'disableSandbox') {
4538
- return this.getAttribute('disableSandbox') !== 'false' && this.getAttribute('disable-sandbox') !== 'false';
4946
+ else if (name === 'disable-sandbox') {
4947
+ return this.getAttribute('disable-sandbox') !== 'false' && this.getAttribute('disableSandbox') !== 'false';
4539
4948
  }
4540
4949
  return this.getAttribute(name) !== 'false';
4541
4950
  }
@@ -4563,7 +4972,7 @@ function defineElement(tagName) {
4563
4972
  */
4564
4973
  updateSsrUrl(baseUrl) {
4565
4974
  if (this.getDisposeResult('ssr')) {
4566
- if (this.getDisposeResult('disable-memory-router')) {
4975
+ if (this.getDisposeResult('disable-memory-router') || this.getDisposeResult('disableSandbox')) {
4567
4976
  const rawLocation = globalEnv.rawWindow.location;
4568
4977
  this.ssrUrl = CompletionPath(rawLocation.pathname + rawLocation.search, baseUrl);
4569
4978
  }
@@ -4647,7 +5056,7 @@ function preFetch(apps) {
4647
5056
  function preFetchInSerial(prefetchApp) {
4648
5057
  return new Promise((resolve) => {
4649
5058
  requestIdleCallback(() => {
4650
- var _a, _b, _c;
5059
+ var _a, _b, _c, _d, _e;
4651
5060
  if (isPlainObject(prefetchApp) && navigator.onLine) {
4652
5061
  prefetchApp.name = formatAppName(prefetchApp.name);
4653
5062
  prefetchApp.url = formatAppURL(prefetchApp.url, prefetchApp.name);
@@ -4655,9 +5064,9 @@ function preFetchInSerial(prefetchApp) {
4655
5064
  const app = new CreateApp({
4656
5065
  name: prefetchApp.name,
4657
5066
  url: prefetchApp.url,
4658
- scopecss: !((_a = prefetchApp.disableScopecss) !== null && _a !== void 0 ? _a : microApp.disableScopecss),
4659
- useSandbox: !((_b = prefetchApp.disableSandbox) !== null && _b !== void 0 ? _b : microApp.disableSandbox),
4660
- useMemoryRouter: !((_c = prefetchApp.disableMemoryRouter) !== null && _c !== void 0 ? _c : microApp.disableMemoryRouter),
5067
+ scopecss: !((_b = (_a = prefetchApp['disable-scopecss']) !== null && _a !== void 0 ? _a : prefetchApp.disableScopecss) !== null && _b !== void 0 ? _b : microApp['disable-scopecss']),
5068
+ useSandbox: !((_d = (_c = prefetchApp['disable-sandbox']) !== null && _c !== void 0 ? _c : prefetchApp.disableSandbox) !== null && _d !== void 0 ? _d : microApp['disable-sandbox']),
5069
+ useMemoryRouter: !((_e = prefetchApp['disable-memory-router']) !== null && _e !== void 0 ? _e : microApp['disable-memory-router']),
4661
5070
  });
4662
5071
  app.isPrefetch = true;
4663
5072
  app.prefetchResolve = resolve;
@@ -4707,7 +5116,7 @@ function fetchGlobalResources(resources, suffix, cache) {
4707
5116
  * @param excludeHiddenApp exclude hidden keep-alive app, default is false
4708
5117
  * @returns active apps
4709
5118
  */
4710
- function getActiveApps(excludeHiddenApp) {
5119
+ function getActiveApps(excludeHiddenApp = false) {
4711
5120
  const activeApps = [];
4712
5121
  appInstanceMap.forEach((app, appName) => {
4713
5122
  if (appStates.UNMOUNT !== app.getAppState() &&
@@ -4803,6 +5212,7 @@ class MicroApp extends EventCenterForBaseApp {
4803
5212
  this.router = router;
4804
5213
  }
4805
5214
  start(options) {
5215
+ var _a, _b;
4806
5216
  if (!isBrowser || !window.customElements) {
4807
5217
  return logError('micro-app is not supported in this environment');
4808
5218
  }
@@ -4828,9 +5238,13 @@ class MicroApp extends EventCenterForBaseApp {
4828
5238
  // @ts-ignore
4829
5239
  this.destory = options.destory;
4830
5240
  this.inline = options.inline;
4831
- this.disableScopecss = options.disableScopecss;
4832
- this.disableSandbox = options.disableSandbox;
4833
- this.disableMemoryRouter = options.disableMemoryRouter;
5241
+ this['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;
5242
+ this['disable-sandbox'] = (_b = options['disable-sandbox']) !== null && _b !== void 0 ? _b : options.disableSandbox;
5243
+ this['disable-memory-router'] = options['disable-memory-router'];
5244
+ this['disable-patch-request'] = options['disable-patch-request'];
5245
+ this['keep-router-state'] = options['keep-router-state'];
5246
+ this['hidden-router'] = options['hidden-router'];
5247
+ this.esmodule = options.esmodule;
4834
5248
  this.ssr = options.ssr;
4835
5249
  isFunction(options.fetch) && (this.fetch = options.fetch);
4836
5250
  isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);