@micro-zoe/micro-app 0.8.4 → 1.0.0-alpha.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/lib/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- const version = '0.8.4';
1
+ const version = '1.0.0-alpha.0';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -7,10 +7,24 @@ const globalThis = (typeof global !== 'undefined')
7
7
  : ((typeof window !== 'undefined')
8
8
  ? window
9
9
  : ((typeof self !== 'undefined') ? self : Function('return this')()));
10
+ const noop = () => { };
11
+ const noopFalse = () => false;
12
+ // Array.isArray
13
+ const isArray = Array.isArray;
14
+ // Object.assign
15
+ const assign = Object.assign;
16
+ // Object prototype methods
17
+ const rawDefineProperty = Object.defineProperty;
18
+ const rawDefineProperties = Object.defineProperties;
19
+ const rawHasOwnProperty = Object.prototype.hasOwnProperty;
10
20
  // is Undefined
11
21
  function isUndefined(target) {
12
22
  return target === undefined;
13
23
  }
24
+ // is Null
25
+ function isNull(target) {
26
+ return target === null;
27
+ }
14
28
  // is String
15
29
  function isString(target) {
16
30
  return typeof target === 'string';
@@ -23,8 +37,6 @@ function isBoolean(target) {
23
37
  function isFunction(target) {
24
38
  return typeof target === 'function';
25
39
  }
26
- // is Array
27
- const isArray = Array.isArray;
28
40
  // is PlainObject
29
41
  function isPlainObject(target) {
30
42
  return toString.call(target) === '[object Object]';
@@ -41,9 +53,9 @@ function isBoundFunction(target) {
41
53
  function isShadowRoot(target) {
42
54
  return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
43
55
  }
44
- const rawDefineProperty = Object.defineProperty;
45
- const rawDefineProperties = Object.defineProperties;
46
- const rawHasOwnProperty = Object.prototype.hasOwnProperty;
56
+ function isURL(target) {
57
+ return target instanceof URL;
58
+ }
47
59
  /**
48
60
  * format error log
49
61
  * @param msg message
@@ -80,6 +92,16 @@ function logWarn(msg, appName = null, ...rest) {
80
92
  function defer(fn, ...args) {
81
93
  Promise.resolve().then(fn.bind(null, ...args));
82
94
  }
95
+ /**
96
+ * create URL as MicroLocation
97
+ */
98
+ const createURL = (function () {
99
+ class Location extends URL {
100
+ }
101
+ return (path, base) => {
102
+ return (base ? new Location('' + path, base) : new Location('' + path));
103
+ };
104
+ })();
83
105
  /**
84
106
  * Add address protocol
85
107
  * @param url address
@@ -97,7 +119,7 @@ function formatAppURL(url, appName = null) {
97
119
  if (!isString(url) || !url)
98
120
  return '';
99
121
  try {
100
- const { origin, pathname, search } = new URL(addProtocol(url));
122
+ const { origin, pathname, search } = createURL(addProtocol(url));
101
123
  // If it ends with .html/.node/.php/.net/.etc, don’t need to add /
102
124
  if (/\.(\w+)$/.test(pathname)) {
103
125
  return `${origin}${pathname}${search}`;
@@ -118,6 +140,7 @@ function formatAppURL(url, appName = null) {
118
140
  * 3. event_center -> EventCenterForBaseApp -> all methods
119
141
  * 4. preFetch
120
142
  * 5. plugins
143
+ * 6. router api (push, replace)
121
144
  */
122
145
  function formatAppName(name) {
123
146
  if (!isString(name) || !name)
@@ -129,7 +152,7 @@ function formatAppName(name) {
129
152
  * @param url app.url
130
153
  */
131
154
  function getEffectivePath(url) {
132
- const { origin, pathname } = new URL(url);
155
+ const { origin, pathname } = createURL(url);
133
156
  if (/\.(\w+)$/.test(pathname)) {
134
157
  const fullPath = `${origin}${pathname}`;
135
158
  const pathArr = fullPath.split('/');
@@ -148,7 +171,7 @@ function CompletionPath(path, baseURI) {
148
171
  /^((((ht|f)tps?)|file):)?\/\//.test(path) ||
149
172
  /^(data|blob):/.test(path))
150
173
  return path;
151
- return new URL(path, getEffectivePath(addProtocol(baseURI))).toString();
174
+ return createURL(path, getEffectivePath(addProtocol(baseURI))).toString();
152
175
  }
153
176
  /**
154
177
  * Get the folder where the link resource is located,
@@ -306,6 +329,98 @@ function trim(str) {
306
329
  function isFireFox() {
307
330
  return navigator.userAgent.indexOf('Firefox') > -1;
308
331
  }
332
+ /**
333
+ * Transforms a queryString into object.
334
+ * @param search - search string to parse
335
+ * @returns a query object
336
+ */
337
+ function parseQuery(search) {
338
+ const result = {};
339
+ const queryList = search.split('&');
340
+ // we will not decode the key/value to ensure that the values are consistent when update URL
341
+ for (const queryItem of queryList) {
342
+ const eqPos = queryItem.indexOf('=');
343
+ const key = eqPos < 0 ? queryItem : queryItem.slice(0, eqPos);
344
+ const value = eqPos < 0 ? null : queryItem.slice(eqPos + 1);
345
+ if (key in result) {
346
+ let currentValue = result[key];
347
+ if (!isArray(currentValue)) {
348
+ currentValue = result[key] = [currentValue];
349
+ }
350
+ currentValue.push(value);
351
+ }
352
+ else {
353
+ result[key] = value;
354
+ }
355
+ }
356
+ return result;
357
+ }
358
+ /**
359
+ * Transforms an object to query string
360
+ * @param queryObject - query object to stringify
361
+ * @returns query string without the leading `?`
362
+ */
363
+ function stringifyQuery(queryObject) {
364
+ let result = '';
365
+ for (const key in queryObject) {
366
+ const value = queryObject[key];
367
+ if (isNull(value)) {
368
+ result += (result.length ? '&' : '') + key;
369
+ }
370
+ else {
371
+ const valueList = isArray(value) ? value : [value];
372
+ valueList.forEach(value => {
373
+ if (!isUndefined(value)) {
374
+ result += (result.length ? '&' : '') + key;
375
+ if (!isNull(value))
376
+ result += '=' + value;
377
+ }
378
+ });
379
+ }
380
+ }
381
+ return result;
382
+ }
383
+ /**
384
+ * Register or unregister callback/guard with Set
385
+ */
386
+ function useSetRecord() {
387
+ const handlers = new Set();
388
+ function add(handler) {
389
+ handlers.add(handler);
390
+ return () => {
391
+ if (handlers.has(handler))
392
+ return handlers.delete(handler);
393
+ return false;
394
+ };
395
+ }
396
+ return {
397
+ add,
398
+ list: () => handlers,
399
+ };
400
+ }
401
+ /**
402
+ * record data with Map
403
+ */
404
+ function useMapRecord() {
405
+ const data = new Map();
406
+ function add(key, value) {
407
+ data.set(key, value);
408
+ return () => {
409
+ if (data.has(key))
410
+ return data.delete(key);
411
+ return false;
412
+ };
413
+ }
414
+ return {
415
+ add,
416
+ get: (key) => data.get(key),
417
+ delete: (key) => {
418
+ if (data.has(key))
419
+ return data.delete(key);
420
+ return false;
421
+ }
422
+ };
423
+ }
309
424
 
310
425
  var ObservedAttrName;
311
426
  (function (ObservedAttrName) {
@@ -315,13 +430,13 @@ var ObservedAttrName;
315
430
  // app status
316
431
  var appStates;
317
432
  (function (appStates) {
318
- appStates["NOT_LOADED"] = "NOT_LOADED";
319
- appStates["LOADING_SOURCE_CODE"] = "LOADING_SOURCE_CODE";
320
- appStates["LOAD_SOURCE_FINISHED"] = "LOAD_SOURCE_FINISHED";
321
- appStates["LOAD_SOURCE_ERROR"] = "LOAD_SOURCE_ERROR";
322
- appStates["MOUNTING"] = "MOUNTING";
323
- appStates["MOUNTED"] = "MOUNTED";
324
- appStates["UNMOUNT"] = "UNMOUNT";
433
+ appStates["CREATED"] = "created";
434
+ appStates["LOADING"] = "loading";
435
+ appStates["LOADED"] = "loaded";
436
+ appStates["LOAD_FAILED"] = "load_failed";
437
+ appStates["MOUNTING"] = "mounting";
438
+ appStates["MOUNTED"] = "mounted";
439
+ appStates["UNMOUNT"] = "unmount";
325
440
  })(appStates || (appStates = {}));
326
441
  // lifecycles
327
442
  var lifeCycles;
@@ -339,16 +454,16 @@ var lifeCycles;
339
454
  // keep-alive status
340
455
  var keepAliveStates;
341
456
  (function (keepAliveStates) {
342
- keepAliveStates["KEEP_ALIVE_SHOW"] = "KEEP_ALIVE_SHOW";
343
- keepAliveStates["KEEP_ALIVE_HIDDEN"] = "KEEP_ALIVE_HIDDEN";
457
+ keepAliveStates["KEEP_ALIVE_SHOW"] = "keep_alive_show";
458
+ keepAliveStates["KEEP_ALIVE_HIDDEN"] = "keep_alive_hidden";
344
459
  })(keepAliveStates || (keepAliveStates = {}));
345
- const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Promise,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,location,navigator,undefined';
460
+ const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Promise,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history,EventSource,fetch,XMLHttpRequest';
346
461
 
347
462
  /**
348
463
  * fetch source of html, js, css
349
464
  * @param url source path
350
465
  * @param appName app name
351
- * @param config config of fetch
466
+ * @param config fetch options
352
467
  */
353
468
  function fetchSource(url, appName = null, options = {}) {
354
469
  if (isFunction(microApp.fetch)) {
@@ -372,7 +487,7 @@ function parseError(msg, linkPath) {
372
487
  throw err;
373
488
  }
374
489
  /**
375
- * Reference resources https://github.com/reworkcss/css
490
+ * Reference https://github.com/reworkcss/css
376
491
  * CSSParser mainly deals with 3 scenes: styleRule, @, and comment
377
492
  * And scopecss deals with 2 scenes: selector & url
378
493
  * And can also disable scopecss with inline comments
@@ -974,51 +1089,49 @@ function handleNewNode(parent, child, app) {
974
1089
  * @param passiveChild second param of insertBefore and replaceChild
975
1090
  */
976
1091
  function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
1092
+ const hijackElement = getHijackElement(parent, app);
977
1093
  /**
978
1094
  * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
979
1095
  * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
980
1096
  */
981
- if (parent === document.head) {
982
- const microAppHead = app.container.querySelector('micro-app-head');
1097
+ if (hijackElement) {
983
1098
  /**
984
1099
  * 1. If passiveChild exists, it must be insertBefore or replaceChild
985
1100
  * 2. When removeChild, targetChild may not be in microAppHead or head
986
1101
  */
987
- if (passiveChild && !microAppHead.contains(passiveChild)) {
988
- return globalEnv.rawAppendChild.call(microAppHead, targetChild);
1102
+ if (passiveChild && !hijackElement.contains(passiveChild)) {
1103
+ return globalEnv.rawAppendChild.call(hijackElement, targetChild);
989
1104
  }
990
- else if (rawMethod === globalEnv.rawRemoveChild && !microAppHead.contains(targetChild)) {
1105
+ else if (rawMethod === globalEnv.rawRemoveChild && !hijackElement.contains(targetChild)) {
991
1106
  if (parent.contains(targetChild)) {
992
1107
  return rawMethod.call(parent, targetChild);
993
1108
  }
994
1109
  return targetChild;
995
1110
  }
996
- else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
997
- return rawMethod.call(microAppHead, targetChild);
998
- }
999
- return rawMethod.call(microAppHead, targetChild, passiveChild);
1111
+ return invokeRawMethod(rawMethod, hijackElement, targetChild, passiveChild);
1000
1112
  }
1001
- else if (parent === document.body) {
1002
- const microAppBody = app.container.querySelector('micro-app-body');
1003
- if (passiveChild && !microAppBody.contains(passiveChild)) {
1004
- return globalEnv.rawAppendChild.call(microAppBody, targetChild);
1005
- }
1006
- else if (rawMethod === globalEnv.rawRemoveChild && !microAppBody.contains(targetChild)) {
1007
- if (parent.contains(targetChild)) {
1008
- return rawMethod.call(parent, targetChild);
1009
- }
1010
- return targetChild;
1011
- }
1012
- else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
1013
- return rawMethod.call(microAppBody, targetChild);
1014
- }
1015
- return rawMethod.call(microAppBody, targetChild, passiveChild);
1113
+ return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
1114
+ }
1115
+ // head/body map to micro-app-head/micro-app-body
1116
+ function getHijackElement(node, app) {
1117
+ var _a, _b;
1118
+ if (node === document.head) {
1119
+ return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
1016
1120
  }
1017
- else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
1121
+ if (node === document.body) {
1122
+ return (_b = app === null || app === void 0 ? void 0 : app.container) === null || _b === void 0 ? void 0 : _b.querySelector('micro-app-body');
1123
+ }
1124
+ return null;
1125
+ }
1126
+ function invokeRawMethod(rawMethod, parent, targetChild, passiveChild) {
1127
+ if (isPendMethod(rawMethod)) {
1018
1128
  return rawMethod.call(parent, targetChild);
1019
1129
  }
1020
1130
  return rawMethod.call(parent, targetChild, passiveChild);
1021
1131
  }
1132
+ function isPendMethod(method) {
1133
+ return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
1134
+ }
1022
1135
  // Get the map element
1023
1136
  function getMappingNode(node) {
1024
1137
  var _a;
@@ -1106,27 +1219,6 @@ function patchElementPrototypeMethods() {
1106
1219
  this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
1107
1220
  return clonedNode;
1108
1221
  };
1109
- // patch getBoundingClientRect
1110
- // TODO: scenes test
1111
- // Element.prototype.getBoundingClientRect = function getBoundingClientRect () {
1112
- // const rawRect: DOMRect = globalEnv.rawGetBoundingClientRect.call(this)
1113
- // if (this.__MICRO_APP_NAME__) {
1114
- // const app = appInstanceMap.get(this.__MICRO_APP_NAME__)
1115
- // if (!app?.container) {
1116
- // return rawRect
1117
- // }
1118
- // const appBody = app.container.querySelector('micro-app-body')
1119
- // const appBodyRect: DOMRect = globalEnv.rawGetBoundingClientRect.call(appBody)
1120
- // const computedRect: DOMRect = new DOMRect(
1121
- // rawRect.x - appBodyRect.x,
1122
- // rawRect.y - appBodyRect.y,
1123
- // rawRect.width,
1124
- // rawRect.height,
1125
- // )
1126
- // return computedRect
1127
- // }
1128
- // return rawRect
1129
- // }
1130
1222
  }
1131
1223
  /**
1132
1224
  * Mark the newly created element in the micro application
@@ -1134,7 +1226,8 @@ function patchElementPrototypeMethods() {
1134
1226
  */
1135
1227
  function markElement(element) {
1136
1228
  const appName = getCurrentAppName();
1137
- appName && (element.__MICRO_APP_NAME__ = appName);
1229
+ if (appName)
1230
+ element.__MICRO_APP_NAME__ = appName;
1138
1231
  return element;
1139
1232
  }
1140
1233
  // methods of document
@@ -1155,27 +1248,29 @@ function patchDocument() {
1155
1248
  };
1156
1249
  // query element👇
1157
1250
  function querySelector(selectors) {
1158
- var _a, _b, _c;
1251
+ var _a, _b, _c, _d;
1159
1252
  const appName = getCurrentAppName();
1160
1253
  if (!appName ||
1254
+ !((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) ||
1161
1255
  !selectors ||
1162
1256
  isUniqueElement(selectors) ||
1163
1257
  // see https://github.com/micro-zoe/micro-app/issues/56
1164
1258
  rawDocument !== this) {
1165
1259
  return globalEnv.rawQuerySelector.call(this, selectors);
1166
1260
  }
1167
- return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) === null || _b === void 0 ? void 0 : _b.querySelector(selectors)) !== null && _c !== void 0 ? _c : null;
1261
+ 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;
1168
1262
  }
1169
1263
  function querySelectorAll(selectors) {
1170
- var _a, _b, _c;
1264
+ var _a, _b, _c, _d;
1171
1265
  const appName = getCurrentAppName();
1172
1266
  if (!appName ||
1267
+ !((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) ||
1173
1268
  !selectors ||
1174
1269
  isUniqueElement(selectors) ||
1175
1270
  rawDocument !== this) {
1176
1271
  return globalEnv.rawQuerySelectorAll.call(this, selectors);
1177
1272
  }
1178
- return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) === null || _b === void 0 ? void 0 : _b.querySelectorAll(selectors)) !== null && _c !== void 0 ? _c : [];
1273
+ 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 : [];
1179
1274
  }
1180
1275
  Document.prototype.querySelector = querySelector;
1181
1276
  Document.prototype.querySelectorAll = querySelectorAll;
@@ -1243,10 +1338,9 @@ function patchSetAttribute() {
1243
1338
  if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
1244
1339
  if (isPlainObject(value)) {
1245
1340
  const cloneValue = {};
1246
- Object.getOwnPropertyNames(value).forEach((propertyKey) => {
1247
- if (!(isString(propertyKey) && propertyKey.indexOf('__') === 0)) {
1248
- // @ts-ignore
1249
- cloneValue[propertyKey] = value[propertyKey];
1341
+ Object.getOwnPropertyNames(value).forEach((key) => {
1342
+ if (!(isString(key) && key.indexOf('__') === 0)) {
1343
+ cloneValue[key] = value[key];
1250
1344
  }
1251
1345
  });
1252
1346
  this.data = cloneValue;
@@ -1293,7 +1387,6 @@ function releasePatches() {
1293
1387
  Element.prototype.append = globalEnv.rawAppend;
1294
1388
  Element.prototype.prepend = globalEnv.rawPrepend;
1295
1389
  Element.prototype.cloneNode = globalEnv.rawCloneNode;
1296
- // Element.prototype.getBoundingClientRect = globalEnv.rawGetBoundingClientRect
1297
1390
  }
1298
1391
  // Set the style of micro-app-head and micro-app-body
1299
1392
  let hasRejectMicroAppStyle = false;
@@ -1307,27 +1400,6 @@ function rejectMicroAppStyle() {
1307
1400
  }
1308
1401
  }
1309
1402
 
1310
- function unmountNestedApp() {
1311
- releaseUnmountOfNestedApp();
1312
- appInstanceMap.forEach(app => {
1313
- // @ts-ignore
1314
- app.container && getRootContainer(app.container).disconnectedCallback();
1315
- });
1316
- !window.__MICRO_APP_UMD_MODE__ && appInstanceMap.clear();
1317
- }
1318
- // if micro-app run in micro application, delete all next generation application when unmount event received
1319
- function listenUmountOfNestedApp() {
1320
- if (window.__MICRO_APP_ENVIRONMENT__) {
1321
- window.addEventListener('unmount', unmountNestedApp, false);
1322
- }
1323
- }
1324
- // release listener
1325
- function releaseUnmountOfNestedApp() {
1326
- if (window.__MICRO_APP_ENVIRONMENT__) {
1327
- window.removeEventListener('unmount', unmountNestedApp, false);
1328
- }
1329
- }
1330
-
1331
1403
  const globalEnv = {};
1332
1404
  /**
1333
1405
  * Note loop nesting
@@ -1347,7 +1419,6 @@ function initGlobalEnv() {
1347
1419
  const rawAppend = Element.prototype.append;
1348
1420
  const rawPrepend = Element.prototype.prepend;
1349
1421
  const rawCloneNode = Element.prototype.cloneNode;
1350
- // const rawGetBoundingClientRect = Element.prototype.getBoundingClientRect
1351
1422
  const rawCreateElement = Document.prototype.createElement;
1352
1423
  const rawCreateElementNS = Document.prototype.createElementNS;
1353
1424
  const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
@@ -1381,7 +1452,7 @@ function initGlobalEnv() {
1381
1452
  const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
1382
1453
  // mark current application as base application
1383
1454
  window.__MICRO_APP_BASE_APPLICATION__ = true;
1384
- Object.assign(globalEnv, {
1455
+ assign(globalEnv, {
1385
1456
  // source/patch
1386
1457
  rawSetAttribute,
1387
1458
  rawAppendChild,
@@ -1391,7 +1462,6 @@ function initGlobalEnv() {
1391
1462
  rawAppend,
1392
1463
  rawPrepend,
1393
1464
  rawCloneNode,
1394
- // rawGetBoundingClientRect,
1395
1465
  rawCreateElement,
1396
1466
  rawCreateElementNS,
1397
1467
  rawCreateDocumentFragment,
@@ -1418,8 +1488,6 @@ function initGlobalEnv() {
1418
1488
  });
1419
1489
  // global effect
1420
1490
  rejectMicroAppStyle();
1421
- releaseUnmountOfNestedApp();
1422
- listenUmountOfNestedApp();
1423
1491
  }
1424
1492
  }
1425
1493
 
@@ -1605,7 +1673,7 @@ function execScripts(scriptList, app, initHook) {
1605
1673
  function runScript(url, app, info, isDynamic, callback) {
1606
1674
  var _a;
1607
1675
  try {
1608
- const code = bindScope(url, app, info.code, info.module);
1676
+ const code = bindScope(url, app, info.code, info);
1609
1677
  if (app.inline || info.module) {
1610
1678
  const scriptElement = pureCreateElement('script');
1611
1679
  runCode2InlineScript(url, code, info.module, scriptElement, callback);
@@ -1658,7 +1726,7 @@ function runDynamicRemoteScript(url, info, app, originScript) {
1658
1726
  app.source.scripts.set(url, info);
1659
1727
  info.isGlobal && globalScripts.set(url, code);
1660
1728
  try {
1661
- code = bindScope(url, app, code, info.module);
1729
+ code = bindScope(url, app, code, info);
1662
1730
  if (app.inline || info.module) {
1663
1731
  runCode2InlineScript(url, code, info.module, replaceElement, dispatchScriptOnLoadEvent);
1664
1732
  }
@@ -1714,13 +1782,13 @@ function runCode2Function(code, info) {
1714
1782
  * @param url script address
1715
1783
  * @param app app
1716
1784
  * @param code code
1717
- * @param module type='module' of script
1785
+ * @param info source script info
1718
1786
  */
1719
- function bindScope(url, app, code, module) {
1787
+ function bindScope(url, app, code, info) {
1720
1788
  if (isPlainObject(microApp.plugins)) {
1721
- code = usePlugins(url, code, app.name, microApp.plugins);
1789
+ code = usePlugins(url, code, app.name, microApp.plugins, info);
1722
1790
  }
1723
- if (app.sandBox && !module) {
1791
+ if (app.sandBox && !info.module) {
1724
1792
  globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
1725
1793
  return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
1726
1794
  }
@@ -1732,19 +1800,20 @@ function bindScope(url, app, code, module) {
1732
1800
  * @param code code
1733
1801
  * @param appName app name
1734
1802
  * @param plugins plugin list
1803
+ * @param info source script info
1735
1804
  */
1736
- function usePlugins(url, code, appName, plugins) {
1805
+ function usePlugins(url, code, appName, plugins, info) {
1737
1806
  var _a;
1738
- const newCode = processCode(plugins.global, code, url);
1739
- return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, url);
1807
+ const newCode = processCode(plugins.global, code, url, info);
1808
+ return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, url, info);
1740
1809
  }
1741
- function processCode(configs, code, url) {
1810
+ function processCode(configs, code, url, info) {
1742
1811
  if (!isArray(configs)) {
1743
1812
  return code;
1744
1813
  }
1745
1814
  return configs.reduce((preCode, config) => {
1746
1815
  if (isPlainObject(config) && isFunction(config.loader)) {
1747
- return config.loader(preCode, url, config.options);
1816
+ return config.loader(preCode, url, config.options, info);
1748
1817
  }
1749
1818
  return preCode;
1750
1819
  }, code);
@@ -2139,6 +2208,28 @@ function rebuildDataCenterSnapshot(microAppEventCenter) {
2139
2208
  }
2140
2209
  }
2141
2210
 
2211
+ function unmountNestedApp() {
2212
+ appInstanceMap.forEach(app => {
2213
+ // @ts-ignore
2214
+ app.container && getRootContainer(app.container).disconnectedCallback();
2215
+ });
2216
+ !window.__MICRO_APP_UMD_MODE__ && appInstanceMap.clear();
2217
+ }
2218
+ // release listener
2219
+ function releaseUnmountOfNestedApp() {
2220
+ if (window.__MICRO_APP_ENVIRONMENT__) {
2221
+ window.removeEventListener('unmount', unmountNestedApp, false);
2222
+ }
2223
+ }
2224
+ // if micro-app run in micro application, delete all next generation application when unmount event received
2225
+ // unmount event will auto release by sandbox
2226
+ function listenUmountOfNestedApp() {
2227
+ if (window.__MICRO_APP_ENVIRONMENT__) {
2228
+ releaseUnmountOfNestedApp();
2229
+ window.addEventListener('unmount', unmountNestedApp, false);
2230
+ }
2231
+ }
2232
+
2142
2233
  /* eslint-disable no-return-assign */
2143
2234
  function isBoundedFunction(value) {
2144
2235
  if (isBoolean(value.__MICRO_APP_IS_BOUND_FUNCTION__))
@@ -2178,6 +2269,21 @@ function bindFunctionToRawWindow(rawWindow, value) {
2178
2269
  return value;
2179
2270
  }
2180
2271
 
2272
+ // this events should be sent to the specified app
2273
+ const formatEventList = ['unmount', 'appstate-change'];
2274
+ /**
2275
+ * Format event name
2276
+ * @param eventName event name
2277
+ * @param appName app name
2278
+ */
2279
+ function formatEventName$1(eventName, appName) {
2280
+ var _a;
2281
+ if (formatEventList.includes(eventName) ||
2282
+ ((eventName === 'popstate' || eventName === 'hashchange') && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.useMemoryRouter))) {
2283
+ return `${eventName}-${appName}`;
2284
+ }
2285
+ return eventName;
2286
+ }
2181
2287
  // document.onclick binding list, the binding function of each application is unique
2182
2288
  const documentClickListMap = new Map();
2183
2289
  let hasRewriteDocumentOnClick = false;
@@ -2271,19 +2377,6 @@ function releaseEffectDocumentEvent() {
2271
2377
  document.addEventListener = globalEnv.rawDocumentAddEventListener;
2272
2378
  document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
2273
2379
  }
2274
- // this events should be sent to the specified app
2275
- const formatEventList = ['unmount', 'appstate-change'];
2276
- /**
2277
- * Format event name
2278
- * @param type event name
2279
- * @param microAppWindow micro window
2280
- */
2281
- function formatEventType(type, microAppWindow) {
2282
- if (formatEventList.includes(type)) {
2283
- return `${type}-${microAppWindow.__MICRO_APP_NAME__}`;
2284
- }
2285
- return type;
2286
- }
2287
2380
  /**
2288
2381
  * Rewrite side-effect events
2289
2382
  * @param microAppWindow micro window
@@ -2296,7 +2389,7 @@ function effect(microAppWindow) {
2296
2389
  const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
2297
2390
  // listener may be null, e.g test-passive
2298
2391
  microAppWindow.addEventListener = function (type, listener, options) {
2299
- type = formatEventType(type, microAppWindow);
2392
+ type = formatEventName$1(type, appName);
2300
2393
  const listenerList = eventListenerMap.get(type);
2301
2394
  if (listenerList) {
2302
2395
  listenerList.add(listener);
@@ -2308,7 +2401,7 @@ function effect(microAppWindow) {
2308
2401
  rawWindowAddEventListener.call(rawWindow, type, listener, options);
2309
2402
  };
2310
2403
  microAppWindow.removeEventListener = function (type, listener, options) {
2311
- type = formatEventType(type, microAppWindow);
2404
+ type = formatEventName$1(type, appName);
2312
2405
  const listenerList = eventListenerMap.get(type);
2313
2406
  if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
2314
2407
  listenerList.delete(listener);
@@ -2435,8 +2528,790 @@ function effect(microAppWindow) {
2435
2528
  };
2436
2529
  }
2437
2530
 
2531
+ // set micro app state to origin state
2532
+ function setMicroState(appName, rawState, microState) {
2533
+ const additionalState = {
2534
+ microAppState: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.microAppState, {
2535
+ [appName]: microState
2536
+ })
2537
+ };
2538
+ // create new state object
2539
+ return assign({}, rawState, additionalState);
2540
+ }
2541
+ // delete micro app state form origin state
2542
+ function removeMicroState(appName, rawState) {
2543
+ if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.microAppState)) {
2544
+ if (!isUndefined(rawState.microAppState[appName])) {
2545
+ delete rawState.microAppState[appName];
2546
+ }
2547
+ if (!Object.keys(rawState.microAppState).length) {
2548
+ delete rawState.microAppState;
2549
+ }
2550
+ }
2551
+ // 生成新的state对象
2552
+ return assign({}, rawState);
2553
+ }
2554
+ // get micro app state form origin state
2555
+ function getMicroState(appName, state) {
2556
+ var _a;
2557
+ return ((_a = state === null || state === void 0 ? void 0 : state.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
2558
+ }
2559
+ const ENC_AD_RE = /&/g; // %M1
2560
+ const ENC_EQ_RE = /=/g; // %M2
2561
+ const DEC_AD_RE = /%M1/g; // &
2562
+ const DEC_EQ_RE = /%M2/g; // =
2563
+ function encodeMicroPath(path) {
2564
+ return encodeURIComponent(commonDecode(path).replace(ENC_AD_RE, '%M1').replace(ENC_EQ_RE, '%M2'));
2565
+ }
2566
+ function decodeMicroPath(path) {
2567
+ return commonDecode(path).replace(DEC_AD_RE, '&').replace(DEC_EQ_RE, '=');
2568
+ }
2569
+ function commonDecode(path) {
2570
+ try {
2571
+ const decPath = decodeURIComponent(path);
2572
+ if (path === decPath || DEC_AD_RE.test(decPath) || DEC_EQ_RE.test(decPath))
2573
+ return decPath;
2574
+ return commonDecode(decPath);
2575
+ }
2576
+ catch (_a) {
2577
+ return path;
2578
+ }
2579
+ }
2580
+ // 格式化query参数key,防止与原有参数的冲突
2581
+ function formatQueryAppName(appName) {
2582
+ return `app-${appName}`;
2583
+ }
2584
+ // 根据浏览器url参数,获取当前子应用的path
2585
+ function getMicroPathFromURL(appName) {
2586
+ var _a, _b;
2587
+ const rawLocation = globalEnv.rawWindow.location;
2588
+ const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
2589
+ const microPath = ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) || ((_b = queryObject.searchQuery) === null || _b === void 0 ? void 0 : _b[formatQueryAppName(appName)]);
2590
+ return isString(microPath) ? decodeMicroPath(microPath) : null;
2591
+ }
2592
+ // 将name=encodeUrl地址插入到浏览器url上
2593
+ function setMicroPathToURL(appName, microLocation) {
2594
+ let { pathname, search, hash } = globalEnv.rawWindow.location;
2595
+ const queryObject = getQueryObjectFromURL(search, hash);
2596
+ const encodedMicroPath = encodeMicroPath(microLocation.pathname +
2597
+ microLocation.search +
2598
+ microLocation.hash);
2599
+ let isAttach2Hash = false; // 基座是否是hash模式,这个其实也不准,只是表示参数加到了hash上
2600
+ // hash存在且search不存在,则认为是hash路由
2601
+ if (hash && !search) {
2602
+ isAttach2Hash = true;
2603
+ if (queryObject.hashQuery) {
2604
+ queryObject.hashQuery[formatQueryAppName(appName)] = encodedMicroPath;
2605
+ }
2606
+ else {
2607
+ queryObject.hashQuery = {
2608
+ [formatQueryAppName(appName)]: encodedMicroPath
2609
+ };
2610
+ }
2611
+ const baseHash = hash.includes('?') ? hash.slice(0, hash.indexOf('?') + 1) : hash + '?';
2612
+ hash = baseHash + stringifyQuery(queryObject.hashQuery);
2613
+ }
2614
+ else {
2615
+ if (queryObject.searchQuery) {
2616
+ queryObject.searchQuery[formatQueryAppName(appName)] = encodedMicroPath;
2617
+ }
2618
+ else {
2619
+ queryObject.searchQuery = {
2620
+ [formatQueryAppName(appName)]: encodedMicroPath
2621
+ };
2622
+ }
2623
+ search = '?' + stringifyQuery(queryObject.searchQuery);
2624
+ }
2625
+ return {
2626
+ fullPath: pathname + search + hash,
2627
+ isAttach2Hash,
2628
+ };
2629
+ }
2630
+ // 将name=encodeUrl的参数从浏览器url上删除
2631
+ function removeMicroPathFromURL(appName, targetLocation) {
2632
+ var _a, _b, _c, _d;
2633
+ let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
2634
+ const queryObject = getQueryObjectFromURL(search, hash);
2635
+ let isAttach2Hash = false;
2636
+ if ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) {
2637
+ isAttach2Hash = true;
2638
+ (_b = queryObject.hashQuery) === null || _b === void 0 ? true : delete _b[formatQueryAppName(appName)];
2639
+ const hashQueryStr = stringifyQuery(queryObject.hashQuery);
2640
+ hash = hash.slice(0, hash.indexOf('?') + Number(Boolean(hashQueryStr))) + hashQueryStr;
2641
+ }
2642
+ else if ((_c = queryObject.searchQuery) === null || _c === void 0 ? void 0 : _c[formatQueryAppName(appName)]) {
2643
+ (_d = queryObject.searchQuery) === null || _d === void 0 ? true : delete _d[formatQueryAppName(appName)];
2644
+ const searchQueryStr = stringifyQuery(queryObject.searchQuery);
2645
+ search = searchQueryStr ? '?' + searchQueryStr : '';
2646
+ }
2647
+ return {
2648
+ fullPath: pathname + search + hash,
2649
+ isAttach2Hash,
2650
+ };
2651
+ }
2652
+ /**
2653
+ * 根据location获取query对象
2654
+ */
2655
+ function getQueryObjectFromURL(search, hash) {
2656
+ const queryObject = {};
2657
+ if (search !== '' && search !== '?') {
2658
+ queryObject.searchQuery = parseQuery(search.slice(1));
2659
+ }
2660
+ if (hash.includes('?')) {
2661
+ queryObject.hashQuery = parseQuery(hash.slice(hash.indexOf('?') + 1));
2662
+ }
2663
+ return queryObject;
2664
+ }
2665
+ /**
2666
+ * get microApp path from browser URL without hash
2667
+ */
2668
+ function getNoHashMicroPathFromURL(appName, baseUrl) {
2669
+ const microPath = getMicroPathFromURL(appName);
2670
+ if (!microPath)
2671
+ return '';
2672
+ const formatLocation = createURL(microPath, baseUrl);
2673
+ return formatLocation.origin + formatLocation.pathname + formatLocation.search;
2674
+ }
2675
+
2676
+ /**
2677
+ * dispatch PopStateEvent & HashChangeEvent to child app
2678
+ * each child app will listen for popstate event when sandbox start
2679
+ * and release it when sandbox stop
2680
+ * @param appName app name
2681
+ * @returns release callback
2682
+ */
2683
+ function addHistoryListener(appName) {
2684
+ const rawWindow = globalEnv.rawWindow;
2685
+ // handle popstate event and distribute to child app
2686
+ const popStateHandler = (e) => {
2687
+ // exclude hidden keep-alive app
2688
+ if (getActiveApps(true).includes(appName) && !e.onlyForBrowser) {
2689
+ const microPath = getMicroPathFromURL(appName);
2690
+ const app = appInstanceMap.get(appName);
2691
+ const proxyWindow = app.sandBox.proxyWindow;
2692
+ let isHashChange = false;
2693
+ // for hashChangeEvent
2694
+ const oldHref = proxyWindow.location.href;
2695
+ // Do not attach micro state to url when microPath is empty
2696
+ if (microPath) {
2697
+ const oldHash = proxyWindow.location.hash;
2698
+ updateMicroLocation(appName, microPath, proxyWindow.location);
2699
+ isHashChange = proxyWindow.location.hash !== oldHash;
2700
+ }
2701
+ // dispatch formatted popStateEvent to child
2702
+ dispatchPopStateEventToMicroApp(appName, proxyWindow, rawWindow.history.state);
2703
+ // dispatch formatted hashChangeEvent to child when hash change
2704
+ if (isHashChange)
2705
+ dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref);
2706
+ // clear element scope before trigger event of next app
2707
+ removeDomScope();
2708
+ }
2709
+ };
2710
+ rawWindow.addEventListener('popstate', popStateHandler);
2711
+ return () => {
2712
+ rawWindow.removeEventListener('popstate', popStateHandler);
2713
+ };
2714
+ }
2715
+ /**
2716
+ * dispatch formatted popstate event to microApp
2717
+ * @param appName app name
2718
+ * @param proxyWindow sandbox window
2719
+ * @param eventState history.state
2720
+ */
2721
+ function dispatchPopStateEventToMicroApp(appName, proxyWindow, eventState) {
2722
+ // create PopStateEvent named popstate-appName with sub app state
2723
+ const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName, eventState) });
2724
+ globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
2725
+ // call function window.onpopstate if it exists
2726
+ typeof proxyWindow.onpopstate === 'function' && proxyWindow.onpopstate(newPopStateEvent);
2727
+ }
2728
+ /**
2729
+ * dispatch formatted hashchange event to microApp
2730
+ * @param appName app name
2731
+ * @param proxyWindow sandbox window
2732
+ * @param oldHref old href
2733
+ */
2734
+ function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
2735
+ const newHashChangeEvent = new HashChangeEvent(formatEventName$1('hashchange', appName), {
2736
+ newURL: proxyWindow.location.href,
2737
+ oldURL: oldHref,
2738
+ });
2739
+ globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
2740
+ // call function window.onhashchange if it exists
2741
+ typeof proxyWindow.onhashchange === 'function' && proxyWindow.onhashchange(newHashChangeEvent);
2742
+ }
2743
+ /**
2744
+ * dispatch native PopStateEvent, simulate location behavior
2745
+ * @param onlyForBrowser only dispatch PopStateEvent to browser
2746
+ */
2747
+ function dispatchNativePopStateEvent(onlyForBrowser) {
2748
+ const event = new PopStateEvent('popstate', { state: null });
2749
+ if (onlyForBrowser)
2750
+ event.onlyForBrowser = true;
2751
+ globalEnv.rawWindow.dispatchEvent(event);
2752
+ }
2753
+ /**
2754
+ * dispatch hashchange event to browser
2755
+ * @param oldHref old href of rawWindow.location
2756
+ */
2757
+ function dispatchNativeHashChangeEvent(oldHref) {
2758
+ const newHashChangeEvent = new HashChangeEvent('hashchange', {
2759
+ newURL: globalEnv.rawWindow.location.href,
2760
+ oldURL: oldHref,
2761
+ });
2762
+ globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
2763
+ }
2764
+ /**
2765
+ * dispatch popstate & hashchange event to browser
2766
+ * @param onlyForBrowser only dispatch event to browser
2767
+ * @param oldHref old href of rawWindow.location
2768
+ */
2769
+ function dispatchNativeEvent(onlyForBrowser, oldHref) {
2770
+ // clear element scope before dispatch global event
2771
+ removeDomScope();
2772
+ dispatchNativePopStateEvent(onlyForBrowser);
2773
+ if (oldHref) {
2774
+ dispatchNativeHashChangeEvent(oldHref);
2775
+ }
2776
+ }
2777
+
2778
+ /**
2779
+ * create proxyHistory for microApp
2780
+ * MDN https://developer.mozilla.org/en-US/docs/Web/API/History
2781
+ * @param appName app name
2782
+ * @param microLocation microApp location
2783
+ */
2784
+ function createMicroHistory(appName, microLocation) {
2785
+ const rawHistory = globalEnv.rawWindow.history;
2786
+ function getMicroHistoryMethod(methodName) {
2787
+ return function (...rests) {
2788
+ if ((methodName === 'pushState' || methodName === 'replaceState') &&
2789
+ (isString(rests[2]) || isURL(rests[2]))) {
2790
+ const targetLocation = createURL(rests[2], microLocation.href);
2791
+ if (targetLocation.origin === microLocation.origin) {
2792
+ navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rawHistory.state, rests[0]), rests[1]);
2793
+ const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
2794
+ if (targetFullPath !== microLocation.fullPath) {
2795
+ updateMicroLocation(appName, targetFullPath, microLocation);
2796
+ }
2797
+ }
2798
+ else {
2799
+ rawHistory[methodName].apply(rawHistory, rests);
2800
+ }
2801
+ }
2802
+ else {
2803
+ rawHistory[methodName].apply(rawHistory, rests);
2804
+ }
2805
+ };
2806
+ }
2807
+ return new Proxy(rawHistory, {
2808
+ get(target, key) {
2809
+ if (key === 'state') {
2810
+ return getMicroState(appName, rawHistory.state);
2811
+ }
2812
+ else if (isFunction(Reflect.get(target, key))) {
2813
+ return getMicroHistoryMethod(key);
2814
+ }
2815
+ return Reflect.get(target, key);
2816
+ },
2817
+ set(target, key, value) {
2818
+ return Reflect.set(target, key, value);
2819
+ }
2820
+ });
2821
+ }
2822
+ /**
2823
+ * navigate to new path base on native method of history
2824
+ * @param methodName pushState/replaceState
2825
+ * @param fullPath full path
2826
+ * @param state history.state, default is null
2827
+ * @param title history.title, default is ''
2828
+ */
2829
+ function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
2830
+ globalEnv.rawWindow.history[methodName](state, title, fullPath);
2831
+ }
2832
+ /**
2833
+ * Navigate to new path, and dispatch native popStateEvent/hashChangeEvent to browser
2834
+ * Use scenes:
2835
+ * 1. mount/unmount through updateBrowserURL with limited popstateEvent
2836
+ * 2. proxyHistory.pushState/replaceState with limited popstateEvent
2837
+ * 3. api microApp.router.push/replace
2838
+ * 4. proxyLocation.hash = xxx
2839
+ * @param methodName pushState/replaceState
2840
+ * @param result result of add/remove microApp path on browser url
2841
+ * @param onlyForBrowser only dispatch event to browser
2842
+ * @param state history.state, not required
2843
+ * @param title history.title, not required
2844
+ */
2845
+ function navigateWithNativeEvent(methodName, result, onlyForBrowser, state, title) {
2846
+ const rawLocation = globalEnv.rawWindow.location;
2847
+ const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
2848
+ const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
2849
+ // navigate with native history method
2850
+ nativeHistoryNavigate(methodName, result.fullPath, state, title);
2851
+ if (oldFullPath !== result.fullPath)
2852
+ dispatchNativeEvent(onlyForBrowser, oldHref);
2853
+ }
2854
+ /**
2855
+ * update browser url when mount/unmount/hidden/show
2856
+ * @param result result of add/remove microApp path on browser url
2857
+ * @param state history.state
2858
+ */
2859
+ function updateBrowserURL(result, state) {
2860
+ navigateWithNativeEvent('replaceState', result, true, state);
2861
+ }
2862
+ /**
2863
+ * When path is same, keep the microAppState in history.state
2864
+ * Fix bug of missing microAppState in next.js & angular
2865
+ * @param method history.pushState/replaceState
2866
+ */
2867
+ function patchHistoryState(method) {
2868
+ const rawWindow = globalEnv.rawWindow;
2869
+ return function (...rests) {
2870
+ var _a;
2871
+ if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.microAppState) &&
2872
+ (!isPlainObject(rests[0]) || !rests[0].microAppState) &&
2873
+ (isString(rests[2]) || isURL(rests[2]))) {
2874
+ const currentHref = rawWindow.location.href;
2875
+ const targetLocation = createURL(rests[2], currentHref);
2876
+ if (targetLocation.href === currentHref) {
2877
+ rests[0] = assign({}, rests[0], {
2878
+ microAppState: rawWindow.history.state.microAppState,
2879
+ });
2880
+ }
2881
+ }
2882
+ method.apply(rawWindow.history, rests);
2883
+ };
2884
+ }
2885
+ let isReWriteHistoryState = false;
2886
+ /**
2887
+ * rewrite history.pushState/replaceState
2888
+ * used to fix the problem that the microAppState maybe missing when mainApp navigate to same path
2889
+ * e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
2890
+ */
2891
+ function rewriteHistoryState() {
2892
+ // filter nest app
2893
+ if (!isReWriteHistoryState && !window.__MICRO_APP_ENVIRONMENT__) {
2894
+ isReWriteHistoryState = true;
2895
+ const rawWindow = globalEnv.rawWindow;
2896
+ rawWindow.history.pushState = patchHistoryState(rawWindow.history.pushState);
2897
+ rawWindow.history.replaceState = patchHistoryState(rawWindow.history.replaceState);
2898
+ }
2899
+ }
2900
+
2901
+ function createRouterApi() {
2902
+ /**
2903
+ * common handler for router.push/router.replace method
2904
+ * @param appName app name
2905
+ * @param methodName replaceState/pushState
2906
+ * @param targetLocation target location
2907
+ * @param state to.state
2908
+ */
2909
+ function navigateWithRawHistory(appName, methodName, targetLocation, state) {
2910
+ navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, globalEnv.rawWindow.history.state, state !== null && state !== void 0 ? state : null));
2911
+ // clear element scope after navigate
2912
+ removeDomScope();
2913
+ }
2914
+ /**
2915
+ * create method of router.push/replace
2916
+ * NOTE:
2917
+ * 1. The same fullPath will be blocked
2918
+ * 2. name & path is required
2919
+ * 3. path is fullPath except for the domain (the domain can be taken, but not valid)
2920
+ * @param replace use router.replace?
2921
+ */
2922
+ function createNavigationMethod(replace) {
2923
+ return function (to) {
2924
+ const appName = formatAppName(to.name);
2925
+ // console.log(3333333, appInstanceMap.get(appName))
2926
+ if (appName && isString(to.path)) {
2927
+ const app = appInstanceMap.get(appName);
2928
+ if (app && !app.sandBox)
2929
+ return logError(`navigation failed, sandBox of app ${appName} is closed`);
2930
+ // active apps, include hidden keep-alive app
2931
+ if (getActiveApps().includes(appName)) {
2932
+ const microLocation = app.sandBox.proxyWindow.location;
2933
+ const targetLocation = createURL(to.path, microLocation.href);
2934
+ // Only get path data, even if the origin is different from microApp
2935
+ const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
2936
+ if (microLocation.fullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
2937
+ const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
2938
+ navigateWithRawHistory(appName, methodName, targetLocation, to.state);
2939
+ }
2940
+ }
2941
+ else {
2942
+ /**
2943
+ * app not exit or unmounted, update browser URL with replaceState
2944
+ * use base app location.origin as baseURL
2945
+ */
2946
+ const rawLocation = globalEnv.rawWindow.location;
2947
+ const targetLocation = createURL(to.path, rawLocation.origin);
2948
+ const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
2949
+ if (getMicroPathFromURL(appName) !== targetFullPath) {
2950
+ navigateWithRawHistory(appName, to.replace === false ? 'pushState' : 'replaceState', targetLocation, to.state);
2951
+ }
2952
+ }
2953
+ }
2954
+ else {
2955
+ logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`);
2956
+ }
2957
+ };
2958
+ }
2959
+ // create method of router.go/back/forward
2960
+ function createRawHistoryMethod(methodName) {
2961
+ return function (...rests) {
2962
+ return globalEnv.rawWindow.history[methodName](...rests);
2963
+ };
2964
+ }
2965
+ const beforeGuards = useSetRecord();
2966
+ const afterGuards = useSetRecord();
2967
+ /**
2968
+ * run all of beforeEach/afterEach guards
2969
+ * NOTE:
2970
+ * 1. Modify browser url first, and then run guards,
2971
+ * consistent with the browser forward & back button
2972
+ * 2. Note the element binding
2973
+ * @param appName app name
2974
+ * @param to target location
2975
+ * @param from old location
2976
+ * @param guards guards list
2977
+ */
2978
+ function runGuards(appName, to, from, guards) {
2979
+ // clear element scope before execute function of parent
2980
+ removeDomScope();
2981
+ for (const guard of guards) {
2982
+ if (isFunction(guard)) {
2983
+ guard(appName, to, from);
2984
+ }
2985
+ else if (isPlainObject(guard) && isFunction(guard[appName])) {
2986
+ guard[appName](to, from);
2987
+ }
2988
+ }
2989
+ }
2990
+ /**
2991
+ * global hook for router
2992
+ * update router information base on microLocation
2993
+ * @param appName app name
2994
+ * @param microLocation location of microApp
2995
+ */
2996
+ function executeNavigationGuard(appName, to, from) {
2997
+ router.current.set(appName, to);
2998
+ runGuards(appName, to, from, beforeGuards.list());
2999
+ requestIdleCallback(() => {
3000
+ runGuards(appName, to, from, afterGuards.list());
3001
+ });
3002
+ }
3003
+ function clearRouterWhenUnmount(appName) {
3004
+ router.current.delete(appName);
3005
+ }
3006
+ // defaultPage data
3007
+ const defaultPageRecord = useMapRecord();
3008
+ /**
3009
+ * defaultPage只在子应用初始化时生效,且优先级比浏览器上的子应用路由地址低
3010
+ * @param appName app name
3011
+ * @param path page path
3012
+ */
3013
+ function setDefaultPage(appName, path) {
3014
+ appName = formatAppName(appName);
3015
+ if (!appName)
3016
+ return noopFalse;
3017
+ return defaultPageRecord.add(appName, path);
3018
+ }
3019
+ function removeDefaultPage(appName) {
3020
+ appName = formatAppName(appName);
3021
+ if (!appName)
3022
+ return false;
3023
+ return defaultPageRecord.delete(appName);
3024
+ }
3025
+ // Router API for developer
3026
+ const router = {
3027
+ current: new Map(),
3028
+ encode: encodeMicroPath,
3029
+ decode: decodeMicroPath,
3030
+ push: createNavigationMethod(false),
3031
+ replace: createNavigationMethod(true),
3032
+ go: createRawHistoryMethod('go'),
3033
+ back: createRawHistoryMethod('back'),
3034
+ forward: createRawHistoryMethod('forward'),
3035
+ beforeEach: beforeGuards.add,
3036
+ afterEach: afterGuards.add,
3037
+ // attachToURL: 将指定的子应用路由信息添加到浏览器地址上
3038
+ // attachAllToURL: 将所有正在运行的子应用路由信息添加到浏览器地址上
3039
+ setDefaultPage,
3040
+ removeDefaultPage,
3041
+ getDefaultPage: defaultPageRecord.get,
3042
+ };
3043
+ return {
3044
+ router,
3045
+ executeNavigationGuard,
3046
+ clearRouterWhenUnmount,
3047
+ };
3048
+ }
3049
+ const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
3050
+
3051
+ const shadowLocationKeys = ['href', 'pathname', 'search', 'hash'];
3052
+ // origin is readonly, so we ignore when updateMicroLocation
3053
+ const locationKeys = [...shadowLocationKeys, 'host', 'hostname', 'port', 'protocol', 'search'];
3054
+ // origin, fullPath is necessary for guardLocation
3055
+ const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
3056
+ /**
3057
+ * create guardLocation by microLocation, used for router guard
3058
+ */
3059
+ function createGuardLocation(appName, microLocation) {
3060
+ const guardLocation = assign({ name: appName }, microLocation);
3061
+ // The prototype values on the URL needs to be manually transferred
3062
+ for (const key of guardLocationKeys)
3063
+ guardLocation[key] = microLocation[key];
3064
+ return guardLocation;
3065
+ }
3066
+ // for updateBrowserURLWithLocation when initial
3067
+ function autoTriggerNavigationGuard(appName, microLocation) {
3068
+ executeNavigationGuard(appName, createGuardLocation(appName, microLocation), createGuardLocation(appName, microLocation));
3069
+ }
3070
+ /**
3071
+ * The following scenes will trigger location update:
3072
+ * 1. pushState/replaceState
3073
+ * 2. popStateEvent
3074
+ * 3. query on browser url when init sub app
3075
+ * 4. set defaultPage when when init sub app
3076
+ * NOTE:
3077
+ * 1. update browser URL first, and then update microLocation
3078
+ * 2. the same fullPath will not trigger router guards
3079
+ * @param appName app name
3080
+ * @param path target path
3081
+ * @param base base url
3082
+ * @param microLocation micro app location
3083
+ * @param type auto prevent
3084
+ */
3085
+ function updateMicroLocation(appName, path, microLocation, type) {
3086
+ const newLocation = createURL(path, microLocation.href);
3087
+ // record old values of microLocation to `from`
3088
+ const from = createGuardLocation(appName, microLocation);
3089
+ for (const key of locationKeys) {
3090
+ if (shadowLocationKeys.includes(key)) {
3091
+ // reference of shadowLocation
3092
+ microLocation.shadowLocation[key] = newLocation[key];
3093
+ }
3094
+ else {
3095
+ // @ts-ignore reference of microLocation
3096
+ microLocation[key] = newLocation[key];
3097
+ }
3098
+ }
3099
+ // update latest values of microLocation to `to`
3100
+ const to = createGuardLocation(appName, microLocation);
3101
+ // The hook called only when fullPath changed
3102
+ if (type === 'auto' || (from.fullPath !== to.fullPath && type !== 'prevent')) {
3103
+ executeNavigationGuard(appName, to, from);
3104
+ }
3105
+ }
3106
+ /**
3107
+ * Create location for microApp, each microApp has only one location object, it is a reference type
3108
+ * MDN https://developer.mozilla.org/en-US/docs/Web/API/Location
3109
+ * @param appName app name
3110
+ * @param url app url
3111
+ */
3112
+ function createMicroLocation(appName, url) {
3113
+ const rawWindow = globalEnv.rawWindow;
3114
+ const rawLocation = rawWindow.location;
3115
+ // microLocation is the location of child app, it is globally unique
3116
+ const microLocation = createURL(url);
3117
+ // shadowLocation is the current location information (href, pathname, search, hash)
3118
+ const shadowLocation = {
3119
+ href: microLocation.href,
3120
+ pathname: microLocation.pathname,
3121
+ search: microLocation.search,
3122
+ hash: microLocation.hash,
3123
+ };
3124
+ /**
3125
+ * Common handler for href, assign, replace
3126
+ * It is mainly used to deal with special scenes about hash
3127
+ * @param value target path
3128
+ * @param methodName pushState/replaceState
3129
+ * @returns origin value or formatted value
3130
+ */
3131
+ const commonHandler = (value, methodName) => {
3132
+ const targetLocation = createURL(value, microLocation.href);
3133
+ // Even if the origin is the same, developers still have the possibility of want to jump to a new page
3134
+ if (targetLocation.origin === microLocation.origin) {
3135
+ const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
3136
+ /**
3137
+ * change hash with location.href will not trigger the browser reload
3138
+ * so we use pushState & reload to imitate href behavior
3139
+ * NOTE:
3140
+ * 1. if child app only change hash, it should not trigger browser reload
3141
+ * 2. if address is same and has hash, it should not add route stack
3142
+ */
3143
+ if (targetLocation.pathname === shadowLocation.pathname &&
3144
+ targetLocation.search === shadowLocation.search) {
3145
+ let oldHref = null;
3146
+ if (targetLocation.hash !== shadowLocation.hash) {
3147
+ if (setMicroPathResult.isAttach2Hash)
3148
+ oldHref = rawLocation.href;
3149
+ nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
3150
+ }
3151
+ if (targetLocation.hash) {
3152
+ dispatchNativeEvent(false, oldHref);
3153
+ }
3154
+ else {
3155
+ rawLocation.reload();
3156
+ }
3157
+ return void 0;
3158
+ /**
3159
+ * when baseApp is hash router, address change of child can not reload browser
3160
+ * so we imitate behavior of browser (reload)
3161
+ */
3162
+ }
3163
+ else if (setMicroPathResult.isAttach2Hash) {
3164
+ nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
3165
+ rawLocation.reload();
3166
+ return void 0;
3167
+ }
3168
+ value = setMicroPathResult.fullPath;
3169
+ }
3170
+ return value;
3171
+ };
3172
+ /**
3173
+ * create location PropertyDescriptor (href, pathname, search, hash)
3174
+ * @param key property name
3175
+ * @param setter setter of location property
3176
+ */
3177
+ function createPropertyDescriptor(getter, setter) {
3178
+ return {
3179
+ enumerable: true,
3180
+ configurable: true,
3181
+ get: getter,
3182
+ set: setter,
3183
+ };
3184
+ }
3185
+ /**
3186
+ * common handler for location.pathname & location.search
3187
+ * @param targetPath target fullPath
3188
+ * @param key pathname/search
3189
+ */
3190
+ function handleForPathNameAndSearch(targetPath, key) {
3191
+ const targetLocation = createURL(targetPath, url);
3192
+ // When the browser url has a hash value, the same pathname/search will not refresh browser
3193
+ if (targetLocation[key] === shadowLocation[key] && shadowLocation.hash) {
3194
+ // The href has not changed, not need to dispatch hashchange event
3195
+ dispatchNativeEvent(false);
3196
+ }
3197
+ else {
3198
+ /**
3199
+ * When the value is the same, no new route stack will be added
3200
+ * Special scenes such as:
3201
+ * pathname: /path ==> /path#hash, /path ==> /path?query
3202
+ * search: ?query ==> ?query#hash
3203
+ */
3204
+ nativeHistoryNavigate(targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
3205
+ rawLocation.reload();
3206
+ }
3207
+ }
3208
+ /**
3209
+ * Special processing for four keys: href, pathname, search and hash
3210
+ * They take values from shadowLocation, and require special operations when assigning values
3211
+ */
3212
+ rawDefineProperties(microLocation, {
3213
+ href: createPropertyDescriptor(() => shadowLocation.href, (value) => {
3214
+ const targetPath = commonHandler(value, 'pushState');
3215
+ if (targetPath)
3216
+ rawLocation.href = targetPath;
3217
+ }),
3218
+ pathname: createPropertyDescriptor(() => shadowLocation.pathname, (value) => {
3219
+ const targetPath = ('/' + value).replace(/^\/+/, '/') + shadowLocation.search + shadowLocation.hash;
3220
+ handleForPathNameAndSearch(targetPath, 'pathname');
3221
+ }),
3222
+ search: createPropertyDescriptor(() => shadowLocation.search, (value) => {
3223
+ const targetPath = shadowLocation.pathname + ('?' + value).replace(/^\?+/, '?') + shadowLocation.hash;
3224
+ handleForPathNameAndSearch(targetPath, 'search');
3225
+ }),
3226
+ hash: createPropertyDescriptor(() => shadowLocation.hash, (value) => {
3227
+ const targetPath = shadowLocation.pathname + shadowLocation.search + ('#' + value).replace(/^#+/, '#');
3228
+ const targetLocation = createURL(targetPath, url);
3229
+ // The same hash will not trigger popStateEvent
3230
+ if (targetLocation.hash !== shadowLocation.hash) {
3231
+ navigateWithNativeEvent('pushState', setMicroPathToURL(appName, targetLocation), false);
3232
+ }
3233
+ }),
3234
+ fullPath: createPropertyDescriptor(() => shadowLocation.pathname + shadowLocation.search + shadowLocation.hash, noop),
3235
+ });
3236
+ const createLocationMethod = (locationMethodName) => {
3237
+ return function (value) {
3238
+ const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
3239
+ if (targetPath)
3240
+ rawLocation[locationMethodName](targetPath);
3241
+ };
3242
+ };
3243
+ return assign(microLocation, {
3244
+ assign: createLocationMethod('assign'),
3245
+ replace: createLocationMethod('replace'),
3246
+ reload: (forcedReload) => rawLocation.reload(forcedReload),
3247
+ shadowLocation,
3248
+ });
3249
+ }
3250
+
3251
+ /**
3252
+ * The router system has two operations: read and write
3253
+ * Read through location and write through history & location
3254
+ * @param appName app name
3255
+ * @param url app url
3256
+ * @returns MicroRouter
3257
+ */
3258
+ function createMicroRouter(appName, url) {
3259
+ rewriteHistoryState();
3260
+ const microLocation = createMicroLocation(appName, url);
3261
+ return {
3262
+ microLocation,
3263
+ microHistory: createMicroHistory(appName, microLocation),
3264
+ };
3265
+ }
3266
+ // 当沙箱执行start, 或者隐藏的keep-alive应用重新渲染时时才根据浏览器url更新location 或者 将参数更新到url上
3267
+ function initRouteStateWithURL(appName, microLocation, defaultPage) {
3268
+ const microPath = getMicroPathFromURL(appName);
3269
+ if (microPath) {
3270
+ updateMicroLocation(appName, microPath, microLocation, 'auto');
3271
+ }
3272
+ else {
3273
+ updateBrowserURLWithLocation(appName, microLocation, defaultPage);
3274
+ }
3275
+ }
3276
+ /**
3277
+ * initialize browser information according to microLocation
3278
+ * called on sandbox.start or reshow of keep-alive app
3279
+ */
3280
+ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
3281
+ // update microLocation with defaultPage
3282
+ if (defaultPage)
3283
+ updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
3284
+ // attach microApp route info to browser URL
3285
+ updateBrowserURL(setMicroPathToURL(appName, microLocation), setMicroState(appName, globalEnv.rawWindow.history.state, null));
3286
+ // trigger guards after change browser URL
3287
+ autoTriggerNavigationGuard(appName, microLocation);
3288
+ }
3289
+ /**
3290
+ * In any case, microPath & microState will be removed from browser, but location will be initialized only when keep-router-state is false
3291
+ * @param appName app name
3292
+ * @param url app url
3293
+ * @param microLocation location of microApp
3294
+ * @param keepRouteState keep-router-state is only used to control whether to clear the location of microApp
3295
+ */
3296
+ function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
3297
+ if (!keepRouteState) {
3298
+ const { pathname, search, hash } = createURL(url);
3299
+ updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
3300
+ }
3301
+ removeStateAndPathFromBrowser(appName);
3302
+ clearRouterWhenUnmount(appName);
3303
+ }
3304
+ /**
3305
+ * remove microState from history.state and remove microPath from browserURL
3306
+ * called on sandbox.stop or hidden of keep-alive app
3307
+ */
3308
+ function removeStateAndPathFromBrowser(appName) {
3309
+ updateBrowserURL(removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
3310
+ }
3311
+
2438
3312
  // Variables that can escape to rawWindow
2439
3313
  const staticEscapeProperties = [
3314
+ '__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
2440
3315
  'System',
2441
3316
  '__cjsWrapper',
2442
3317
  ];
@@ -2446,7 +3321,7 @@ const escapeSetterKeyList = [
2446
3321
  ];
2447
3322
  const globalPropertyList = ['window', 'self', 'globalThis'];
2448
3323
  class SandBox {
2449
- constructor(appName, url) {
3324
+ constructor(appName, url, useMemoryRouter = true) {
2450
3325
  /**
2451
3326
  * Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
2452
3327
  * https://github.com/micro-zoe/micro-app/issues/234
@@ -2466,25 +3341,32 @@ class SandBox {
2466
3341
  // create proxyWindow with Proxy(microAppWindow)
2467
3342
  this.proxyWindow = this.createProxyWindow(appName);
2468
3343
  // inject global properties
2469
- this.initMicroAppWindow(this.microAppWindow, appName, url);
3344
+ this.initMicroAppWindow(this.microAppWindow, appName, url, useMemoryRouter);
2470
3345
  // Rewrite global event listener & timeout
2471
- Object.assign(this, effect(this.microAppWindow));
3346
+ assign(this, effect(this.microAppWindow));
2472
3347
  }
2473
- start(baseRoute) {
3348
+ start(baseRoute, useMemoryRouter = true, defaultPage = '') {
2474
3349
  if (!this.active) {
2475
3350
  this.active = true;
2476
- this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseRoute;
2477
- // BUG FIX: bable-polyfill@6.x
2478
- globalEnv.rawWindow._babelPolyfill && (globalEnv.rawWindow._babelPolyfill = false);
3351
+ if (useMemoryRouter) {
3352
+ this.initRouteState(defaultPage);
3353
+ // unique listener of popstate event for sub app
3354
+ this.removeHistoryListener = addHistoryListener(this.proxyWindow.__MICRO_APP_NAME__);
3355
+ }
3356
+ else {
3357
+ this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseRoute;
3358
+ }
2479
3359
  if (++SandBox.activeCount === 1) {
2480
3360
  effectDocumentEvent();
2481
3361
  patchElementPrototypeMethods();
3362
+ listenUmountOfNestedApp();
2482
3363
  }
3364
+ // BUG FIX: bable-polyfill@6.x
3365
+ globalEnv.rawWindow._babelPolyfill && (globalEnv.rawWindow._babelPolyfill = false);
2483
3366
  }
2484
3367
  }
2485
- stop() {
3368
+ stop(keepRouteState = false) {
2486
3369
  if (this.active) {
2487
- this.active = false;
2488
3370
  this.releaseEffect();
2489
3371
  this.microAppWindow.microApp.clearDataListener();
2490
3372
  this.microAppWindow.microApp.clearGlobalDataListener();
@@ -2496,10 +3378,16 @@ class SandBox {
2496
3378
  Reflect.deleteProperty(globalEnv.rawWindow, key);
2497
3379
  });
2498
3380
  this.escapeKeys.clear();
3381
+ if (this.removeHistoryListener) {
3382
+ this.clearRouteState(keepRouteState);
3383
+ // release listener of popstate
3384
+ this.removeHistoryListener();
3385
+ }
2499
3386
  if (--SandBox.activeCount === 0) {
2500
3387
  releaseEffectDocumentEvent();
2501
3388
  releasePatches();
2502
3389
  }
3390
+ this.active = false;
2503
3391
  }
2504
3392
  }
2505
3393
  // record umd snapshot before the first execution of umdHookMount
@@ -2644,20 +3532,25 @@ class SandBox {
2644
3532
  * @param appName app name
2645
3533
  * @param url app url
2646
3534
  */
2647
- initMicroAppWindow(microAppWindow, appName, url) {
3535
+ initMicroAppWindow(microAppWindow, appName, url, useMemoryRouter) {
2648
3536
  microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
2649
3537
  microAppWindow.__MICRO_APP_NAME__ = appName;
3538
+ microAppWindow.__MICRO_APP_URL__ = url;
2650
3539
  microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
2651
3540
  microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
2652
- microAppWindow.microApp = Object.assign(new EventCenterForMicroApp(appName), {
3541
+ microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
2653
3542
  removeDomScope,
2654
3543
  pureCreateElement,
3544
+ router,
2655
3545
  });
2656
3546
  microAppWindow.rawWindow = globalEnv.rawWindow;
2657
3547
  microAppWindow.rawDocument = globalEnv.rawDocument;
2658
3548
  microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
2659
3549
  this.setMappingPropertiesWithRawDescriptor(microAppWindow);
2660
3550
  this.setHijackProperties(microAppWindow, appName);
3551
+ // this.patchHijackRequest(microAppWindow, appName, url)
3552
+ if (useMemoryRouter)
3553
+ this.setRouterApi(microAppWindow, appName, url);
2661
3554
  }
2662
3555
  // properties associated with the native window
2663
3556
  setMappingPropertiesWithRawDescriptor(microAppWindow) {
@@ -2691,14 +3584,16 @@ class SandBox {
2691
3584
  let modifiedEval, modifiedImage;
2692
3585
  rawDefineProperties(microAppWindow, {
2693
3586
  document: {
3587
+ configurable: false,
3588
+ enumerable: true,
2694
3589
  get() {
2695
3590
  throttleDeferForSetAppName(appName);
2696
3591
  return globalEnv.rawDocument;
2697
3592
  },
2698
- configurable: false,
2699
- enumerable: true,
2700
3593
  },
2701
3594
  eval: {
3595
+ configurable: true,
3596
+ enumerable: false,
2702
3597
  get() {
2703
3598
  throttleDeferForSetAppName(appName);
2704
3599
  return modifiedEval || eval;
@@ -2706,10 +3601,10 @@ class SandBox {
2706
3601
  set: (value) => {
2707
3602
  modifiedEval = value;
2708
3603
  },
2709
- configurable: true,
2710
- enumerable: false,
2711
3604
  },
2712
3605
  Image: {
3606
+ configurable: true,
3607
+ enumerable: false,
2713
3608
  get() {
2714
3609
  throttleDeferForSetAppName(appName);
2715
3610
  return modifiedImage || globalEnv.ImageProxy;
@@ -2717,11 +3612,101 @@ class SandBox {
2717
3612
  set: (value) => {
2718
3613
  modifiedImage = value;
2719
3614
  },
3615
+ },
3616
+ });
3617
+ }
3618
+ // private patchHijackRequest (microAppWindow: microAppWindowType, appName: string, url: string) {
3619
+ // let modifiedImage: unknown
3620
+ // function EventSource (...rests: any[]) {
3621
+ // console.log(appName + ' EventSource', rests)
3622
+ // if (typeof rests[0] === 'string') {
3623
+ // rests[0] = (new URL(rests[0], url)).toString()
3624
+ // }
3625
+ // return new globalEnv.rawWindow.EventSource(...rests)
3626
+ // }
3627
+ // function patchFetch (...rests: any[]) {
3628
+ // console.log(appName + ' fetch', rests)
3629
+ // if (typeof rests[0] === 'string') {
3630
+ // rests[0] = (new URL(rests[0], url)).toString()
3631
+ // }
3632
+ // return globalEnv.rawWindow.fetch(...rests)
3633
+ // }
3634
+ // const rawXMLHttpRequest = globalEnv.rawWindow.XMLHttpRequest
3635
+ // class XMLHttpRequest extends rawXMLHttpRequest {
3636
+ // open (method: string, reqUrl: string) {
3637
+ // console.log(appName + ' XMLHttpRequest', method, reqUrl)
3638
+ // reqUrl = (new URL(reqUrl, url)).toString()
3639
+ // super.open(method, reqUrl)
3640
+ // }
3641
+ // }
3642
+ // rawDefineProperties(microAppWindow, {
3643
+ // EventSource: {
3644
+ // configurable: true,
3645
+ // enumerable: true,
3646
+ // get () {
3647
+ // return EventSource
3648
+ // },
3649
+ // set: (value) => {
3650
+ // modifiedImage = value
3651
+ // },
3652
+ // },
3653
+ // fetch: {
3654
+ // configurable: true,
3655
+ // enumerable: true,
3656
+ // get () {
3657
+ // return patchFetch
3658
+ // },
3659
+ // set: (value) => {
3660
+ // modifiedImage = value
3661
+ // },
3662
+ // },
3663
+ // XMLHttpRequest: {
3664
+ // configurable: true,
3665
+ // enumerable: true,
3666
+ // get () {
3667
+ // return XMLHttpRequest
3668
+ // },
3669
+ // set: (value) => {
3670
+ // modifiedImage = value
3671
+ // },
3672
+ // },
3673
+ // })
3674
+ // }
3675
+ // set location & history for memory router
3676
+ setRouterApi(microAppWindow, appName, url) {
3677
+ const { microLocation, microHistory } = createMicroRouter(appName, url);
3678
+ rawDefineProperties(microAppWindow, {
3679
+ location: {
3680
+ configurable: false,
3681
+ enumerable: true,
3682
+ get() {
3683
+ return microLocation;
3684
+ },
3685
+ set: (value) => {
3686
+ globalEnv.rawWindow.location = value;
3687
+ },
3688
+ },
3689
+ history: {
2720
3690
  configurable: true,
2721
- enumerable: false,
3691
+ enumerable: true,
3692
+ get() {
3693
+ return microHistory;
3694
+ },
2722
3695
  },
2723
3696
  });
2724
3697
  }
3698
+ initRouteState(defaultPage) {
3699
+ initRouteStateWithURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location, defaultPage);
3700
+ }
3701
+ clearRouteState(keepRouteState) {
3702
+ clearRouteStateFromURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__, this.proxyWindow.location, keepRouteState);
3703
+ }
3704
+ setRouteInfoForKeepAliveApp() {
3705
+ updateBrowserURLWithLocation(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location);
3706
+ }
3707
+ removeRouteInfoForKeepAliveApp() {
3708
+ removeStateAndPathFromBrowser(this.proxyWindow.__MICRO_APP_NAME__);
3709
+ }
2725
3710
  }
2726
3711
  SandBox.activeCount = 0; // number of active sandbox
2727
3712
 
@@ -2755,7 +3740,7 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
2755
3740
  element = getRootContainer(element);
2756
3741
  // clear dom scope before dispatch lifeCycles event to base app, especially mounted & unmount
2757
3742
  removeDomScope();
2758
- const detail = Object.assign({
3743
+ const detail = assign({
2759
3744
  name: appName,
2760
3745
  container: element,
2761
3746
  }, error && {
@@ -2780,7 +3765,7 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
2780
3765
  * @param detail event detail
2781
3766
  */
2782
3767
  function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
2783
- const event = new CustomEvent(`${eventName}-${appName}`, {
3768
+ const event = new CustomEvent(formatEventName$1(eventName, appName), {
2784
3769
  detail,
2785
3770
  });
2786
3771
  window.dispatchEvent(event);
@@ -2789,8 +3774,8 @@ function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
2789
3774
  // micro app instances
2790
3775
  const appInstanceMap = new Map();
2791
3776
  class CreateApp {
2792
- constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, baseroute, }) {
2793
- this.state = appStates.NOT_LOADED;
3777
+ constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, useMemoryRouter, baseroute, keepRouteState, defaultPage, }) {
3778
+ this.state = appStates.CREATED;
2794
3779
  this.keepAliveState = null;
2795
3780
  this.keepAliveContainer = null;
2796
3781
  this.loadSourceLevel = 0;
@@ -2801,27 +3786,29 @@ class CreateApp {
2801
3786
  this.isPrefetch = false;
2802
3787
  this.prefetchResolve = null;
2803
3788
  this.container = null;
2804
- this.baseroute = '';
2805
3789
  this.sandBox = null;
2806
3790
  this.container = container !== null && container !== void 0 ? container : null;
2807
3791
  this.inline = inline !== null && inline !== void 0 ? inline : false;
2808
3792
  this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : '';
3793
+ this.keepRouteState = keepRouteState !== null && keepRouteState !== void 0 ? keepRouteState : false;
2809
3794
  this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
2810
3795
  // optional during init👆
2811
3796
  this.name = name;
2812
3797
  this.url = url;
2813
3798
  this.useSandbox = useSandbox;
2814
3799
  this.scopecss = this.useSandbox && scopecss;
3800
+ this.useMemoryRouter = this.useSandbox && useMemoryRouter;
3801
+ this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : '';
2815
3802
  this.source = {
2816
3803
  links: new Map(),
2817
3804
  scripts: new Map(),
2818
3805
  };
2819
3806
  this.loadSourceCode();
2820
- this.useSandbox && (this.sandBox = new SandBox(name, url));
3807
+ this.useSandbox && (this.sandBox = new SandBox(name, url, this.useMemoryRouter));
2821
3808
  }
2822
3809
  // Load resources
2823
3810
  loadSourceCode() {
2824
- this.state = appStates.LOADING_SOURCE_CODE;
3811
+ this.state = appStates.LOADING;
2825
3812
  extractHtml(this);
2826
3813
  }
2827
3814
  /**
@@ -2836,7 +3823,7 @@ class CreateApp {
2836
3823
  this.prefetchResolve = null;
2837
3824
  }
2838
3825
  else if (appStates.UNMOUNT !== this.state) {
2839
- this.state = appStates.LOAD_SOURCE_FINISHED;
3826
+ this.state = appStates.LOADED;
2840
3827
  this.mount();
2841
3828
  }
2842
3829
  }
@@ -2853,7 +3840,7 @@ class CreateApp {
2853
3840
  }
2854
3841
  if (appStates.UNMOUNT !== this.state) {
2855
3842
  this.onerror(e);
2856
- this.state = appStates.LOAD_SOURCE_ERROR;
3843
+ this.state = appStates.LOAD_FAILED;
2857
3844
  }
2858
3845
  }
2859
3846
  /**
@@ -2861,22 +3848,26 @@ class CreateApp {
2861
3848
  * @param container app container
2862
3849
  * @param inline js runs in inline mode
2863
3850
  * @param baseroute route prefix, default is ''
3851
+ * @param keepRouteState keep route state when unmount, default is false
2864
3852
  */
2865
- mount(container, inline, baseroute) {
3853
+ mount(container, inline, baseroute, keepRouteState, defaultPage) {
2866
3854
  var _a, _b, _c;
2867
- if (isBoolean(inline) && inline !== this.inline) {
3855
+ if (isBoolean(inline))
2868
3856
  this.inline = inline;
2869
- }
3857
+ // keepRouteState effective on unmount
3858
+ if (isBoolean(keepRouteState))
3859
+ this.keepRouteState = keepRouteState;
2870
3860
  this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
2871
3861
  this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
3862
+ this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : this.defaultPage;
2872
3863
  if (this.loadSourceLevel !== 2) {
2873
- this.state = appStates.LOADING_SOURCE_CODE;
3864
+ this.state = appStates.LOADING;
2874
3865
  return;
2875
3866
  }
2876
3867
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
2877
3868
  this.state = appStates.MOUNTING;
2878
3869
  cloneContainer(this.source.html, this.container, !this.umdMode);
2879
- (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute);
3870
+ (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute, this.useMemoryRouter, this.defaultPage);
2880
3871
  let umdHookMountResult; // result of mount function
2881
3872
  if (!this.umdMode) {
2882
3873
  let hasDispatchMountedEvent = false;
@@ -2941,11 +3932,12 @@ class CreateApp {
2941
3932
  }
2942
3933
  /**
2943
3934
  * unmount app
3935
+ * NOTE: Do not add any params on account of unmountApp
2944
3936
  * @param destroy completely destroy, delete cache resources
2945
3937
  * @param unmountcb callback of unmount
2946
3938
  */
2947
3939
  unmount(destroy, unmountcb) {
2948
- if (this.state === appStates.LOAD_SOURCE_ERROR) {
3940
+ if (this.state === appStates.LOAD_FAILED) {
2949
3941
  destroy = true;
2950
3942
  }
2951
3943
  this.state = appStates.UNMOUNT;
@@ -2999,7 +3991,7 @@ class CreateApp {
2999
3991
  cloneContainer(this.container, this.source.html, false);
3000
3992
  }
3001
3993
  // this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
3002
- (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop();
3994
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop(this.keepRouteState && !destroy);
3003
3995
  if (!getActiveApps().length) {
3004
3996
  releasePatchSetAttribute();
3005
3997
  }
@@ -3018,34 +4010,40 @@ class CreateApp {
3018
4010
  }
3019
4011
  // hidden app when disconnectedCallback called with keep-alive
3020
4012
  hiddenKeepAliveApp() {
4013
+ var _a;
3021
4014
  const oldContainer = this.container;
3022
4015
  cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
3023
4016
  this.container = this.keepAliveContainer;
3024
4017
  this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
3025
4018
  // event should dispatch before clone node
3026
- // dispatch afterhidden event to micro-app
4019
+ // dispatch afterHidden event to micro-app
3027
4020
  dispatchCustomEventToMicroApp('appstate-change', this.name, {
3028
4021
  appState: 'afterhidden',
3029
4022
  });
3030
- // dispatch afterhidden event to base app
4023
+ // dispatch afterHidden event to base app
3031
4024
  dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
4025
+ // called after lifeCyclesEvent
4026
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
3032
4027
  }
3033
4028
  // show app when connectedCallback called with keep-alive
3034
4029
  showKeepAliveApp(container) {
3035
- // dispatch beforeshow event to micro-app
4030
+ var _a;
4031
+ // dispatch beforeShow event to micro-app
3036
4032
  dispatchCustomEventToMicroApp('appstate-change', this.name, {
3037
4033
  appState: 'beforeshow',
3038
4034
  });
3039
- // dispatch beforeshow event to base app
4035
+ // dispatch beforeShow event to base app
3040
4036
  dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
3041
4037
  cloneContainer(this.container, container, false);
3042
4038
  this.container = container;
3043
4039
  this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
3044
- // dispatch aftershow event to micro-app
4040
+ // called before lifeCyclesEvent
4041
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setRouteInfoForKeepAliveApp();
4042
+ // dispatch afterShow event to micro-app
3045
4043
  dispatchCustomEventToMicroApp('appstate-change', this.name, {
3046
4044
  appState: 'aftershow',
3047
4045
  });
3048
- // dispatch aftershow event to base app
4046
+ // dispatch afterShow event to base app
3049
4047
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
3050
4048
  }
3051
4049
  /**
@@ -3153,12 +4151,17 @@ function defineElement(tagName) {
3153
4151
  }
3154
4152
  disconnectedCallback() {
3155
4153
  this.hasConnected = false;
3156
- // keep-alive
3157
- if (this.getKeepAliveModeResult()) {
3158
- this.handleHiddenKeepAliveApp();
3159
- }
3160
- else {
3161
- this.handleUnmount(this.getDestroyCompatibleResult());
4154
+ const app = appInstanceMap.get(this.appName);
4155
+ if (app &&
4156
+ app.getAppState() !== appStates.UNMOUNT &&
4157
+ app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
4158
+ // keep-alive
4159
+ if (this.getKeepAliveModeResult()) {
4160
+ this.handleHiddenKeepAliveApp();
4161
+ }
4162
+ else {
4163
+ this.handleUnmount(this.getDestroyCompatibleResult());
4164
+ }
3162
4165
  }
3163
4166
  }
3164
4167
  attributeChangedCallback(attr, _oldVal, newVal) {
@@ -3206,12 +4209,7 @@ function defineElement(tagName) {
3206
4209
  if (this.getDisposeResult('shadowDOM') && !this.shadowRoot && isFunction(this.attachShadow)) {
3207
4210
  this.attachShadow({ mode: 'open' });
3208
4211
  }
3209
- if (this.getDisposeResult('ssr')) {
3210
- this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, this.appUrl);
3211
- }
3212
- else if (this.ssrUrl) {
3213
- this.ssrUrl = '';
3214
- }
4212
+ this.updateSsrUrl(this.appUrl);
3215
4213
  if (appInstanceMap.has(this.appName)) {
3216
4214
  const app = appInstanceMap.get(this.appName);
3217
4215
  const existAppUrl = app.ssrUrl || app.url;
@@ -3245,15 +4243,9 @@ function defineElement(tagName) {
3245
4243
  actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
3246
4244
  var _a;
3247
4245
  /**
3248
- * change ssrUrl in ssr mode
3249
4246
  * do not add judgment of formatAttrUrl === this.appUrl
3250
4247
  */
3251
- if (this.getDisposeResult('ssr')) {
3252
- this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
3253
- }
3254
- else if (this.ssrUrl) {
3255
- this.ssrUrl = '';
3256
- }
4248
+ this.updateSsrUrl(formatAttrUrl);
3257
4249
  this.appName = formatAttrName;
3258
4250
  this.appUrl = formatAttrUrl;
3259
4251
  ((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
@@ -3313,14 +4305,14 @@ function defineElement(tagName) {
3313
4305
  app.isPrefetch = false;
3314
4306
  defer(() => {
3315
4307
  var _a;
3316
- return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible());
4308
+ return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible(), this.getDisposeResult('keep-router-state'), this.getDefaultPageValue());
3317
4309
  });
3318
4310
  }
3319
4311
  // create app instance
3320
4312
  handleCreateApp() {
3321
4313
  var _a;
3322
4314
  /**
3323
- * actions for destory old app
4315
+ * actions for destroy old app
3324
4316
  * fix of unmounted umd app with disableSandbox
3325
4317
  */
3326
4318
  if (appInstanceMap.has(this.appName)) {
@@ -3334,7 +4326,10 @@ function defineElement(tagName) {
3334
4326
  inline: this.getDisposeResult('inline'),
3335
4327
  scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')),
3336
4328
  useSandbox: !this.getDisposeResult('disableSandbox'),
4329
+ useMemoryRouter: !this.getDisposeResult('disable-memory-router'),
3337
4330
  baseroute: this.getBaseRouteCompatible(),
4331
+ keepRouteState: this.getDisposeResult('keep-router-state'),
4332
+ defaultPage: this.getDefaultPageValue(),
3338
4333
  });
3339
4334
  appInstanceMap.set(this.appName, instance);
3340
4335
  }
@@ -3342,11 +4337,12 @@ function defineElement(tagName) {
3342
4337
  * unmount app
3343
4338
  * @param destroy delete cache resources when unmount
3344
4339
  */
3345
- handleUnmount(destroy, unmountcb) {
4340
+ handleUnmount(destroy, unmountCb) {
3346
4341
  const app = appInstanceMap.get(this.appName);
3347
4342
  if (app &&
3348
- app.getAppState() !== appStates.UNMOUNT)
3349
- app.unmount(destroy, unmountcb);
4343
+ app.getAppState() !== appStates.UNMOUNT) {
4344
+ app.unmount(destroy, unmountCb);
4345
+ }
3350
4346
  }
3351
4347
  // hidden app when disconnectedCallback called with keep-alive
3352
4348
  handleHiddenKeepAliveApp() {
@@ -3409,6 +4405,37 @@ function defineElement(tagName) {
3409
4405
  getKeepAliveModeResult() {
3410
4406
  return this.getDisposeResult('keep-alive') && !this.getDestroyCompatibleResult();
3411
4407
  }
4408
+ /**
4409
+ * change ssrUrl in ssr mode
4410
+ */
4411
+ updateSsrUrl(baseUrl) {
4412
+ if (this.getDisposeResult('ssr')) {
4413
+ if (this.getDisposeResult('disable-memory-router')) {
4414
+ const rawLocation = globalEnv.rawWindow.location;
4415
+ this.ssrUrl = CompletionPath(rawLocation.pathname + rawLocation.search, baseUrl);
4416
+ }
4417
+ else {
4418
+ // get path from browser URL
4419
+ let targetPath = getNoHashMicroPathFromURL(this.appName, baseUrl);
4420
+ const defaultPagePath = this.getDefaultPageValue();
4421
+ if (!targetPath && defaultPagePath) {
4422
+ const targetLocation = createURL(defaultPagePath, baseUrl);
4423
+ targetPath = targetLocation.origin + targetLocation.pathname + targetLocation.search;
4424
+ }
4425
+ this.ssrUrl = targetPath;
4426
+ }
4427
+ }
4428
+ else if (this.ssrUrl) {
4429
+ this.ssrUrl = '';
4430
+ }
4431
+ }
4432
+ /**
4433
+ * get config of default page
4434
+ */
4435
+ getDefaultPageValue() {
4436
+ var _a, _b, _c;
4437
+ return (_c = (_b = (_a = router.getDefaultPage(this.appName)) !== null && _a !== void 0 ? _a : this.getAttribute('default-page')) !== null && _b !== void 0 ? _b : this.getAttribute('defaultPage')) !== null && _c !== void 0 ? _c : '';
4438
+ }
3412
4439
  /**
3413
4440
  * Data from the base application
3414
4441
  */
@@ -3443,12 +4470,13 @@ function defineElement(tagName) {
3443
4470
  * url: string,
3444
4471
  * disableScopecss?: boolean,
3445
4472
  * disableSandbox?: boolean,
4473
+ * disableMemoryRouter?: boolean,
3446
4474
  * },
3447
4475
  * ...
3448
4476
  * ])
3449
4477
  * Note:
3450
4478
  * 1: preFetch is asynchronous and is performed only when the browser is idle
3451
- * 2: disableScopecss, disableSandbox must be same with micro-app element, if conflict, the one who executes first shall prevail
4479
+ * 2: disableScopecss, disableSandbox, disableMemoryRouter must be same with micro-app element, if conflict, the one who executes first shall prevail
3452
4480
  * @param apps micro apps
3453
4481
  */
3454
4482
  function preFetch(apps) {
@@ -3466,7 +4494,7 @@ function preFetch(apps) {
3466
4494
  function preFetchInSerial(prefetchApp) {
3467
4495
  return new Promise((resolve) => {
3468
4496
  requestIdleCallback(() => {
3469
- var _a, _b;
4497
+ var _a, _b, _c;
3470
4498
  if (isPlainObject(prefetchApp) && navigator.onLine) {
3471
4499
  prefetchApp.name = formatAppName(prefetchApp.name);
3472
4500
  prefetchApp.url = formatAppURL(prefetchApp.url, prefetchApp.name);
@@ -3476,6 +4504,7 @@ function preFetchInSerial(prefetchApp) {
3476
4504
  url: prefetchApp.url,
3477
4505
  scopecss: !((_a = prefetchApp.disableScopecss) !== null && _a !== void 0 ? _a : microApp.disableScopecss),
3478
4506
  useSandbox: !((_b = prefetchApp.disableSandbox) !== null && _b !== void 0 ? _b : microApp.disableSandbox),
4507
+ useMemoryRouter: !((_c = prefetchApp.disableMemoryRouter) !== null && _c !== void 0 ? _c : microApp.disableMemoryRouter),
3479
4508
  });
3480
4509
  app.isPrefetch = true;
3481
4510
  app.prefetchResolve = resolve;
@@ -3544,7 +4573,7 @@ function getAllApps() {
3544
4573
  /**
3545
4574
  * unmount app by appName
3546
4575
  * @param appName
3547
- * @param options unmountAppParams
4576
+ * @param options unmountAppOptions
3548
4577
  * @returns Promise<void>
3549
4578
  */
3550
4579
  function unmountApp(appName, options) {
@@ -3618,6 +4647,7 @@ class MicroApp extends EventCenterForBaseApp {
3618
4647
  super(...arguments);
3619
4648
  this.tagName = 'micro-app';
3620
4649
  this.preFetch = preFetch;
4650
+ this.router = router;
3621
4651
  }
3622
4652
  start(options) {
3623
4653
  if (!isBrowser || !window.customElements) {
@@ -3647,6 +4677,7 @@ class MicroApp extends EventCenterForBaseApp {
3647
4677
  this.inline = options.inline;
3648
4678
  this.disableScopecss = options.disableScopecss;
3649
4679
  this.disableSandbox = options.disableSandbox;
4680
+ this.disableMemoryRouter = options.disableMemoryRouter;
3650
4681
  this.ssr = options.ssr;
3651
4682
  isFunction(options.fetch) && (this.fetch = options.fetch);
3652
4683
  isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);