@micro-zoe/micro-app 1.0.0-rc.2 → 1.0.0-rc.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-rc.2';
1
+ const version = '1.0.0-rc.4';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -15,7 +15,9 @@ const assign = Object.assign;
15
15
  // Object prototype methods
16
16
  const rawDefineProperty = Object.defineProperty;
17
17
  const rawDefineProperties = Object.defineProperties;
18
+ const rawToString = Object.prototype.toString;
18
19
  const rawHasOwnProperty = Object.prototype.hasOwnProperty;
20
+ const toTypeString = (value) => rawToString.call(value);
19
21
  // is Undefined
20
22
  function isUndefined(target) {
21
23
  return target === undefined;
@@ -42,15 +44,15 @@ function isFunction(target) {
42
44
  }
43
45
  // is PlainObject
44
46
  function isPlainObject(target) {
45
- return toString.call(target) === '[object Object]';
47
+ return toTypeString(target) === '[object Object]';
46
48
  }
47
49
  // is Object
48
50
  function isObject(target) {
49
- return typeof target === 'object';
51
+ return !isNull(target) && typeof target === 'object';
50
52
  }
51
53
  // is Promise
52
54
  function isPromise(target) {
53
- return toString.call(target) === '[object Promise]';
55
+ return toTypeString(target) === '[object Promise]';
54
56
  }
55
57
  // is bind function
56
58
  function isBoundFunction(target) {
@@ -87,40 +89,52 @@ function isNode(target) {
87
89
  return target instanceof Node || isNumber((_a = target) === null || _a === void 0 ? void 0 : _a.nodeType);
88
90
  }
89
91
  function isLinkElement(target) {
90
- var _a, _b;
91
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'LINK';
92
+ return toTypeString(target) === '[object HTMLLinkElement]';
92
93
  }
93
94
  function isStyleElement(target) {
94
- var _a, _b;
95
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'STYLE';
95
+ return toTypeString(target) === '[object HTMLStyleElement]';
96
96
  }
97
97
  function isScriptElement(target) {
98
- var _a, _b;
99
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'SCRIPT';
98
+ return toTypeString(target) === '[object HTMLScriptElement]';
100
99
  }
101
100
  function isIFrameElement(target) {
102
- var _a, _b;
103
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IFRAME';
101
+ return toTypeString(target) === '[object HTMLIFrameElement]';
104
102
  }
105
103
  function isDivElement(target) {
106
- var _a, _b;
107
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'DIV';
104
+ return toTypeString(target) === '[object HTMLDivElement]';
108
105
  }
109
106
  function isImageElement(target) {
110
- var _a, _b;
111
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IMG';
107
+ return toTypeString(target) === '[object HTMLImageElement]';
112
108
  }
113
109
  function isBaseElement(target) {
114
- var _a, _b;
115
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'BASE';
110
+ return toTypeString(target) === '[object HTMLBaseElement]';
116
111
  }
117
112
  function isMicroAppBody(target) {
118
- var _a, _b;
119
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'MICRO-APP-BODY';
113
+ return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-BODY';
120
114
  }
121
115
  // is ProxyDocument
122
116
  function isProxyDocument(target) {
123
- return toString.call(target) === '[object ProxyDocument]';
117
+ return toTypeString(target) === '[object ProxyDocument]';
118
+ }
119
+ function includes(target, searchElement, fromIndex) {
120
+ if (target == null) {
121
+ throw new TypeError('includes target is null or undefined');
122
+ }
123
+ const O = Object(target);
124
+ const len = parseInt(O.length, 10) || 0;
125
+ if (len === 0)
126
+ return false;
127
+ // @ts-ignore
128
+ fromIndex = parseInt(fromIndex, 10) || 0;
129
+ let i = Math.max(fromIndex >= 0 ? fromIndex : len + fromIndex, 0);
130
+ while (i < len) {
131
+ // NaN !== NaN
132
+ if (searchElement === O[i] || (searchElement !== searchElement && O[i] !== O[i])) {
133
+ return true;
134
+ }
135
+ i++;
136
+ }
137
+ return false;
124
138
  }
125
139
  /**
126
140
  * format error log
@@ -185,7 +199,7 @@ function formatAppURL(url, appName = null) {
185
199
  if (!isString(url) || !url)
186
200
  return '';
187
201
  try {
188
- const { origin, pathname, search } = createURL(addProtocol(url));
202
+ const { origin, pathname, search } = createURL(addProtocol(url), (window.rawWindow || window).location.href);
189
203
  // If it ends with .html/.node/.php/.net/.etc, don’t need to add /
190
204
  if (/\.(\w+)$/.test(pathname)) {
191
205
  return `${origin}${pathname}${search}`;
@@ -324,21 +338,28 @@ let currentMicroAppName = null;
324
338
  function setCurrentAppName(appName) {
325
339
  currentMicroAppName = appName;
326
340
  }
327
- function throttleDeferForSetAppName(appName) {
328
- if (currentMicroAppName !== appName) {
329
- setCurrentAppName(appName);
330
- defer(() => {
331
- setCurrentAppName(null);
332
- });
333
- }
334
- }
335
341
  // get the currently running app.name
336
342
  function getCurrentAppName() {
337
343
  return currentMicroAppName;
338
344
  }
339
345
  // Clear appName
340
- function removeDomScope() {
346
+ let preventSetAppName = false;
347
+ function removeDomScope(force) {
341
348
  setCurrentAppName(null);
349
+ if (force && !preventSetAppName) {
350
+ preventSetAppName = true;
351
+ defer(() => {
352
+ preventSetAppName = false;
353
+ });
354
+ }
355
+ }
356
+ function throttleDeferForSetAppName(appName) {
357
+ if (currentMicroAppName !== appName && !preventSetAppName) {
358
+ setCurrentAppName(appName);
359
+ defer(() => {
360
+ setCurrentAppName(null);
361
+ });
362
+ }
342
363
  }
343
364
  /**
344
365
  * Create pure elements
@@ -350,33 +371,6 @@ function pureCreateElement(tagName, options) {
350
371
  element.__PURE_ELEMENT__ = true;
351
372
  return element;
352
373
  }
353
- /**
354
- * clone origin elements to target
355
- * @param origin Cloned element
356
- * @param target Accept cloned elements
357
- * @param deep deep clone or transfer dom
358
- */
359
- function cloneContainer(target, origin, deep) {
360
- // 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
361
- if (origin) {
362
- target.innerHTML = '';
363
- if (deep) {
364
- // TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
365
- const clonedNode = origin.cloneNode(true);
366
- const fragment = document.createDocumentFragment();
367
- Array.from(clonedNode.childNodes).forEach((node) => {
368
- fragment.appendChild(node);
369
- });
370
- target.appendChild(fragment);
371
- }
372
- else {
373
- Array.from(origin.childNodes).forEach((node) => {
374
- target.appendChild(node);
375
- });
376
- }
377
- }
378
- return target;
379
- }
380
374
  // is invalid key of querySelector
381
375
  function isInvalidQuerySelectorKey(key) {
382
376
  return !key || /(^\d)|([^\w\d-_\u4e00-\u9fa5])/gi.test(key);
@@ -666,7 +660,10 @@ class HTMLLoader {
666
660
  run(app, successCb) {
667
661
  const appName = app.name;
668
662
  const htmlUrl = app.ssrUrl || app.url;
669
- fetchSource(htmlUrl, appName, { cache: 'no-cache' }).then((htmlStr) => {
663
+ const htmlPromise = htmlUrl.includes('.js')
664
+ ? Promise.resolve(`<micro-app-head><script src='${htmlUrl}'></script></micro-app-head><micro-app-body></micro-app-body>`)
665
+ : fetchSource(htmlUrl, appName, { cache: 'no-cache' });
666
+ htmlPromise.then((htmlStr) => {
670
667
  if (!htmlStr) {
671
668
  const msg = 'html is empty, please check in detail';
672
669
  app.onerror(new Error(msg));
@@ -821,8 +818,8 @@ class CSSParser {
821
818
  return parseError("Declaration missing '}'", this.linkPath);
822
819
  return true;
823
820
  }
824
- matchAllDeclarations() {
825
- let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^}/])*/, true)[0];
821
+ matchAllDeclarations(nesting = 1) {
822
+ let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^{}/])*/, true)[0];
826
823
  if (cssValue) {
827
824
  if (!this.scopecssDisableNextLine &&
828
825
  (!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
@@ -841,16 +838,30 @@ class CSSParser {
841
838
  }
842
839
  // reset scopecssDisableNextLine
843
840
  this.scopecssDisableNextLine = false;
844
- if (!this.cssText || this.cssText.charAt(0) === '}')
841
+ if (!this.cssText)
845
842
  return;
843
+ if (this.cssText.charAt(0) === '}') {
844
+ if (!nesting)
845
+ return;
846
+ if (nesting > 1) {
847
+ this.commonMatch(/}+/);
848
+ }
849
+ return this.matchAllDeclarations(nesting - 1);
850
+ }
846
851
  // extract comments in declarations
847
- if (this.cssText.charAt(0) === '/' && this.cssText.charAt(1) === '*') {
848
- this.matchComments();
852
+ if (this.cssText.charAt(0) === '/') {
853
+ if (this.cssText.charAt(1) === '*') {
854
+ this.matchComments();
855
+ }
856
+ else {
857
+ this.commonMatch(/\/+/);
858
+ }
849
859
  }
850
- else {
851
- this.commonMatch(/\/+/);
860
+ if (this.cssText.charAt(0) === '{') {
861
+ this.commonMatch(/{+\s*/);
862
+ nesting++;
852
863
  }
853
- return this.matchAllDeclarations();
864
+ return this.matchAllDeclarations(nesting);
854
865
  }
855
866
  matchAtRule() {
856
867
  if (this.cssText[0] !== '@')
@@ -1284,12 +1295,12 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
1284
1295
  */
1285
1296
  if (fiberStyleResult) {
1286
1297
  fiberStyleResult.then(() => {
1287
- fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
1298
+ fiberLinkTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
1288
1299
  serialExecFiberTasks(fiberLinkTasks);
1289
1300
  });
1290
1301
  }
1291
1302
  else {
1292
- app.onLoad(wrapElement);
1303
+ app.onLoad({ html: wrapElement });
1293
1304
  }
1294
1305
  });
1295
1306
  }
@@ -1462,13 +1473,24 @@ var MicroAppConfig;
1462
1473
  // prefetch level
1463
1474
  const PREFETCH_LEVEL = [1, 2, 3];
1464
1475
  // memory router constants
1476
+ // default mode, child router info will sync to browser url
1465
1477
  const DEFAULT_ROUTER_MODE = 'search';
1466
- const ROUTER_MODE_HISTORY = 'history';
1467
- const ROUTER_MODE_CUSTOM = 'custom';
1478
+ /**
1479
+ * render base on browser url, and location.origin location.href point to base app
1480
+ * equal to disable-memory-router
1481
+ * NOTE:
1482
+ * 1. The only difference between native and native-scope is location.origin, in native-scope mode location.origin point to child app
1483
+ */
1484
+ const ROUTER_MODE_NATIVE = 'native';
1485
+ // render base on browser url, but location.origin location.href point to child app
1486
+ const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
1487
+ // search mode, but child router info will not sync to browser url
1488
+ const ROUTER_MODE_PURE = 'pure';
1468
1489
  const ROUTER_MODE_LIST = [
1469
1490
  DEFAULT_ROUTER_MODE,
1470
- ROUTER_MODE_HISTORY,
1471
- ROUTER_MODE_CUSTOM,
1491
+ ROUTER_MODE_NATIVE,
1492
+ ROUTER_MODE_NATIVE_SCOPE,
1493
+ ROUTER_MODE_PURE,
1472
1494
  ];
1473
1495
  // event bound to child app window
1474
1496
  const SCOPE_WINDOW_EVENT = [
@@ -1479,14 +1501,18 @@ const SCOPE_WINDOW_EVENT = [
1479
1501
  'unload',
1480
1502
  'unmount',
1481
1503
  'appstate-change',
1504
+ 'statechange',
1505
+ 'mounted',
1482
1506
  ];
1483
1507
  // on event bound to child app window
1508
+ // TODO: with和iframe处理方式不同,需修改
1484
1509
  const SCOPE_WINDOW_ON_EVENT = [
1485
1510
  'onpopstate',
1486
1511
  'onhashchange',
1487
1512
  'onload',
1488
1513
  'onbeforeunload',
1489
1514
  'onunload',
1515
+ 'onerror'
1490
1516
  ];
1491
1517
  // event bound to child app document
1492
1518
  const SCOPE_DOCUMENT_EVENT = [
@@ -1776,16 +1802,16 @@ function fetchScriptsFromHtml(wrapElement, app) {
1776
1802
  logError(err, app.name);
1777
1803
  }, () => {
1778
1804
  if (fiberScriptTasks) {
1779
- fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
1805
+ fiberScriptTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
1780
1806
  serialExecFiberTasks(fiberScriptTasks);
1781
1807
  }
1782
1808
  else {
1783
- app.onLoad(wrapElement);
1809
+ app.onLoad({ html: wrapElement });
1784
1810
  }
1785
1811
  });
1786
1812
  }
1787
1813
  else {
1788
- app.onLoad(wrapElement);
1814
+ app.onLoad({ html: wrapElement });
1789
1815
  }
1790
1816
  }
1791
1817
  /**
@@ -1952,6 +1978,8 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
1952
1978
  }
1953
1979
  catch (e) {
1954
1980
  console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
1981
+ // throw error in with sandbox to parent app
1982
+ throw e;
1955
1983
  }
1956
1984
  }
1957
1985
  /**
@@ -2107,15 +2135,6 @@ function processCode(configs, code, address) {
2107
2135
  }, code);
2108
2136
  }
2109
2137
 
2110
- /**
2111
- * transform html string to dom
2112
- * @param str string dom
2113
- */
2114
- function getWrapElement(str) {
2115
- const wrapDiv = pureCreateElement('div');
2116
- wrapDiv.innerHTML = str;
2117
- return wrapDiv;
2118
- }
2119
2138
  /**
2120
2139
  * Recursively process each child element
2121
2140
  * @param parent parent element
@@ -2172,7 +2191,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2172
2191
  * @param app app
2173
2192
  */
2174
2193
  function extractSourceDom(htmlStr, app) {
2175
- const wrapElement = getWrapElement(htmlStr);
2194
+ const wrapElement = app.parseHtmlString(htmlStr);
2176
2195
  const microAppHead = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-head');
2177
2196
  const microAppBody = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-body');
2178
2197
  if (!microAppHead || !microAppBody) {
@@ -2190,16 +2209,16 @@ function extractSourceDom(htmlStr, app) {
2190
2209
  fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult);
2191
2210
  }
2192
2211
  else if (fiberStyleResult) {
2193
- fiberStyleResult.then(() => app.onLoad(wrapElement));
2212
+ fiberStyleResult.then(() => app.onLoad({ html: wrapElement }));
2194
2213
  }
2195
2214
  else {
2196
- app.onLoad(wrapElement);
2215
+ app.onLoad({ html: wrapElement });
2197
2216
  }
2198
2217
  if (app.source.scripts.size) {
2199
2218
  fetchScriptsFromHtml(wrapElement, app);
2200
2219
  }
2201
2220
  else {
2202
- app.onLoad(wrapElement);
2221
+ app.onLoad({ html: wrapElement });
2203
2222
  }
2204
2223
  }
2205
2224
 
@@ -2735,12 +2754,17 @@ function createProxyDocument(appName, sandbox) {
2735
2754
  const sstEventListenerMap = new Map();
2736
2755
  let onClickHandler = null;
2737
2756
  let sstOnClickHandler = null;
2738
- const { rawDocument, rawCreateElement, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
2757
+ const { rawDocument, rawCreateElement, rawCreateElementNS, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
2739
2758
  function createElement(tagName, options) {
2740
2759
  const element = rawCreateElement.call(rawDocument, tagName, options);
2741
2760
  element.__MICRO_APP_NAME__ = appName;
2742
2761
  return element;
2743
2762
  }
2763
+ function createElementNS(namespaceURI, name, options) {
2764
+ const element = rawCreateElementNS.call(rawDocument, namespaceURI, name, options);
2765
+ element.__MICRO_APP_NAME__ = appName;
2766
+ return element;
2767
+ }
2744
2768
  /**
2745
2769
  * TODO:
2746
2770
  * 1. listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
@@ -2856,6 +2880,8 @@ function createProxyDocument(appName, sandbox) {
2856
2880
  // TODO: 转换成数据形式,类似iframe的方式
2857
2881
  if (key === 'createElement')
2858
2882
  return createElement;
2883
+ if (key === 'createElementNS')
2884
+ return createElementNS;
2859
2885
  if (key === Symbol.toStringTag)
2860
2886
  return 'ProxyDocument';
2861
2887
  if (key === 'defaultView')
@@ -2908,7 +2934,8 @@ function createMicroDocument(appName, proxyDocument) {
2908
2934
  class MicroDocument {
2909
2935
  static [Symbol.hasInstance](target) {
2910
2936
  let proto = target;
2911
- while (proto = Object.getPrototypeOf(proto)) {
2937
+ while (proto) {
2938
+ proto = Object.getPrototypeOf(proto);
2912
2939
  if (proto === MicroDocument.prototype) {
2913
2940
  return true;
2914
2941
  }
@@ -2951,7 +2978,7 @@ function createMicroDocument(appName, proxyDocument) {
2951
2978
  function patchWindow(appName, microAppWindow, sandbox) {
2952
2979
  patchWindowProperty(microAppWindow);
2953
2980
  createProxyWindow(appName, microAppWindow, sandbox);
2954
- return patchWindowEffect(microAppWindow);
2981
+ return patchWindowEffect(microAppWindow, appName);
2955
2982
  }
2956
2983
  /**
2957
2984
  * rewrite special properties of window
@@ -2992,22 +3019,22 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
2992
3019
  throttleDeferForSetAppName(appName);
2993
3020
  if (Reflect.has(target, key) ||
2994
3021
  (isString(key) && /^__MICRO_APP_/.test(key)) ||
2995
- sandbox.scopeProperties.includes(key)) {
2996
- if (RAW_GLOBAL_TARGET.includes(key))
3022
+ includes(sandbox.scopeProperties, key)) {
3023
+ if (includes(RAW_GLOBAL_TARGET, key))
2997
3024
  removeDomScope();
2998
3025
  return Reflect.get(target, key);
2999
3026
  }
3000
3027
  return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
3001
3028
  },
3002
3029
  set: (target, key, value) => {
3003
- if (sandbox.adapter.escapeSetterKeyList.includes(key)) {
3030
+ if (includes(sandbox.rawWindowScopeKeyList, key)) {
3004
3031
  Reflect.set(rawWindow, key, value);
3005
3032
  }
3006
3033
  else if (
3007
3034
  // target.hasOwnProperty has been rewritten
3008
3035
  !rawHasOwnProperty.call(target, key) &&
3009
3036
  rawHasOwnProperty.call(rawWindow, key) &&
3010
- !sandbox.scopeProperties.includes(key)) {
3037
+ !includes(sandbox.scopeProperties, key)) {
3011
3038
  const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
3012
3039
  const { configurable, enumerable, writable, set } = descriptor;
3013
3040
  // set value because it can be set
@@ -3020,32 +3047,37 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
3020
3047
  sandbox.injectedKeys.add(key);
3021
3048
  }
3022
3049
  else {
3023
- !Reflect.has(target, key) && sandbox.injectedKeys.add(key);
3050
+ // all scopeProperties will add to injectedKeys, use for key in window (Proxy.has)
3051
+ if (!Reflect.has(target, key) || includes(sandbox.scopeProperties, key)) {
3052
+ sandbox.injectedKeys.add(key);
3053
+ }
3024
3054
  Reflect.set(target, key, value);
3025
3055
  }
3026
- if ((sandbox.escapeProperties.includes(key) ||
3027
- (sandbox.adapter.staticEscapeProperties.includes(key) &&
3056
+ if ((includes(sandbox.escapeProperties, key) ||
3057
+ (
3058
+ // TODO: staticEscapeProperties 合并到 escapeProperties
3059
+ includes(sandbox.staticEscapeProperties, key) &&
3028
3060
  !Reflect.has(rawWindow, key))) &&
3029
- !sandbox.scopeProperties.includes(key)) {
3061
+ !includes(sandbox.scopeProperties, key)) {
3030
3062
  !Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
3031
3063
  Reflect.set(rawWindow, key, value);
3032
3064
  }
3033
3065
  return true;
3034
3066
  },
3035
3067
  has: (target, key) => {
3036
- if (sandbox.scopeProperties.includes(key)) {
3037
- /**
3038
- * Some keywords, such as Vue, need to meet two conditions at the same time:
3039
- * 1. 'Vue' in window --> false
3040
- * 2. Vue (top level variable) // undefined
3041
- * Issue https://github.com/micro-zoe/micro-app/issues/686
3042
- */
3043
- if (sandbox.adapter.staticScopeProperties.includes(key)) {
3044
- return !!target[key];
3068
+ /**
3069
+ * Some keywords, such as Vue, need to meet two conditions at the same time:
3070
+ * 1. window.Vue --> undefined
3071
+ * 2. 'Vue' in window --> false
3072
+ * Issue https://github.com/micro-zoe/micro-app/issues/686
3073
+ */
3074
+ if (includes(sandbox.scopeProperties, key)) {
3075
+ if (sandbox.injectedKeys.has(key)) {
3076
+ return Reflect.has(target, key); // true
3045
3077
  }
3046
- return key in target;
3078
+ return !!target[key]; // false
3047
3079
  }
3048
- return key in target || key in rawWindow;
3080
+ return Reflect.has(target, key) || Reflect.has(rawWindow, key);
3049
3081
  },
3050
3082
  // Object.getOwnPropertyDescriptor(window, key)
3051
3083
  getOwnPropertyDescriptor: (target, key) => {
@@ -3090,14 +3122,26 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
3090
3122
  * Rewrite side-effect events
3091
3123
  * @param microAppWindow micro window
3092
3124
  */
3093
- function patchWindowEffect(microAppWindow) {
3125
+ function patchWindowEffect(microAppWindow, appName) {
3094
3126
  const eventListenerMap = new Map();
3095
3127
  const sstEventListenerMap = new Map();
3096
3128
  const intervalIdMap = new Map();
3097
3129
  const timeoutIdMap = new Map();
3098
3130
  const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, } = globalEnv;
3131
+ /**
3132
+ * All events will bind to microAppElement or rawWindow
3133
+ * Some special events, such as popstate、load、unmount、appstate-change、statechange..., bind to microAppElement, others bind to rawWindow
3134
+ * NOTE:
3135
+ * 1、At first, microAppWindow = new EventTarget(), but it can not compatible with iOS 14 or below, so microAppElement was used instead. (2024.1.22)
3136
+ * @param type event name
3137
+ * @returns microAppElement/rawWindow
3138
+ */
3099
3139
  function getEventTarget(type) {
3100
- return SCOPE_WINDOW_EVENT.includes(type) ? microAppWindow : rawWindow;
3140
+ var _a;
3141
+ if (SCOPE_WINDOW_EVENT.includes(type) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
3142
+ return getRootContainer(appInstanceMap.get(appName).container);
3143
+ }
3144
+ return rawWindow;
3101
3145
  }
3102
3146
  /**
3103
3147
  * listener may be null, e.g test-passive
@@ -3211,7 +3255,7 @@ function patchWindowEffect(microAppWindow) {
3211
3255
 
3212
3256
  // set micro app state to origin state
3213
3257
  function setMicroState(appName, microState) {
3214
- if (!isRouterModeCustom(appName)) {
3258
+ if (isRouterModeSearch(appName)) {
3215
3259
  const rawState = globalEnv.rawWindow.history.state;
3216
3260
  const additionalState = {
3217
3261
  microAppState: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.microAppState, {
@@ -3225,7 +3269,7 @@ function setMicroState(appName, microState) {
3225
3269
  }
3226
3270
  // delete micro app state form origin state
3227
3271
  function removeMicroState(appName, rawState) {
3228
- if (!isRouterModeCustom(appName)) {
3272
+ if (isRouterModeSearch(appName)) {
3229
3273
  if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.microAppState)) {
3230
3274
  if (!isUndefined(rawState.microAppState[appName])) {
3231
3275
  delete rawState.microAppState[appName];
@@ -3242,7 +3286,7 @@ function removeMicroState(appName, rawState) {
3242
3286
  function getMicroState(appName) {
3243
3287
  var _a;
3244
3288
  const rawState = globalEnv.rawWindow.history.state;
3245
- if (!isRouterModeCustom(appName)) {
3289
+ if (isRouterModeSearch(appName)) {
3246
3290
  return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
3247
3291
  }
3248
3292
  return rawState;
@@ -3282,8 +3326,11 @@ function formatQueryAppName(appName) {
3282
3326
  */
3283
3327
  function getMicroPathFromURL(appName) {
3284
3328
  var _a, _b;
3329
+ // TODO: pure模式从state中获取地址
3330
+ if (isRouterModePure(appName))
3331
+ return null;
3285
3332
  const rawLocation = globalEnv.rawWindow.location;
3286
- if (!isRouterModeCustom(appName)) {
3333
+ if (isRouterModeSearch(appName)) {
3287
3334
  const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
3288
3335
  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)]);
3289
3336
  return isString(microPath) ? decodeMicroPath(microPath) : null;
@@ -3298,7 +3345,7 @@ function getMicroPathFromURL(appName) {
3298
3345
  function setMicroPathToURL(appName, targetLocation) {
3299
3346
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3300
3347
  let isAttach2Hash = false;
3301
- if (!isRouterModeCustom(appName)) {
3348
+ if (isRouterModeSearch(appName)) {
3302
3349
  let { pathname, search, hash } = globalEnv.rawWindow.location;
3303
3350
  const queryObject = getQueryObjectFromURL(search, hash);
3304
3351
  const encodedMicroPath = encodeMicroPath(targetFullPath);
@@ -3350,7 +3397,7 @@ function removeMicroPathFromURL(appName, targetLocation) {
3350
3397
  var _a, _b, _c, _d;
3351
3398
  let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
3352
3399
  let isAttach2Hash = false;
3353
- if (!isRouterModeCustom(appName)) {
3400
+ if (isRouterModeSearch(appName)) {
3354
3401
  const queryObject = getQueryObjectFromURL(search, hash);
3355
3402
  if ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) {
3356
3403
  isAttach2Hash = true;
@@ -3410,15 +3457,31 @@ function isEffectiveApp(appName) {
3410
3457
  */
3411
3458
  return !!(app && !app.isPrefetch);
3412
3459
  }
3460
+ // router mode is search
3461
+ function isRouterModeSearch(appName) {
3462
+ const app = appInstanceMap.get(appName);
3463
+ return !!(app && app.sandBox && app.routerMode === DEFAULT_ROUTER_MODE);
3464
+ }
3465
+ // router mode is history
3466
+ function isRouterModeNative(appName) {
3467
+ const app = appInstanceMap.get(appName);
3468
+ return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_NATIVE);
3469
+ }
3470
+ // router mode is disable
3471
+ function isRouterModeNativeScope(appName) {
3472
+ const app = appInstanceMap.get(appName);
3473
+ return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_NATIVE_SCOPE);
3474
+ }
3475
+ // router mode is pure
3476
+ function isRouterModePure(appName) {
3477
+ const app = appInstanceMap.get(appName);
3478
+ return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_PURE);
3479
+ }
3413
3480
  /**
3414
- * router mode is custom
3415
- * NOTE:
3416
- * 1. if sandbox disabled, router mode defaults to custom
3417
- * 2. if app not exist, router mode defaults to custom
3481
+ * router mode is history or disable
3418
3482
  */
3419
3483
  function isRouterModeCustom(appName) {
3420
- const app = appInstanceMap.get(appName);
3421
- return !app || !app.sandBox || app.routerMode === ROUTER_MODE_CUSTOM;
3484
+ return isRouterModeNative(appName) || isRouterModeNativeScope(appName);
3422
3485
  }
3423
3486
  /**
3424
3487
  * get memory router mode of child app
@@ -3426,21 +3489,21 @@ function isRouterModeCustom(appName) {
3426
3489
  * 1. if microAppElement exists, it means the app render by the micro-app element
3427
3490
  * 2. if microAppElement not exists, it means it is prerender app
3428
3491
  * @param mode native config
3429
- * @param microAppElement micro-app element
3430
- * @returns mode
3492
+ * @param inlineDisableMemoryRouter disable-memory-router set by micro-app element or prerender
3493
+ * @returns router mode
3431
3494
  */
3432
- function getRouterMode(mode, microAppElement) {
3433
- let routerMode;
3495
+ function getRouterMode(mode, inlineDisableMemoryRouter) {
3434
3496
  /**
3435
3497
  * compatible with disable-memory-router in older versions
3436
- * if disable-memory-router is true, router-mode will be custom
3498
+ * if disable-memory-router is true, router-mode will be disable
3499
+ * Priority:
3500
+ * inline disable-memory-router > inline router-mode > global disable-memory-router > global router-mode
3437
3501
  */
3438
- if (microAppElement) {
3439
- routerMode = microAppElement.getDisposeResult('disable-memory-router') ? ROUTER_MODE_CUSTOM : mode || microApp.options['router-mode'] || '';
3440
- }
3441
- else {
3442
- routerMode = microApp.options['disable-memory-router'] ? ROUTER_MODE_CUSTOM : mode || microApp.options['router-mode'] || '';
3443
- }
3502
+ const routerMode = ((inlineDisableMemoryRouter && ROUTER_MODE_NATIVE) ||
3503
+ mode ||
3504
+ (microApp.options['disable-memory-router'] && ROUTER_MODE_NATIVE) ||
3505
+ microApp.options['router-mode'] ||
3506
+ DEFAULT_ROUTER_MODE);
3444
3507
  return ROUTER_MODE_LIST.includes(routerMode) ? routerMode : DEFAULT_ROUTER_MODE;
3445
3508
  }
3446
3509
 
@@ -3586,7 +3649,7 @@ function dispatchNativeEvent(appName, onlyForBrowser, oldHref) {
3586
3649
  * create proxyHistory for microApp
3587
3650
  * MDN https://developer.mozilla.org/en-US/docs/Web/API/History
3588
3651
  * @param appName app name
3589
- * @param microLocation microApp location
3652
+ * @param microLocation microApp location(with: proxyLocation iframe: iframeWindow.location)
3590
3653
  */
3591
3654
  function createMicroHistory(appName, microLocation) {
3592
3655
  const rawHistory = globalEnv.rawWindow.history;
@@ -3597,7 +3660,9 @@ function createMicroHistory(appName, microLocation) {
3597
3660
  if (isString(rests[2]) || isURL(rests[2])) {
3598
3661
  const targetLocation = createURL(rests[2], microLocation.href);
3599
3662
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3600
- navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
3663
+ if (!isRouterModePure(appName)) {
3664
+ navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
3665
+ }
3601
3666
  if (targetFullPath !== microLocation.fullPath) {
3602
3667
  updateMicroLocation(appName, targetFullPath, microLocation);
3603
3668
  }
@@ -3676,10 +3741,10 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
3676
3741
  nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
3677
3742
  /**
3678
3743
  * TODO:
3679
- * 1. 如果所有模式统一发送popstate事件,则!isRouterModeCustom(appName)要去掉
3744
+ * 1. 如果所有模式统一发送popstate事件,则isRouterModeSearch(appName)要去掉
3680
3745
  * 2. 如果发送事件,则会导致vue router-view :key='router.path'绑定,无限卸载应用,死循环
3681
3746
  */
3682
- if (oldFullPath !== result.fullPath && !isRouterModeCustom(appName)) {
3747
+ if (oldFullPath !== result.fullPath && isRouterModeSearch(appName)) {
3683
3748
  dispatchNativeEvent(appName, onlyForBrowser, oldHref);
3684
3749
  }
3685
3750
  }
@@ -3726,7 +3791,7 @@ function reWriteHistoryMethod(method) {
3726
3791
  excludeHiddenApp: true,
3727
3792
  excludePreRender: true,
3728
3793
  }).forEach(appName => {
3729
- if (!isRouterModeCustom(appName) && !getMicroPathFromURL(appName)) {
3794
+ if (isRouterModeSearch(appName) && !getMicroPathFromURL(appName)) {
3730
3795
  const app = appInstanceMap.get(appName);
3731
3796
  attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
3732
3797
  }
@@ -3778,8 +3843,10 @@ function createRouterApi() {
3778
3843
  const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
3779
3844
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3780
3845
  if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
3781
- const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
3782
- navigateWithRawHistory(appName, methodName, targetLocation, to.state);
3846
+ if (!isRouterModePure(appName)) {
3847
+ const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
3848
+ navigateWithRawHistory(appName, methodName, targetLocation, to.state);
3849
+ }
3783
3850
  /**
3784
3851
  * TODO:
3785
3852
  * 1. 关闭虚拟路由的跳转地址不同:baseRoute + 子应用地址,文档中要说明
@@ -3792,7 +3859,7 @@ function createRouterApi() {
3792
3859
  * NOTE1: history和search模式采用2,这样可以解决vue3的问题,custom采用1,避免vue循环刷新的问题,这样在用户出现问题时各有解决方案。但反过来说,每种方案又分别导致另外的问题,不统一,导致复杂度增高
3793
3860
  * NOTE2: 关闭虚拟路由,同时发送popstate事件还是无法解决vue3的问题(毕竟history.state理论上还是会冲突),那么就没必要发送popstate事件了。
3794
3861
  */
3795
- if (isRouterModeCustom(appName)) {
3862
+ if (isRouterModeCustom(appName) || isRouterModePure(appName)) {
3796
3863
  updateMicroLocationWithEvent(appName, targetFullPath);
3797
3864
  }
3798
3865
  }
@@ -3807,52 +3874,53 @@ function createRouterApi() {
3807
3874
  */
3808
3875
  function createNavigationMethod(replace) {
3809
3876
  return function (to) {
3810
- const appName = formatAppName(to.name);
3811
- if (appName && isString(to.path)) {
3812
- /**
3813
- * active apps, exclude prerender app or hidden keep-alive app
3814
- * NOTE:
3815
- * 1. prerender app or hidden keep-alive app clear and record popstate event, so we cannot control app jump through the API
3816
- * 2. disable memory-router
3817
- */
3818
- /**
3819
- * TODO: 子应用开始渲染但是还没渲染完成
3820
- * 1、调用跳转改如何处理
3821
- * 2、iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
3822
- * 3hidden app 是否支持跳转
3823
- */
3824
- if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
3825
- const app = appInstanceMap.get(appName);
3826
- const navigateAction = () => handleNavigate(appName, app, to, replace);
3827
- app.iframe ? app.sandBox.sandboxReady.then(navigateAction) : navigateAction();
3877
+ return new Promise((resolve, reject) => {
3878
+ const appName = formatAppName(to.name);
3879
+ if (appName && isString(to.path)) {
3880
+ /**
3881
+ * active apps, exclude prerender app or hidden keep-alive app
3882
+ * NOTE:
3883
+ * 1. prerender app or hidden keep-alive app clear and record popstate event, so we cannot control app jump through the API
3884
+ * 2. disable memory-router
3885
+ */
3886
+ /**
3887
+ * TODO: 子应用开始渲染但是还没渲染完成
3888
+ * 1、调用跳转改如何处理
3889
+ * 2iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
3890
+ * 3、hidden app 是否支持跳转
3891
+ */
3892
+ if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
3893
+ const app = appInstanceMap.get(appName);
3894
+ resolve(app.sandBox.sandboxReady.then(() => handleNavigate(appName, app, to, replace)));
3895
+ }
3896
+ else {
3897
+ reject(logError('navigation failed, app does not exist or is inactive'));
3898
+ }
3899
+ // /**
3900
+ // * app not exit or unmounted, update browser URL with replaceState
3901
+ // * use base app location.origin as baseURL
3902
+ // * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
3903
+ // */
3904
+ // /**
3905
+ // * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
3906
+ // * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
3907
+ // */
3908
+ // const rawLocation = globalEnv.rawWindow.location
3909
+ // const targetLocation = createURL(to.path, rawLocation.origin)
3910
+ // const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
3911
+ // if (getMicroPathFromURL(appName) !== targetFullPath) {
3912
+ // navigateWithRawHistory(
3913
+ // appName,
3914
+ // to.replace === false ? 'pushState' : 'replaceState',
3915
+ // targetLocation,
3916
+ // to.state,
3917
+ // )
3918
+ // }
3828
3919
  }
3829
3920
  else {
3830
- logWarn('navigation failed, app does not exist or is inactive');
3921
+ reject(logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`));
3831
3922
  }
3832
- // /**
3833
- // * app not exit or unmounted, update browser URL with replaceState
3834
- // * use base app location.origin as baseURL
3835
- // * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
3836
- // */
3837
- // /**
3838
- // * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
3839
- // * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
3840
- // */
3841
- // const rawLocation = globalEnv.rawWindow.location
3842
- // const targetLocation = createURL(to.path, rawLocation.origin)
3843
- // const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
3844
- // if (getMicroPathFromURL(appName) !== targetFullPath) {
3845
- // navigateWithRawHistory(
3846
- // appName,
3847
- // to.replace === false ? 'pushState' : 'replaceState',
3848
- // targetLocation,
3849
- // to.state,
3850
- // )
3851
- // }
3852
- }
3853
- else {
3854
- logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`);
3855
- }
3923
+ });
3856
3924
  };
3857
3925
  }
3858
3926
  // create method of router.go/back/forward
@@ -3909,7 +3977,7 @@ function createRouterApi() {
3909
3977
  * 3. router mode is custom
3910
3978
  */
3911
3979
  function commonHandlerForAttachToURL(appName) {
3912
- if (!isRouterModeCustom(appName)) {
3980
+ if (isRouterModeSearch(appName)) {
3913
3981
  const app = appInstanceMap.get(appName);
3914
3982
  attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
3915
3983
  }
@@ -4141,7 +4209,7 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4141
4209
  if (targetLocation.origin === proxyLocation.origin) {
4142
4210
  const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
4143
4211
  // if disable memory-router, navigate directly through rawLocation
4144
- if (!isRouterModeCustom(appName)) {
4212
+ if (isRouterModeSearch(appName)) {
4145
4213
  /**
4146
4214
  * change hash with location.href will not trigger the browser reload
4147
4215
  * so we use pushState & reload to imitate href behavior
@@ -4227,6 +4295,20 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4227
4295
  const proxyLocation = new Proxy({}, {
4228
4296
  get: (_, key) => {
4229
4297
  const target = getTarget();
4298
+ if (key === 'assign')
4299
+ return assign;
4300
+ if (key === 'replace')
4301
+ return replace;
4302
+ if (key === 'reload')
4303
+ return reload;
4304
+ if (key === 'self')
4305
+ return target;
4306
+ if (key === 'fullPath')
4307
+ return target.fullPath;
4308
+ if (isRouterModeNative(appName)) {
4309
+ return bindFunctionToRawTarget(Reflect.get(rawLocation, key), rawLocation, 'LOCATION');
4310
+ }
4311
+ // src of iframe is base app address, it needs to be replaced separately
4230
4312
  if (isIframe) {
4231
4313
  // host hostname port protocol
4232
4314
  if (hijackMicroLocationKeys.includes(key)) {
@@ -4237,29 +4319,21 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4237
4319
  return target[key].replace(browserHost, childHost);
4238
4320
  }
4239
4321
  }
4240
- if (key === 'assign')
4241
- return assign;
4242
- if (key === 'replace')
4243
- return replace;
4244
- if (key === 'reload')
4245
- return reload;
4246
- if (key === 'self')
4247
- return target;
4248
4322
  return bindFunctionToRawTarget(Reflect.get(target, key), target, 'LOCATION');
4249
4323
  },
4250
4324
  set: (_, key, value) => {
4251
4325
  if (isEffectiveApp(appName)) {
4252
4326
  const target = getTarget();
4253
4327
  if (key === 'href') {
4254
- const targetPath = commonHandler(value, 'pushState');
4255
4328
  /**
4256
4329
  * In vite, targetPath without origin will be completed with child origin
4257
4330
  * So we use browser origin to complete targetPath to avoid this problem
4258
- * But, why child app can affect browser jump?
4259
- * Guess(need check):
4260
- * 1. vite records the origin when init
4261
- * 2. listen for browser jump and automatically complete the address
4331
+ * NOTE:
4332
+ * 1. history mode & value is childOrigin + path ==> jump to browserOrigin + path
4333
+ * 2. disable mode & value is childOrigin + path ==> jump to childOrigin + path
4334
+ * 3. search mode & value is browserOrigin + path ==> jump to browserOrigin + path
4262
4335
  */
4336
+ const targetPath = commonHandler(value, 'pushState');
4263
4337
  if (targetPath) {
4264
4338
  rawLocation.href = createURL(targetPath, rawLocation.origin).href;
4265
4339
  }
@@ -4344,9 +4418,11 @@ function updateMicroLocation(appName, path, microLocation, type) {
4344
4418
  (_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
4345
4419
  }
4346
4420
  else {
4347
- for (const key of locationKeys) {
4348
- microLocation.self[key] = newLocation[key];
4421
+ let targetHref = newLocation.href;
4422
+ if (microLocation.self.origin !== newLocation.origin) {
4423
+ targetHref = targetHref.replace(newLocation.origin, microLocation.self.origin);
4349
4424
  }
4425
+ microLocation.self.href = targetHref;
4350
4426
  }
4351
4427
  // update latest values of microLocation to `to`
4352
4428
  const to = createGuardLocation(appName, microLocation);
@@ -4357,13 +4433,9 @@ function updateMicroLocation(appName, path, microLocation, type) {
4357
4433
  }
4358
4434
 
4359
4435
  /**
4360
- * TODO: 关于关闭虚拟路由系统的临时笔记 - 即custom模式,虚拟路由不支持关闭
4361
- * 1. with沙箱关闭虚拟路由最好和iframe保持一致
4362
- * 2. default-page无法使用,但是用基座的地址可以实现一样的效果
4363
- * 3. keep-router-state功能失效,因为始终为true
4364
- * 4. 基座控制子应用跳转地址改变,正确的值为:baseRoute + 子应用地址,这要在文档中说明,否则很容易出错,确实也很难理解
4365
- * 5. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
4366
- * 6. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
4436
+ * TODO: 关于关闭虚拟路由系统的custom、history模式
4437
+ * 1. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
4438
+ * 2. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
4367
4439
  */
4368
4440
  /**
4369
4441
  * The router system has two operations: read and write
@@ -4404,8 +4476,10 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
4404
4476
  // update microLocation with defaultPage
4405
4477
  if (defaultPage)
4406
4478
  updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
4407
- // attach microApp route info to browser URL
4408
- attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
4479
+ if (!isRouterModePure(appName)) {
4480
+ // attach microApp route info to browser URL
4481
+ attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
4482
+ }
4409
4483
  // trigger guards after change browser URL
4410
4484
  autoTriggerNavigationGuard(appName, microLocation);
4411
4485
  }
@@ -4422,7 +4496,9 @@ function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
4422
4496
  const { pathname, search, hash } = createURL(url);
4423
4497
  updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
4424
4498
  }
4425
- removePathFromBrowser(appName);
4499
+ if (!isRouterModePure(appName)) {
4500
+ removePathFromBrowser(appName);
4501
+ }
4426
4502
  }
4427
4503
  clearRouterWhenUnmount(appName);
4428
4504
  }
@@ -4434,10 +4510,10 @@ function removePathFromBrowser(appName) {
4434
4510
  attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
4435
4511
  }
4436
4512
 
4437
- class Adapter {
4513
+ class BaseSandbox {
4438
4514
  constructor() {
4439
4515
  // keys that can only assigned to rawWindow
4440
- this.escapeSetterKeyList = [
4516
+ this.rawWindowScopeKeyList = [
4441
4517
  'location',
4442
4518
  ];
4443
4519
  // keys that can escape to rawWindow
@@ -4450,7 +4526,18 @@ class Adapter {
4450
4526
  'webpackJsonp',
4451
4527
  'webpackHotUpdate',
4452
4528
  'Vue',
4529
+ // TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
4530
+ 'onpopstate',
4531
+ 'onhashchange',
4453
4532
  ];
4533
+ // Properties that can only get and set in microAppWindow, will not escape to rawWindow
4534
+ this.scopeProperties = Array.from(this.staticScopeProperties);
4535
+ // Properties that can be escape to rawWindow
4536
+ this.escapeProperties = [];
4537
+ // Properties newly added to microAppWindow
4538
+ this.injectedKeys = new Set();
4539
+ // Properties escape to rawWindow, cleared when unmount
4540
+ this.escapeKeys = new Set();
4454
4541
  this.injectReactHMRProperty();
4455
4542
  }
4456
4543
  // adapter for react
@@ -4468,6 +4555,14 @@ class Adapter {
4468
4555
  }
4469
4556
  }
4470
4557
  }
4558
+ /**
4559
+ * TODO:
4560
+ * 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
4561
+ * 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
4562
+ * 修改时机:在iframe沙箱支持插件后再修改
4563
+ */
4564
+ class CustomWindow {
4565
+ }
4471
4566
  // Fix conflict of babel-polyfill@6.x
4472
4567
  function fixBabelPolyfill6() {
4473
4568
  if (globalEnv.rawWindow._babelPolyfill)
@@ -4522,11 +4617,11 @@ function updateElementInfo(node, appName) {
4522
4617
  * 1. 测试baseURI和ownerDocument在with沙箱中是否正确
4523
4618
  * 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
4524
4619
  * 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
4525
- * 3. 性能: defineProperty的性能肯定不如直接设置
4526
4620
  */
4527
4621
  rawDefineProperties(node, {
4528
4622
  baseURI: {
4529
4623
  configurable: true,
4624
+ // if disable-memory-router or router-mode='disable', href point to base app
4530
4625
  get: () => proxyWindow.location.href,
4531
4626
  },
4532
4627
  __MICRO_APP_NAME__: {
@@ -4535,12 +4630,6 @@ function updateElementInfo(node, appName) {
4535
4630
  value: appName,
4536
4631
  },
4537
4632
  });
4538
- if (isIframeSandbox(appName)) {
4539
- rawDefineProperty(node, 'ownerDocument', {
4540
- configurable: true,
4541
- get: () => proxyWindow.document,
4542
- });
4543
- }
4544
4633
  }
4545
4634
  return node;
4546
4635
  }
@@ -4647,32 +4736,26 @@ function useMicroEventSource() {
4647
4736
  }
4648
4737
 
4649
4738
  const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
4650
- class WithSandBox {
4739
+ class WithSandBox extends BaseSandbox {
4651
4740
  constructor(appName, url) {
4741
+ super();
4652
4742
  this.active = false;
4653
- /**
4654
- * Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
4655
- * Fix https://github.com/micro-zoe/micro-app/issues/234
4656
- */
4657
- this.scopeProperties = [];
4658
- // Properties that can be escape to rawWindow
4659
- this.escapeProperties = [];
4660
- // Properties escape to rawWindow, cleared when unmount
4661
- this.escapeKeys = new Set();
4662
- // Properties newly added to microAppWindow
4663
- this.injectedKeys = new Set();
4664
- this.microAppWindow = new EventTarget(); // Proxy target
4665
- this.adapter = new Adapter();
4666
- // get scopeProperties and escapeProperties from plugins
4667
- this.getSpecialProperties(appName);
4668
- // create location, history for child app
4669
- this.patchRouter(appName, url, this.microAppWindow);
4670
- // patch window of child app
4671
- this.windowEffect = patchWindow(appName, this.microAppWindow, this);
4672
- // patch document of child app
4673
- this.documentEffect = patchDocument(appName, this.microAppWindow, this);
4674
- // inject global properties
4675
- this.initStaticGlobalKeys(appName, url, this.microAppWindow);
4743
+ this.microAppWindow = new CustomWindow(); // Proxy target
4744
+ this.patchWith((resolve) => {
4745
+ // get scopeProperties and escapeProperties from plugins
4746
+ this.getSpecialProperties(appName);
4747
+ // create location, history for child app
4748
+ this.patchRouter(appName, url, this.microAppWindow);
4749
+ // patch window of child app
4750
+ this.windowEffect = patchWindow(appName, this.microAppWindow, this);
4751
+ // patch document of child app
4752
+ this.documentEffect = patchDocument(appName, this.microAppWindow, this);
4753
+ // properties associated with the native window
4754
+ this.setMappingPropertiesWithRawDescriptor(this.microAppWindow);
4755
+ // inject global properties
4756
+ this.initStaticGlobalKeys(appName, url, this.microAppWindow);
4757
+ resolve();
4758
+ });
4676
4759
  }
4677
4760
  /**
4678
4761
  * open sandbox and perform some initial actions
@@ -4690,7 +4773,9 @@ class WithSandBox {
4690
4773
  this.initRouteState(defaultPage);
4691
4774
  // unique listener of popstate event for sub app
4692
4775
  this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
4693
- this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
4776
+ if (isRouterModeCustom(this.microAppWindow.__MICRO_APP_NAME__)) {
4777
+ this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
4778
+ }
4694
4779
  /* --- memory router part --- end */
4695
4780
  /**
4696
4781
  * Target: Ensure default mode action exactly same to first time when render again
@@ -4755,6 +4840,7 @@ class WithSandBox {
4755
4840
  }
4756
4841
  /**
4757
4842
  * inject global properties to microAppWindow
4843
+ * TODO: 设置为只读变量
4758
4844
  * @param appName app name
4759
4845
  * @param url app url
4760
4846
  * @param microAppWindow micro window
@@ -4768,6 +4854,7 @@ class WithSandBox {
4768
4854
  microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
4769
4855
  microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
4770
4856
  microAppWindow.__MICRO_APP_UMD_MODE__ = false;
4857
+ microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
4771
4858
  microAppWindow.__MICRO_APP_SANDBOX__ = this;
4772
4859
  microAppWindow.__MICRO_APP_SANDBOX_TYPE__ = 'with';
4773
4860
  microAppWindow.rawWindow = globalEnv.rawWindow;
@@ -4777,7 +4864,6 @@ class WithSandBox {
4777
4864
  pureCreateElement,
4778
4865
  router,
4779
4866
  });
4780
- this.setMappingPropertiesWithRawDescriptor(microAppWindow);
4781
4867
  }
4782
4868
  /**
4783
4869
  * Record global effect and then release (effect: global event, timeout, data listener)
@@ -4860,7 +4946,6 @@ class WithSandBox {
4860
4946
  */
4861
4947
  getSpecialProperties(appName) {
4862
4948
  var _a;
4863
- this.scopeProperties = this.scopeProperties.concat(this.adapter.staticScopeProperties);
4864
4949
  if (isPlainObject(microApp.options.plugins)) {
4865
4950
  this.commonActionForSpecialProperties(microApp.options.plugins.global);
4866
4951
  this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
@@ -4888,6 +4973,9 @@ class WithSandBox {
4888
4973
  markUmdMode(state) {
4889
4974
  this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
4890
4975
  }
4976
+ patchWith(cb) {
4977
+ this.sandboxReady = new Promise((resolve) => cb(resolve));
4978
+ }
4891
4979
  // properties associated with the native window
4892
4980
  setMappingPropertiesWithRawDescriptor(microAppWindow) {
4893
4981
  let topValue, parentValue;
@@ -4899,9 +4987,10 @@ class WithSandBox {
4899
4987
  topValue = rawWindow.top;
4900
4988
  parentValue = rawWindow.parent;
4901
4989
  }
4902
- // TODO: 用rawDefineProperties
4903
- rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
4904
- rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
4990
+ rawDefineProperties(microAppWindow, {
4991
+ top: this.createDescriptorForMicroAppWindow('top', topValue),
4992
+ parent: this.createDescriptorForMicroAppWindow('parent', parentValue),
4993
+ });
4905
4994
  GLOBAL_KEY_TO_WINDOW.forEach((key) => {
4906
4995
  rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
4907
4996
  });
@@ -5059,11 +5148,14 @@ class WithSandBox {
5059
5148
  actionBeforeExecScripts(container) {
5060
5149
  this.patchStaticElement(container);
5061
5150
  }
5151
+ setStaticAppState(state) {
5152
+ this.microAppWindow.__MICRO_APP_STATE__ = state;
5153
+ }
5062
5154
  }
5063
5155
  WithSandBox.activeCount = 0; // number of active sandbox
5064
5156
 
5065
5157
  function patchRouter(appName, url, microAppWindow, browserHost) {
5066
- const childStaticLocation = new URL(url);
5158
+ const childStaticLocation = createURL(url);
5067
5159
  const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
5068
5160
  const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
5069
5161
  // rewrite microAppWindow.history
@@ -5156,18 +5248,35 @@ function patchWindowProperty$1(appName, microAppWindow) {
5156
5248
  */
5157
5249
  function createProxyWindow$1(microAppWindow, sandbox) {
5158
5250
  const rawWindow = globalEnv.rawWindow;
5159
- const customProperties = [];
5251
+ const customProperties = new Set();
5252
+ /**
5253
+ * proxyWindow will only take effect in certain scenes, such as window.key
5254
+ * e.g:
5255
+ * 1. window.key in normal app --> fall into proxyWindow
5256
+ * 2. window.key in module app(vite), fall into microAppWindow(iframeWindow)
5257
+ * 3. if (key)... --> fall into microAppWindow(iframeWindow)
5258
+ */
5160
5259
  const proxyWindow = new Proxy(microAppWindow, {
5161
5260
  get: (target, key) => {
5162
5261
  if (key === 'location') {
5163
5262
  return sandbox.proxyLocation;
5164
5263
  }
5165
- if (GLOBAL_KEY_TO_WINDOW.includes(key.toString())) {
5264
+ if (includes(GLOBAL_KEY_TO_WINDOW, key)) {
5166
5265
  return proxyWindow;
5167
5266
  }
5168
- if (customProperties.includes(key)) {
5267
+ if (customProperties.has(key)) {
5169
5268
  return Reflect.get(target, key);
5170
5269
  }
5270
+ /**
5271
+ * Same as proxyWindow, escapeProperties will only take effect in certain scenes
5272
+ * e.g:
5273
+ * 1. window.key in normal app --> fall into proxyWindow, escapeProperties will effect
5274
+ * 2. window.key in module app(vite), fall into microAppWindow(iframeWindow), escapeProperties will not take effect
5275
+ * 3. if (key)... --> fall into microAppWindow(iframeWindow), escapeProperties will not take effect
5276
+ */
5277
+ if (includes(sandbox.escapeProperties, key) && !Reflect.has(target, key)) {
5278
+ return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
5279
+ }
5171
5280
  return bindFunctionToRawTarget(Reflect.get(target, key), target);
5172
5281
  },
5173
5282
  set: (target, key, value) => {
@@ -5175,10 +5284,10 @@ function createProxyWindow$1(microAppWindow, sandbox) {
5175
5284
  return Reflect.set(rawWindow, key, value);
5176
5285
  }
5177
5286
  if (!Reflect.has(target, key)) {
5178
- customProperties.push(key);
5287
+ customProperties.add(key);
5179
5288
  }
5180
5289
  Reflect.set(target, key, value);
5181
- if (sandbox.escapeProperties.includes(key)) {
5290
+ if (includes(sandbox.escapeProperties, key)) {
5182
5291
  !Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
5183
5292
  Reflect.set(rawWindow, key, value);
5184
5293
  }
@@ -5293,7 +5402,9 @@ function patchDocumentPrototype(appName, microAppWindow) {
5293
5402
  const microRootDocument = microAppWindow.Document;
5294
5403
  const microDocument = microAppWindow.document;
5295
5404
  const rawMicroCreateElement = microRootDocument.prototype.createElement;
5405
+ const rawMicroCreateElementNS = microRootDocument.prototype.createElementNS;
5296
5406
  const rawMicroCreateTextNode = microRootDocument.prototype.createTextNode;
5407
+ const rawMicroCreateDocumentFragment = microRootDocument.prototype.createDocumentFragment;
5297
5408
  const rawMicroCreateComment = microRootDocument.prototype.createComment;
5298
5409
  const rawMicroQuerySelector = microRootDocument.prototype.querySelector;
5299
5410
  const rawMicroQuerySelectorAll = microRootDocument.prototype.querySelectorAll;
@@ -5314,10 +5425,18 @@ function patchDocumentPrototype(appName, microAppWindow) {
5314
5425
  const element = rawMicroCreateElement.call(this, tagName, options);
5315
5426
  return updateElementInfo(element, appName);
5316
5427
  };
5428
+ microRootDocument.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
5429
+ const element = rawMicroCreateElementNS.call(this, namespaceURI, name, options);
5430
+ return updateElementInfo(element, appName);
5431
+ };
5317
5432
  microRootDocument.prototype.createTextNode = function createTextNode(data) {
5318
5433
  const element = rawMicroCreateTextNode.call(this, data);
5319
5434
  return updateElementInfo(element, appName);
5320
5435
  };
5436
+ microRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
5437
+ const element = rawMicroCreateDocumentFragment.call(this);
5438
+ return updateElementInfo(element, appName);
5439
+ };
5321
5440
  microRootDocument.prototype.createComment = function createComment(data) {
5322
5441
  const element = rawMicroCreateComment.call(this, data);
5323
5442
  return updateElementInfo(element, appName);
@@ -5418,6 +5537,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5418
5537
  const createDescriptors = () => {
5419
5538
  const result = {};
5420
5539
  const descList = [
5540
+ // if disable-memory-router or router-mode='disable', href point to base app
5421
5541
  ['documentURI', () => sandbox.proxyLocation.href],
5422
5542
  ['URL', () => sandbox.proxyLocation.href],
5423
5543
  ['documentElement', () => rawDocument.documentElement],
@@ -5454,7 +5574,10 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5454
5574
  rawDefineProperty(microDocument, tagName, {
5455
5575
  enumerable: true,
5456
5576
  configurable: true,
5457
- get: () => rawDocument[tagName],
5577
+ get: () => {
5578
+ throttleDeferForSetAppName(appName);
5579
+ return rawDocument[tagName];
5580
+ },
5458
5581
  set: (value) => { rawDocument[tagName] = value; },
5459
5582
  });
5460
5583
  });
@@ -5626,7 +5749,8 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5626
5749
  const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
5627
5750
  const rawMicroCloneNode = microRootNode.prototype.cloneNode;
5628
5751
  const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
5629
- const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
5752
+ const rawParentNodeDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
5753
+ const rawOwnerDocumentDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'ownerDocument');
5630
5754
  const isPureNode = (target) => {
5631
5755
  return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
5632
5756
  };
@@ -5647,6 +5771,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5647
5771
  // return rootNode
5648
5772
  };
5649
5773
  microRootNode.prototype.appendChild = function appendChild(node) {
5774
+ // TODO: 有必要执行这么多次updateElementInfo?
5650
5775
  updateElementInfo(node, appName);
5651
5776
  if (isPureNode(node)) {
5652
5777
  return rawMicroAppendChild.call(this, node);
@@ -5718,6 +5843,15 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5718
5843
  const clonedNode = rawMicroCloneNode.call(this, deep);
5719
5844
  return updateElementInfo(clonedNode, appName);
5720
5845
  };
5846
+ rawDefineProperty(microRootNode.prototype, 'ownerDocument', {
5847
+ configurable: true,
5848
+ enumerable: true,
5849
+ get() {
5850
+ return this.__PURE_ELEMENT__
5851
+ ? rawOwnerDocumentDesc.get.call(this)
5852
+ : microDocument;
5853
+ },
5854
+ });
5721
5855
  rawDefineProperty(microRootElement.prototype, 'innerHTML', {
5722
5856
  configurable: true,
5723
5857
  enumerable: true,
@@ -5745,21 +5879,21 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5745
5879
  * 1. Is there a problem with setting the current appName in iframe mode
5746
5880
  */
5747
5881
  throttleDeferForSetAppName(appName);
5748
- const result = rawParentNodeLDesc.get.call(this);
5882
+ const result = rawParentNodeDesc.get.call(this);
5749
5883
  /**
5750
- * If parentNode is <micro-app-body>, return rawDocument.body
5751
- * Scenes:
5752
- * 1. element-ui@2/lib/utils/vue-popper.js
5753
- * if (this.popperElm.parentNode === document.body) ...
5754
- * WARNING:
5755
- * Will it cause other problems ?
5756
- * e.g. target.parentNode.remove(target)
5757
- */
5884
+ * If parentNode is <micro-app-body>, return rawDocument.body
5885
+ * Scenes:
5886
+ * 1. element-ui@2/lib/utils/vue-popper.js
5887
+ * if (this.popperElm.parentNode === document.body) ...
5888
+ * WARNING:
5889
+ * Will it cause other problems ?
5890
+ * e.g. target.parentNode.remove(target)
5891
+ */
5758
5892
  if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
5759
- return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || rawDocument.body;
5893
+ return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
5760
5894
  }
5761
5895
  return result;
5762
- },
5896
+ }
5763
5897
  });
5764
5898
  // Adapt to new image(...) scene
5765
5899
  const ImageProxy = new Proxy(microAppWindow.Image, {
@@ -5821,14 +5955,17 @@ class IframeSandbox {
5821
5955
  this.escapeProperties = [];
5822
5956
  // Properties escape to rawWindow, cleared when unmount
5823
5957
  this.escapeKeys = new Set();
5824
- // TODO: 初始化和每次跳转时都要更新base的href
5958
+ // 初始化和每次跳转时都要更新base的href
5825
5959
  this.updateIframeBase = () => {
5826
5960
  var _a;
5827
- (_a = this.baseElement) === null || _a === void 0 ? void 0 : _a.setAttribute('href', this.proxyLocation.protocol + '//' + this.proxyLocation.host + this.proxyLocation.pathname);
5961
+ // origin must be child app origin
5962
+ (_a = this.baseElement) === null || _a === void 0 ? void 0 : _a.setAttribute('href', createURL(this.url).origin + this.proxyLocation.pathname);
5828
5963
  };
5964
+ this.appName = appName;
5965
+ this.url = url;
5829
5966
  const rawLocation = globalEnv.rawWindow.location;
5830
5967
  const browserHost = rawLocation.protocol + '//' + rawLocation.host;
5831
- this.deleteIframeElement = this.createIframeElement(appName, browserHost);
5968
+ this.deleteIframeElement = this.createIframeElement(appName, browserHost + rawLocation.pathname);
5832
5969
  this.microAppWindow = this.iframe.contentWindow;
5833
5970
  this.patchIframe(this.microAppWindow, (resolve) => {
5834
5971
  // create new html to iframe
@@ -5856,13 +5993,13 @@ class IframeSandbox {
5856
5993
  /**
5857
5994
  * create iframe for sandbox
5858
5995
  * @param appName app name
5859
- * @param browserHost browser origin
5996
+ * @param browserPath browser origin
5860
5997
  * @returns release callback
5861
5998
  */
5862
- createIframeElement(appName, browserHost) {
5999
+ createIframeElement(appName, browserPath) {
5863
6000
  this.iframe = pureCreateElement('iframe');
5864
6001
  const iframeAttrs = {
5865
- src: browserHost,
6002
+ src: microApp.options.iframeSrc || browserPath,
5866
6003
  style: 'display: none',
5867
6004
  id: appName,
5868
6005
  };
@@ -5910,7 +6047,9 @@ class IframeSandbox {
5910
6047
  this.initRouteState(defaultPage);
5911
6048
  // unique listener of popstate event for child app
5912
6049
  this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
5913
- this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
6050
+ if (isRouterModeCustom(this.microAppWindow.__MICRO_APP_NAME__)) {
6051
+ this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
6052
+ }
5914
6053
  /* --- memory router part --- end */
5915
6054
  /**
5916
6055
  * create base element to iframe
@@ -5955,6 +6094,7 @@ class IframeSandbox {
5955
6094
  * NOTE:
5956
6095
  * 1. execute as early as possible
5957
6096
  * 2. run after patchRouter & createProxyWindow
6097
+ * TODO: 设置为只读变量
5958
6098
  */
5959
6099
  initStaticGlobalKeys(appName, url, microAppWindow) {
5960
6100
  microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
@@ -6156,6 +6296,7 @@ class IframeSandbox {
6156
6296
  patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
6157
6297
  }
6158
6298
  /**
6299
+ * action before exec scripts when mount
6159
6300
  * Actions:
6160
6301
  * 1. patch static elements from html
6161
6302
  * @param container micro app container
@@ -6163,6 +6304,9 @@ class IframeSandbox {
6163
6304
  actionBeforeExecScripts(container) {
6164
6305
  this.patchStaticElement(container);
6165
6306
  }
6307
+ setStaticAppState(state) {
6308
+ this.microAppWindow.__MICRO_APP_STATE__ = state;
6309
+ }
6166
6310
  }
6167
6311
  IframeSandbox.activeCount = 0; // number of active sandbox
6168
6312
 
@@ -6175,6 +6319,7 @@ class CreateApp {
6175
6319
  this.loadSourceLevel = 0;
6176
6320
  this.umdHookMount = null;
6177
6321
  this.umdHookUnmount = null;
6322
+ this.lifeCycleState = null;
6178
6323
  this.umdMode = false;
6179
6324
  // TODO: 类型优化,加上iframe沙箱
6180
6325
  this.sandBox = null;
@@ -6211,8 +6356,11 @@ class CreateApp {
6211
6356
  }
6212
6357
  /**
6213
6358
  * When resource is loaded, mount app if it is not prefetch or unmount
6359
+ * defaultPage disablePatchRequest routerMode baseroute is only for prerender app
6214
6360
  */
6215
- onLoad(html, defaultPage, disablePatchRequest, routerMode, baseroute) {
6361
+ onLoad({ html,
6362
+ // below params is only for prerender app
6363
+ defaultPage, routerMode, baseroute, disablePatchRequest, }) {
6216
6364
  var _a;
6217
6365
  if (++this.loadSourceLevel === 2) {
6218
6366
  this.source.html = html;
@@ -6243,11 +6391,11 @@ class CreateApp {
6243
6391
  this.mount({
6244
6392
  container,
6245
6393
  inline: this.inline,
6246
- routerMode: routerMode,
6247
- baseroute: baseroute || '',
6248
6394
  fiber: true,
6249
6395
  defaultPage: defaultPage || '',
6250
6396
  disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
6397
+ routerMode: routerMode,
6398
+ baseroute: baseroute || '',
6251
6399
  });
6252
6400
  }
6253
6401
  }
@@ -6284,6 +6432,10 @@ class CreateApp {
6284
6432
  this.container = container;
6285
6433
  // mount before prerender exec mount (loading source), set isPrerender to false
6286
6434
  this.isPrerender = false;
6435
+ // dispatch state event to micro app
6436
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6437
+ appState: appStates.LOADING
6438
+ });
6287
6439
  // reset app state to LOADING
6288
6440
  return this.setAppState(appStates.LOADING);
6289
6441
  }
@@ -6313,7 +6465,7 @@ class CreateApp {
6313
6465
  */
6314
6466
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
6315
6467
  // current this.container is <div prerender='true'></div>
6316
- cloneContainer(container, this.container, false);
6468
+ this.cloneContainer(container, this.container, false);
6317
6469
  /**
6318
6470
  * set this.container to <micro-app></micro-app>
6319
6471
  * NOTE:
@@ -6333,7 +6485,10 @@ class CreateApp {
6333
6485
  this.inline = this.getInlineModeState(inline);
6334
6486
  this.fiber = fiber;
6335
6487
  this.routerMode = routerMode;
6336
- const dispatchBeforeMount = () => dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
6488
+ const dispatchBeforeMount = () => {
6489
+ this.setLifeCycleState(lifeCycles.BEFOREMOUNT);
6490
+ dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
6491
+ };
6337
6492
  if (this.isPrerender) {
6338
6493
  ((_d = this.preRenderEvents) !== null && _d !== void 0 ? _d : (this.preRenderEvents = [])).push(dispatchBeforeMount);
6339
6494
  }
@@ -6341,8 +6496,12 @@ class CreateApp {
6341
6496
  dispatchBeforeMount();
6342
6497
  }
6343
6498
  this.setAppState(appStates.MOUNTING);
6499
+ // dispatch state event to micro app
6500
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6501
+ appState: appStates.MOUNTING
6502
+ });
6344
6503
  // TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
6345
- cloneContainer(this.container, this.source.html, !this.umdMode);
6504
+ this.cloneContainer(this.container, this.source.html, !this.umdMode);
6346
6505
  (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
6347
6506
  umdMode: this.umdMode,
6348
6507
  baseroute,
@@ -6360,6 +6519,7 @@ class CreateApp {
6360
6519
  * umdHookUnmount can works in default mode
6361
6520
  * register through window.unmount
6362
6521
  */
6522
+ // TODO: 不对,这里要改,因为unmount不一定是函数
6363
6523
  this.umdHookUnmount = unmount;
6364
6524
  // if mount & unmount is function, the sub app is umd mode
6365
6525
  if (isFunction(mount) && isFunction(unmount)) {
@@ -6395,8 +6555,8 @@ class CreateApp {
6395
6555
  }
6396
6556
  }
6397
6557
  };
6398
- // TODO: any替换为iframe沙箱类型
6399
- this.iframe ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
6558
+ // TODO: 可优化?
6559
+ this.sandBox ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
6400
6560
  }
6401
6561
  /**
6402
6562
  * handle for promise umdHookMount
@@ -6434,6 +6594,13 @@ class CreateApp {
6434
6594
  this.setAppState(appStates.MOUNTED);
6435
6595
  // call window.onmount of child app
6436
6596
  execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONMOUNT), this.name, microGlobalEvent.ONMOUNT, microApp.getData(this.name, true));
6597
+ // dispatch state event to micro app
6598
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6599
+ appState: appStates.MOUNTED
6600
+ });
6601
+ // dispatch mounted event to micro app
6602
+ dispatchCustomEventToMicroApp(this, 'mounted');
6603
+ this.setLifeCycleState(lifeCycles.MOUNTED);
6437
6604
  // dispatch event mounted to parent
6438
6605
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
6439
6606
  /**
@@ -6473,6 +6640,10 @@ class CreateApp {
6473
6640
  catch (e) {
6474
6641
  logError('An error occurred in window.unmount \n', this.name, e);
6475
6642
  }
6643
+ // dispatch state event to micro app
6644
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6645
+ appState: appStates.UNMOUNT
6646
+ });
6476
6647
  // dispatch unmount event to micro app
6477
6648
  dispatchCustomEventToMicroApp(this, 'unmount');
6478
6649
  // call window.onunmount of child app
@@ -6519,7 +6690,7 @@ class CreateApp {
6519
6690
  actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
6520
6691
  var _a;
6521
6692
  if (this.umdMode && this.container && !destroy) {
6522
- cloneContainer(this.source.html, this.container, false);
6693
+ this.cloneContainer(this.source.html, this.container, false);
6523
6694
  }
6524
6695
  /**
6525
6696
  * this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
@@ -6533,6 +6704,7 @@ class CreateApp {
6533
6704
  destroy,
6534
6705
  clearData: clearData || destroy,
6535
6706
  });
6707
+ this.setLifeCycleState(lifeCycles.UNMOUNT);
6536
6708
  // dispatch unmount event to base app
6537
6709
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
6538
6710
  this.clearOptions(destroy);
@@ -6545,6 +6717,7 @@ class CreateApp {
6545
6717
  this.preRenderEvents = null;
6546
6718
  this.setKeepAliveState(null);
6547
6719
  // in iframe sandbox & default mode, delete the sandbox & iframeElement
6720
+ // TODO: with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
6548
6721
  if (this.iframe && !this.umdMode)
6549
6722
  this.sandBox = null;
6550
6723
  if (destroy)
@@ -6573,9 +6746,10 @@ class CreateApp {
6573
6746
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
6574
6747
  appState: 'afterhidden',
6575
6748
  });
6749
+ this.setLifeCycleState(lifeCycles.AFTERHIDDEN);
6576
6750
  // dispatch afterHidden event to base app
6577
6751
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
6578
- if (this.routerMode !== ROUTER_MODE_CUSTOM) {
6752
+ if (isRouterModeSearch(this.name)) {
6579
6753
  // called after lifeCyclesEvent
6580
6754
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
6581
6755
  }
@@ -6586,7 +6760,7 @@ class CreateApp {
6586
6760
  getRootContainer(this.container).unmount();
6587
6761
  }
6588
6762
  else {
6589
- this.container = cloneContainer(pureCreateElement('div'), this.container, false);
6763
+ this.container = this.cloneContainer(pureCreateElement('div'), this.container, false);
6590
6764
  (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
6591
6765
  }
6592
6766
  callback === null || callback === void 0 ? void 0 : callback();
@@ -6602,13 +6776,13 @@ class CreateApp {
6602
6776
  // dispatch beforeShow event to base app
6603
6777
  dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
6604
6778
  this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
6605
- this.container = cloneContainer(container, this.container, false);
6779
+ this.container = this.cloneContainer(container, this.container, false);
6606
6780
  /**
6607
6781
  * TODO:
6608
6782
  * 问题:当路由模式为custom时,keep-alive应用在重新展示,是否需要根据子应用location信息更新浏览器地址?
6609
6783
  * 暂时不这么做吧,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
6610
6784
  */
6611
- if (this.routerMode !== ROUTER_MODE_CUSTOM) {
6785
+ if (isRouterModeSearch(this.name)) {
6612
6786
  // called before lifeCyclesEvent
6613
6787
  (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
6614
6788
  }
@@ -6616,6 +6790,7 @@ class CreateApp {
6616
6790
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
6617
6791
  appState: 'aftershow',
6618
6792
  });
6793
+ this.setLifeCycleState(lifeCycles.AFTERSHOW);
6619
6794
  // dispatch afterShow event to base app
6620
6795
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
6621
6796
  }
@@ -6624,8 +6799,41 @@ class CreateApp {
6624
6799
  * @param e Error
6625
6800
  */
6626
6801
  onerror(e) {
6802
+ this.setLifeCycleState(lifeCycles.ERROR);
6803
+ // dispatch state event to micro app
6804
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6805
+ appState: appStates.LOAD_FAILED
6806
+ });
6627
6807
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
6628
6808
  }
6809
+ /**
6810
+ * Parse htmlString to DOM
6811
+ * NOTE: iframe sandbox will use DOMParser of iframeWindow, with sandbox will use DOMParser of base app
6812
+ * @param htmlString DOMString
6813
+ * @returns parsed DOM
6814
+ */
6815
+ parseHtmlString(htmlString) {
6816
+ var _a;
6817
+ const DOMParser = ((_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) ? this.sandBox.proxyWindow.DOMParser
6818
+ : globalEnv.rawWindow.DOMParser;
6819
+ return (new DOMParser()).parseFromString(htmlString, 'text/html').body;
6820
+ }
6821
+ /**
6822
+ * clone origin elements to target
6823
+ * @param origin Cloned element
6824
+ * @param target Accept cloned elements
6825
+ * @param deep deep clone or transfer dom
6826
+ */
6827
+ cloneContainer(target, origin, deep) {
6828
+ // 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
6829
+ if (origin) {
6830
+ target.innerHTML = '';
6831
+ Array.from(deep ? this.parseHtmlString(origin.innerHTML).childNodes : origin.childNodes).forEach((node) => {
6832
+ target.appendChild(node);
6833
+ });
6834
+ }
6835
+ return target;
6836
+ }
6629
6837
  /**
6630
6838
  * Scene:
6631
6839
  * 1. create app
@@ -6634,22 +6842,28 @@ class CreateApp {
6634
6842
  */
6635
6843
  createSandbox() {
6636
6844
  if (this.useSandbox && !this.sandBox) {
6637
- if (this.iframe) {
6638
- this.sandBox = new IframeSandbox(this.name, this.url);
6639
- }
6640
- else {
6641
- this.sandBox = new WithSandBox(this.name, this.url);
6642
- }
6845
+ this.sandBox = this.iframe ? new IframeSandbox(this.name, this.url) : new WithSandBox(this.name, this.url);
6643
6846
  }
6644
6847
  }
6645
6848
  // set app state
6646
6849
  setAppState(state) {
6850
+ var _a;
6647
6851
  this.state = state;
6852
+ // set window.__MICRO_APP_STATE__
6853
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setStaticAppState(state);
6648
6854
  }
6649
6855
  // get app state
6650
6856
  getAppState() {
6651
6857
  return this.state;
6652
6858
  }
6859
+ // set app lifeCycleState
6860
+ setLifeCycleState(state) {
6861
+ this.lifeCycleState = state;
6862
+ }
6863
+ // get app lifeCycleState
6864
+ getLifeCycleState() {
6865
+ return this.lifeCycleState || '';
6866
+ }
6653
6867
  // set keep-alive state
6654
6868
  setKeepAliveState(state) {
6655
6869
  this.keepAliveState = state;
@@ -6793,10 +7007,6 @@ function handleNewNode(child, app) {
6793
7007
  */
6794
7008
  function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
6795
7009
  const hijackParent = getHijackParent(parent, targetChild, app);
6796
- /**
6797
- * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
6798
- * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
6799
- */
6800
7010
  if (hijackParent) {
6801
7011
  /**
6802
7012
  * If parentNode is <micro-app-body>, return rawDocument.body
@@ -6835,11 +7045,28 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
6835
7045
  });
6836
7046
  }
6837
7047
  }
7048
+ if ((process.env.NODE_ENV !== 'production') &&
7049
+ isIFrameElement(targetChild) &&
7050
+ rawMethod === globalEnv.rawAppendChild) {
7051
+ fixReactHMRConflict(app);
7052
+ }
6838
7053
  /**
6839
7054
  * 1. If passiveChild exists, it must be insertBefore or replaceChild
6840
7055
  * 2. When removeChild, targetChild may not be in microAppHead or head
7056
+ * NOTE:
7057
+ * 1. If passiveChild not in hijackParent, insertBefore replaceChild will be degraded to appendChild
7058
+ * E.g: document.head.replaceChild(targetChild, document.scripts[0])
7059
+ * 2. If passiveChild not in hijackParent but in parent and method is insertBefore, try insert it into the position corresponding to hijackParent
7060
+ * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
7061
+ * ISSUE: https://github.com/micro-zoe/micro-app/issues/1071
6841
7062
  */
6842
7063
  if (passiveChild && !hijackParent.contains(passiveChild)) {
7064
+ if (rawMethod === globalEnv.rawInsertBefore && parent.contains(passiveChild)) {
7065
+ const indexOfParent = Array.from(parent.childNodes).indexOf(passiveChild);
7066
+ if (hijackParent.childNodes[indexOfParent]) {
7067
+ return invokeRawMethod(rawMethod, hijackParent, targetChild, hijackParent.childNodes[indexOfParent]);
7068
+ }
7069
+ }
6843
7070
  return globalEnv.rawAppendChild.call(hijackParent, targetChild);
6844
7071
  }
6845
7072
  else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
@@ -6848,11 +7075,6 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
6848
7075
  }
6849
7076
  return targetChild;
6850
7077
  }
6851
- if ((process.env.NODE_ENV !== 'production') &&
6852
- isIFrameElement(targetChild) &&
6853
- rawMethod === globalEnv.rawAppendChild) {
6854
- fixReactHMRConflict(app);
6855
- }
6856
7078
  return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
6857
7079
  }
6858
7080
  return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
@@ -6922,6 +7144,11 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
6922
7144
  currentAppName)) {
6923
7145
  newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
6924
7146
  const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
7147
+ if (isStyleElement(newChild)) {
7148
+ const isShadowNode = parent.getRootNode();
7149
+ const isShadowEnvironment = isShadowNode instanceof ShadowRoot;
7150
+ isShadowEnvironment && newChild.setAttribute('ignore', 'true');
7151
+ }
6925
7152
  if (app === null || app === void 0 ? void 0 : app.container) {
6926
7153
  completePathDynamic(app, newChild);
6927
7154
  return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
@@ -7008,30 +7235,34 @@ function patchElementAndDocument() {
7008
7235
  this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
7009
7236
  return clonedNode;
7010
7237
  };
7011
- function getQueryTarget(node) {
7238
+ /**
7239
+ * document.body(head).querySelector(querySelectorAll) hijack to microAppBody(microAppHead).querySelector(querySelectorAll)
7240
+ * NOTE:
7241
+ * 1. May cause some problems!
7242
+ * 2. Add config options?
7243
+ */
7244
+ function getQueryTarget(target) {
7012
7245
  const currentAppName = getCurrentAppName();
7013
- if ((node === document.body || node === document.head) && currentAppName) {
7246
+ if ((target === document.body || target === document.head) && currentAppName) {
7014
7247
  const app = appInstanceMap.get(currentAppName);
7015
7248
  if (app === null || app === void 0 ? void 0 : app.container) {
7016
- if (node === document.body) {
7249
+ if (target === document.body) {
7017
7250
  return app.querySelector('micro-app-body');
7018
7251
  }
7019
- else if (node === document.head) {
7252
+ else if (target === document.head) {
7020
7253
  return app.querySelector('micro-app-head');
7021
7254
  }
7022
7255
  }
7023
7256
  }
7024
- return null;
7257
+ return target;
7025
7258
  }
7026
7259
  rawRootElement.prototype.querySelector = function querySelector(selectors) {
7027
7260
  var _a;
7028
- const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
7029
- return globalEnv.rawElementQuerySelector.call(target, selectors);
7261
+ return globalEnv.rawElementQuerySelector.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
7030
7262
  };
7031
7263
  rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
7032
7264
  var _a;
7033
- const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
7034
- return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
7265
+ return globalEnv.rawElementQuerySelectorAll.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
7035
7266
  };
7036
7267
  // rewrite setAttribute, complete resource address
7037
7268
  rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
@@ -7090,6 +7321,7 @@ function patchElementAndDocument() {
7090
7321
  const currentAppName = getCurrentAppName();
7091
7322
  Array.from(this.children).forEach((child) => {
7092
7323
  if (isElement(child) && currentAppName) {
7324
+ // TODO: 使用updateElementInfo进行更新
7093
7325
  child.__MICRO_APP_NAME__ = currentAppName;
7094
7326
  }
7095
7327
  });
@@ -7106,7 +7338,7 @@ function patchElementAndDocument() {
7106
7338
  * 1. element-ui@2/lib/utils/popper.js
7107
7339
  * // root is child app window, so root.document is proxyDocument or microDocument
7108
7340
  * if (element.parentNode === root.document) ...
7109
- */
7341
+ */
7110
7342
  const currentAppName = getCurrentAppName();
7111
7343
  if (currentAppName && this === globalEnv.rawDocument.firstElementChild) {
7112
7344
  const microDocument = (_c = (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow) === null || _c === void 0 ? void 0 : _c.document;
@@ -7158,14 +7390,15 @@ function patchDocument$2() {
7158
7390
  const element = globalEnv.rawCreateElementNS.call(getBindTarget(this), namespaceURI, name, options);
7159
7391
  return markElement(element);
7160
7392
  };
7161
- rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
7162
- const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
7163
- return markElement(element);
7164
- };
7393
+ // TODO: 放开
7165
7394
  // rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
7166
7395
  // const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
7167
7396
  // return markElement(element)
7168
7397
  // }
7398
+ rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
7399
+ const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
7400
+ return markElement(element);
7401
+ };
7169
7402
  rawRootDocument.prototype.createComment = function createComment(data) {
7170
7403
  const element = globalEnv.rawCreateComment.call(getBindTarget(this), data);
7171
7404
  return markElement(element);
@@ -7178,7 +7411,7 @@ function patchDocument$2() {
7178
7411
  if (!currentAppName ||
7179
7412
  !selectors ||
7180
7413
  isUniqueElement(selectors) ||
7181
- // see https://github.com/micro-zoe/micro-app/issues/56
7414
+ // ISSUE: https://github.com/micro-zoe/micro-app/issues/56
7182
7415
  rawDocument !== _this) {
7183
7416
  return globalEnv.rawQuerySelector.call(_this, selectors);
7184
7417
  }
@@ -7328,8 +7561,8 @@ function initGlobalEnv() {
7328
7561
  // Document proto methods
7329
7562
  const rawCreateElement = rawRootDocument.prototype.createElement;
7330
7563
  const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
7331
- const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
7332
7564
  const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
7565
+ const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
7333
7566
  const rawCreateComment = rawRootDocument.prototype.createComment;
7334
7567
  const rawQuerySelector = rawRootDocument.prototype.querySelector;
7335
7568
  const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
@@ -7889,7 +8122,9 @@ function defineElement(tagName) {
7889
8122
  * @returns router-mode
7890
8123
  */
7891
8124
  getMemoryRouterMode() {
7892
- return getRouterMode(this.getAttribute('router-mode'), this);
8125
+ return getRouterMode(this.getAttribute('router-mode'),
8126
+ // is micro-app element set disable-memory-router, like <micro-app disable-memory-router></micro-app>
8127
+ this.compatibleProperties('disable-memory-router') && this.compatibleDisableProperties('disable-memory-router'));
7893
8128
  }
7894
8129
  /**
7895
8130
  * rewrite micro-app.setAttribute, process attr data
@@ -7938,6 +8173,18 @@ function defineElement(tagName) {
7938
8173
  }
7939
8174
  return null;
7940
8175
  }
8176
+ /**
8177
+ * get publicPath from a valid address,it can used in micro-app-devtools
8178
+ */
8179
+ get publicPath() {
8180
+ return getEffectivePath(this.appUrl);
8181
+ }
8182
+ /**
8183
+ * get baseRoute from attribute,it can used in micro-app-devtools
8184
+ */
8185
+ get baseRoute() {
8186
+ return this.getBaseRouteCompatible();
8187
+ }
7941
8188
  }
7942
8189
  globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
7943
8190
  }
@@ -8016,9 +8263,22 @@ function preFetchAction(options) {
8016
8263
  });
8017
8264
  const oldOnload = app.onLoad;
8018
8265
  const oldOnLoadError = app.onLoadError;
8019
- app.onLoad = (html) => {
8266
+ app.onLoad = (onLoadParam) => {
8267
+ if (app.isPrerender) {
8268
+ assign(onLoadParam, {
8269
+ defaultPage: options['default-page'],
8270
+ /**
8271
+ * TODO: 预渲染支持disable-memory-router,默认渲染首页即可,文档中也要保留
8272
+ * 问题:
8273
+ * 1、如何确保子应用进行跳转时不影响到浏览器地址??pure??
8274
+ */
8275
+ routerMode: getRouterMode(options['router-mode']),
8276
+ baseroute: options.baseroute,
8277
+ disablePatchRequest: options['disable-patch-request'],
8278
+ });
8279
+ }
8020
8280
  resolve();
8021
- oldOnload.call(app, html, options['default-page'], options['disable-patch-request'], getRouterMode(options['router-mode']), options.baseroute);
8281
+ oldOnload.call(app, onLoadParam);
8022
8282
  };
8023
8283
  app.onLoadError = (...rests) => {
8024
8284
  resolve();
@@ -8278,6 +8538,20 @@ function renderApp(options) {
8278
8538
  container.appendChild(microAppElement);
8279
8539
  });
8280
8540
  }
8541
+ /**
8542
+ * get app state
8543
+ * @param appName app.name
8544
+ * @returns app.state
8545
+ */
8546
+ function getAppStatus(appName) {
8547
+ const app = appInstanceMap.get(formatAppName(appName));
8548
+ if (app) {
8549
+ return app.getLifeCycleState();
8550
+ }
8551
+ else {
8552
+ logWarn(`app ${appName} does not exist`);
8553
+ }
8554
+ }
8281
8555
  class MicroApp extends EventCenterForBaseApp {
8282
8556
  constructor() {
8283
8557
  super(...arguments);
@@ -8292,6 +8566,7 @@ class MicroApp extends EventCenterForBaseApp {
8292
8566
  this.getAllApps = getAllApps;
8293
8567
  this.reload = reload;
8294
8568
  this.renderApp = renderApp;
8569
+ this.getAppStatus = getAppStatus;
8295
8570
  }
8296
8571
  start(options) {
8297
8572
  var _a, _b;
@@ -8347,5 +8622,5 @@ class MicroApp extends EventCenterForBaseApp {
8347
8622
  const microApp = new MicroApp();
8348
8623
 
8349
8624
  export default microApp;
8350
- export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
8625
+ export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, getAppStatus, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
8351
8626
  //# sourceMappingURL=index.esm.js.map