@micro-zoe/micro-app 1.0.0-rc.3 → 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.3';
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
@@ -116,6 +116,26 @@ function isMicroAppBody(target) {
116
116
  function isProxyDocument(target) {
117
117
  return toTypeString(target) === '[object ProxyDocument]';
118
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;
138
+ }
119
139
  /**
120
140
  * format error log
121
141
  * @param msg message
@@ -179,7 +199,7 @@ function formatAppURL(url, appName = null) {
179
199
  if (!isString(url) || !url)
180
200
  return '';
181
201
  try {
182
- const { origin, pathname, search } = createURL(addProtocol(url));
202
+ const { origin, pathname, search } = createURL(addProtocol(url), (window.rawWindow || window).location.href);
183
203
  // If it ends with .html/.node/.php/.net/.etc, don’t need to add /
184
204
  if (/\.(\w+)$/.test(pathname)) {
185
205
  return `${origin}${pathname}${search}`;
@@ -318,21 +338,28 @@ let currentMicroAppName = null;
318
338
  function setCurrentAppName(appName) {
319
339
  currentMicroAppName = appName;
320
340
  }
321
- function throttleDeferForSetAppName(appName) {
322
- if (currentMicroAppName !== appName) {
323
- setCurrentAppName(appName);
324
- defer(() => {
325
- setCurrentAppName(null);
326
- });
327
- }
328
- }
329
341
  // get the currently running app.name
330
342
  function getCurrentAppName() {
331
343
  return currentMicroAppName;
332
344
  }
333
345
  // Clear appName
334
- function removeDomScope() {
346
+ let preventSetAppName = false;
347
+ function removeDomScope(force) {
335
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
+ }
336
363
  }
337
364
  /**
338
365
  * Create pure elements
@@ -344,33 +371,6 @@ function pureCreateElement(tagName, options) {
344
371
  element.__PURE_ELEMENT__ = true;
345
372
  return element;
346
373
  }
347
- /**
348
- * clone origin elements to target
349
- * @param origin Cloned element
350
- * @param target Accept cloned elements
351
- * @param deep deep clone or transfer dom
352
- */
353
- function cloneContainer(target, origin, deep) {
354
- // 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
355
- if (origin) {
356
- target.innerHTML = '';
357
- if (deep) {
358
- // TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
359
- const clonedNode = origin.cloneNode(true);
360
- const fragment = document.createDocumentFragment();
361
- Array.from(clonedNode.childNodes).forEach((node) => {
362
- fragment.appendChild(node);
363
- });
364
- target.appendChild(fragment);
365
- }
366
- else {
367
- Array.from(origin.childNodes).forEach((node) => {
368
- target.appendChild(node);
369
- });
370
- }
371
- }
372
- return target;
373
- }
374
374
  // is invalid key of querySelector
375
375
  function isInvalidQuerySelectorKey(key) {
376
376
  return !key || /(^\d)|([^\w\d-_\u4e00-\u9fa5])/gi.test(key);
@@ -1295,12 +1295,12 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
1295
1295
  */
1296
1296
  if (fiberStyleResult) {
1297
1297
  fiberStyleResult.then(() => {
1298
- fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
1298
+ fiberLinkTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
1299
1299
  serialExecFiberTasks(fiberLinkTasks);
1300
1300
  });
1301
1301
  }
1302
1302
  else {
1303
- app.onLoad(wrapElement);
1303
+ app.onLoad({ html: wrapElement });
1304
1304
  }
1305
1305
  });
1306
1306
  }
@@ -1473,13 +1473,24 @@ var MicroAppConfig;
1473
1473
  // prefetch level
1474
1474
  const PREFETCH_LEVEL = [1, 2, 3];
1475
1475
  // memory router constants
1476
+ // default mode, child router info will sync to browser url
1476
1477
  const DEFAULT_ROUTER_MODE = 'search';
1477
- const ROUTER_MODE_HISTORY = 'history';
1478
- 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';
1479
1489
  const ROUTER_MODE_LIST = [
1480
1490
  DEFAULT_ROUTER_MODE,
1481
- ROUTER_MODE_HISTORY,
1482
- ROUTER_MODE_CUSTOM,
1491
+ ROUTER_MODE_NATIVE,
1492
+ ROUTER_MODE_NATIVE_SCOPE,
1493
+ ROUTER_MODE_PURE,
1483
1494
  ];
1484
1495
  // event bound to child app window
1485
1496
  const SCOPE_WINDOW_EVENT = [
@@ -1494,6 +1505,7 @@ const SCOPE_WINDOW_EVENT = [
1494
1505
  'mounted',
1495
1506
  ];
1496
1507
  // on event bound to child app window
1508
+ // TODO: with和iframe处理方式不同,需修改
1497
1509
  const SCOPE_WINDOW_ON_EVENT = [
1498
1510
  'onpopstate',
1499
1511
  'onhashchange',
@@ -1790,16 +1802,16 @@ function fetchScriptsFromHtml(wrapElement, app) {
1790
1802
  logError(err, app.name);
1791
1803
  }, () => {
1792
1804
  if (fiberScriptTasks) {
1793
- fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
1805
+ fiberScriptTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
1794
1806
  serialExecFiberTasks(fiberScriptTasks);
1795
1807
  }
1796
1808
  else {
1797
- app.onLoad(wrapElement);
1809
+ app.onLoad({ html: wrapElement });
1798
1810
  }
1799
1811
  });
1800
1812
  }
1801
1813
  else {
1802
- app.onLoad(wrapElement);
1814
+ app.onLoad({ html: wrapElement });
1803
1815
  }
1804
1816
  }
1805
1817
  /**
@@ -2123,15 +2135,6 @@ function processCode(configs, code, address) {
2123
2135
  }, code);
2124
2136
  }
2125
2137
 
2126
- /**
2127
- * transform html string to dom
2128
- * @param str string dom
2129
- */
2130
- function getWrapElement(str) {
2131
- const wrapDiv = pureCreateElement('div');
2132
- wrapDiv.innerHTML = str;
2133
- return wrapDiv;
2134
- }
2135
2138
  /**
2136
2139
  * Recursively process each child element
2137
2140
  * @param parent parent element
@@ -2188,7 +2191,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
2188
2191
  * @param app app
2189
2192
  */
2190
2193
  function extractSourceDom(htmlStr, app) {
2191
- const wrapElement = getWrapElement(htmlStr);
2194
+ const wrapElement = app.parseHtmlString(htmlStr);
2192
2195
  const microAppHead = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-head');
2193
2196
  const microAppBody = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-body');
2194
2197
  if (!microAppHead || !microAppBody) {
@@ -2206,16 +2209,16 @@ function extractSourceDom(htmlStr, app) {
2206
2209
  fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult);
2207
2210
  }
2208
2211
  else if (fiberStyleResult) {
2209
- fiberStyleResult.then(() => app.onLoad(wrapElement));
2212
+ fiberStyleResult.then(() => app.onLoad({ html: wrapElement }));
2210
2213
  }
2211
2214
  else {
2212
- app.onLoad(wrapElement);
2215
+ app.onLoad({ html: wrapElement });
2213
2216
  }
2214
2217
  if (app.source.scripts.size) {
2215
2218
  fetchScriptsFromHtml(wrapElement, app);
2216
2219
  }
2217
2220
  else {
2218
- app.onLoad(wrapElement);
2221
+ app.onLoad({ html: wrapElement });
2219
2222
  }
2220
2223
  }
2221
2224
 
@@ -2751,12 +2754,17 @@ function createProxyDocument(appName, sandbox) {
2751
2754
  const sstEventListenerMap = new Map();
2752
2755
  let onClickHandler = null;
2753
2756
  let sstOnClickHandler = null;
2754
- const { rawDocument, rawCreateElement, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
2757
+ const { rawDocument, rawCreateElement, rawCreateElementNS, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
2755
2758
  function createElement(tagName, options) {
2756
2759
  const element = rawCreateElement.call(rawDocument, tagName, options);
2757
2760
  element.__MICRO_APP_NAME__ = appName;
2758
2761
  return element;
2759
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
+ }
2760
2768
  /**
2761
2769
  * TODO:
2762
2770
  * 1. listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
@@ -2872,6 +2880,8 @@ function createProxyDocument(appName, sandbox) {
2872
2880
  // TODO: 转换成数据形式,类似iframe的方式
2873
2881
  if (key === 'createElement')
2874
2882
  return createElement;
2883
+ if (key === 'createElementNS')
2884
+ return createElementNS;
2875
2885
  if (key === Symbol.toStringTag)
2876
2886
  return 'ProxyDocument';
2877
2887
  if (key === 'defaultView')
@@ -2968,7 +2978,7 @@ function createMicroDocument(appName, proxyDocument) {
2968
2978
  function patchWindow(appName, microAppWindow, sandbox) {
2969
2979
  patchWindowProperty(microAppWindow);
2970
2980
  createProxyWindow(appName, microAppWindow, sandbox);
2971
- return patchWindowEffect(microAppWindow);
2981
+ return patchWindowEffect(microAppWindow, appName);
2972
2982
  }
2973
2983
  /**
2974
2984
  * rewrite special properties of window
@@ -3009,22 +3019,22 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
3009
3019
  throttleDeferForSetAppName(appName);
3010
3020
  if (Reflect.has(target, key) ||
3011
3021
  (isString(key) && /^__MICRO_APP_/.test(key)) ||
3012
- sandbox.scopeProperties.includes(key)) {
3013
- if (RAW_GLOBAL_TARGET.includes(key))
3022
+ includes(sandbox.scopeProperties, key)) {
3023
+ if (includes(RAW_GLOBAL_TARGET, key))
3014
3024
  removeDomScope();
3015
3025
  return Reflect.get(target, key);
3016
3026
  }
3017
3027
  return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
3018
3028
  },
3019
3029
  set: (target, key, value) => {
3020
- if (sandbox.adapter.escapeSetterKeyList.includes(key)) {
3030
+ if (includes(sandbox.rawWindowScopeKeyList, key)) {
3021
3031
  Reflect.set(rawWindow, key, value);
3022
3032
  }
3023
3033
  else if (
3024
3034
  // target.hasOwnProperty has been rewritten
3025
3035
  !rawHasOwnProperty.call(target, key) &&
3026
3036
  rawHasOwnProperty.call(rawWindow, key) &&
3027
- !sandbox.scopeProperties.includes(key)) {
3037
+ !includes(sandbox.scopeProperties, key)) {
3028
3038
  const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
3029
3039
  const { configurable, enumerable, writable, set } = descriptor;
3030
3040
  // set value because it can be set
@@ -3037,32 +3047,37 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
3037
3047
  sandbox.injectedKeys.add(key);
3038
3048
  }
3039
3049
  else {
3040
- !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
+ }
3041
3054
  Reflect.set(target, key, value);
3042
3055
  }
3043
- if ((sandbox.escapeProperties.includes(key) ||
3044
- (sandbox.adapter.staticEscapeProperties.includes(key) &&
3056
+ if ((includes(sandbox.escapeProperties, key) ||
3057
+ (
3058
+ // TODO: staticEscapeProperties 合并到 escapeProperties
3059
+ includes(sandbox.staticEscapeProperties, key) &&
3045
3060
  !Reflect.has(rawWindow, key))) &&
3046
- !sandbox.scopeProperties.includes(key)) {
3061
+ !includes(sandbox.scopeProperties, key)) {
3047
3062
  !Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
3048
3063
  Reflect.set(rawWindow, key, value);
3049
3064
  }
3050
3065
  return true;
3051
3066
  },
3052
3067
  has: (target, key) => {
3053
- if (sandbox.scopeProperties.includes(key)) {
3054
- /**
3055
- * Some keywords, such as Vue, need to meet two conditions at the same time:
3056
- * 1. 'Vue' in window --> false
3057
- * 2. Vue (top level variable) // undefined
3058
- * Issue https://github.com/micro-zoe/micro-app/issues/686
3059
- */
3060
- if (sandbox.adapter.staticScopeProperties.includes(key)) {
3061
- 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
3062
3077
  }
3063
- return key in target;
3078
+ return !!target[key]; // false
3064
3079
  }
3065
- return key in target || key in rawWindow;
3080
+ return Reflect.has(target, key) || Reflect.has(rawWindow, key);
3066
3081
  },
3067
3082
  // Object.getOwnPropertyDescriptor(window, key)
3068
3083
  getOwnPropertyDescriptor: (target, key) => {
@@ -3107,14 +3122,26 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
3107
3122
  * Rewrite side-effect events
3108
3123
  * @param microAppWindow micro window
3109
3124
  */
3110
- function patchWindowEffect(microAppWindow) {
3125
+ function patchWindowEffect(microAppWindow, appName) {
3111
3126
  const eventListenerMap = new Map();
3112
3127
  const sstEventListenerMap = new Map();
3113
3128
  const intervalIdMap = new Map();
3114
3129
  const timeoutIdMap = new Map();
3115
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
+ */
3116
3139
  function getEventTarget(type) {
3117
- 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;
3118
3145
  }
3119
3146
  /**
3120
3147
  * listener may be null, e.g test-passive
@@ -3228,7 +3255,7 @@ function patchWindowEffect(microAppWindow) {
3228
3255
 
3229
3256
  // set micro app state to origin state
3230
3257
  function setMicroState(appName, microState) {
3231
- if (!isRouterModeCustom(appName)) {
3258
+ if (isRouterModeSearch(appName)) {
3232
3259
  const rawState = globalEnv.rawWindow.history.state;
3233
3260
  const additionalState = {
3234
3261
  microAppState: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.microAppState, {
@@ -3242,7 +3269,7 @@ function setMicroState(appName, microState) {
3242
3269
  }
3243
3270
  // delete micro app state form origin state
3244
3271
  function removeMicroState(appName, rawState) {
3245
- if (!isRouterModeCustom(appName)) {
3272
+ if (isRouterModeSearch(appName)) {
3246
3273
  if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.microAppState)) {
3247
3274
  if (!isUndefined(rawState.microAppState[appName])) {
3248
3275
  delete rawState.microAppState[appName];
@@ -3259,7 +3286,7 @@ function removeMicroState(appName, rawState) {
3259
3286
  function getMicroState(appName) {
3260
3287
  var _a;
3261
3288
  const rawState = globalEnv.rawWindow.history.state;
3262
- if (!isRouterModeCustom(appName)) {
3289
+ if (isRouterModeSearch(appName)) {
3263
3290
  return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
3264
3291
  }
3265
3292
  return rawState;
@@ -3299,8 +3326,11 @@ function formatQueryAppName(appName) {
3299
3326
  */
3300
3327
  function getMicroPathFromURL(appName) {
3301
3328
  var _a, _b;
3329
+ // TODO: pure模式从state中获取地址
3330
+ if (isRouterModePure(appName))
3331
+ return null;
3302
3332
  const rawLocation = globalEnv.rawWindow.location;
3303
- if (!isRouterModeCustom(appName)) {
3333
+ if (isRouterModeSearch(appName)) {
3304
3334
  const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
3305
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)]);
3306
3336
  return isString(microPath) ? decodeMicroPath(microPath) : null;
@@ -3315,7 +3345,7 @@ function getMicroPathFromURL(appName) {
3315
3345
  function setMicroPathToURL(appName, targetLocation) {
3316
3346
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3317
3347
  let isAttach2Hash = false;
3318
- if (!isRouterModeCustom(appName)) {
3348
+ if (isRouterModeSearch(appName)) {
3319
3349
  let { pathname, search, hash } = globalEnv.rawWindow.location;
3320
3350
  const queryObject = getQueryObjectFromURL(search, hash);
3321
3351
  const encodedMicroPath = encodeMicroPath(targetFullPath);
@@ -3367,7 +3397,7 @@ function removeMicroPathFromURL(appName, targetLocation) {
3367
3397
  var _a, _b, _c, _d;
3368
3398
  let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
3369
3399
  let isAttach2Hash = false;
3370
- if (!isRouterModeCustom(appName)) {
3400
+ if (isRouterModeSearch(appName)) {
3371
3401
  const queryObject = getQueryObjectFromURL(search, hash);
3372
3402
  if ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) {
3373
3403
  isAttach2Hash = true;
@@ -3427,15 +3457,31 @@ function isEffectiveApp(appName) {
3427
3457
  */
3428
3458
  return !!(app && !app.isPrefetch);
3429
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
+ }
3430
3480
  /**
3431
- * router mode is custom
3432
- * NOTE:
3433
- * 1. if sandbox disabled, router mode defaults to custom
3434
- * 2. if app not exist, router mode defaults to custom
3481
+ * router mode is history or disable
3435
3482
  */
3436
3483
  function isRouterModeCustom(appName) {
3437
- const app = appInstanceMap.get(appName);
3438
- return !app || !app.sandBox || app.routerMode === ROUTER_MODE_CUSTOM;
3484
+ return isRouterModeNative(appName) || isRouterModeNativeScope(appName);
3439
3485
  }
3440
3486
  /**
3441
3487
  * get memory router mode of child app
@@ -3443,21 +3489,21 @@ function isRouterModeCustom(appName) {
3443
3489
  * 1. if microAppElement exists, it means the app render by the micro-app element
3444
3490
  * 2. if microAppElement not exists, it means it is prerender app
3445
3491
  * @param mode native config
3446
- * @param microAppElement micro-app element
3447
- * @returns mode
3492
+ * @param inlineDisableMemoryRouter disable-memory-router set by micro-app element or prerender
3493
+ * @returns router mode
3448
3494
  */
3449
- function getRouterMode(mode, microAppElement) {
3450
- let routerMode;
3495
+ function getRouterMode(mode, inlineDisableMemoryRouter) {
3451
3496
  /**
3452
3497
  * compatible with disable-memory-router in older versions
3453
- * 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
3454
3501
  */
3455
- if (microAppElement) {
3456
- routerMode = microAppElement.getDisposeResult('disable-memory-router') ? ROUTER_MODE_CUSTOM : mode || microApp.options['router-mode'] || '';
3457
- }
3458
- else {
3459
- routerMode = microApp.options['disable-memory-router'] ? ROUTER_MODE_CUSTOM : mode || microApp.options['router-mode'] || '';
3460
- }
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);
3461
3507
  return ROUTER_MODE_LIST.includes(routerMode) ? routerMode : DEFAULT_ROUTER_MODE;
3462
3508
  }
3463
3509
 
@@ -3603,7 +3649,7 @@ function dispatchNativeEvent(appName, onlyForBrowser, oldHref) {
3603
3649
  * create proxyHistory for microApp
3604
3650
  * MDN https://developer.mozilla.org/en-US/docs/Web/API/History
3605
3651
  * @param appName app name
3606
- * @param microLocation microApp location
3652
+ * @param microLocation microApp location(with: proxyLocation iframe: iframeWindow.location)
3607
3653
  */
3608
3654
  function createMicroHistory(appName, microLocation) {
3609
3655
  const rawHistory = globalEnv.rawWindow.history;
@@ -3614,7 +3660,9 @@ function createMicroHistory(appName, microLocation) {
3614
3660
  if (isString(rests[2]) || isURL(rests[2])) {
3615
3661
  const targetLocation = createURL(rests[2], microLocation.href);
3616
3662
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3617
- 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
+ }
3618
3666
  if (targetFullPath !== microLocation.fullPath) {
3619
3667
  updateMicroLocation(appName, targetFullPath, microLocation);
3620
3668
  }
@@ -3693,10 +3741,10 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
3693
3741
  nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
3694
3742
  /**
3695
3743
  * TODO:
3696
- * 1. 如果所有模式统一发送popstate事件,则!isRouterModeCustom(appName)要去掉
3744
+ * 1. 如果所有模式统一发送popstate事件,则isRouterModeSearch(appName)要去掉
3697
3745
  * 2. 如果发送事件,则会导致vue router-view :key='router.path'绑定,无限卸载应用,死循环
3698
3746
  */
3699
- if (oldFullPath !== result.fullPath && !isRouterModeCustom(appName)) {
3747
+ if (oldFullPath !== result.fullPath && isRouterModeSearch(appName)) {
3700
3748
  dispatchNativeEvent(appName, onlyForBrowser, oldHref);
3701
3749
  }
3702
3750
  }
@@ -3743,7 +3791,7 @@ function reWriteHistoryMethod(method) {
3743
3791
  excludeHiddenApp: true,
3744
3792
  excludePreRender: true,
3745
3793
  }).forEach(appName => {
3746
- if (!isRouterModeCustom(appName) && !getMicroPathFromURL(appName)) {
3794
+ if (isRouterModeSearch(appName) && !getMicroPathFromURL(appName)) {
3747
3795
  const app = appInstanceMap.get(appName);
3748
3796
  attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
3749
3797
  }
@@ -3795,8 +3843,10 @@ function createRouterApi() {
3795
3843
  const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
3796
3844
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3797
3845
  if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
3798
- const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
3799
- 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
+ }
3800
3850
  /**
3801
3851
  * TODO:
3802
3852
  * 1. 关闭虚拟路由的跳转地址不同:baseRoute + 子应用地址,文档中要说明
@@ -3809,7 +3859,7 @@ function createRouterApi() {
3809
3859
  * NOTE1: history和search模式采用2,这样可以解决vue3的问题,custom采用1,避免vue循环刷新的问题,这样在用户出现问题时各有解决方案。但反过来说,每种方案又分别导致另外的问题,不统一,导致复杂度增高
3810
3860
  * NOTE2: 关闭虚拟路由,同时发送popstate事件还是无法解决vue3的问题(毕竟history.state理论上还是会冲突),那么就没必要发送popstate事件了。
3811
3861
  */
3812
- if (isRouterModeCustom(appName)) {
3862
+ if (isRouterModeCustom(appName) || isRouterModePure(appName)) {
3813
3863
  updateMicroLocationWithEvent(appName, targetFullPath);
3814
3864
  }
3815
3865
  }
@@ -3927,7 +3977,7 @@ function createRouterApi() {
3927
3977
  * 3. router mode is custom
3928
3978
  */
3929
3979
  function commonHandlerForAttachToURL(appName) {
3930
- if (!isRouterModeCustom(appName)) {
3980
+ if (isRouterModeSearch(appName)) {
3931
3981
  const app = appInstanceMap.get(appName);
3932
3982
  attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
3933
3983
  }
@@ -4159,7 +4209,7 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4159
4209
  if (targetLocation.origin === proxyLocation.origin) {
4160
4210
  const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
4161
4211
  // if disable memory-router, navigate directly through rawLocation
4162
- if (!isRouterModeCustom(appName)) {
4212
+ if (isRouterModeSearch(appName)) {
4163
4213
  /**
4164
4214
  * change hash with location.href will not trigger the browser reload
4165
4215
  * so we use pushState & reload to imitate href behavior
@@ -4245,6 +4295,20 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4245
4295
  const proxyLocation = new Proxy({}, {
4246
4296
  get: (_, key) => {
4247
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
4248
4312
  if (isIframe) {
4249
4313
  // host hostname port protocol
4250
4314
  if (hijackMicroLocationKeys.includes(key)) {
@@ -4255,29 +4319,21 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4255
4319
  return target[key].replace(browserHost, childHost);
4256
4320
  }
4257
4321
  }
4258
- if (key === 'assign')
4259
- return assign;
4260
- if (key === 'replace')
4261
- return replace;
4262
- if (key === 'reload')
4263
- return reload;
4264
- if (key === 'self')
4265
- return target;
4266
4322
  return bindFunctionToRawTarget(Reflect.get(target, key), target, 'LOCATION');
4267
4323
  },
4268
4324
  set: (_, key, value) => {
4269
4325
  if (isEffectiveApp(appName)) {
4270
4326
  const target = getTarget();
4271
4327
  if (key === 'href') {
4272
- const targetPath = commonHandler(value, 'pushState');
4273
4328
  /**
4274
4329
  * In vite, targetPath without origin will be completed with child origin
4275
4330
  * So we use browser origin to complete targetPath to avoid this problem
4276
- * But, why child app can affect browser jump?
4277
- * Guess(need check):
4278
- * 1. vite records the origin when init
4279
- * 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
4280
4335
  */
4336
+ const targetPath = commonHandler(value, 'pushState');
4281
4337
  if (targetPath) {
4282
4338
  rawLocation.href = createURL(targetPath, rawLocation.origin).href;
4283
4339
  }
@@ -4362,9 +4418,11 @@ function updateMicroLocation(appName, path, microLocation, type) {
4362
4418
  (_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
4363
4419
  }
4364
4420
  else {
4365
- for (const key of locationKeys) {
4366
- 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);
4367
4424
  }
4425
+ microLocation.self.href = targetHref;
4368
4426
  }
4369
4427
  // update latest values of microLocation to `to`
4370
4428
  const to = createGuardLocation(appName, microLocation);
@@ -4375,13 +4433,9 @@ function updateMicroLocation(appName, path, microLocation, type) {
4375
4433
  }
4376
4434
 
4377
4435
  /**
4378
- * TODO: 关于关闭虚拟路由系统的临时笔记 - 即custom模式,虚拟路由不支持关闭
4379
- * 1. with沙箱关闭虚拟路由最好和iframe保持一致
4380
- * 2. default-page无法使用,但是用基座的地址可以实现一样的效果
4381
- * 3. keep-router-state功能失效,因为始终为true
4382
- * 4. 基座控制子应用跳转地址改变,正确的值为:baseRoute + 子应用地址,这要在文档中说明,否则很容易出错,确实也很难理解
4383
- * 5. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
4384
- * 6. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
4436
+ * TODO: 关于关闭虚拟路由系统的custom、history模式
4437
+ * 1. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
4438
+ * 2. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
4385
4439
  */
4386
4440
  /**
4387
4441
  * The router system has two operations: read and write
@@ -4422,8 +4476,10 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
4422
4476
  // update microLocation with defaultPage
4423
4477
  if (defaultPage)
4424
4478
  updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
4425
- // attach microApp route info to browser URL
4426
- 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
+ }
4427
4483
  // trigger guards after change browser URL
4428
4484
  autoTriggerNavigationGuard(appName, microLocation);
4429
4485
  }
@@ -4440,7 +4496,9 @@ function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
4440
4496
  const { pathname, search, hash } = createURL(url);
4441
4497
  updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
4442
4498
  }
4443
- removePathFromBrowser(appName);
4499
+ if (!isRouterModePure(appName)) {
4500
+ removePathFromBrowser(appName);
4501
+ }
4444
4502
  }
4445
4503
  clearRouterWhenUnmount(appName);
4446
4504
  }
@@ -4452,10 +4510,10 @@ function removePathFromBrowser(appName) {
4452
4510
  attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
4453
4511
  }
4454
4512
 
4455
- class Adapter {
4513
+ class BaseSandbox {
4456
4514
  constructor() {
4457
4515
  // keys that can only assigned to rawWindow
4458
- this.escapeSetterKeyList = [
4516
+ this.rawWindowScopeKeyList = [
4459
4517
  'location',
4460
4518
  ];
4461
4519
  // keys that can escape to rawWindow
@@ -4468,7 +4526,18 @@ class Adapter {
4468
4526
  'webpackJsonp',
4469
4527
  'webpackHotUpdate',
4470
4528
  'Vue',
4529
+ // TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
4530
+ 'onpopstate',
4531
+ 'onhashchange',
4471
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();
4472
4541
  this.injectReactHMRProperty();
4473
4542
  }
4474
4543
  // adapter for react
@@ -4486,6 +4555,14 @@ class Adapter {
4486
4555
  }
4487
4556
  }
4488
4557
  }
4558
+ /**
4559
+ * TODO:
4560
+ * 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
4561
+ * 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
4562
+ * 修改时机:在iframe沙箱支持插件后再修改
4563
+ */
4564
+ class CustomWindow {
4565
+ }
4489
4566
  // Fix conflict of babel-polyfill@6.x
4490
4567
  function fixBabelPolyfill6() {
4491
4568
  if (globalEnv.rawWindow._babelPolyfill)
@@ -4544,6 +4621,7 @@ function updateElementInfo(node, appName) {
4544
4621
  rawDefineProperties(node, {
4545
4622
  baseURI: {
4546
4623
  configurable: true,
4624
+ // if disable-memory-router or router-mode='disable', href point to base app
4547
4625
  get: () => proxyWindow.location.href,
4548
4626
  },
4549
4627
  __MICRO_APP_NAME__: {
@@ -4552,58 +4630,9 @@ function updateElementInfo(node, appName) {
4552
4630
  value: appName,
4553
4631
  },
4554
4632
  });
4555
- if (isIframeSandbox(appName)) {
4556
- /**
4557
- * If HTML built-in node belongs to base app, it needs to be handled separately for parentNode
4558
- * Fix error for nuxt@2.x + ElementUI@2.x
4559
- */
4560
- if (node instanceof globalEnv.rawRootNode) {
4561
- rawDefineProperty(node, 'parentNode', {
4562
- configurable: true,
4563
- get: createGetterForIframeParentNode(appName, globalEnv.rawParentNodeDesc, true)
4564
- });
4565
- }
4566
- }
4567
4633
  }
4568
4634
  return node;
4569
4635
  }
4570
- /**
4571
- * patch iframe node parentNode
4572
- * Scenes:
4573
- * 1. iframe common node: patch Node.prototype.parentNode to hijack parentNode
4574
- * 2. iframe HTML built-in node: belongs to base app, we should rewrite parentNode for every built-in node
4575
- * NOTE:
4576
- * 1. HTML built-in node parentNode cannot point to raw body, otherwise Vue2 will render failed
4577
- * @param appName app name
4578
- * @param parentNode parentNode Descriptor of iframe or browser
4579
- * @param HTMLBuildInNode is HTML built-in node
4580
- */
4581
- function createGetterForIframeParentNode(appName, parentNodeDesc, HTMLBuildInNode) {
4582
- return function () {
4583
- var _a, _b, _c;
4584
- /**
4585
- * set current appName for hijack parentNode of html
4586
- * NOTE:
4587
- * 1. Is there a problem with setting the current appName in iframe mode
4588
- */
4589
- throttleDeferForSetAppName(appName);
4590
- const result = parentNodeDesc.get.call(this);
4591
- /**
4592
- * If parentNode is <micro-app-body>, return rawDocument.body
4593
- * Scenes:
4594
- * 1. element-ui@2/lib/utils/vue-popper.js
4595
- * if (this.popperElm.parentNode === document.body) ...
4596
- * WARNING:
4597
- * Will it cause other problems ?
4598
- * e.g. target.parentNode.remove(target)
4599
- */
4600
- if (!HTMLBuildInNode &&
4601
- isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
4602
- return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
4603
- }
4604
- return result;
4605
- };
4606
- }
4607
4636
 
4608
4637
  /**
4609
4638
  * https://developer.mozilla.org/en-US/docs/Web/API/fetch
@@ -4707,23 +4736,12 @@ function useMicroEventSource() {
4707
4736
  }
4708
4737
 
4709
4738
  const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
4710
- class WithSandBox {
4739
+ class WithSandBox extends BaseSandbox {
4711
4740
  constructor(appName, url) {
4741
+ super();
4712
4742
  this.active = false;
4713
- /**
4714
- * Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
4715
- * Fix https://github.com/micro-zoe/micro-app/issues/234
4716
- */
4717
- this.scopeProperties = [];
4718
- // Properties that can be escape to rawWindow
4719
- this.escapeProperties = [];
4720
- // Properties escape to rawWindow, cleared when unmount
4721
- this.escapeKeys = new Set();
4722
- // Properties newly added to microAppWindow
4723
- this.injectedKeys = new Set();
4724
- this.microAppWindow = new EventTarget(); // Proxy target
4743
+ this.microAppWindow = new CustomWindow(); // Proxy target
4725
4744
  this.patchWith((resolve) => {
4726
- this.adapter = new Adapter();
4727
4745
  // get scopeProperties and escapeProperties from plugins
4728
4746
  this.getSpecialProperties(appName);
4729
4747
  // create location, history for child app
@@ -4732,6 +4750,8 @@ class WithSandBox {
4732
4750
  this.windowEffect = patchWindow(appName, this.microAppWindow, this);
4733
4751
  // patch document of child app
4734
4752
  this.documentEffect = patchDocument(appName, this.microAppWindow, this);
4753
+ // properties associated with the native window
4754
+ this.setMappingPropertiesWithRawDescriptor(this.microAppWindow);
4735
4755
  // inject global properties
4736
4756
  this.initStaticGlobalKeys(appName, url, this.microAppWindow);
4737
4757
  resolve();
@@ -4820,6 +4840,7 @@ class WithSandBox {
4820
4840
  }
4821
4841
  /**
4822
4842
  * inject global properties to microAppWindow
4843
+ * TODO: 设置为只读变量
4823
4844
  * @param appName app name
4824
4845
  * @param url app url
4825
4846
  * @param microAppWindow micro window
@@ -4833,6 +4854,7 @@ class WithSandBox {
4833
4854
  microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
4834
4855
  microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
4835
4856
  microAppWindow.__MICRO_APP_UMD_MODE__ = false;
4857
+ microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
4836
4858
  microAppWindow.__MICRO_APP_SANDBOX__ = this;
4837
4859
  microAppWindow.__MICRO_APP_SANDBOX_TYPE__ = 'with';
4838
4860
  microAppWindow.rawWindow = globalEnv.rawWindow;
@@ -4842,7 +4864,6 @@ class WithSandBox {
4842
4864
  pureCreateElement,
4843
4865
  router,
4844
4866
  });
4845
- this.setMappingPropertiesWithRawDescriptor(microAppWindow);
4846
4867
  }
4847
4868
  /**
4848
4869
  * Record global effect and then release (effect: global event, timeout, data listener)
@@ -4925,7 +4946,6 @@ class WithSandBox {
4925
4946
  */
4926
4947
  getSpecialProperties(appName) {
4927
4948
  var _a;
4928
- this.scopeProperties = this.scopeProperties.concat(this.adapter.staticScopeProperties);
4929
4949
  if (isPlainObject(microApp.options.plugins)) {
4930
4950
  this.commonActionForSpecialProperties(microApp.options.plugins.global);
4931
4951
  this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
@@ -4967,9 +4987,10 @@ class WithSandBox {
4967
4987
  topValue = rawWindow.top;
4968
4988
  parentValue = rawWindow.parent;
4969
4989
  }
4970
- // TODO: 用rawDefineProperties
4971
- rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
4972
- rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
4990
+ rawDefineProperties(microAppWindow, {
4991
+ top: this.createDescriptorForMicroAppWindow('top', topValue),
4992
+ parent: this.createDescriptorForMicroAppWindow('parent', parentValue),
4993
+ });
4973
4994
  GLOBAL_KEY_TO_WINDOW.forEach((key) => {
4974
4995
  rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
4975
4996
  });
@@ -5134,7 +5155,7 @@ class WithSandBox {
5134
5155
  WithSandBox.activeCount = 0; // number of active sandbox
5135
5156
 
5136
5157
  function patchRouter(appName, url, microAppWindow, browserHost) {
5137
- const childStaticLocation = new URL(url);
5158
+ const childStaticLocation = createURL(url);
5138
5159
  const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
5139
5160
  const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
5140
5161
  // rewrite microAppWindow.history
@@ -5227,18 +5248,35 @@ function patchWindowProperty$1(appName, microAppWindow) {
5227
5248
  */
5228
5249
  function createProxyWindow$1(microAppWindow, sandbox) {
5229
5250
  const rawWindow = globalEnv.rawWindow;
5230
- 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
+ */
5231
5259
  const proxyWindow = new Proxy(microAppWindow, {
5232
5260
  get: (target, key) => {
5233
5261
  if (key === 'location') {
5234
5262
  return sandbox.proxyLocation;
5235
5263
  }
5236
- if (GLOBAL_KEY_TO_WINDOW.includes(key.toString())) {
5264
+ if (includes(GLOBAL_KEY_TO_WINDOW, key)) {
5237
5265
  return proxyWindow;
5238
5266
  }
5239
- if (customProperties.includes(key)) {
5267
+ if (customProperties.has(key)) {
5240
5268
  return Reflect.get(target, key);
5241
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
+ }
5242
5280
  return bindFunctionToRawTarget(Reflect.get(target, key), target);
5243
5281
  },
5244
5282
  set: (target, key, value) => {
@@ -5246,10 +5284,10 @@ function createProxyWindow$1(microAppWindow, sandbox) {
5246
5284
  return Reflect.set(rawWindow, key, value);
5247
5285
  }
5248
5286
  if (!Reflect.has(target, key)) {
5249
- customProperties.push(key);
5287
+ customProperties.add(key);
5250
5288
  }
5251
5289
  Reflect.set(target, key, value);
5252
- if (sandbox.escapeProperties.includes(key)) {
5290
+ if (includes(sandbox.escapeProperties, key)) {
5253
5291
  !Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
5254
5292
  Reflect.set(rawWindow, key, value);
5255
5293
  }
@@ -5364,7 +5402,9 @@ function patchDocumentPrototype(appName, microAppWindow) {
5364
5402
  const microRootDocument = microAppWindow.Document;
5365
5403
  const microDocument = microAppWindow.document;
5366
5404
  const rawMicroCreateElement = microRootDocument.prototype.createElement;
5405
+ const rawMicroCreateElementNS = microRootDocument.prototype.createElementNS;
5367
5406
  const rawMicroCreateTextNode = microRootDocument.prototype.createTextNode;
5407
+ const rawMicroCreateDocumentFragment = microRootDocument.prototype.createDocumentFragment;
5368
5408
  const rawMicroCreateComment = microRootDocument.prototype.createComment;
5369
5409
  const rawMicroQuerySelector = microRootDocument.prototype.querySelector;
5370
5410
  const rawMicroQuerySelectorAll = microRootDocument.prototype.querySelectorAll;
@@ -5385,10 +5425,18 @@ function patchDocumentPrototype(appName, microAppWindow) {
5385
5425
  const element = rawMicroCreateElement.call(this, tagName, options);
5386
5426
  return updateElementInfo(element, appName);
5387
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
+ };
5388
5432
  microRootDocument.prototype.createTextNode = function createTextNode(data) {
5389
5433
  const element = rawMicroCreateTextNode.call(this, data);
5390
5434
  return updateElementInfo(element, appName);
5391
5435
  };
5436
+ microRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
5437
+ const element = rawMicroCreateDocumentFragment.call(this);
5438
+ return updateElementInfo(element, appName);
5439
+ };
5392
5440
  microRootDocument.prototype.createComment = function createComment(data) {
5393
5441
  const element = rawMicroCreateComment.call(this, data);
5394
5442
  return updateElementInfo(element, appName);
@@ -5489,6 +5537,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5489
5537
  const createDescriptors = () => {
5490
5538
  const result = {};
5491
5539
  const descList = [
5540
+ // if disable-memory-router or router-mode='disable', href point to base app
5492
5541
  ['documentURI', () => sandbox.proxyLocation.href],
5493
5542
  ['URL', () => sandbox.proxyLocation.href],
5494
5543
  ['documentElement', () => rawDocument.documentElement],
@@ -5722,6 +5771,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5722
5771
  // return rootNode
5723
5772
  };
5724
5773
  microRootNode.prototype.appendChild = function appendChild(node) {
5774
+ // TODO: 有必要执行这么多次updateElementInfo?
5725
5775
  updateElementInfo(node, appName);
5726
5776
  if (isPureNode(node)) {
5727
5777
  return rawMicroAppendChild.call(this, node);
@@ -5821,7 +5871,29 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5821
5871
  rawDefineProperty(microRootNode.prototype, 'parentNode', {
5822
5872
  configurable: true,
5823
5873
  enumerable: true,
5824
- get: createGetterForIframeParentNode(appName, rawParentNodeDesc),
5874
+ get() {
5875
+ var _a, _b, _c;
5876
+ /**
5877
+ * set current appName for hijack parentNode of html
5878
+ * NOTE:
5879
+ * 1. Is there a problem with setting the current appName in iframe mode
5880
+ */
5881
+ throttleDeferForSetAppName(appName);
5882
+ const result = rawParentNodeDesc.get.call(this);
5883
+ /**
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
+ */
5892
+ if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
5893
+ return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
5894
+ }
5895
+ return result;
5896
+ }
5825
5897
  });
5826
5898
  // Adapt to new image(...) scene
5827
5899
  const ImageProxy = new Proxy(microAppWindow.Image, {
@@ -5883,14 +5955,17 @@ class IframeSandbox {
5883
5955
  this.escapeProperties = [];
5884
5956
  // Properties escape to rawWindow, cleared when unmount
5885
5957
  this.escapeKeys = new Set();
5886
- // TODO: 初始化和每次跳转时都要更新base的href
5958
+ // 初始化和每次跳转时都要更新base的href
5887
5959
  this.updateIframeBase = () => {
5888
5960
  var _a;
5889
- (_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);
5890
5963
  };
5964
+ this.appName = appName;
5965
+ this.url = url;
5891
5966
  const rawLocation = globalEnv.rawWindow.location;
5892
5967
  const browserHost = rawLocation.protocol + '//' + rawLocation.host;
5893
- this.deleteIframeElement = this.createIframeElement(appName, browserHost);
5968
+ this.deleteIframeElement = this.createIframeElement(appName, browserHost + rawLocation.pathname);
5894
5969
  this.microAppWindow = this.iframe.contentWindow;
5895
5970
  this.patchIframe(this.microAppWindow, (resolve) => {
5896
5971
  // create new html to iframe
@@ -5918,13 +5993,13 @@ class IframeSandbox {
5918
5993
  /**
5919
5994
  * create iframe for sandbox
5920
5995
  * @param appName app name
5921
- * @param browserHost browser origin
5996
+ * @param browserPath browser origin
5922
5997
  * @returns release callback
5923
5998
  */
5924
- createIframeElement(appName, browserHost) {
5999
+ createIframeElement(appName, browserPath) {
5925
6000
  this.iframe = pureCreateElement('iframe');
5926
6001
  const iframeAttrs = {
5927
- src: browserHost,
6002
+ src: microApp.options.iframeSrc || browserPath,
5928
6003
  style: 'display: none',
5929
6004
  id: appName,
5930
6005
  };
@@ -6019,6 +6094,7 @@ class IframeSandbox {
6019
6094
  * NOTE:
6020
6095
  * 1. execute as early as possible
6021
6096
  * 2. run after patchRouter & createProxyWindow
6097
+ * TODO: 设置为只读变量
6022
6098
  */
6023
6099
  initStaticGlobalKeys(appName, url, microAppWindow) {
6024
6100
  microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
@@ -6220,6 +6296,7 @@ class IframeSandbox {
6220
6296
  patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
6221
6297
  }
6222
6298
  /**
6299
+ * action before exec scripts when mount
6223
6300
  * Actions:
6224
6301
  * 1. patch static elements from html
6225
6302
  * @param container micro app container
@@ -6279,8 +6356,11 @@ class CreateApp {
6279
6356
  }
6280
6357
  /**
6281
6358
  * When resource is loaded, mount app if it is not prefetch or unmount
6359
+ * defaultPage disablePatchRequest routerMode baseroute is only for prerender app
6282
6360
  */
6283
- onLoad(html, defaultPage, disablePatchRequest, routerMode, baseroute) {
6361
+ onLoad({ html,
6362
+ // below params is only for prerender app
6363
+ defaultPage, routerMode, baseroute, disablePatchRequest, }) {
6284
6364
  var _a;
6285
6365
  if (++this.loadSourceLevel === 2) {
6286
6366
  this.source.html = html;
@@ -6311,11 +6391,11 @@ class CreateApp {
6311
6391
  this.mount({
6312
6392
  container,
6313
6393
  inline: this.inline,
6314
- routerMode: routerMode,
6315
- baseroute: baseroute || '',
6316
6394
  fiber: true,
6317
6395
  defaultPage: defaultPage || '',
6318
6396
  disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
6397
+ routerMode: routerMode,
6398
+ baseroute: baseroute || '',
6319
6399
  });
6320
6400
  }
6321
6401
  }
@@ -6385,7 +6465,7 @@ class CreateApp {
6385
6465
  */
6386
6466
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
6387
6467
  // current this.container is <div prerender='true'></div>
6388
- cloneContainer(container, this.container, false);
6468
+ this.cloneContainer(container, this.container, false);
6389
6469
  /**
6390
6470
  * set this.container to <micro-app></micro-app>
6391
6471
  * NOTE:
@@ -6421,7 +6501,7 @@ class CreateApp {
6421
6501
  appState: appStates.MOUNTING
6422
6502
  });
6423
6503
  // TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
6424
- cloneContainer(this.container, this.source.html, !this.umdMode);
6504
+ this.cloneContainer(this.container, this.source.html, !this.umdMode);
6425
6505
  (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
6426
6506
  umdMode: this.umdMode,
6427
6507
  baseroute,
@@ -6439,6 +6519,7 @@ class CreateApp {
6439
6519
  * umdHookUnmount can works in default mode
6440
6520
  * register through window.unmount
6441
6521
  */
6522
+ // TODO: 不对,这里要改,因为unmount不一定是函数
6442
6523
  this.umdHookUnmount = unmount;
6443
6524
  // if mount & unmount is function, the sub app is umd mode
6444
6525
  if (isFunction(mount) && isFunction(unmount)) {
@@ -6609,7 +6690,7 @@ class CreateApp {
6609
6690
  actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
6610
6691
  var _a;
6611
6692
  if (this.umdMode && this.container && !destroy) {
6612
- cloneContainer(this.source.html, this.container, false);
6693
+ this.cloneContainer(this.source.html, this.container, false);
6613
6694
  }
6614
6695
  /**
6615
6696
  * this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
@@ -6636,6 +6717,7 @@ class CreateApp {
6636
6717
  this.preRenderEvents = null;
6637
6718
  this.setKeepAliveState(null);
6638
6719
  // in iframe sandbox & default mode, delete the sandbox & iframeElement
6720
+ // TODO: with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
6639
6721
  if (this.iframe && !this.umdMode)
6640
6722
  this.sandBox = null;
6641
6723
  if (destroy)
@@ -6667,7 +6749,7 @@ class CreateApp {
6667
6749
  this.setLifeCycleState(lifeCycles.AFTERHIDDEN);
6668
6750
  // dispatch afterHidden event to base app
6669
6751
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
6670
- if (this.routerMode !== ROUTER_MODE_CUSTOM) {
6752
+ if (isRouterModeSearch(this.name)) {
6671
6753
  // called after lifeCyclesEvent
6672
6754
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
6673
6755
  }
@@ -6678,7 +6760,7 @@ class CreateApp {
6678
6760
  getRootContainer(this.container).unmount();
6679
6761
  }
6680
6762
  else {
6681
- this.container = cloneContainer(pureCreateElement('div'), this.container, false);
6763
+ this.container = this.cloneContainer(pureCreateElement('div'), this.container, false);
6682
6764
  (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
6683
6765
  }
6684
6766
  callback === null || callback === void 0 ? void 0 : callback();
@@ -6694,13 +6776,13 @@ class CreateApp {
6694
6776
  // dispatch beforeShow event to base app
6695
6777
  dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
6696
6778
  this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
6697
- this.container = cloneContainer(container, this.container, false);
6779
+ this.container = this.cloneContainer(container, this.container, false);
6698
6780
  /**
6699
6781
  * TODO:
6700
6782
  * 问题:当路由模式为custom时,keep-alive应用在重新展示,是否需要根据子应用location信息更新浏览器地址?
6701
6783
  * 暂时不这么做吧,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
6702
6784
  */
6703
- if (this.routerMode !== ROUTER_MODE_CUSTOM) {
6785
+ if (isRouterModeSearch(this.name)) {
6704
6786
  // called before lifeCyclesEvent
6705
6787
  (_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
6706
6788
  }
@@ -6724,6 +6806,34 @@ class CreateApp {
6724
6806
  });
6725
6807
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
6726
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
+ }
6727
6837
  /**
6728
6838
  * Scene:
6729
6839
  * 1. create app
@@ -6732,12 +6842,7 @@ class CreateApp {
6732
6842
  */
6733
6843
  createSandbox() {
6734
6844
  if (this.useSandbox && !this.sandBox) {
6735
- if (this.iframe) {
6736
- this.sandBox = new IframeSandbox(this.name, this.url);
6737
- }
6738
- else {
6739
- this.sandBox = new WithSandBox(this.name, this.url);
6740
- }
6845
+ this.sandBox = this.iframe ? new IframeSandbox(this.name, this.url) : new WithSandBox(this.name, this.url);
6741
6846
  }
6742
6847
  }
6743
6848
  // set app state
@@ -6902,10 +7007,6 @@ function handleNewNode(child, app) {
6902
7007
  */
6903
7008
  function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
6904
7009
  const hijackParent = getHijackParent(parent, targetChild, app);
6905
- /**
6906
- * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
6907
- * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
6908
- */
6909
7010
  if (hijackParent) {
6910
7011
  /**
6911
7012
  * If parentNode is <micro-app-body>, return rawDocument.body
@@ -6944,11 +7045,28 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
6944
7045
  });
6945
7046
  }
6946
7047
  }
7048
+ if ((process.env.NODE_ENV !== 'production') &&
7049
+ isIFrameElement(targetChild) &&
7050
+ rawMethod === globalEnv.rawAppendChild) {
7051
+ fixReactHMRConflict(app);
7052
+ }
6947
7053
  /**
6948
7054
  * 1. If passiveChild exists, it must be insertBefore or replaceChild
6949
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
6950
7062
  */
6951
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
+ }
6952
7070
  return globalEnv.rawAppendChild.call(hijackParent, targetChild);
6953
7071
  }
6954
7072
  else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
@@ -6957,11 +7075,6 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
6957
7075
  }
6958
7076
  return targetChild;
6959
7077
  }
6960
- if ((process.env.NODE_ENV !== 'production') &&
6961
- isIFrameElement(targetChild) &&
6962
- rawMethod === globalEnv.rawAppendChild) {
6963
- fixReactHMRConflict(app);
6964
- }
6965
7078
  return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
6966
7079
  }
6967
7080
  return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
@@ -7031,6 +7144,11 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
7031
7144
  currentAppName)) {
7032
7145
  newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
7033
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
+ }
7034
7152
  if (app === null || app === void 0 ? void 0 : app.container) {
7035
7153
  completePathDynamic(app, newChild);
7036
7154
  return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
@@ -7117,30 +7235,34 @@ function patchElementAndDocument() {
7117
7235
  this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
7118
7236
  return clonedNode;
7119
7237
  };
7120
- 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) {
7121
7245
  const currentAppName = getCurrentAppName();
7122
- if ((node === document.body || node === document.head) && currentAppName) {
7246
+ if ((target === document.body || target === document.head) && currentAppName) {
7123
7247
  const app = appInstanceMap.get(currentAppName);
7124
7248
  if (app === null || app === void 0 ? void 0 : app.container) {
7125
- if (node === document.body) {
7249
+ if (target === document.body) {
7126
7250
  return app.querySelector('micro-app-body');
7127
7251
  }
7128
- else if (node === document.head) {
7252
+ else if (target === document.head) {
7129
7253
  return app.querySelector('micro-app-head');
7130
7254
  }
7131
7255
  }
7132
7256
  }
7133
- return null;
7257
+ return target;
7134
7258
  }
7135
7259
  rawRootElement.prototype.querySelector = function querySelector(selectors) {
7136
7260
  var _a;
7137
- const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
7138
- return globalEnv.rawElementQuerySelector.call(target, selectors);
7261
+ return globalEnv.rawElementQuerySelector.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
7139
7262
  };
7140
7263
  rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
7141
7264
  var _a;
7142
- const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
7143
- return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
7265
+ return globalEnv.rawElementQuerySelectorAll.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
7144
7266
  };
7145
7267
  // rewrite setAttribute, complete resource address
7146
7268
  rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
@@ -7268,14 +7390,15 @@ function patchDocument$2() {
7268
7390
  const element = globalEnv.rawCreateElementNS.call(getBindTarget(this), namespaceURI, name, options);
7269
7391
  return markElement(element);
7270
7392
  };
7271
- rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
7272
- const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
7273
- return markElement(element);
7274
- };
7393
+ // TODO: 放开
7275
7394
  // rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
7276
7395
  // const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
7277
7396
  // return markElement(element)
7278
7397
  // }
7398
+ rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
7399
+ const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
7400
+ return markElement(element);
7401
+ };
7279
7402
  rawRootDocument.prototype.createComment = function createComment(data) {
7280
7403
  const element = globalEnv.rawCreateComment.call(getBindTarget(this), data);
7281
7404
  return markElement(element);
@@ -7288,7 +7411,7 @@ function patchDocument$2() {
7288
7411
  if (!currentAppName ||
7289
7412
  !selectors ||
7290
7413
  isUniqueElement(selectors) ||
7291
- // see https://github.com/micro-zoe/micro-app/issues/56
7414
+ // ISSUE: https://github.com/micro-zoe/micro-app/issues/56
7292
7415
  rawDocument !== _this) {
7293
7416
  return globalEnv.rawQuerySelector.call(_this, selectors);
7294
7417
  }
@@ -7438,8 +7561,8 @@ function initGlobalEnv() {
7438
7561
  // Document proto methods
7439
7562
  const rawCreateElement = rawRootDocument.prototype.createElement;
7440
7563
  const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
7441
- const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
7442
7564
  const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
7565
+ const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
7443
7566
  const rawCreateComment = rawRootDocument.prototype.createComment;
7444
7567
  const rawQuerySelector = rawRootDocument.prototype.querySelector;
7445
7568
  const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
@@ -7999,7 +8122,9 @@ function defineElement(tagName) {
7999
8122
  * @returns router-mode
8000
8123
  */
8001
8124
  getMemoryRouterMode() {
8002
- 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'));
8003
8128
  }
8004
8129
  /**
8005
8130
  * rewrite micro-app.setAttribute, process attr data
@@ -8048,6 +8173,18 @@ function defineElement(tagName) {
8048
8173
  }
8049
8174
  return null;
8050
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
+ }
8051
8188
  }
8052
8189
  globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
8053
8190
  }
@@ -8126,9 +8263,22 @@ function preFetchAction(options) {
8126
8263
  });
8127
8264
  const oldOnload = app.onLoad;
8128
8265
  const oldOnLoadError = app.onLoadError;
8129
- 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
+ }
8130
8280
  resolve();
8131
- oldOnload.call(app, html, options['default-page'], options['disable-patch-request'], getRouterMode(options['router-mode']), options.baseroute);
8281
+ oldOnload.call(app, onLoadParam);
8132
8282
  };
8133
8283
  app.onLoadError = (...rests) => {
8134
8284
  resolve();