@micro-zoe/micro-app 1.0.0-rc.4 → 1.0.0-rc.6

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.4';
1
+ const version = '1.0.0-rc.6';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -56,7 +56,8 @@ function isPromise(target) {
56
56
  }
57
57
  // is bind function
58
58
  function isBoundFunction(target) {
59
- return isFunction(target) && target.name.indexOf('bound ') === 0 && !target.hasOwnProperty('prototype');
59
+ var _a;
60
+ return isFunction(target) && ((_a = target.name) === null || _a === void 0 ? void 0 : _a.indexOf('bound ')) === 0 && !target.hasOwnProperty('prototype');
60
61
  }
61
62
  // is constructor function
62
63
  function isConstructor(target) {
@@ -109,13 +110,27 @@ function isImageElement(target) {
109
110
  function isBaseElement(target) {
110
111
  return toTypeString(target) === '[object HTMLBaseElement]';
111
112
  }
113
+ function isDocumentFragment(target) {
114
+ return toTypeString(target) === '[object DocumentFragment]';
115
+ }
112
116
  function isMicroAppBody(target) {
113
117
  return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-BODY';
114
118
  }
119
+ function isMicroAppHead(target) {
120
+ return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-HEAD';
121
+ }
115
122
  // is ProxyDocument
116
123
  function isProxyDocument(target) {
117
124
  return toTypeString(target) === '[object ProxyDocument]';
118
125
  }
126
+ function isTargetExtension(path, suffix) {
127
+ try {
128
+ return createURL(path).pathname.split('.').pop() === suffix;
129
+ }
130
+ catch (_a) {
131
+ return false;
132
+ }
133
+ }
119
134
  function includes(target, searchElement, fromIndex) {
120
135
  if (target == null) {
121
136
  throw new TypeError('includes target is null or undefined');
@@ -172,6 +187,14 @@ function logWarn(msg, appName = null, ...rest) {
172
187
  function defer(fn, ...args) {
173
188
  Promise.resolve().then(fn.bind(null, ...args));
174
189
  }
190
+ /**
191
+ * async execution with macro task
192
+ * @param fn callback
193
+ * @param args params
194
+ */
195
+ function macro(fn, delay = 0, ...args) {
196
+ setTimeout(fn.bind(null, ...args), delay);
197
+ }
175
198
  /**
176
199
  * create URL as MicroLocation
177
200
  */
@@ -200,12 +223,12 @@ function formatAppURL(url, appName = null) {
200
223
  return '';
201
224
  try {
202
225
  const { origin, pathname, search } = createURL(addProtocol(url), (window.rawWindow || window).location.href);
203
- // If it ends with .html/.node/.php/.net/.etc, don’t need to add /
204
- if (/\.(\w+)$/.test(pathname)) {
205
- return `${origin}${pathname}${search}`;
206
- }
207
- const fullPath = `${origin}${pathname}/`.replace(/\/\/$/, '/');
208
- return /^https?:\/\//.test(fullPath) ? `${fullPath}${search}` : '';
226
+ /**
227
+ * keep the original url unchanged, such as .html .node .php .net .etc, search, except hash
228
+ * BUG FIX: Never using '/' to complete url, refer to https://github.com/micro-zoe/micro-app/issues/1147
229
+ */
230
+ const fullPath = `${origin}${pathname}${search}`;
231
+ return /^https?:\/\//.test(fullPath) ? fullPath : '';
209
232
  }
210
233
  catch (e) {
211
234
  logError(e, appName);
@@ -228,14 +251,15 @@ function formatAppName(name) {
228
251
  return name.replace(/(^\d+)|([^\w\d-_])/gi, '');
229
252
  }
230
253
  /**
231
- * Get valid address, such as https://xxx/xx/xx.html to https://xxx/xx/
254
+ * Get valid address, such as
255
+ * 1. https://domain/xx/xx.html to https://domain/xx/
256
+ * 2. https://domain/xx to https://domain/xx/
232
257
  * @param url app.url
233
258
  */
234
259
  function getEffectivePath(url) {
235
260
  const { origin, pathname } = createURL(url);
236
261
  if (/\.(\w+)$/.test(pathname)) {
237
- const fullPath = `${origin}${pathname}`;
238
- const pathArr = fullPath.split('/');
262
+ const pathArr = `${origin}${pathname}`.split('/');
239
263
  pathArr.pop();
240
264
  return pathArr.join('/') + '/';
241
265
  }
@@ -334,33 +358,65 @@ function promiseRequestIdle(callback) {
334
358
  /**
335
359
  * Record the currently running app.name
336
360
  */
337
- let currentMicroAppName = null;
361
+ let currentAppName = null;
338
362
  function setCurrentAppName(appName) {
339
- currentMicroAppName = appName;
363
+ currentAppName = appName;
340
364
  }
341
365
  // get the currently running app.name
342
366
  function getCurrentAppName() {
343
- return currentMicroAppName;
367
+ return currentAppName;
344
368
  }
345
- // Clear appName
346
- let preventSetAppName = false;
347
- function removeDomScope(force) {
348
- setCurrentAppName(null);
349
- if (force && !preventSetAppName) {
350
- preventSetAppName = true;
369
+ function throttleDeferForSetAppName(appName) {
370
+ if (currentAppName !== appName && !getPreventSetState()) {
371
+ setCurrentAppName(appName);
351
372
  defer(() => {
352
- preventSetAppName = false;
373
+ setCurrentAppName(null);
353
374
  });
354
375
  }
355
376
  }
356
- function throttleDeferForSetAppName(appName) {
357
- if (currentMicroAppName !== appName && !preventSetAppName) {
358
- setCurrentAppName(appName);
377
+ // only for iframe document.body(head).querySelector(querySelectorAll)
378
+ let iframeCurrentAppName = null;
379
+ function setIframeCurrentAppName(appName) {
380
+ iframeCurrentAppName = appName;
381
+ }
382
+ function getIframeCurrentAppName() {
383
+ return iframeCurrentAppName;
384
+ }
385
+ function throttleDeferForIframeAppName(appName) {
386
+ if (iframeCurrentAppName !== appName && !getPreventSetState()) {
387
+ setIframeCurrentAppName(appName);
359
388
  defer(() => {
360
- setCurrentAppName(null);
389
+ setIframeCurrentAppName(null);
361
390
  });
362
391
  }
363
392
  }
393
+ // prevent set app name
394
+ let preventSetState = false;
395
+ function getPreventSetState() {
396
+ return preventSetState;
397
+ }
398
+ /**
399
+ * prevent set appName
400
+ * usage:
401
+ * removeDomScope(true)
402
+ * -----> element scope point to base app <-----
403
+ * removeDomScope(false)
404
+ */
405
+ function removeDomScope(force) {
406
+ if (force !== false) {
407
+ setCurrentAppName(null);
408
+ setIframeCurrentAppName(null);
409
+ if (force && !preventSetState) {
410
+ preventSetState = true;
411
+ defer(() => {
412
+ preventSetState = false;
413
+ });
414
+ }
415
+ }
416
+ else {
417
+ preventSetState = false;
418
+ }
419
+ }
364
420
  /**
365
421
  * Create pure elements
366
422
  */
@@ -553,13 +609,39 @@ function clearDOM($dom) {
553
609
  $dom.removeChild($dom.firstChild);
554
610
  }
555
611
  }
612
+ function instanceOf(instance, constructor) {
613
+ if (instance === null || instance === undefined) {
614
+ return false;
615
+ }
616
+ else if (!isFunction(constructor)) {
617
+ throw new TypeError("Right-hand side of 'instanceof' is not callable");
618
+ }
619
+ let proto = Object.getPrototypeOf(instance);
620
+ while (proto) {
621
+ if (proto === constructor.prototype) {
622
+ return true;
623
+ }
624
+ proto = Object.getPrototypeOf(proto);
625
+ }
626
+ return false;
627
+ }
556
628
  /**
557
- * get HTMLElement from base app
558
- * @returns HTMLElement
629
+ * Format event name
630
+ * In with sandbox, child event and lifeCycles bind to microAppElement, there are two events with same name - mounted unmount, it should be handled specifically to prevent conflicts
631
+ * Issue: https://github.com/micro-zoe/micro-app/issues/1161
632
+ * @param type event name
633
+ * @param appName app name
559
634
  */
560
- function getBaseHTMLElement() {
561
- var _a;
562
- return (((_a = window.rawWindow) === null || _a === void 0 ? void 0 : _a.HTMLElement) || window.HTMLElement);
635
+ const formatEventList = ['mounted', 'unmount'];
636
+ function formatEventType(type, appName) {
637
+ return formatEventList.includes(type) ? `${type}-${appName}` : type;
638
+ }
639
+ /**
640
+ * Is the object empty
641
+ * target maybe number, string, array ...
642
+ */
643
+ function isEmptyObject(target) {
644
+ return isPlainObject(target) ? !Object.keys(target).length : true;
563
645
  }
564
646
 
565
647
  function formatEventInfo(event, element) {
@@ -587,7 +669,7 @@ function formatEventInfo(event, element) {
587
669
  function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
588
670
  var _a;
589
671
  if (!element) {
590
- return logError(`element does not exist in lifecycle ${lifecycleName}`, appName);
672
+ return logWarn(`element does not exist in lifecycle ${lifecycleName}`, appName);
591
673
  }
592
674
  element = getRootContainer(element);
593
675
  // clear dom scope before dispatch lifeCycles event to base app, especially mounted & unmount
@@ -604,19 +686,19 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
604
686
  formatEventInfo(event, element);
605
687
  // global hooks
606
688
  if (isFunction((_a = microApp.options.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
607
- microApp.options.lifeCycles[lifecycleName](event);
689
+ microApp.options.lifeCycles[lifecycleName](event, appName);
608
690
  }
609
691
  element.dispatchEvent(event);
610
692
  }
611
693
  /**
612
694
  * Dispatch custom event to micro app
613
695
  * @param app app
614
- * @param eventName event name ['unmount', 'appstate-change']
696
+ * @param eventName event name ['mounted', 'unmount', 'appstate-change', 'statechange']
615
697
  * @param detail event detail
616
698
  */
617
699
  function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
618
700
  var _a;
619
- const event = new CustomEvent(eventName, {
701
+ const event = new CustomEvent(formatEventType(eventName, app.name), {
620
702
  detail,
621
703
  });
622
704
  (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microAppWindow.dispatchEvent(event);
@@ -660,7 +742,8 @@ class HTMLLoader {
660
742
  run(app, successCb) {
661
743
  const appName = app.name;
662
744
  const htmlUrl = app.ssrUrl || app.url;
663
- const htmlPromise = htmlUrl.includes('.js')
745
+ const isJsResource = isTargetExtension(htmlUrl, 'js');
746
+ const htmlPromise = isJsResource
664
747
  ? Promise.resolve(`<micro-app-head><script src='${htmlUrl}'></script></micro-app-head><micro-app-body></micro-app-body>`)
665
748
  : fetchSource(htmlUrl, appName, { cache: 'no-cache' });
666
749
  htmlPromise.then((htmlStr) => {
@@ -793,9 +876,24 @@ class CSSParser {
793
876
  const m = this.commonMatch(/^[^{]+/, skip);
794
877
  if (!m)
795
878
  return false;
879
+ /**
880
+ * NOTE:
881
+ * 1. :is(h1, h2, h3):has(+ h2, + h3, + h4) {}
882
+ * should be ==> micro-app[name=xxx] :is(h1, h2, h3):has(+ h2, + h3, + h4) {}
883
+ * 2. :dir(ltr) {}
884
+ * should be ==> micro-app[name=xxx] :dir(ltr) {}
885
+ * 3. body :not(div, .fancy) {}
886
+ * should be ==> micro-app[name=xxx] micro-app-body :not(div, .fancy) {}
887
+ * 4. .a, .b, li:nth-child(3)
888
+ * should be ==> micro-app[name=xxx] .a, micro-app[name=xxx] .b, micro-app[name=xxx] li:nth-child(3)
889
+ * 5. :is(.a, .b, .c) a {}
890
+ * should be ==> micro-app[name=xxx] :is(.a, .b, .c) a {}
891
+ * 6. :where(.a, .b, .c) a {}
892
+ * should be ==> micro-app[name=xxx] :where(.a, .b, .c) a {}
893
+ */
796
894
  return m[0].replace(/(^|,[\n\s]*)([^,]+)/g, (_, separator, selector) => {
797
895
  selector = trim(selector);
798
- if (!(this.scopecssDisableNextLine ||
896
+ if (selector && !(this.scopecssDisableNextLine ||
799
897
  (this.scopecssDisable && (!this.scopecssDisableSelectors.length ||
800
898
  this.scopecssDisableSelectors.includes(selector))) ||
801
899
  rootSelectorREG.test(selector))) {
@@ -818,13 +916,13 @@ class CSSParser {
818
916
  return parseError("Declaration missing '}'", this.linkPath);
819
917
  return true;
820
918
  }
821
- matchAllDeclarations(nesting = 1) {
919
+ matchAllDeclarations(nesting = 0) {
822
920
  let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^{}/])*/, true)[0];
823
921
  if (cssValue) {
824
922
  if (!this.scopecssDisableNextLine &&
825
923
  (!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
826
924
  cssValue = cssValue.replace(/url\(["']?([^)"']+)["']?\)/gm, (all, $1) => {
827
- if (/^((data|blob):|#)/.test($1) || /^(https?:)?\/\//.test($1)) {
925
+ if (/^((data|blob):|#|%23)/.test($1) || /^(https?:)?\/\//.test($1)) {
828
926
  return all;
829
927
  }
830
928
  // ./a/b.png ../a/b.png a/b.png
@@ -840,14 +938,6 @@ class CSSParser {
840
938
  this.scopecssDisableNextLine = false;
841
939
  if (!this.cssText)
842
940
  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
- }
851
941
  // extract comments in declarations
852
942
  if (this.cssText.charAt(0) === '/') {
853
943
  if (this.cssText.charAt(1) === '*') {
@@ -857,10 +947,16 @@ class CSSParser {
857
947
  this.commonMatch(/\/+/);
858
948
  }
859
949
  }
860
- if (this.cssText.charAt(0) === '{') {
861
- this.commonMatch(/{+\s*/);
950
+ else if (this.cssText.charAt(0) === '{') {
951
+ this.matchOpenBrace();
862
952
  nesting++;
863
953
  }
954
+ else if (this.cssText.charAt(0) === '}') {
955
+ if (nesting < 1)
956
+ return;
957
+ this.matchCloseBrace();
958
+ nesting--;
959
+ }
864
960
  return this.matchAllDeclarations(nesting);
865
961
  }
866
962
  matchAtRule() {
@@ -879,7 +975,8 @@ class CSSParser {
879
975
  this.documentRule() ||
880
976
  this.pageRule() ||
881
977
  this.hostRule() ||
882
- this.fontFaceRule();
978
+ this.fontFaceRule() ||
979
+ this.layerRule();
883
980
  }
884
981
  // :global is CSS Modules rule, it will be converted to normal syntax
885
982
  // private matchGlobalRule (): boolean | void {
@@ -941,6 +1038,19 @@ class CSSParser {
941
1038
  return false;
942
1039
  return this.commonHandlerForAtRuleWithSelfRule('font-face');
943
1040
  }
1041
+ // https://developer.mozilla.org/en-US/docs/Web/CSS/@layer
1042
+ layerRule() {
1043
+ if (!this.commonMatch(/^@layer\s*([^{;]+)/))
1044
+ return false;
1045
+ if (!this.matchOpenBrace())
1046
+ return !!this.commonMatch(/^[;]+/);
1047
+ this.matchComments();
1048
+ this.matchRules();
1049
+ if (!this.matchCloseBrace())
1050
+ return parseError('@layer missing \'}\'', this.linkPath);
1051
+ this.matchLeadingSpaces();
1052
+ return true;
1053
+ }
944
1054
  // common matcher for @media, @supports, @document, @host, :global, @container
945
1055
  createMatcherForRuleWithChildRule(reg, name) {
946
1056
  return () => {
@@ -1036,7 +1146,7 @@ class CSSParser {
1036
1146
  return this.commonMatch(/^{\s*/);
1037
1147
  }
1038
1148
  matchCloseBrace() {
1039
- return this.commonMatch(/^}/);
1149
+ return this.commonMatch(/^}\s*/);
1040
1150
  }
1041
1151
  // match and slice the leading spaces
1042
1152
  matchLeadingSpaces() {
@@ -1250,7 +1360,7 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
1250
1360
  return { address: href, linkInfo };
1251
1361
  }
1252
1362
  }
1253
- else if (rel && ['prefetch', 'preload', 'prerender'].includes(rel)) {
1363
+ else if (rel && ['prefetch', 'preload', 'prerender', 'modulepreload', 'icon'].includes(rel)) {
1254
1364
  // preload prefetch prerender ....
1255
1365
  if (isDynamic) {
1256
1366
  replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
@@ -1464,23 +1574,37 @@ var MicroAppConfig;
1464
1574
  MicroAppConfig["DISABLE_MEMORY_ROUTER"] = "disable-memory-router";
1465
1575
  MicroAppConfig["DISABLE_PATCH_REQUEST"] = "disable-patch-request";
1466
1576
  MicroAppConfig["KEEP_ROUTER_STATE"] = "keep-router-state";
1467
- MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
1468
1577
  MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
1469
1578
  MicroAppConfig["CLEAR_DATA"] = "clear-data";
1470
1579
  MicroAppConfig["SSR"] = "ssr";
1471
1580
  MicroAppConfig["FIBER"] = "fiber";
1472
1581
  })(MicroAppConfig || (MicroAppConfig = {}));
1582
+ /**
1583
+ * global key must be static key, they can not rewrite
1584
+ * e.g.
1585
+ * window.Promise = newValue
1586
+ * new Promise ==> still get old value, not newValue, because they are cached by top function
1587
+ * NOTE:
1588
+ * 1. Do not add fetch, XMLHttpRequest, EventSource
1589
+ */
1590
+ const GLOBAL_CACHED_KEY = 'window,self,globalThis,document,Document,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
1473
1591
  // prefetch level
1474
1592
  const PREFETCH_LEVEL = [1, 2, 3];
1475
- // memory router constants
1476
- // default mode, child router info will sync to browser url
1477
- const DEFAULT_ROUTER_MODE = 'search';
1478
1593
  /**
1479
- * render base on browser url, and location.origin location.href point to base app
1480
- * equal to disable-memory-router
1594
+ * memory router modes
1481
1595
  * NOTE:
1482
1596
  * 1. The only difference between native and native-scope is location.origin, in native-scope mode location.origin point to child app
1597
+ * 2. native mode equal to disable-memory-router
1483
1598
  */
1599
+ // 临时注释,1.0版本放开,默认模式切换为state
1600
+ // // default mode, sync child app router info to history.state
1601
+ // export const DEFAULT_ROUTER_MODE = 'state'
1602
+ // // sync child app router info to browser url as search
1603
+ // export const ROUTER_MODE_SEARCH = 'search'
1604
+ // 临时放开,1.0版本去除
1605
+ const ROUTER_MODE_STATE = 'state';
1606
+ const DEFAULT_ROUTER_MODE = 'search';
1607
+ // render base on browser url, and location.origin location.href point to base app
1484
1608
  const ROUTER_MODE_NATIVE = 'native';
1485
1609
  // render base on browser url, but location.origin location.href point to child app
1486
1610
  const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
@@ -1488,32 +1612,45 @@ const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
1488
1612
  const ROUTER_MODE_PURE = 'pure';
1489
1613
  const ROUTER_MODE_LIST = [
1490
1614
  DEFAULT_ROUTER_MODE,
1615
+ ROUTER_MODE_STATE,
1491
1616
  ROUTER_MODE_NATIVE,
1492
1617
  ROUTER_MODE_NATIVE_SCOPE,
1493
1618
  ROUTER_MODE_PURE,
1494
1619
  ];
1495
1620
  // event bound to child app window
1496
- const SCOPE_WINDOW_EVENT = [
1621
+ const BASE_SCOPE_WINDOW_EVENT = [
1497
1622
  'popstate',
1498
1623
  'hashchange',
1499
1624
  'load',
1500
- 'beforeunload',
1501
1625
  'unload',
1502
1626
  'unmount',
1503
1627
  'appstate-change',
1504
1628
  'statechange',
1505
1629
  'mounted',
1506
1630
  ];
1631
+ // bind event of with sandbox
1632
+ const SCOPE_WINDOW_EVENT_OF_WITH = BASE_SCOPE_WINDOW_EVENT;
1633
+ // bind event of iframe sandbox
1634
+ const SCOPE_WINDOW_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_EVENT.concat([
1635
+ 'unhandledrejection',
1636
+ 'message'
1637
+ ]);
1507
1638
  // on event bound to child app window
1508
1639
  // TODO: with和iframe处理方式不同,需修改
1509
- const SCOPE_WINDOW_ON_EVENT = [
1640
+ const BASE_SCOPE_WINDOW_ON_EVENT = [
1510
1641
  'onpopstate',
1511
1642
  'onhashchange',
1512
1643
  'onload',
1513
- 'onbeforeunload',
1514
1644
  'onunload',
1515
1645
  'onerror'
1646
+ // 'onbeforeunload', // remove at 2024.5.30 by cangdu
1516
1647
  ];
1648
+ // bind on event of with sandbox
1649
+ const SCOPE_WINDOW_ON_EVENT_OF_WITH = BASE_SCOPE_WINDOW_ON_EVENT;
1650
+ // bind on event of iframe sandbox
1651
+ const SCOPE_WINDOW_ON_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_ON_EVENT.concat([
1652
+ 'onunhandledrejection',
1653
+ ]);
1517
1654
  // event bound to child app document
1518
1655
  const SCOPE_DOCUMENT_EVENT = [
1519
1656
  'DOMContentLoaded',
@@ -1530,15 +1667,13 @@ const GLOBAL_KEY_TO_WINDOW = [
1530
1667
  'globalThis',
1531
1668
  ];
1532
1669
  const RAW_GLOBAL_TARGET = ['rawWindow', 'rawDocument'];
1533
- /**
1534
- * global key must be static key, they can not rewrite
1535
- * e.g.
1536
- * window.Promise = newValue
1537
- * new Promise ==> still get old value, not newValue, because they are cached by top function
1538
- * NOTE:
1539
- * 1. Do not add fetch, XMLHttpRequest, EventSource
1540
- */
1541
- const GLOBAL_CACHED_KEY = 'window,self,globalThis,document,Document,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
1670
+ const HIJACK_LOCATION_KEYS = [
1671
+ 'host',
1672
+ 'hostname',
1673
+ 'port',
1674
+ 'protocol',
1675
+ 'origin',
1676
+ ];
1542
1677
 
1543
1678
  const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
1544
1679
  // whether use type='module' script
@@ -1938,6 +2073,7 @@ function execScripts(app, initHook) {
1938
2073
  * @param callback callback of module script
1939
2074
  */
1940
2075
  function runScript(address, app, scriptInfo, callback, replaceElement) {
2076
+ var _a;
1941
2077
  try {
1942
2078
  actionsBeforeRunScript(app);
1943
2079
  const appSpaceData = scriptInfo.appSpace[app.name];
@@ -1968,7 +2104,7 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
1968
2104
  */
1969
2105
  if (!replaceElement) {
1970
2106
  // TEST IGNORE
1971
- const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
2107
+ const parent = app.iframe ? (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microBody : app.querySelector('micro-app-body');
1972
2108
  parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
1973
2109
  }
1974
2110
  }
@@ -1990,7 +2126,7 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
1990
2126
  * @param originScript origin script element
1991
2127
  */
1992
2128
  function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
1993
- const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
2129
+ const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment(`dynamic script with src='${address}' extract by micro-app`);
1994
2130
  const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
1995
2131
  const runDynamicScript = () => {
1996
2132
  const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
@@ -2024,7 +2160,7 @@ function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
2024
2160
  * @param scriptInfo scriptInfo
2025
2161
  */
2026
2162
  function runDynamicInlineScript(address, app, scriptInfo) {
2027
- const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
2163
+ const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic inline script extract by micro-app');
2028
2164
  runScript(address, app, scriptInfo, void 0, replaceElement);
2029
2165
  return replaceElement;
2030
2166
  }
@@ -2202,7 +2338,7 @@ function extractSourceDom(htmlStr, app) {
2202
2338
  const fiberStyleTasks = app.isPrefetch || app.fiber ? [] : null;
2203
2339
  flatChildren(wrapElement, app, microAppHead, fiberStyleTasks);
2204
2340
  /**
2205
- * Style and link are parallel, because it takes a lot of time for link to request resources. During this period, style processing can be performed to improve efficiency.
2341
+ * Style and link are parallel, as it takes a lot of time for link to request resources. During this period, style processing can be performed to improve efficiency.
2206
2342
  */
2207
2343
  const fiberStyleResult = serialExecFiberTasks(fiberStyleTasks);
2208
2344
  if (app.source.links.size) {
@@ -2397,7 +2533,7 @@ const eventCenter = new EventCenter();
2397
2533
  function createEventName(appName, fromBaseApp) {
2398
2534
  if (!isString(appName) || !appName)
2399
2535
  return '';
2400
- return fromBaseApp ? `__from_base_app_${appName}__` : `__from_micro_app_${appName}__`;
2536
+ return fromBaseApp ? `__${appName}_from_base_app__` : `__${appName}_from_micro_app__`;
2401
2537
  }
2402
2538
  // Global data
2403
2539
  class EventCenterForGlobal {
@@ -2696,7 +2832,15 @@ function isConstructorFunction(value) {
2696
2832
  }
2697
2833
  // eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
2698
2834
  function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
2699
- if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
2835
+ /**
2836
+ * In safari, nest app like: A -> B -> C
2837
+ * if B is iframe sandbox, and C is with sandbox, same property of document in C is abnormal
2838
+ * e.g:
2839
+ * document.all:
2840
+ * - typeof document.all ==> 'function'
2841
+ * - document.all.bind ==> undefined
2842
+ */
2843
+ if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value) && value.bind) {
2700
2844
  const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
2701
2845
  if (value[cacheKey])
2702
2846
  return value[cacheKey];
@@ -2717,6 +2861,198 @@ function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
2717
2861
  return value;
2718
2862
  }
2719
2863
 
2864
+ class BaseSandbox {
2865
+ constructor(appName, url) {
2866
+ // keys that can only assigned to rawWindow
2867
+ this.rawWindowScopeKeyList = [
2868
+ 'location',
2869
+ ];
2870
+ // keys that can escape to rawWindow
2871
+ this.staticEscapeProperties = [
2872
+ 'System',
2873
+ '__cjsWrapper',
2874
+ ];
2875
+ // keys that scoped in child app
2876
+ this.staticScopeProperties = [
2877
+ 'webpackJsonp',
2878
+ 'webpackHotUpdate',
2879
+ 'Vue',
2880
+ // TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
2881
+ 'onpopstate',
2882
+ 'onhashchange',
2883
+ ];
2884
+ // Properties that can only get and set in microAppWindow, will not escape to rawWindow
2885
+ this.scopeProperties = Array.from(this.staticScopeProperties);
2886
+ // Properties that can be escape to rawWindow
2887
+ this.escapeProperties = [];
2888
+ // Properties newly added to microAppWindow
2889
+ this.injectedKeys = new Set();
2890
+ // Properties escape to rawWindow, cleared when unmount
2891
+ this.escapeKeys = new Set();
2892
+ this.appName = appName;
2893
+ this.url = url;
2894
+ this.injectReactHMRProperty();
2895
+ }
2896
+ // adapter for react
2897
+ injectReactHMRProperty() {
2898
+ if ((process.env.NODE_ENV !== 'production')) {
2899
+ // react child in non-react env
2900
+ this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
2901
+ // in react parent
2902
+ if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
2903
+ this.staticScopeProperties = this.staticScopeProperties.concat([
2904
+ '__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
2905
+ '__reactRefreshInjected',
2906
+ ]);
2907
+ }
2908
+ }
2909
+ }
2910
+ }
2911
+ /**
2912
+ * TODO:
2913
+ * 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
2914
+ * 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
2915
+ * 修改时机:在iframe沙箱支持插件后再修改
2916
+ */
2917
+ class CustomWindow {
2918
+ }
2919
+ // Fix conflict of babel-polyfill@6.x
2920
+ function fixBabelPolyfill6() {
2921
+ if (globalEnv.rawWindow._babelPolyfill)
2922
+ globalEnv.rawWindow._babelPolyfill = false;
2923
+ }
2924
+ /**
2925
+ * Fix error of hot reload when parent&child created by create-react-app in development environment
2926
+ * Issue: https://github.com/micro-zoe/micro-app/issues/382
2927
+ */
2928
+ function fixReactHMRConflict(app) {
2929
+ var _a;
2930
+ if ((process.env.NODE_ENV !== 'production')) {
2931
+ const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
2932
+ const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
2933
+ if (rawReactErrorHook && childReactErrorHook) {
2934
+ globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
2935
+ defer(() => {
2936
+ globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
2937
+ });
2938
+ }
2939
+ }
2940
+ }
2941
+ /**
2942
+ * update dom tree of target dom
2943
+ * @param container target dom
2944
+ * @param appName app name
2945
+ */
2946
+ function patchElementTree(container, appName) {
2947
+ const children = Array.from(container.childNodes);
2948
+ children.length && children.forEach((child) => {
2949
+ patchElementTree(child, appName);
2950
+ });
2951
+ updateElementInfo(container, appName);
2952
+ }
2953
+ /**
2954
+ * rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
2955
+ * @param node target node
2956
+ * @param appName app name
2957
+ * @returns target node
2958
+ */
2959
+ function updateElementInfo(node, appName) {
2960
+ var _a, _b;
2961
+ if (appName &&
2962
+ isNode(node) &&
2963
+ node.__MICRO_APP_NAME__ !== appName &&
2964
+ !node.__PURE_ELEMENT__ &&
2965
+ !getPreventSetState()) {
2966
+ /**
2967
+ * TODO:
2968
+ * 1. 测试baseURI和ownerDocument在with沙箱中是否正确
2969
+ * 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
2970
+ */
2971
+ rawDefineProperties(node, {
2972
+ __MICRO_APP_NAME__: {
2973
+ configurable: true,
2974
+ enumerable: true,
2975
+ writable: true,
2976
+ value: appName,
2977
+ },
2978
+ });
2979
+ /**
2980
+ * In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
2981
+ *
2982
+ * Performance:
2983
+ * iframe element.__proto__ === browser HTMLElement.prototype // Chrome: false, FireFox: true
2984
+ * iframe element.__proto__ === iframe HTMLElement.prototype // Chrome: true, FireFox: false
2985
+ *
2986
+ * NOTE:
2987
+ * 1. Node.prototype.baseURI
2988
+ * 2. Node.prototype.ownerDocument
2989
+ * 3. Node.prototype.parentNode
2990
+ * 4. Node.prototype.getRootNode
2991
+ * 5. Node.prototype.cloneNode
2992
+ * 6. Element.prototype.innerHTML
2993
+ * 7. Image
2994
+ */
2995
+ if (isIframeSandbox(appName)) {
2996
+ const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
2997
+ if (proxyWindow) {
2998
+ rawDefineProperties(node, {
2999
+ baseURI: {
3000
+ configurable: true,
3001
+ enumerable: true,
3002
+ get: () => proxyWindow.location.href,
3003
+ },
3004
+ ownerDocument: {
3005
+ configurable: true,
3006
+ enumerable: true,
3007
+ get: () => node !== proxyWindow.document ? proxyWindow.document : null,
3008
+ },
3009
+ parentNode: getIframeParentNodeDesc(appName, globalEnv.rawParentNodeDesc),
3010
+ getRootNode: {
3011
+ configurable: true,
3012
+ enumerable: true,
3013
+ writable: true,
3014
+ value: function getRootNode() {
3015
+ return proxyWindow.document;
3016
+ }
3017
+ },
3018
+ });
3019
+ }
3020
+ }
3021
+ }
3022
+ return node;
3023
+ }
3024
+ /**
3025
+ * get Descriptor of Node.prototype.parentNode for iframe
3026
+ * @param appName app name
3027
+ * @param parentNode parentNode Descriptor of iframe or browser
3028
+ */
3029
+ function getIframeParentNodeDesc(appName, parentNodeDesc) {
3030
+ return {
3031
+ configurable: true,
3032
+ enumerable: true,
3033
+ get() {
3034
+ var _a, _b, _c, _d;
3035
+ throttleDeferForIframeAppName(appName);
3036
+ const result = (_a = parentNodeDesc.get) === null || _a === void 0 ? void 0 : _a.call(this);
3037
+ /**
3038
+ * If parentNode is <micro-app-body>, return rawDocument.body
3039
+ * Scenes:
3040
+ * 1. element-ui@2/lib/utils/vue-popper.js
3041
+ * if (this.popperElm.parentNode === document.body) ...
3042
+ * e.g.:
3043
+ * 1. element-ui@2.x el-dropdown
3044
+ * WARNING:
3045
+ * Will it cause other problems ?
3046
+ * e.g. target.parentNode.remove(target)
3047
+ */
3048
+ if (isMicroAppBody(result) && ((_b = appInstanceMap.get(appName)) === null || _b === void 0 ? void 0 : _b.container)) {
3049
+ return ((_d = (_c = microApp.options).getRootElementParentNode) === null || _d === void 0 ? void 0 : _d.call(_c, this, appName)) || globalEnv.rawDocument.body;
3050
+ }
3051
+ return result;
3052
+ }
3053
+ };
3054
+ }
3055
+
2720
3056
  /**
2721
3057
  * create proxyDocument and MicroDocument, rewrite document of child app
2722
3058
  * @param appName app name
@@ -2757,13 +3093,11 @@ function createProxyDocument(appName, sandbox) {
2757
3093
  const { rawDocument, rawCreateElement, rawCreateElementNS, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
2758
3094
  function createElement(tagName, options) {
2759
3095
  const element = rawCreateElement.call(rawDocument, tagName, options);
2760
- element.__MICRO_APP_NAME__ = appName;
2761
- return element;
3096
+ return updateElementInfo(element, appName);
2762
3097
  }
2763
3098
  function createElementNS(namespaceURI, name, options) {
2764
3099
  const element = rawCreateElementNS.call(rawDocument, namespaceURI, name, options);
2765
- element.__MICRO_APP_NAME__ = appName;
2766
- return element;
3100
+ return updateElementInfo(element, appName);
2767
3101
  }
2768
3102
  /**
2769
3103
  * TODO:
@@ -2989,7 +3323,7 @@ function patchWindowProperty(microAppWindow) {
2989
3323
  const rawWindow = globalEnv.rawWindow;
2990
3324
  Object.getOwnPropertyNames(rawWindow)
2991
3325
  .filter((key) => {
2992
- return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT.includes(key);
3326
+ return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_WITH.includes(key);
2993
3327
  })
2994
3328
  .forEach((eventName) => {
2995
3329
  const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(rawWindow, eventName) || {
@@ -3138,7 +3472,7 @@ function patchWindowEffect(microAppWindow, appName) {
3138
3472
  */
3139
3473
  function getEventTarget(type) {
3140
3474
  var _a;
3141
- if (SCOPE_WINDOW_EVENT.includes(type) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
3475
+ if (SCOPE_WINDOW_EVENT_OF_WITH.includes(type) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
3142
3476
  return getRootContainer(appInstanceMap.get(appName).container);
3143
3477
  }
3144
3478
  return rawWindow;
@@ -3151,6 +3485,7 @@ function patchWindowEffect(microAppWindow, appName) {
3151
3485
  * window.addEventListener.call(非window, type, listener, options)
3152
3486
  */
3153
3487
  microAppWindow.addEventListener = function (type, listener, options) {
3488
+ type = formatEventType(type, appName);
3154
3489
  const listenerList = eventListenerMap.get(type);
3155
3490
  if (listenerList) {
3156
3491
  listenerList.add(listener);
@@ -3162,6 +3497,7 @@ function patchWindowEffect(microAppWindow, appName) {
3162
3497
  rawAddEventListener.call(getEventTarget(type), type, listener, options);
3163
3498
  };
3164
3499
  microAppWindow.removeEventListener = function (type, listener, options) {
3500
+ type = formatEventType(type, appName);
3165
3501
  const listenerList = eventListenerMap.get(type);
3166
3502
  if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
3167
3503
  listenerList.delete(listener);
@@ -3254,42 +3590,44 @@ function patchWindowEffect(microAppWindow, appName) {
3254
3590
  }
3255
3591
 
3256
3592
  // set micro app state to origin state
3257
- function setMicroState(appName, microState) {
3258
- if (isRouterModeSearch(appName)) {
3259
- const rawState = globalEnv.rawWindow.history.state;
3260
- const additionalState = {
3261
- microAppState: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.microAppState, {
3262
- [appName]: microState
3263
- })
3264
- };
3265
- // create new state object
3266
- return assign({}, rawState, additionalState);
3267
- }
3268
- return microState;
3593
+ function setMicroState(appName, microState, targetLocation) {
3594
+ // TODO: 验证native模式下修改state nextjs路由是否正常
3595
+ const rawState = globalEnv.rawWindow.history.state;
3596
+ const additionalState = {
3597
+ __MICRO_APP_STATE__: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__, {
3598
+ [appName]: {
3599
+ fullPath: targetLocation ? targetLocation.pathname + targetLocation.search + targetLocation.hash : null,
3600
+ state: microState !== null && microState !== void 0 ? microState : null,
3601
+ mode: getRouterMode(appName),
3602
+ }
3603
+ }),
3604
+ };
3605
+ // create new state object
3606
+ return assign({}, rawState, additionalState);
3269
3607
  }
3270
3608
  // delete micro app state form origin state
3271
3609
  function removeMicroState(appName, rawState) {
3272
- if (isRouterModeSearch(appName)) {
3273
- if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.microAppState)) {
3274
- if (!isUndefined(rawState.microAppState[appName])) {
3275
- delete rawState.microAppState[appName];
3276
- }
3277
- if (!Object.keys(rawState.microAppState).length) {
3278
- delete rawState.microAppState;
3279
- }
3610
+ if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__)) {
3611
+ if (!isUndefined(rawState.__MICRO_APP_STATE__[appName])) {
3612
+ delete rawState.__MICRO_APP_STATE__[appName];
3613
+ }
3614
+ if (!Object.keys(rawState.__MICRO_APP_STATE__).length) {
3615
+ delete rawState.__MICRO_APP_STATE__;
3280
3616
  }
3281
- return assign({}, rawState);
3282
3617
  }
3283
- return rawState;
3618
+ return !isEmptyObject(rawState) ? assign({}, rawState) : null;
3284
3619
  }
3285
3620
  // get micro app state form origin state
3286
3621
  function getMicroState(appName) {
3622
+ var _a, _b;
3623
+ const rawState = globalEnv.rawWindow.history.state;
3624
+ return ((_b = (_a = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _a === void 0 ? void 0 : _a[appName]) === null || _b === void 0 ? void 0 : _b.state) || null;
3625
+ }
3626
+ // get micro app router info state form origin state
3627
+ function getMicroRouterInfoState(appName) {
3287
3628
  var _a;
3288
3629
  const rawState = globalEnv.rawWindow.history.state;
3289
- if (isRouterModeSearch(appName)) {
3290
- return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
3291
- }
3292
- return rawState;
3630
+ return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _a === void 0 ? void 0 : _a[appName]) || null;
3293
3631
  }
3294
3632
  const ENC_AD_RE = /&/g; // %M1
3295
3633
  const ENC_EQ_RE = /=/g; // %M2
@@ -3325,17 +3663,35 @@ function formatQueryAppName(appName) {
3325
3663
  * @param appName app.name
3326
3664
  */
3327
3665
  function getMicroPathFromURL(appName) {
3328
- var _a, _b;
3329
- // TODO: pure模式从state中获取地址
3330
- if (isRouterModePure(appName))
3331
- return null;
3666
+ var _a, _b, _c, _d;
3332
3667
  const rawLocation = globalEnv.rawWindow.location;
3668
+ const rawState = globalEnv.rawWindow.history.state;
3333
3669
  if (isRouterModeSearch(appName)) {
3334
3670
  const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
3335
3671
  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)]);
3336
3672
  return isString(microPath) ? decodeMicroPath(microPath) : null;
3337
3673
  }
3338
- return rawLocation.pathname + rawLocation.search + rawLocation.hash;
3674
+ /**
3675
+ * Get fullPath from __MICRO_APP_STATE__
3676
+ * NOTE:
3677
+ * 1. state mode: all base on __MICRO_APP_STATE__
3678
+ * 2. pure mode: navigate by location.xxx may contain one-time information in __MICRO_APP_STATE__
3679
+ * 3. native mode: vue-router@4 will exec replaceState with history.state before pushState, like:
3680
+ * history.replaceState(
3681
+ * assign({}, history.state, {...}),
3682
+ * title,
3683
+ * history.state.current, <---
3684
+ * )
3685
+ * when base app jump to another page from child page, it will replace child path with base app path
3686
+ * e.g: base-home --> child-home --> child-about(will replace with child-home before jump to base-home) --> base-home, when go back, it will back to child-home not child-about
3687
+ * So we take the fullPath as standard
3688
+ */
3689
+ // 问题:1、同一个页面多个子应用,一个修改后... --- native模式不支持多个子应用同时渲染,多个子应用推荐使用其它模式
3690
+ // if (isRouterModeCustom(appName)) {
3691
+ // return rawLocation.pathname + rawLocation.search + rawLocation.hash
3692
+ // }
3693
+ // return rawState?.__MICRO_APP_STATE__?.[appName]?.fullPath || null
3694
+ return ((_d = (_c = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _c === void 0 ? void 0 : _c[appName]) === null || _d === void 0 ? void 0 : _d.fullPath) || (isRouterModeCustom(appName) ? rawLocation.pathname + rawLocation.search + rawLocation.hash : null);
3339
3695
  }
3340
3696
  /**
3341
3697
  * Attach child app fullPath to browser url
@@ -3343,10 +3699,11 @@ function getMicroPathFromURL(appName) {
3343
3699
  * @param targetLocation location of child app or rawLocation of window
3344
3700
  */
3345
3701
  function setMicroPathToURL(appName, targetLocation) {
3346
- const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3702
+ const rawLocation = globalEnv.rawWindow.location;
3703
+ let targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3347
3704
  let isAttach2Hash = false;
3348
3705
  if (isRouterModeSearch(appName)) {
3349
- let { pathname, search, hash } = globalEnv.rawWindow.location;
3706
+ let { pathname, search, hash } = rawLocation;
3350
3707
  const queryObject = getQueryObjectFromURL(search, hash);
3351
3708
  const encodedMicroPath = encodeMicroPath(targetFullPath);
3352
3709
  /**
@@ -3356,6 +3713,7 @@ function setMicroPathToURL(appName, targetLocation) {
3356
3713
  // If hash exists and search does not exist, it is considered as a hash route
3357
3714
  if (hash && !search) {
3358
3715
  isAttach2Hash = true;
3716
+ // TODO: 这里和下面的if判断可以简化一下
3359
3717
  if (queryObject.hashQuery) {
3360
3718
  queryObject.hashQuery[formatQueryAppName(appName)] = encodedMicroPath;
3361
3719
  }
@@ -3383,6 +3741,9 @@ function setMicroPathToURL(appName, targetLocation) {
3383
3741
  isAttach2Hash,
3384
3742
  };
3385
3743
  }
3744
+ if (isRouterModeState(appName) || isRouterModePure(appName)) {
3745
+ targetFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
3746
+ }
3386
3747
  return {
3387
3748
  fullPath: targetFullPath,
3388
3749
  isAttach2Hash,
@@ -3391,11 +3752,10 @@ function setMicroPathToURL(appName, targetLocation) {
3391
3752
  /**
3392
3753
  * Delete child app fullPath from browser url
3393
3754
  * @param appName app.name
3394
- * @param targetLocation target Location, default is rawLocation
3395
3755
  */
3396
- function removeMicroPathFromURL(appName, targetLocation) {
3756
+ function removeMicroPathFromURL(appName) {
3397
3757
  var _a, _b, _c, _d;
3398
- let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
3758
+ let { pathname, search, hash } = globalEnv.rawWindow.location;
3399
3759
  let isAttach2Hash = false;
3400
3760
  if (isRouterModeSearch(appName)) {
3401
3761
  const queryObject = getQueryObjectFromURL(search, hash);
@@ -3457,25 +3817,33 @@ function isEffectiveApp(appName) {
3457
3817
  */
3458
3818
  return !!(app && !app.isPrefetch);
3459
3819
  }
3820
+ /**
3821
+ * get router mode of app
3822
+ * NOTE: app maybe undefined
3823
+ */
3824
+ function getRouterMode(appName) {
3825
+ var _a;
3826
+ return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.routerMode;
3827
+ }
3460
3828
  // router mode is search
3461
3829
  function isRouterModeSearch(appName) {
3462
- const app = appInstanceMap.get(appName);
3463
- return !!(app && app.sandBox && app.routerMode === DEFAULT_ROUTER_MODE);
3830
+ return getRouterMode(appName) === DEFAULT_ROUTER_MODE;
3831
+ }
3832
+ // router mode is state
3833
+ function isRouterModeState(appName) {
3834
+ return getRouterMode(appName) === ROUTER_MODE_STATE;
3464
3835
  }
3465
3836
  // router mode is history
3466
3837
  function isRouterModeNative(appName) {
3467
- const app = appInstanceMap.get(appName);
3468
- return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_NATIVE);
3838
+ return getRouterMode(appName) === ROUTER_MODE_NATIVE;
3469
3839
  }
3470
3840
  // router mode is disable
3471
3841
  function isRouterModeNativeScope(appName) {
3472
- const app = appInstanceMap.get(appName);
3473
- return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_NATIVE_SCOPE);
3842
+ return getRouterMode(appName) === ROUTER_MODE_NATIVE_SCOPE;
3474
3843
  }
3475
3844
  // router mode is pure
3476
3845
  function isRouterModePure(appName) {
3477
- const app = appInstanceMap.get(appName);
3478
- return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_PURE);
3846
+ return getRouterMode(appName) === ROUTER_MODE_PURE;
3479
3847
  }
3480
3848
  /**
3481
3849
  * router mode is history or disable
@@ -3492,7 +3860,7 @@ function isRouterModeCustom(appName) {
3492
3860
  * @param inlineDisableMemoryRouter disable-memory-router set by micro-app element or prerender
3493
3861
  * @returns router mode
3494
3862
  */
3495
- function getRouterMode(mode, inlineDisableMemoryRouter) {
3863
+ function initRouterMode(mode, inlineDisableMemoryRouter) {
3496
3864
  /**
3497
3865
  * compatible with disable-memory-router in older versions
3498
3866
  * if disable-memory-router is true, router-mode will be disable
@@ -3518,6 +3886,7 @@ function addHistoryListener(appName) {
3518
3886
  const rawWindow = globalEnv.rawWindow;
3519
3887
  // handle popstate event and distribute to child app
3520
3888
  const popStateHandler = (e) => {
3889
+ var _a, _b, _c;
3521
3890
  /**
3522
3891
  * 1. unmount app & hidden keep-alive app will not receive popstate event
3523
3892
  * 2. filter out onlyForBrowser
@@ -3527,7 +3896,28 @@ function addHistoryListener(appName) {
3527
3896
  excludePreRender: true,
3528
3897
  }).includes(appName) &&
3529
3898
  !e.onlyForBrowser) {
3530
- updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName));
3899
+ /**
3900
+ * base app may respond to popstateEvent async(lazy load page & browser back/forward), but child app will respond to popstateEvent immediately(vue2, react), this will cause some problems
3901
+ * 2 solutions:
3902
+ * 1. child app respond to popstateEvent async -- router-event-delay
3903
+ * 2. child app will not respond to popstateEvent in some scenarios (history.state===null || history.state?__MICRO_APP_STATE__[appName])
3904
+ * NOTE 1:
3905
+ * 1. browser back/forward
3906
+ * 2. location.hash/search/pathname = xxx
3907
+ * 3. <a href="/#/xxx">, <a href="/xxx">
3908
+ * 4. history.back/go/forward
3909
+ * 5. history.pushState/replaceState
3910
+ *
3911
+ * NOTE2:
3912
+ * 1、react16 hash mode navigate by location.hash = xxx, history.state is always null, but react16 respond to popstateEvent sync
3913
+ * 2、multiple child apps may has problems
3914
+ */
3915
+ if (!isRouterModeCustom(appName) ||
3916
+ !globalEnv.rawWindow.history.state ||
3917
+ getMicroRouterInfoState(appName)) {
3918
+ const container = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container;
3919
+ macro(() => updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName)), (_c = (_b = (container && getRootContainer(container))) === null || _b === void 0 ? void 0 : _b.getRouterEventDelay()) !== null && _c !== void 0 ? _c : 0);
3920
+ }
3531
3921
  }
3532
3922
  };
3533
3923
  rawWindow.addEventListener('popstate', popStateHandler);
@@ -3545,24 +3935,26 @@ function addHistoryListener(appName) {
3545
3935
  */
3546
3936
  function updateMicroLocationWithEvent(appName, targetFullPath) {
3547
3937
  const app = appInstanceMap.get(appName);
3548
- const proxyWindow = app.sandBox.proxyWindow;
3549
- const microAppWindow = app.sandBox.microAppWindow;
3550
- let isHashChange = false;
3551
- // for hashChangeEvent
3552
- const oldHref = proxyWindow.location.href;
3553
- // Do not attach micro state to url when targetFullPath is empty
3554
- if (targetFullPath) {
3555
- const oldHash = proxyWindow.location.hash;
3556
- updateMicroLocation(appName, targetFullPath, microAppWindow.location);
3557
- isHashChange = proxyWindow.location.hash !== oldHash;
3558
- }
3559
- // dispatch formatted popStateEvent to child
3560
- dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
3561
- // dispatch formatted hashChangeEvent to child when hash change
3562
- if (isHashChange)
3563
- dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
3564
- // clear element scope before trigger event of next app
3565
- removeDomScope();
3938
+ if (app === null || app === void 0 ? void 0 : app.sandBox) {
3939
+ const proxyWindow = app.sandBox.proxyWindow;
3940
+ const microAppWindow = app.sandBox.microAppWindow;
3941
+ let isHashChange = false;
3942
+ // for hashChangeEvent
3943
+ const oldHref = proxyWindow.location.href;
3944
+ // Do not attach micro state to url when targetFullPath is empty
3945
+ if (targetFullPath) {
3946
+ const oldHash = proxyWindow.location.hash;
3947
+ updateMicroLocation(appName, targetFullPath, microAppWindow.location);
3948
+ isHashChange = proxyWindow.location.hash !== oldHash;
3949
+ }
3950
+ // dispatch formatted popStateEvent to child
3951
+ dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
3952
+ // dispatch formatted hashChangeEvent to child when hash change
3953
+ if (isHashChange)
3954
+ dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
3955
+ // clear element scope before trigger event of next app
3956
+ removeDomScope();
3957
+ }
3566
3958
  }
3567
3959
  /**
3568
3960
  * dispatch formatted popstate event to microApp
@@ -3575,14 +3967,18 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
3575
3967
  * TODO: test
3576
3968
  * angular14 takes e.type as type judgment
3577
3969
  * when e.type is popstate-appName popstate event will be invalid
3970
+ * Object.defineProperty(newPopStateEvent, 'type', {
3971
+ * value: 'popstate',
3972
+ * writable: true,
3973
+ * configurable: true,
3974
+ * enumerable: true,
3975
+ * })
3976
+ */
3977
+ /**
3978
+ * create PopStateEvent named popstate-appName with sub app state
3979
+ * TODO: feeling like there's something wrong, check carefully
3980
+ * In native mode, getMicroState(appName) return rawWindow.history.state when use microApp.router.push/replace or other scenes when state.__MICRO_APP_STATE__[appName] is null
3578
3981
  */
3579
- // Object.defineProperty(newPopStateEvent, 'type', {
3580
- // value: 'popstate',
3581
- // writable: true,
3582
- // configurable: true,
3583
- // enumerable: true,
3584
- // })
3585
- // create PopStateEvent named popstate-appName with sub app state
3586
3982
  const newPopStateEvent = new PopStateEvent('popstate', { state: getMicroState(appName) });
3587
3983
  microAppWindow.dispatchEvent(newPopStateEvent);
3588
3984
  if (!isIframeSandbox(appName)) {
@@ -3657,26 +4053,29 @@ function createMicroHistory(appName, microLocation) {
3657
4053
  return function (...rests) {
3658
4054
  var _a, _b, _c;
3659
4055
  // TODO: 测试iframe的URL兼容isURL的情况
3660
- if (isString(rests[2]) || isURL(rests[2])) {
3661
- const targetLocation = createURL(rests[2], microLocation.href);
3662
- const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3663
- if (!isRouterModePure(appName)) {
3664
- navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
3665
- }
3666
- if (targetFullPath !== microLocation.fullPath) {
3667
- updateMicroLocation(appName, targetFullPath, microLocation);
3668
- }
3669
- (_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
4056
+ rests[2] = isUndefined(rests[2]) || isNull(rests[2]) || ('' + rests[2] === '') ? microLocation.href : '' + rests[2];
4057
+ const targetLocation = createURL(rests[2], microLocation.href);
4058
+ const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
4059
+ if (!isRouterModePure(appName)) {
4060
+ navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0], targetLocation), rests[1]);
3670
4061
  }
3671
- else {
3672
- nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
4062
+ if (targetFullPath !== microLocation.fullPath) {
4063
+ updateMicroLocation(appName, targetFullPath, microLocation);
3673
4064
  }
4065
+ (_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
3674
4066
  };
3675
4067
  }
3676
4068
  const pushState = getMicroHistoryMethod('pushState');
3677
4069
  const replaceState = getMicroHistoryMethod('replaceState');
3678
- if (isIframeSandbox(appName))
3679
- return { pushState, replaceState };
4070
+ if (isIframeSandbox(appName)) {
4071
+ return {
4072
+ pushState,
4073
+ replaceState,
4074
+ go(delta) {
4075
+ return rawHistory.go(delta);
4076
+ }
4077
+ };
4078
+ }
3680
4079
  return new Proxy(rawHistory, {
3681
4080
  get(target, key) {
3682
4081
  if (key === 'state') {
@@ -3739,11 +4138,7 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
3739
4138
  const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
3740
4139
  // navigate with native history method
3741
4140
  nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
3742
- /**
3743
- * TODO:
3744
- * 1. 如果所有模式统一发送popstate事件,则isRouterModeSearch(appName)要去掉
3745
- * 2. 如果发送事件,则会导致vue router-view :key='router.path'绑定,无限卸载应用,死循环
3746
- */
4141
+ // just search mode will dispatch native event
3747
4142
  if (oldFullPath !== result.fullPath && isRouterModeSearch(appName)) {
3748
4143
  dispatchNativeEvent(appName, onlyForBrowser, oldHref);
3749
4144
  }
@@ -3760,22 +4155,22 @@ function attachRouteToBrowserURL(appName, result, state) {
3760
4155
  navigateWithNativeEvent(appName, 'replaceState', result, true, state);
3761
4156
  }
3762
4157
  /**
3763
- * When path is same, keep the microAppState in history.state
3764
- * Fix bug of missing microAppState when base app is next.js or angular
4158
+ * When path is same, keep the __MICRO_APP_STATE__ in history.state
4159
+ * Fix bug of missing __MICRO_APP_STATE__ when base app is next.js or angular
3765
4160
  * @param method history.pushState/replaceState
3766
4161
  */
3767
4162
  function reWriteHistoryMethod(method) {
3768
4163
  const rawWindow = globalEnv.rawWindow;
3769
4164
  return function (...rests) {
3770
4165
  var _a;
3771
- if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.microAppState) &&
3772
- (!isPlainObject(rests[0]) || !rests[0].microAppState) &&
4166
+ if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.__MICRO_APP_STATE__) &&
4167
+ (!isPlainObject(rests[0]) || !rests[0].__MICRO_APP_STATE__) &&
3773
4168
  (isString(rests[2]) || isURL(rests[2]))) {
3774
4169
  const currentHref = rawWindow.location.href;
3775
4170
  const targetLocation = createURL(rests[2], currentHref);
3776
4171
  if (targetLocation.href === currentHref) {
3777
4172
  rests[0] = assign({}, rests[0], {
3778
- microAppState: rawWindow.history.state.microAppState,
4173
+ __MICRO_APP_STATE__: rawWindow.history.state.__MICRO_APP_STATE__,
3779
4174
  });
3780
4175
  }
3781
4176
  }
@@ -3791,10 +4186,24 @@ function reWriteHistoryMethod(method) {
3791
4186
  excludeHiddenApp: true,
3792
4187
  excludePreRender: true,
3793
4188
  }).forEach(appName => {
3794
- if (isRouterModeSearch(appName) && !getMicroPathFromURL(appName)) {
4189
+ // TODO: 大部分情况下,history.pushState 都是先执行,micro-app后卸载,所以会产生一种情况:跳转到新地址后,search模式会在url上添加参数,卸载后再将参数删除,所以会导致浏览器地址闪烁,是否需要去掉这个功能
4190
+ if ((isRouterModeSearch(appName) || isRouterModeState(appName)) && !getMicroPathFromURL(appName)) {
3795
4191
  const app = appInstanceMap.get(appName);
3796
- attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
4192
+ attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
3797
4193
  }
4194
+ if (isRouterModeCustom(appName) && !getMicroRouterInfoState(appName)) {
4195
+ nativeHistoryNavigate(appName, 'replaceState', rawWindow.location.href, setMicroState(appName));
4196
+ }
4197
+ // if (isRouterModeCustom(appName) || isRouterModeSearch(appName)) {
4198
+ /**
4199
+ * history.pushState/replaceState后主动触发子应用响应
4200
+ * 问题:子应用的卸载可能是异步的,而跳转的地址不一定在基础路径中,太快响应pushState可能会导致url地址被子应用改变或者子应用404,Promise太快卸载时出问题、setTimeout太慢keep-alive二次渲染后出问题
4201
+ * 1、history.pushState/replaceState执行后,子应用以异步的形式被主应用卸载,Promise响应时子应用还在,导致子应用跳转404后者浏览器url被子应用修改,产生异常
4202
+ * 2、keep-alive应用二次渲染时,由于setTimeout响应过慢,子应用在渲染后才接受到popstate事件,响应新的url,从而导致状态丢失
4203
+ * 3、同一个页面多个子应用,修改地址响应
4204
+ * 4、vue3跳转前会执行一次replace,有没有影响?
4205
+ */
4206
+ // }
3798
4207
  });
3799
4208
  // fix bug for nest app
3800
4209
  removeDomScope();
@@ -3802,7 +4211,7 @@ function reWriteHistoryMethod(method) {
3802
4211
  }
3803
4212
  /**
3804
4213
  * rewrite history.pushState/replaceState
3805
- * used to fix the problem that the microAppState maybe missing when mainApp navigate to same path
4214
+ * used to fix the problem that the __MICRO_APP_STATE__ maybe missing when mainApp navigate to same path
3806
4215
  * e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
3807
4216
  */
3808
4217
  function patchHistory() {
@@ -3825,7 +4234,7 @@ function createRouterApi() {
3825
4234
  * @param state to.state
3826
4235
  */
3827
4236
  function navigateWithRawHistory(appName, methodName, targetLocation, state) {
3828
- navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
4237
+ navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null, targetLocation));
3829
4238
  // clear element scope after navigate
3830
4239
  removeDomScope();
3831
4240
  }
@@ -3843,23 +4252,13 @@ function createRouterApi() {
3843
4252
  const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
3844
4253
  const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
3845
4254
  if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
4255
+ // pure mode will not call history.pushState/replaceState
3846
4256
  if (!isRouterModePure(appName)) {
3847
4257
  const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
3848
4258
  navigateWithRawHistory(appName, methodName, targetLocation, to.state);
3849
4259
  }
3850
- /**
3851
- * TODO:
3852
- * 1. 关闭虚拟路由的跳转地址不同:baseRoute + 子应用地址,文档中要说明
3853
- * 2. 关闭虚拟路由时跳转方式不同:1、基座跳转但不发送popstate事件 2、控制子应用更新location,内部发送popstate事件。
3854
- * 核心思路:减小对基座的影响(子应用跳转不向基座发送popstate事件,其他操作一致),但这是必要的吗,只是多了一个触发popstate的操作
3855
- * 路由优化方案有两种:
3856
- * 1、减少对基座的影响,主要是解决vue循环刷新的问题
3857
- * 2、全局发送popstate事件,解决主、子都是vue3的冲突问题
3858
- * 两者选一个吧,如果选2,则下面这两行代码可以去掉
3859
- * NOTE1: history和search模式采用2,这样可以解决vue3的问题,custom采用1,避免vue循环刷新的问题,这样在用户出现问题时各有解决方案。但反过来说,每种方案又分别导致另外的问题,不统一,导致复杂度增高
3860
- * NOTE2: 关闭虚拟路由,同时发送popstate事件还是无法解决vue3的问题(毕竟history.state理论上还是会冲突),那么就没必要发送popstate事件了。
3861
- */
3862
- if (isRouterModeCustom(appName) || isRouterModePure(appName)) {
4260
+ // only search mode will dispatch PopStateEvent to browser
4261
+ if (!isRouterModeSearch(appName)) {
3863
4262
  updateMicroLocationWithEvent(appName, targetFullPath);
3864
4263
  }
3865
4264
  }
@@ -3884,27 +4283,18 @@ function createRouterApi() {
3884
4283
  * 2. disable memory-router
3885
4284
  */
3886
4285
  /**
3887
- * TODO: 子应用开始渲染但是还没渲染完成
3888
- * 1、调用跳转改如何处理
4286
+ * TODO:
4287
+ * 1、子应用开始渲染但是还没渲染完成,调用跳转改如何处理
3889
4288
  * 2、iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
3890
- * 3、hidden app 是否支持跳转
4289
+ * 3、hidden app、预渲染 app 是否支持跳转 --- 支持(这里还涉及子应用内部跳转的支持)
3891
4290
  */
3892
4291
  if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
3893
4292
  const app = appInstanceMap.get(appName);
3894
4293
  resolve(app.sandBox.sandboxReady.then(() => handleNavigate(appName, app, to, replace)));
3895
4294
  }
3896
4295
  else {
3897
- reject(logError('navigation failed, app does not exist or is inactive'));
4296
+ reject(logError('导航失败,请确保子应用渲染后再调用此方法'));
3898
4297
  }
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
4298
  // const rawLocation = globalEnv.rawWindow.location
3909
4299
  // const targetLocation = createURL(to.path, rawLocation.origin)
3910
4300
  // const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
@@ -3977,9 +4367,9 @@ function createRouterApi() {
3977
4367
  * 3. router mode is custom
3978
4368
  */
3979
4369
  function commonHandlerForAttachToURL(appName) {
3980
- if (isRouterModeSearch(appName)) {
4370
+ if (isRouterModeSearch(appName) || isRouterModeState(appName)) {
3981
4371
  const app = appInstanceMap.get(appName);
3982
- attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
4372
+ attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
3983
4373
  }
3984
4374
  }
3985
4375
  /**
@@ -4078,94 +4468,6 @@ function createRouterApi() {
4078
4468
  }
4079
4469
  const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
4080
4470
 
4081
- const escape2RawWindowKeys = [
4082
- 'getComputedStyle',
4083
- 'visualViewport',
4084
- 'matchMedia',
4085
- // 'DOMParser',
4086
- 'ResizeObserver',
4087
- 'IntersectionObserver',
4088
- ];
4089
- const escape2RawWindowRegExpKeys = [
4090
- /animationFrame$/i,
4091
- /mutationObserver$/i,
4092
- /height$|width$/i,
4093
- /offset$/i,
4094
- // /event$/i,
4095
- /selection$/i,
4096
- /^range/i,
4097
- /^screen/i,
4098
- /^scroll/i,
4099
- /X$|Y$/,
4100
- ];
4101
- const uniqueDocumentElement = [
4102
- 'body',
4103
- 'head',
4104
- 'html',
4105
- 'title',
4106
- ];
4107
- const hijackMicroLocationKeys = [
4108
- 'host',
4109
- 'hostname',
4110
- 'port',
4111
- 'protocol',
4112
- 'origin',
4113
- ];
4114
- // 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
4115
- const proxy2RawDocOrShadowKeys = [
4116
- 'childElementCount',
4117
- 'children',
4118
- 'firstElementChild',
4119
- 'firstChild',
4120
- 'lastElementChild',
4121
- 'activeElement',
4122
- 'fullscreenElement',
4123
- 'pictureInPictureElement',
4124
- 'pointerLockElement',
4125
- 'styleSheets',
4126
- ];
4127
- // 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
4128
- const proxy2RawDocOrShadowMethods = [
4129
- 'append',
4130
- 'contains',
4131
- 'replaceChildren',
4132
- 'createRange',
4133
- 'getSelection',
4134
- 'elementFromPoint',
4135
- 'elementsFromPoint',
4136
- 'getAnimations',
4137
- ];
4138
- // 直接代理到原生document上 (属性)
4139
- const proxy2RawDocumentKeys = [
4140
- 'characterSet',
4141
- 'compatMode',
4142
- 'contentType',
4143
- 'designMode',
4144
- 'dir',
4145
- 'doctype',
4146
- 'embeds',
4147
- 'fullscreenEnabled',
4148
- 'hidden',
4149
- 'implementation',
4150
- 'lastModified',
4151
- 'pictureInPictureEnabled',
4152
- 'plugins',
4153
- 'readyState',
4154
- 'referrer',
4155
- 'visibilityState',
4156
- 'fonts',
4157
- ];
4158
- // 直接代理到原生document上 (方法)
4159
- const proxy2RawDocumentMethods = [
4160
- 'execCommand',
4161
- 'createRange',
4162
- 'exitFullscreen',
4163
- 'exitPictureInPicture',
4164
- 'getElementsByTagNameNS',
4165
- 'hasFocus',
4166
- 'prepend',
4167
- ];
4168
-
4169
4471
  // origin is readonly, so we ignore when updateMicroLocation
4170
4472
  const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
4171
4473
  // origin, fullPath is necessary for guardLocation
@@ -4209,39 +4511,47 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4209
4511
  if (targetLocation.origin === proxyLocation.origin) {
4210
4512
  const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
4211
4513
  // if disable memory-router, navigate directly through rawLocation
4212
- if (isRouterModeSearch(appName)) {
4514
+ if (!isRouterModeCustom(appName)) {
4515
+ methodName = isRouterModePure(appName) ? 'replaceState' : methodName;
4213
4516
  /**
4214
4517
  * change hash with location.href will not trigger the browser reload
4215
4518
  * so we use pushState & reload to imitate href behavior
4216
4519
  * NOTE:
4217
- * 1. if child app only change hash, it should not trigger browser reload
4218
- * 2. if address is same and has hash, it should not add route stack
4520
+ * 1. if child app only change hash, it will not reload browser
4521
+ * 2. if address is same and has hash, it will not add route stack
4219
4522
  */
4220
4523
  if (targetLocation.pathname === proxyLocation.pathname &&
4221
4524
  targetLocation.search === proxyLocation.search) {
4222
4525
  let oldHref = null;
4223
- if (targetLocation.hash !== proxyLocation.hash) {
4224
- if (setMicroPathResult.isAttach2Hash)
4526
+ // NOTE: if pathname & search is same, it should record router info to history.state in pure mode
4527
+ if (targetLocation.hash !== proxyLocation.hash || isRouterModePure(appName)) {
4528
+ // search mode only
4529
+ if (setMicroPathResult.isAttach2Hash) {
4225
4530
  oldHref = rawLocation.href;
4226
- nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
4531
+ }
4532
+ // if router mode is pure and targetLocation.hash exist, it will not call nativeHistoryNavigate
4533
+ if (!isRouterModePure(appName) || !targetLocation.hash) {
4534
+ nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
4535
+ }
4227
4536
  }
4228
4537
  if (targetLocation.hash) {
4229
- dispatchNativeEvent(appName, false, oldHref);
4538
+ if (isRouterModeSearch(appName)) {
4539
+ dispatchNativeEvent(appName, false, oldHref);
4540
+ }
4541
+ else {
4542
+ updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
4543
+ }
4230
4544
  }
4231
4545
  else {
4232
4546
  reload();
4233
4547
  }
4234
4548
  return void 0;
4235
- /**
4236
- * when baseApp is hash router, address change of child can not reload browser
4237
- * so we imitate behavior of browser (reload) manually
4238
- */
4239
- }
4240
- else if (setMicroPathResult.isAttach2Hash) {
4241
- nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
4242
- reload();
4243
- return void 0;
4244
4549
  }
4550
+ // when pathname or search change, simulate behavior of browser (reload) manually
4551
+ // TODO: state模式下pushState会带上上一个页面的state,会不会有问题,尤其是vue3,应不应该将主应用的state设置为null
4552
+ nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
4553
+ reload();
4554
+ return void 0;
4245
4555
  }
4246
4556
  return setMicroPathResult.fullPath;
4247
4557
  }
@@ -4266,7 +4576,9 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4266
4576
  * pathname: /path ==> /path#hash, /path ==> /path?query
4267
4577
  * search: ?query ==> ?query#hash
4268
4578
  */
4269
- nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
4579
+ nativeHistoryNavigate(appName, (targetLocation[key] === proxyLocation[key] || isRouterModePure(appName))
4580
+ ? 'replaceState'
4581
+ : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
4270
4582
  reload();
4271
4583
  }
4272
4584
  }
@@ -4305,17 +4617,27 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4305
4617
  return target;
4306
4618
  if (key === 'fullPath')
4307
4619
  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
4312
- if (isIframe) {
4313
- // host hostname port protocol
4314
- if (hijackMicroLocationKeys.includes(key)) {
4620
+ /**
4621
+ * Special keys: host, hostname, port, protocol, origin, href
4622
+ * NOTE:
4623
+ * 1. In native mode this keys point to browser, in other mode this keys point to child app origin
4624
+ * 2. In iframe sandbox, iframe.src is base app address, so origin points to the browser by default, we need to replace it with child app origin
4625
+ * 3. In other modes, origin points to child app
4626
+ */
4627
+ if (HIJACK_LOCATION_KEYS.includes(key)) {
4628
+ if (isRouterModeNative(appName)) {
4629
+ return rawLocation[key];
4630
+ }
4631
+ if (isIframe) {
4315
4632
  return childStaticLocation[key];
4316
4633
  }
4317
- if (key === 'href') {
4318
- // do not use target, because target may be deleted
4634
+ }
4635
+ if (key === 'href') {
4636
+ if (isRouterModeNative(appName)) {
4637
+ return target[key].replace(target.origin, rawLocation.origin);
4638
+ }
4639
+ if (isIframe) {
4640
+ // target may be deleted
4319
4641
  return target[key].replace(browserHost, childHost);
4320
4642
  }
4321
4643
  }
@@ -4365,7 +4687,12 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
4365
4687
  const targetLocation = createURL(targetPath, url);
4366
4688
  // The same hash will not trigger popStateEvent
4367
4689
  if (targetLocation.hash !== proxyLocation.hash) {
4368
- navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
4690
+ if (!isRouterModePure(appName)) {
4691
+ navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, null, targetLocation));
4692
+ }
4693
+ if (!isRouterModeSearch(appName)) {
4694
+ updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
4695
+ }
4369
4696
  }
4370
4697
  }
4371
4698
  }
@@ -4407,12 +4734,12 @@ function autoTriggerNavigationGuard(appName, microLocation) {
4407
4734
  * @param microLocation micro app location
4408
4735
  * @param type auto prevent
4409
4736
  */
4410
- function updateMicroLocation(appName, path, microLocation, type) {
4737
+ function updateMicroLocation(appName, targetFullPath, microLocation, type) {
4411
4738
  var _a;
4412
4739
  // record old values of microLocation to `from`
4413
4740
  const from = createGuardLocation(appName, microLocation);
4414
4741
  // if is iframeSandbox, microLocation muse be rawLocation of iframe, not proxyLocation
4415
- const newLocation = createURL(path, microLocation.href);
4742
+ const newLocation = createURL(targetFullPath, microLocation.href);
4416
4743
  if (isIframeSandbox(appName)) {
4417
4744
  const microAppWindow = appInstanceMap.get(appName).sandBox.microAppWindow;
4418
4745
  (_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
@@ -4424,6 +4751,20 @@ function updateMicroLocation(appName, path, microLocation, type) {
4424
4751
  }
4425
4752
  microLocation.self.href = targetHref;
4426
4753
  }
4754
+ /**
4755
+ * native模式从state中取值,而浏览器地址的修改无法控制,很可能出现浏览器地址和__MICRO_APP_STATE__不一致的情况
4756
+ * 尤其是在初始化和前进后退时,由于vue-router4会主动修改url地址,倒是上述情况经常出现
4757
+ * 为了结局这个问题,在子应用初始化和响应popstate事件后,判断__MICRO_APP_STATE__和浏览器地址是否一致,如果不一致,则将浏览器地址更新为__MICRO_APP_STATE__的地址
4758
+ * 说明:
4759
+ * 1、如果__MICRO_APP_STATE__和url不一样,那么更新url的操作是对的,否则会产生url和渲染页面不一致的问题,开发者会更加困惑
4760
+ * 2、当native模式有多个子应用同时存在,其中一个修改url地址,另外一个并不会改变__MICRO_APP_STATE__,刷新就产生问题,不一致,第二是根据谁更新url?
4761
+ */
4762
+ const rawLocation = globalEnv.rawWindow.location;
4763
+ if (isRouterModeCustom(appName) &&
4764
+ (targetFullPath !== rawLocation.pathname + rawLocation.search + rawLocation.hash) &&
4765
+ type !== 'prevent') {
4766
+ nativeHistoryNavigate(appName, 'replaceState', targetFullPath, globalEnv.rawWindow.history.state);
4767
+ }
4427
4768
  // update latest values of microLocation to `to`
4428
4769
  const to = createGuardLocation(appName, microLocation);
4429
4770
  // The hook called only when fullPath changed
@@ -4432,11 +4773,6 @@ function updateMicroLocation(appName, path, microLocation, type) {
4432
4773
  }
4433
4774
  }
4434
4775
 
4435
- /**
4436
- * TODO: 关于关闭虚拟路由系统的custom、history模式
4437
- * 1. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
4438
- * 2. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
4439
- */
4440
4776
  /**
4441
4777
  * The router system has two operations: read and write
4442
4778
  * Read through location and write through history & location
@@ -4461,6 +4797,9 @@ function initRouteStateWithURL(appName, microLocation, defaultPage) {
4461
4797
  const microPath = getMicroPathFromURL(appName);
4462
4798
  if (microPath) {
4463
4799
  updateMicroLocation(appName, microPath, microLocation, 'auto');
4800
+ if (isRouterModePure(appName)) {
4801
+ removePathFromBrowser(appName);
4802
+ }
4464
4803
  }
4465
4804
  else {
4466
4805
  updateBrowserURLWithLocation(appName, microLocation, defaultPage);
@@ -4478,7 +4817,7 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
4478
4817
  updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
4479
4818
  if (!isRouterModePure(appName)) {
4480
4819
  // attach microApp route info to browser URL
4481
- attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
4820
+ attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null, microLocation));
4482
4821
  }
4483
4822
  // trigger guards after change browser URL
4484
4823
  autoTriggerNavigationGuard(appName, microLocation);
@@ -4491,14 +4830,13 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
4491
4830
  * @param keepRouteState keep-router-state is only used to control whether to clear the location of microApp, default is false
4492
4831
  */
4493
4832
  function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
4494
- if (!isRouterModeCustom(appName)) {
4495
- if (!keepRouteState) {
4496
- const { pathname, search, hash } = createURL(url);
4497
- updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
4498
- }
4499
- if (!isRouterModePure(appName)) {
4500
- removePathFromBrowser(appName);
4501
- }
4833
+ // TODO: keep-router-state 功能太弱,是否可以增加优先级,或者去掉
4834
+ if (!keepRouteState && !isRouterModeCustom(appName)) {
4835
+ const { pathname, search, hash } = createURL(url);
4836
+ updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
4837
+ }
4838
+ if (!isRouterModePure(appName)) {
4839
+ removePathFromBrowser(appName);
4502
4840
  }
4503
4841
  clearRouterWhenUnmount(appName);
4504
4842
  }
@@ -4510,130 +4848,6 @@ function removePathFromBrowser(appName) {
4510
4848
  attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
4511
4849
  }
4512
4850
 
4513
- class BaseSandbox {
4514
- constructor() {
4515
- // keys that can only assigned to rawWindow
4516
- this.rawWindowScopeKeyList = [
4517
- 'location',
4518
- ];
4519
- // keys that can escape to rawWindow
4520
- this.staticEscapeProperties = [
4521
- 'System',
4522
- '__cjsWrapper',
4523
- ];
4524
- // keys that scoped in child app
4525
- this.staticScopeProperties = [
4526
- 'webpackJsonp',
4527
- 'webpackHotUpdate',
4528
- 'Vue',
4529
- // TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
4530
- 'onpopstate',
4531
- 'onhashchange',
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();
4541
- this.injectReactHMRProperty();
4542
- }
4543
- // adapter for react
4544
- injectReactHMRProperty() {
4545
- if ((process.env.NODE_ENV !== 'production')) {
4546
- // react child in non-react env
4547
- this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
4548
- // in react parent
4549
- if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
4550
- this.staticScopeProperties = this.staticScopeProperties.concat([
4551
- '__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
4552
- '__reactRefreshInjected',
4553
- ]);
4554
- }
4555
- }
4556
- }
4557
- }
4558
- /**
4559
- * TODO:
4560
- * 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
4561
- * 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
4562
- * 修改时机:在iframe沙箱支持插件后再修改
4563
- */
4564
- class CustomWindow {
4565
- }
4566
- // Fix conflict of babel-polyfill@6.x
4567
- function fixBabelPolyfill6() {
4568
- if (globalEnv.rawWindow._babelPolyfill)
4569
- globalEnv.rawWindow._babelPolyfill = false;
4570
- }
4571
- /**
4572
- * Fix error of hot reload when parent&child created by create-react-app in development environment
4573
- * Issue: https://github.com/micro-zoe/micro-app/issues/382
4574
- */
4575
- function fixReactHMRConflict(app) {
4576
- var _a;
4577
- if ((process.env.NODE_ENV !== 'production')) {
4578
- const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
4579
- const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
4580
- if (rawReactErrorHook && childReactErrorHook) {
4581
- globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
4582
- defer(() => {
4583
- globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
4584
- });
4585
- }
4586
- }
4587
- }
4588
- /**
4589
- * update dom tree of target dom
4590
- * @param container target dom
4591
- * @param appName app name
4592
- */
4593
- function patchElementTree(container, appName) {
4594
- const children = Array.from(container.children);
4595
- children.length && children.forEach((child) => {
4596
- patchElementTree(child, appName);
4597
- });
4598
- for (const child of children) {
4599
- updateElementInfo(child, appName);
4600
- }
4601
- }
4602
- /**
4603
- * rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
4604
- * @param node target node
4605
- * @param appName app name
4606
- * @returns target node
4607
- */
4608
- function updateElementInfo(node, appName) {
4609
- var _a, _b;
4610
- const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
4611
- if (isNode(node) &&
4612
- !node.__MICRO_APP_NAME__ &&
4613
- !node.__PURE_ELEMENT__ &&
4614
- proxyWindow) {
4615
- /**
4616
- * TODO:
4617
- * 1. 测试baseURI和ownerDocument在with沙箱中是否正确
4618
- * 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
4619
- * 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
4620
- */
4621
- rawDefineProperties(node, {
4622
- baseURI: {
4623
- configurable: true,
4624
- // if disable-memory-router or router-mode='disable', href point to base app
4625
- get: () => proxyWindow.location.href,
4626
- },
4627
- __MICRO_APP_NAME__: {
4628
- configurable: true,
4629
- writable: true,
4630
- value: appName,
4631
- },
4632
- });
4633
- }
4634
- return node;
4635
- }
4636
-
4637
4851
  /**
4638
4852
  * https://developer.mozilla.org/en-US/docs/Web/API/fetch
4639
4853
  * Promise<Response> fetch(input[, init])
@@ -4738,7 +4952,7 @@ function useMicroEventSource() {
4738
4952
  const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
4739
4953
  class WithSandBox extends BaseSandbox {
4740
4954
  constructor(appName, url) {
4741
- super();
4955
+ super(appName, url);
4742
4956
  this.active = false;
4743
4957
  this.microAppWindow = new CustomWindow(); // Proxy target
4744
4958
  this.patchWith((resolve) => {
@@ -4819,6 +5033,7 @@ class WithSandBox extends BaseSandbox {
4819
5033
  * 1. injectedKeys and escapeKeys must be placed at the back
4820
5034
  * 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
4821
5035
  * 3. umd mode will not delete global keys
5036
+ * 4. mount & unmount hook should delete in default mode when stop
4822
5037
  */
4823
5038
  if (!umdMode || destroy) {
4824
5039
  clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
@@ -4830,6 +5045,7 @@ class WithSandBox extends BaseSandbox {
4830
5045
  Reflect.deleteProperty(globalEnv.rawWindow, key);
4831
5046
  });
4832
5047
  this.escapeKeys.clear();
5048
+ this.clearHijackUmdHooks();
4833
5049
  }
4834
5050
  if (--globalEnv.activeSandbox === 0) {
4835
5051
  releasePatchElementAndDocument();
@@ -4862,6 +5078,7 @@ class WithSandBox extends BaseSandbox {
4862
5078
  microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
4863
5079
  removeDomScope,
4864
5080
  pureCreateElement,
5081
+ location: microAppWindow.location,
4865
5082
  router,
4866
5083
  });
4867
5084
  }
@@ -5143,10 +5360,49 @@ class WithSandBox extends BaseSandbox {
5143
5360
  * action before exec scripts when mount
5144
5361
  * Actions:
5145
5362
  * 1. patch static elements from html
5363
+ * 2. hijack umd hooks -- mount, unmount, micro-app-appName
5146
5364
  * @param container micro app container
5147
5365
  */
5148
- actionBeforeExecScripts(container) {
5366
+ actionsBeforeExecScripts(container, handleUmdHooks) {
5149
5367
  this.patchStaticElement(container);
5368
+ this.clearHijackUmdHooks = this.hijackUmdHooks(this.appName, this.microAppWindow, handleUmdHooks);
5369
+ }
5370
+ // hijack mount, unmount, micro-app-appName hook to microAppWindow
5371
+ hijackUmdHooks(appName, microAppWindow, handleUmdHooks) {
5372
+ let mount, unmount, microAppLibrary;
5373
+ rawDefineProperties(microAppWindow, {
5374
+ mount: {
5375
+ configurable: true,
5376
+ get: () => mount,
5377
+ set: (value) => {
5378
+ if (this.active && isFunction(value) && !mount) {
5379
+ handleUmdHooks(mount = value, unmount);
5380
+ }
5381
+ }
5382
+ },
5383
+ unmount: {
5384
+ configurable: true,
5385
+ get: () => unmount,
5386
+ set: (value) => {
5387
+ if (this.active && isFunction(value) && !unmount) {
5388
+ handleUmdHooks(mount, unmount = value);
5389
+ }
5390
+ }
5391
+ },
5392
+ [`micro-app-${appName}`]: {
5393
+ configurable: true,
5394
+ get: () => microAppLibrary,
5395
+ set: (value) => {
5396
+ if (this.active && isPlainObject(value) && !microAppLibrary) {
5397
+ microAppLibrary = value;
5398
+ handleUmdHooks(microAppLibrary.mount, microAppLibrary.unmount);
5399
+ }
5400
+ }
5401
+ }
5402
+ });
5403
+ return () => {
5404
+ mount = unmount = microAppLibrary = null;
5405
+ };
5150
5406
  }
5151
5407
  setStaticAppState(state) {
5152
5408
  this.microAppWindow.__MICRO_APP_STATE__ = state;
@@ -5155,13 +5411,29 @@ class WithSandBox extends BaseSandbox {
5155
5411
  WithSandBox.activeCount = 0; // number of active sandbox
5156
5412
 
5157
5413
  function patchRouter(appName, url, microAppWindow, browserHost) {
5414
+ const rawHistory = globalEnv.rawWindow.history;
5158
5415
  const childStaticLocation = createURL(url);
5159
5416
  const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
5160
5417
  const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
5161
5418
  // rewrite microAppWindow.history
5162
5419
  const microHistory = microAppWindow.history;
5420
+ // save history.replaceState, it will be used in updateMicroLocation
5163
5421
  microAppWindow.rawReplaceState = microHistory.replaceState;
5422
+ // rewrite microAppWindow.history
5164
5423
  assign(microHistory, createMicroHistory(appName, microAppWindow.location));
5424
+ // scrollRestoration proxy to rawHistory
5425
+ rawDefineProperties(microHistory, {
5426
+ scrollRestoration: {
5427
+ configurable: true,
5428
+ enumerable: true,
5429
+ get() {
5430
+ return rawHistory.scrollRestoration;
5431
+ },
5432
+ set(value) {
5433
+ rawHistory.scrollRestoration = value;
5434
+ }
5435
+ }
5436
+ });
5165
5437
  /**
5166
5438
  * Init microLocation before exec sandbox.start
5167
5439
  * NOTE:
@@ -5173,6 +5445,87 @@ function patchRouter(appName, url, microAppWindow, browserHost) {
5173
5445
  return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
5174
5446
  }
5175
5447
 
5448
+ const escape2RawWindowKeys = [
5449
+ 'getComputedStyle',
5450
+ // FIX ISSUE: https://github.com/micro-zoe/micro-app/issues/1292
5451
+ 'DOMParser',
5452
+ 'visualViewport',
5453
+ 'matchMedia',
5454
+ 'ResizeObserver',
5455
+ 'IntersectionObserver',
5456
+ ];
5457
+ const escape2RawWindowRegExpKeys = [
5458
+ /animationFrame$/i,
5459
+ /mutationObserver$/i,
5460
+ /height$|width$/i,
5461
+ /offset$/i,
5462
+ /selection$/i,
5463
+ /^range/i,
5464
+ /^screen/i,
5465
+ /^scroll/i,
5466
+ /X$|Y$/,
5467
+ ];
5468
+ const uniqueDocumentElement = [
5469
+ 'body',
5470
+ 'head',
5471
+ 'html',
5472
+ 'title',
5473
+ ];
5474
+ // proxy to shadowRoot or rawDocument (property)
5475
+ const proxy2RawDocOrShadowKeys = [
5476
+ 'childElementCount',
5477
+ 'children',
5478
+ 'firstElementChild',
5479
+ 'firstChild',
5480
+ 'lastElementChild',
5481
+ 'activeElement',
5482
+ 'fullscreenElement',
5483
+ 'pictureInPictureElement',
5484
+ 'pointerLockElement',
5485
+ 'styleSheets',
5486
+ ];
5487
+ // proxy to shadowRoot or rawDocument (method)
5488
+ const proxy2RawDocOrShadowMethods = [
5489
+ 'append',
5490
+ 'contains',
5491
+ 'replaceChildren',
5492
+ 'createRange',
5493
+ 'getSelection',
5494
+ 'elementFromPoint',
5495
+ 'elementsFromPoint',
5496
+ 'getAnimations',
5497
+ ];
5498
+ // proxy to rawDocument (property)
5499
+ const proxy2RawDocumentKeys = [
5500
+ 'characterSet',
5501
+ 'compatMode',
5502
+ 'contentType',
5503
+ 'designMode',
5504
+ 'dir',
5505
+ 'doctype',
5506
+ 'embeds',
5507
+ 'fullscreenEnabled',
5508
+ 'hidden',
5509
+ 'implementation',
5510
+ 'lastModified',
5511
+ 'pictureInPictureEnabled',
5512
+ 'plugins',
5513
+ 'readyState',
5514
+ 'referrer',
5515
+ 'visibilityState',
5516
+ 'fonts',
5517
+ ];
5518
+ // proxy to rawDocument (method)
5519
+ const proxy2RawDocumentMethods = [
5520
+ 'execCommand',
5521
+ 'createRange',
5522
+ 'exitFullscreen',
5523
+ 'exitPictureInPicture',
5524
+ 'getElementsByTagNameNS',
5525
+ 'hasFocus',
5526
+ 'prepend',
5527
+ ];
5528
+
5176
5529
  /**
5177
5530
  * patch window of child app
5178
5531
  * @param appName app name
@@ -5220,7 +5573,41 @@ function patchWindowProperty$1(appName, microAppWindow) {
5220
5573
  }
5221
5574
  return false;
5222
5575
  });
5223
- return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT.includes(key);
5576
+ /**
5577
+ * In FireFox, iframe Element.prototype will point to native Element.prototype after insert to document
5578
+ * Rewrite all constructor's Symbol.hasInstance of iframeWindow
5579
+ * NOTE:
5580
+ * 1. native event instanceof iframe window.Event
5581
+ * 2. native node instanceof iframe window.Node
5582
+ * 3. native element instanceof iframe window.Element
5583
+ * 4. native url instanceof iframe window.URL
5584
+ * ...
5585
+ */
5586
+ if (isConstructor(microAppWindow[key]) && key in rawWindow) {
5587
+ rawDefineProperty(microAppWindow[key], Symbol.hasInstance, {
5588
+ configurable: true,
5589
+ enumerable: false,
5590
+ value(target) {
5591
+ return target instanceof rawWindow[key] || instanceOf(target, microAppWindow[key]);
5592
+ },
5593
+ });
5594
+ }
5595
+ // hijackInstanceOfWindowRegExpKeys.some((reg: RegExp) => {
5596
+ // if (reg.test(key) && key in rawWindow) {
5597
+ // rawDefineProperty(microAppWindow[key], Symbol.hasInstance, {
5598
+ // configurable: true,
5599
+ // enumerable: false,
5600
+ // value: (target: unknown) => {
5601
+ // return target instanceof rawWindow[key]
5602
+ // ? true
5603
+ // : instanceOf(target, microAppWindow[key])
5604
+ // },
5605
+ // })
5606
+ // return true
5607
+ // }
5608
+ // return false
5609
+ // })
5610
+ return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_IFRAME.includes(key);
5224
5611
  })
5225
5612
  .forEach((eventName) => {
5226
5613
  const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microAppWindow, eventName) || {
@@ -5305,11 +5692,15 @@ function createProxyWindow$1(microAppWindow, sandbox) {
5305
5692
  sandbox.proxyWindow = proxyWindow;
5306
5693
  }
5307
5694
  function patchWindowEffect$1(microAppWindow) {
5308
- const { rawWindow, rawAddEventListener, rawRemoveEventListener } = globalEnv;
5695
+ const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent } = globalEnv;
5309
5696
  const eventListenerMap = new Map();
5310
5697
  const sstEventListenerMap = new Map();
5311
5698
  function getEventTarget(type) {
5312
- return SCOPE_WINDOW_EVENT.includes(type) ? microAppWindow : rawWindow;
5699
+ /**
5700
+ * TODO: SCOPE_WINDOW_EVENT_OF_IFRAME的事件非常少,有可能导致问题
5701
+ * 1、一些未知的需要绑定到iframe的事件被错误的绑定到原生window上
5702
+ */
5703
+ return SCOPE_WINDOW_EVENT_OF_IFRAME.includes(type) ? microAppWindow : rawWindow;
5313
5704
  }
5314
5705
  // TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
5315
5706
  microAppWindow.addEventListener = function (type, listener, options) {
@@ -5330,6 +5721,9 @@ function patchWindowEffect$1(microAppWindow) {
5330
5721
  }
5331
5722
  rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
5332
5723
  };
5724
+ microAppWindow.dispatchEvent = function (event) {
5725
+ return rawDispatchEvent.call(getEventTarget(event === null || event === void 0 ? void 0 : event.type), event);
5726
+ };
5333
5727
  const reset = () => {
5334
5728
  sstEventListenerMap.clear();
5335
5729
  };
@@ -5441,34 +5835,43 @@ function patchDocumentPrototype(appName, microAppWindow) {
5441
5835
  const element = rawMicroCreateComment.call(this, data);
5442
5836
  return updateElementInfo(element, appName);
5443
5837
  };
5444
- function getDefaultRawTarget(target) {
5445
- return microDocument !== target ? target : rawDocument;
5838
+ function getBindTarget(target) {
5839
+ /**
5840
+ * handler for:
5841
+ * 1. document.getElementsByTagName('head')[0].querySelector('script')
5842
+ * 2. document.querySelector('body').querySelectorAll('script')
5843
+ * ...
5844
+ */
5845
+ throttleDeferForIframeAppName(appName);
5846
+ // DOMParser.document !== microDocument
5847
+ return microDocument === target ? rawDocument : target;
5446
5848
  }
5447
5849
  // query element👇
5448
5850
  function querySelector(selectors) {
5449
- var _a, _b;
5851
+ var _a, _b, _c;
5852
+ const _this = getBindTarget(this);
5450
5853
  if (!selectors ||
5451
5854
  isUniqueElement(selectors) ||
5452
- microDocument !== this) {
5453
- const _this = getDefaultRawTarget(this);
5855
+ rawDocument !== _this) {
5454
5856
  return rawMicroQuerySelector.call(_this, selectors);
5455
5857
  }
5456
- return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
5858
+ return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : rawMicroQuerySelector.call(microDocument, selectors)) !== null && _c !== void 0 ? _c : null;
5457
5859
  }
5458
5860
  function querySelectorAll(selectors) {
5459
5861
  var _a, _b;
5862
+ const _this = getBindTarget(this);
5460
5863
  if (!selectors ||
5461
5864
  isUniqueElement(selectors) ||
5462
- microDocument !== this) {
5463
- const _this = getDefaultRawTarget(this);
5865
+ rawDocument !== _this) {
5464
5866
  return rawMicroQuerySelectorAll.call(_this, selectors);
5465
5867
  }
5466
- return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
5868
+ const result = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
5869
+ return result.length ? result : rawMicroQuerySelectorAll.call(microDocument, selectors);
5467
5870
  }
5468
5871
  microRootDocument.prototype.querySelector = querySelector;
5469
5872
  microRootDocument.prototype.querySelectorAll = querySelectorAll;
5470
5873
  microRootDocument.prototype.getElementById = function getElementById(key) {
5471
- const _this = getDefaultRawTarget(this);
5874
+ const _this = getBindTarget(this);
5472
5875
  if (isInvalidQuerySelectorKey(key)) {
5473
5876
  return rawMicroGetElementById.call(_this, key);
5474
5877
  }
@@ -5480,7 +5883,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
5480
5883
  }
5481
5884
  };
5482
5885
  microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
5483
- const _this = getDefaultRawTarget(this);
5886
+ const _this = getBindTarget(this);
5484
5887
  if (isInvalidQuerySelectorKey(key)) {
5485
5888
  return rawMicroGetElementsByClassName.call(_this, key);
5486
5889
  }
@@ -5492,7 +5895,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
5492
5895
  }
5493
5896
  };
5494
5897
  microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
5495
- const _this = getDefaultRawTarget(this);
5898
+ const _this = getBindTarget(this);
5496
5899
  if (isUniqueElement(key) ||
5497
5900
  isInvalidQuerySelectorKey(key)) {
5498
5901
  return rawMicroGetElementsByTagName.call(_this, key);
@@ -5508,7 +5911,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
5508
5911
  }
5509
5912
  };
5510
5913
  microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
5511
- const _this = getDefaultRawTarget(this);
5914
+ const _this = getBindTarget(this);
5512
5915
  if (isInvalidQuerySelectorKey(key)) {
5513
5916
  return rawMicroGetElementsByName.call(_this, key);
5514
5917
  }
@@ -5575,7 +5978,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5575
5978
  enumerable: true,
5576
5979
  configurable: true,
5577
5980
  get: () => {
5578
- throttleDeferForSetAppName(appName);
5981
+ throttleDeferForIframeAppName(appName);
5579
5982
  return rawDocument[tagName];
5580
5983
  },
5581
5984
  set: (value) => { rawDocument[tagName] = value; },
@@ -5583,7 +5986,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5583
5986
  });
5584
5987
  }
5585
5988
  function patchDocumentEffect(appName, microAppWindow) {
5586
- const { rawDocument, rawAddEventListener, rawRemoveEventListener } = globalEnv;
5989
+ const { rawDocument, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent } = globalEnv;
5587
5990
  const eventListenerMap = new Map();
5588
5991
  const sstEventListenerMap = new Map();
5589
5992
  let onClickHandler = null;
@@ -5613,6 +6016,9 @@ function patchDocumentEffect(appName, microAppWindow) {
5613
6016
  const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
5614
6017
  rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
5615
6018
  };
6019
+ microRootDocument.prototype.dispatchEvent = function (event) {
6020
+ return rawDispatchEvent.call(getEventTarget(event === null || event === void 0 ? void 0 : event.type, this), event);
6021
+ };
5616
6022
  // 重新定义microRootDocument.prototype 上的on开头方法
5617
6023
  function createSetterHandler(eventName) {
5618
6024
  if (eventName === 'onclick') {
@@ -5733,12 +6139,18 @@ function patchElement(appName, url, microAppWindow, sandbox) {
5733
6139
  patchIframeNode(appName, microAppWindow, sandbox);
5734
6140
  patchIframeAttribute(url, microAppWindow);
5735
6141
  }
6142
+ /**
6143
+ * patch iframe Node/Element
6144
+ *
6145
+ */
5736
6146
  function patchIframeNode(appName, microAppWindow, sandbox) {
5737
6147
  const rawRootElement = globalEnv.rawRootElement; // native root Element
6148
+ const rawRootNode = globalEnv.rawRootNode;
5738
6149
  const rawDocument = globalEnv.rawDocument;
5739
6150
  const microDocument = microAppWindow.document;
5740
6151
  const microRootNode = microAppWindow.Node;
5741
6152
  const microRootElement = microAppWindow.Element;
6153
+ const microDocumentFragment = microAppWindow.DocumentFragment;
5742
6154
  // const rawMicroGetRootNode = microRootNode.prototype.getRootNode
5743
6155
  const rawMicroAppendChild = microRootNode.prototype.appendChild;
5744
6156
  const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
@@ -5746,6 +6158,8 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5746
6158
  const rawMicroRemoveChild = microRootNode.prototype.removeChild;
5747
6159
  const rawMicroAppend = microRootElement.prototype.append;
5748
6160
  const rawMicroPrepend = microRootElement.prototype.prepend;
6161
+ const rawMicroFragmentAppend = microDocumentFragment.prototype.append;
6162
+ const rawMicroFragmentPrepend = microDocumentFragment.prototype.prepend;
5749
6163
  const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
5750
6164
  const rawMicroCloneNode = microRootNode.prototype.cloneNode;
5751
6165
  const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
@@ -5763,42 +6177,34 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5763
6177
  }
5764
6178
  return parent;
5765
6179
  };
5766
- microRootNode.prototype.getRootNode = function getRootNode() {
5767
- return microDocument;
5768
- // TODO: 什么情况下返回原生document?
5769
- // const rootNode = rawMicroGetRootNode.call(this, options)
5770
- // if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
5771
- // return rootNode
5772
- };
5773
6180
  microRootNode.prototype.appendChild = function appendChild(node) {
5774
- // TODO: 有必要执行这么多次updateElementInfo?
5775
6181
  updateElementInfo(node, appName);
5776
6182
  if (isPureNode(node)) {
5777
6183
  return rawMicroAppendChild.call(this, node);
5778
6184
  }
5779
- return rawRootElement.prototype.appendChild.call(getRawTarget(this), node);
6185
+ return rawRootNode.prototype.appendChild.call(getRawTarget(this), node);
5780
6186
  };
5781
6187
  microRootNode.prototype.insertBefore = function insertBefore(node, child) {
5782
6188
  updateElementInfo(node, appName);
5783
6189
  if (isPureNode(node)) {
5784
6190
  return rawMicroInsertBefore.call(this, node, child);
5785
6191
  }
5786
- return rawRootElement.prototype.insertBefore.call(getRawTarget(this), node, child);
6192
+ return rawRootNode.prototype.insertBefore.call(getRawTarget(this), node, child);
5787
6193
  };
5788
6194
  microRootNode.prototype.replaceChild = function replaceChild(node, child) {
5789
6195
  updateElementInfo(node, appName);
5790
6196
  if (isPureNode(node)) {
5791
6197
  return rawMicroReplaceChild.call(this, node, child);
5792
6198
  }
5793
- return rawRootElement.prototype.replaceChild.call(getRawTarget(this), node, child);
6199
+ return rawRootNode.prototype.replaceChild.call(getRawTarget(this), node, child);
5794
6200
  };
5795
6201
  microRootNode.prototype.removeChild = function removeChild(oldChild) {
5796
6202
  if (isPureNode(oldChild) || this.contains(oldChild)) {
5797
6203
  return rawMicroRemoveChild.call(this, oldChild);
5798
6204
  }
5799
- return rawRootElement.prototype.removeChild.call(getRawTarget(this), oldChild);
6205
+ return rawRootNode.prototype.removeChild.call(getRawTarget(this), oldChild);
5800
6206
  };
5801
- microRootElement.prototype.append = function append(...nodes) {
6207
+ microDocumentFragment.prototype.append = microRootElement.prototype.append = function append(...nodes) {
5802
6208
  let i = 0;
5803
6209
  let hasPureNode = false;
5804
6210
  while (i < nodes.length) {
@@ -5808,11 +6214,11 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5808
6214
  i++;
5809
6215
  }
5810
6216
  if (hasPureNode) {
5811
- return rawMicroAppend.call(this, ...nodes);
6217
+ return (isDocumentFragment(this) ? rawMicroFragmentAppend : rawMicroAppend).call(this, ...nodes);
5812
6218
  }
5813
6219
  return rawRootElement.prototype.append.call(getRawTarget(this), ...nodes);
5814
6220
  };
5815
- microRootElement.prototype.prepend = function prepend(...nodes) {
6221
+ microDocumentFragment.prototype.prepend = microRootElement.prototype.prepend = function prepend(...nodes) {
5816
6222
  let i = 0;
5817
6223
  let hasPureNode = false;
5818
6224
  while (i < nodes.length) {
@@ -5822,7 +6228,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5822
6228
  i++;
5823
6229
  }
5824
6230
  if (hasPureNode) {
5825
- return rawMicroPrepend.call(this, ...nodes);
6231
+ return (isDocumentFragment(this) ? rawMicroFragmentPrepend : rawMicroPrepend).call(this, ...nodes);
5826
6232
  }
5827
6233
  return rawRootElement.prototype.prepend.call(getRawTarget(this), ...nodes);
5828
6234
  };
@@ -5838,28 +6244,53 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5838
6244
  }
5839
6245
  return rawRootElement.prototype.insertAdjacentElement.call(getRawTarget(this), where, element);
5840
6246
  };
5841
- // patch cloneNode
5842
- microRootNode.prototype.cloneNode = function cloneNode(deep) {
5843
- const clonedNode = rawMicroCloneNode.call(this, deep);
5844
- return updateElementInfo(clonedNode, appName);
5845
- };
6247
+ /**
6248
+ * Specific prototype properties:
6249
+ * 1. baseURI
6250
+ * 2. ownerDocument
6251
+ * 3. parentNode
6252
+ * 4. innerHTML
6253
+ */
6254
+ rawDefineProperty(microRootNode.prototype, 'baseURI', {
6255
+ configurable: true,
6256
+ enumerable: true,
6257
+ get() {
6258
+ return sandbox.proxyWindow.location.href;
6259
+ },
6260
+ });
5846
6261
  rawDefineProperty(microRootNode.prototype, 'ownerDocument', {
5847
6262
  configurable: true,
5848
6263
  enumerable: true,
5849
6264
  get() {
5850
- return this.__PURE_ELEMENT__
5851
- ? rawOwnerDocumentDesc.get.call(this)
5852
- : microDocument;
6265
+ var _a;
6266
+ return this.__PURE_ELEMENT__ || this === microDocument
6267
+ ? (_a = rawOwnerDocumentDesc.get) === null || _a === void 0 ? void 0 : _a.call(this) : microDocument;
5853
6268
  },
5854
6269
  });
6270
+ // patch parentNode
6271
+ rawDefineProperty(microRootNode.prototype, 'parentNode', getIframeParentNodeDesc(appName, rawParentNodeDesc));
6272
+ microRootNode.prototype.getRootNode = function getRootNode() {
6273
+ return microDocument;
6274
+ // TODO: any case return document?
6275
+ // const rootNode = rawMicroGetRootNode.call(this, options)
6276
+ // if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
6277
+ // return rootNode
6278
+ };
6279
+ // patch cloneNode
6280
+ microRootNode.prototype.cloneNode = function cloneNode(deep) {
6281
+ const clonedNode = rawMicroCloneNode.call(this, deep);
6282
+ return updateElementInfo(clonedNode, appName);
6283
+ };
5855
6284
  rawDefineProperty(microRootElement.prototype, 'innerHTML', {
5856
6285
  configurable: true,
5857
6286
  enumerable: true,
5858
6287
  get() {
5859
- return rawInnerHTMLDesc.get.call(this);
6288
+ var _a;
6289
+ return (_a = rawInnerHTMLDesc.get) === null || _a === void 0 ? void 0 : _a.call(this);
5860
6290
  },
5861
6291
  set(code) {
5862
- rawInnerHTMLDesc.set.call(this, code);
6292
+ var _a;
6293
+ (_a = rawInnerHTMLDesc.set) === null || _a === void 0 ? void 0 : _a.call(this, code);
5863
6294
  Array.from(this.children).forEach((child) => {
5864
6295
  if (isElement(child)) {
5865
6296
  updateElementInfo(child, appName);
@@ -5867,34 +6298,6 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5867
6298
  });
5868
6299
  }
5869
6300
  });
5870
- // patch parentNode
5871
- rawDefineProperty(microRootNode.prototype, 'parentNode', {
5872
- configurable: true,
5873
- enumerable: true,
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
- }
5897
- });
5898
6301
  // Adapt to new image(...) scene
5899
6302
  const ImageProxy = new Proxy(microAppWindow.Image, {
5900
6303
  construct(Target, args) {
@@ -5913,16 +6316,24 @@ function patchIframeAttribute(url, microAppWindow) {
5913
6316
  const microRootElement = microAppWindow.Element;
5914
6317
  const rawMicroSetAttribute = microRootElement.prototype.setAttribute;
5915
6318
  microRootElement.prototype.setAttribute = function setAttribute(key, value) {
5916
- if (((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
5917
- (key === 'href' && /^link$/i.test(this.tagName))) {
5918
- value = CompletionPath(value, url);
6319
+ if (/^micro-app(-\S+)?/i.test(this.tagName) &&
6320
+ key === 'data' &&
6321
+ this.setAttribute !== microRootElement.prototype.setAttribute) {
6322
+ this.setAttribute(key, value);
6323
+ }
6324
+ else {
6325
+ if (((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
6326
+ (key === 'href' && /^(link|image)$/i.test(this.tagName))) {
6327
+ value = CompletionPath(value, url);
6328
+ }
6329
+ rawMicroSetAttribute.call(this, key, value);
5919
6330
  }
5920
- rawMicroSetAttribute.call(this, key, value);
5921
6331
  };
5922
6332
  const protoAttrList = [
5923
6333
  [microAppWindow.HTMLImageElement.prototype, 'src'],
5924
6334
  [microAppWindow.HTMLScriptElement.prototype, 'src'],
5925
6335
  [microAppWindow.HTMLLinkElement.prototype, 'href'],
6336
+ [microAppWindow.SVGImageElement.prototype, 'href'],
5926
6337
  ];
5927
6338
  /**
5928
6339
  * element.setAttribute does not trigger this actions:
@@ -5999,9 +6410,10 @@ class IframeSandbox {
5999
6410
  createIframeElement(appName, browserPath) {
6000
6411
  this.iframe = pureCreateElement('iframe');
6001
6412
  const iframeAttrs = {
6413
+ id: appName,
6002
6414
  src: microApp.options.iframeSrc || browserPath,
6003
6415
  style: 'display: none',
6004
- id: appName,
6416
+ 'powered-by': 'micro-app',
6005
6417
  };
6006
6418
  Object.keys(iframeAttrs).forEach((key) => this.iframe.setAttribute(key, iframeAttrs[key]));
6007
6419
  // effect action during construct
@@ -6035,15 +6447,6 @@ class IframeSandbox {
6035
6447
  * 1. iframe router and browser router are separated, we should update iframe router manually
6036
6448
  * 2. withSandbox location is browser location when disable memory-router, so no need to do anything
6037
6449
  */
6038
- /**
6039
- * TODO:
6040
- * 1. iframe关闭虚拟路由系统后,default-page无法使用,推荐用户直接使用浏览器地址控制首页渲染
6041
- * 补充:keep-router-state 也无法配置,因为keep-router-state一定为true。
6042
- * 2. 导航拦截、current.route 可以正常使用
6043
- * 3. 可以正常控制子应用跳转,方式还是自上而下(也可以是子应用内部跳转,这种方式更好一点,减小对基座的影响,不会导致vue的循环刷新)
6044
- * 4. 关闭虚拟路由以后会对应 route-mode='custom' 模式,包括with沙箱也会这么做
6045
- * 5. 关闭虚拟路由是指尽可能模拟没有虚拟路由的情况,子应用直接获取浏览器location和history,控制浏览器跳转
6046
- */
6047
6450
  this.initRouteState(defaultPage);
6048
6451
  // unique listener of popstate event for child app
6049
6452
  this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
@@ -6066,6 +6469,7 @@ class IframeSandbox {
6066
6469
  }
6067
6470
  stop({ umdMode, keepRouteState, destroy, clearData, }) {
6068
6471
  var _a;
6472
+ // sandbox.stop may exec before sandbox.start, e.g: iframe sandbox + default mode + remount
6069
6473
  if (!this.active)
6070
6474
  return;
6071
6475
  this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
@@ -6081,6 +6485,7 @@ class IframeSandbox {
6081
6485
  Reflect.deleteProperty(globalEnv.rawWindow, key);
6082
6486
  });
6083
6487
  this.escapeKeys.clear();
6488
+ this.clearHijackUmdHooks();
6084
6489
  }
6085
6490
  if (--globalEnv.activeSandbox === 0) {
6086
6491
  releasePatchElementAndDocument();
@@ -6299,10 +6704,49 @@ class IframeSandbox {
6299
6704
  * action before exec scripts when mount
6300
6705
  * Actions:
6301
6706
  * 1. patch static elements from html
6707
+ * 2. hijack umd hooks -- mount, unmount, micro-app-appName
6302
6708
  * @param container micro app container
6303
6709
  */
6304
- actionBeforeExecScripts(container) {
6710
+ actionsBeforeExecScripts(container, handleUmdHooks) {
6305
6711
  this.patchStaticElement(container);
6712
+ this.clearHijackUmdHooks = this.hijackUmdHooks(this.appName, this.microAppWindow, handleUmdHooks);
6713
+ }
6714
+ // hijack mount, unmount, micro-app-appName hook to microAppWindow
6715
+ hijackUmdHooks(appName, microAppWindow, handleUmdHooks) {
6716
+ let mount, unmount, microAppLibrary;
6717
+ rawDefineProperties(microAppWindow, {
6718
+ mount: {
6719
+ configurable: true,
6720
+ get: () => mount,
6721
+ set: (value) => {
6722
+ if (this.active && isFunction(value) && !mount) {
6723
+ handleUmdHooks(mount = value, unmount);
6724
+ }
6725
+ }
6726
+ },
6727
+ unmount: {
6728
+ configurable: true,
6729
+ get: () => unmount,
6730
+ set: (value) => {
6731
+ if (this.active && isFunction(value) && !unmount) {
6732
+ handleUmdHooks(mount, unmount = value);
6733
+ }
6734
+ }
6735
+ },
6736
+ [`micro-app-${appName}`]: {
6737
+ configurable: true,
6738
+ get: () => microAppLibrary,
6739
+ set: (value) => {
6740
+ if (this.active && isPlainObject(value) && !microAppLibrary) {
6741
+ microAppLibrary = value;
6742
+ handleUmdHooks(microAppLibrary.mount, microAppLibrary.unmount);
6743
+ }
6744
+ }
6745
+ }
6746
+ });
6747
+ return () => {
6748
+ mount = unmount = microAppLibrary = null;
6749
+ };
6306
6750
  }
6307
6751
  setStaticAppState(state) {
6308
6752
  this.microAppWindow.__MICRO_APP_STATE__ = state;
@@ -6319,7 +6763,6 @@ class CreateApp {
6319
6763
  this.loadSourceLevel = 0;
6320
6764
  this.umdHookMount = null;
6321
6765
  this.umdHookUnmount = null;
6322
- this.lifeCycleState = null;
6323
6766
  this.umdMode = false;
6324
6767
  // TODO: 类型优化,加上iframe沙箱
6325
6768
  this.sandBox = null;
@@ -6364,7 +6807,9 @@ class CreateApp {
6364
6807
  var _a;
6365
6808
  if (++this.loadSourceLevel === 2) {
6366
6809
  this.source.html = html;
6367
- if (!this.isPrefetch && !this.isUnmounted()) {
6810
+ if (this.isUnmounted())
6811
+ return;
6812
+ if (!this.isPrefetch) {
6368
6813
  getRootContainer(this.container).mount(this);
6369
6814
  }
6370
6815
  else if (this.isPrerender) {
@@ -6433,6 +6878,7 @@ class CreateApp {
6433
6878
  // mount before prerender exec mount (loading source), set isPrerender to false
6434
6879
  this.isPrerender = false;
6435
6880
  // dispatch state event to micro app
6881
+ // TODO: statechange 还是 state-change,保持一致
6436
6882
  dispatchCustomEventToMicroApp(this, 'statechange', {
6437
6883
  appState: appStates.LOADING
6438
6884
  });
@@ -6456,6 +6902,14 @@ class CreateApp {
6456
6902
  if (this.isPrerender &&
6457
6903
  isDivElement(this.container) &&
6458
6904
  this.container.hasAttribute('prerender')) {
6905
+ /**
6906
+ * current this.container is <div prerender='true'></div>
6907
+ * set this.container to <micro-app></micro-app>
6908
+ * NOTE:
6909
+ * 1. must exec before this.sandBox.rebuildEffectSnapshot
6910
+ * 2. must exec before this.preRenderEvents?.forEach((cb) => cb())
6911
+ */
6912
+ this.container = this.cloneContainer(container, this.container, false);
6459
6913
  /**
6460
6914
  * rebuild effect event of window, document, data center
6461
6915
  * explain:
@@ -6464,14 +6918,6 @@ class CreateApp {
6464
6918
  * 3. rebuild after js exec end, normal recovery effect event
6465
6919
  */
6466
6920
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
6467
- // current this.container is <div prerender='true'></div>
6468
- this.cloneContainer(container, this.container, false);
6469
- /**
6470
- * set this.container to <micro-app></micro-app>
6471
- * NOTE:
6472
- * must exec before this.preRenderEvents?.forEach((cb) => cb())
6473
- */
6474
- this.container = container;
6475
6921
  (_b = this.preRenderEvents) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
6476
6922
  // reset isPrerender config
6477
6923
  this.isPrerender = false;
@@ -6486,7 +6932,6 @@ class CreateApp {
6486
6932
  this.fiber = fiber;
6487
6933
  this.routerMode = routerMode;
6488
6934
  const dispatchBeforeMount = () => {
6489
- this.setLifeCycleState(lifeCycles.BEFOREMOUNT);
6490
6935
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
6491
6936
  };
6492
6937
  if (this.isPrerender) {
@@ -6500,7 +6945,7 @@ class CreateApp {
6500
6945
  dispatchCustomEventToMicroApp(this, 'statechange', {
6501
6946
  appState: appStates.MOUNTING
6502
6947
  });
6503
- // TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
6948
+ // TODO: 兼容shadowRoot的场景
6504
6949
  this.cloneContainer(this.container, this.source.html, !this.umdMode);
6505
6950
  (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
6506
6951
  umdMode: this.umdMode,
@@ -6509,38 +6954,35 @@ class CreateApp {
6509
6954
  disablePatchRequest,
6510
6955
  });
6511
6956
  if (!this.umdMode) {
6512
- // update element info of html
6513
- (_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.actionBeforeExecScripts(this.container);
6514
- // if all js are executed, param isFinished will be true
6515
- execScripts(this, (isFinished) => {
6516
- if (!this.umdMode) {
6517
- const { mount, unmount } = this.getUmdLibraryHooks();
6518
- /**
6519
- * umdHookUnmount can works in default mode
6520
- * register through window.unmount
6521
- */
6522
- // TODO: 不对,这里要改,因为unmount不一定是函数
6523
- this.umdHookUnmount = unmount;
6957
+ // patch element info of html
6958
+ (_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.actionsBeforeExecScripts(this.container, (mount, unmount) => {
6959
+ var _a;
6960
+ if (!this.umdMode && !this.isUnmounted()) {
6961
+ this.umdHookMount = isFunction(mount) ? mount : null;
6962
+ // umdHookUnmount can works in default mode, register by window.unmount
6963
+ this.umdHookUnmount = isFunction(unmount) ? unmount : null;
6524
6964
  // if mount & unmount is function, the sub app is umd mode
6525
- if (isFunction(mount) && isFunction(unmount)) {
6526
- this.umdHookMount = mount;
6527
- // sandbox must exist
6528
- this.sandBox.markUmdMode(this.umdMode = true);
6965
+ if (isFunction(this.umdHookMount) && isFunction(this.umdHookUnmount)) {
6966
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.markUmdMode(this.umdMode = true);
6529
6967
  try {
6530
- this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
6968
+ // if appState is mounted, it means that isFinished is true and this.handleMounted has already been executed, just exec this.umdHookMount
6969
+ if (this.getAppState() === appStates.MOUNTED) {
6970
+ this.umdHookMount(microApp.getData(this.name, true));
6971
+ }
6972
+ else {
6973
+ this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
6974
+ }
6531
6975
  }
6532
6976
  catch (e) {
6533
- /**
6534
- * TODO:
6535
- * 1. 是否应该直接抛出错误
6536
- * 2. 是否应该触发error生命周期
6537
- */
6538
- logError('An error occurred in window.mount \n', this.name, e);
6977
+ logError('An error occurred when mount \n', this.name, e);
6539
6978
  }
6540
6979
  }
6541
- else if (isFinished === true) {
6542
- this.handleMounted();
6543
- }
6980
+ }
6981
+ });
6982
+ // if all js are executed, param isFinished will be true
6983
+ execScripts(this, (isFinished) => {
6984
+ if (!this.umdMode && isFinished === true) {
6985
+ this.handleMounted();
6544
6986
  }
6545
6987
  });
6546
6988
  }
@@ -6550,13 +6992,22 @@ class CreateApp {
6550
6992
  this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
6551
6993
  }
6552
6994
  catch (e) {
6553
- logError('An error occurred in window.mount \n', this.name, e);
6995
+ logError('An error occurred when mount \n', this.name, e);
6554
6996
  }
6555
6997
  }
6556
6998
  }
6557
6999
  };
7000
+ /**
7001
+ * Initialization of sandbox is async, especially iframe sandbox are macro tasks
7002
+ * when child apps switch quickly, we need to pay attention to the following points:
7003
+ * NOTE:
7004
+ * 1. unmount app before exec nextAction (especially: iframe sandbox + default mode + remount)
7005
+ * this.container is null, this.sandBox will not start
7006
+ * 2. remount app of note 1
7007
+ * 3. unmount app during exec js
7008
+ */
6558
7009
  // TODO: 可优化?
6559
- this.sandBox ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
7010
+ this.sandBox ? this.sandBox.sandboxReady.then(() => !this.isUnmounted() && nextAction()) : nextAction();
6560
7011
  }
6561
7012
  /**
6562
7013
  * handle for promise umdHookMount
@@ -6565,16 +7016,17 @@ class CreateApp {
6565
7016
  handleMounted(umdHookMountResult) {
6566
7017
  var _a, _b;
6567
7018
  const dispatchAction = () => {
7019
+ const nextAction = () => this.actionsAfterMounted();
6568
7020
  if (isPromise(umdHookMountResult)) {
6569
7021
  umdHookMountResult
6570
- .then(() => this.dispatchMountedEvent())
7022
+ .then(nextAction)
6571
7023
  .catch((e) => {
6572
7024
  logError('An error occurred in window.mount \n', this.name, e);
6573
- this.dispatchMountedEvent();
7025
+ nextAction();
6574
7026
  });
6575
7027
  }
6576
7028
  else {
6577
- this.dispatchMountedEvent();
7029
+ nextAction();
6578
7030
  }
6579
7031
  };
6580
7032
  if (this.isPrerender) {
@@ -6588,7 +7040,7 @@ class CreateApp {
6588
7040
  /**
6589
7041
  * dispatch mounted event when app run finished
6590
7042
  */
6591
- dispatchMountedEvent() {
7043
+ actionsAfterMounted() {
6592
7044
  var _a;
6593
7045
  if (!this.isUnmounted()) {
6594
7046
  this.setAppState(appStates.MOUNTED);
@@ -6600,7 +7052,6 @@ class CreateApp {
6600
7052
  });
6601
7053
  // dispatch mounted event to micro app
6602
7054
  dispatchCustomEventToMicroApp(this, 'mounted');
6603
- this.setLifeCycleState(lifeCycles.MOUNTED);
6604
7055
  // dispatch event mounted to parent
6605
7056
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
6606
7057
  /**
@@ -6623,6 +7074,8 @@ class CreateApp {
6623
7074
  * unmount app
6624
7075
  * NOTE:
6625
7076
  * 1. do not add any params on account of unmountApp
7077
+ * 2. this.container maybe null: Initialization of sandbox is async, child app may unmount before exec nextAction of mount
7078
+ * 3. unmount app when loading files (this.container is not null)
6626
7079
  * @param destroy completely destroy, delete cache resources
6627
7080
  * @param clearData clear data of dateCenter
6628
7081
  * @param keepRouteState keep route state when unmount, default is false
@@ -6632,29 +7085,12 @@ class CreateApp {
6632
7085
  var _a;
6633
7086
  destroy = destroy || this.state === appStates.LOAD_FAILED;
6634
7087
  this.setAppState(appStates.UNMOUNT);
6635
- let umdHookUnmountResult = null;
6636
7088
  try {
6637
- // call umd unmount hook before the sandbox is cleared
6638
- umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
7089
+ this.handleUnmounted(destroy, clearData, keepRouteState, unmountcb, (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true)));
6639
7090
  }
6640
7091
  catch (e) {
6641
- logError('An error occurred in window.unmount \n', this.name, e);
7092
+ logError('An error occurred when unmount \n', this.name, e);
6642
7093
  }
6643
- // dispatch state event to micro app
6644
- dispatchCustomEventToMicroApp(this, 'statechange', {
6645
- appState: appStates.UNMOUNT
6646
- });
6647
- // dispatch unmount event to micro app
6648
- dispatchCustomEventToMicroApp(this, 'unmount');
6649
- // call window.onunmount of child app
6650
- execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
6651
- this.handleUnmounted({
6652
- destroy,
6653
- clearData,
6654
- keepRouteState,
6655
- unmountcb,
6656
- umdHookUnmountResult,
6657
- });
6658
7094
  }
6659
7095
  /**
6660
7096
  * handle for promise umdHookUnmount
@@ -6664,8 +7100,16 @@ class CreateApp {
6664
7100
  * @param unmountcb callback of unmount
6665
7101
  * @param umdHookUnmountResult result of umdHookUnmount
6666
7102
  */
6667
- handleUnmounted({ destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult, }) {
6668
- const nextAction = () => this.actionsForUnmount({
7103
+ handleUnmounted(destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult) {
7104
+ // dispatch state event to micro app
7105
+ dispatchCustomEventToMicroApp(this, 'statechange', {
7106
+ appState: appStates.UNMOUNT
7107
+ });
7108
+ // dispatch unmount event to micro app
7109
+ dispatchCustomEventToMicroApp(this, 'unmount');
7110
+ // call window.onunmount of child app
7111
+ execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
7112
+ const nextAction = () => this.actionsAfterUnmounted({
6669
7113
  destroy,
6670
7114
  clearData,
6671
7115
  keepRouteState,
@@ -6674,7 +7118,12 @@ class CreateApp {
6674
7118
  if (isPromise(umdHookUnmountResult)) {
6675
7119
  // async window.unmount will cause appName bind error in nest app
6676
7120
  removeDomScope();
6677
- umdHookUnmountResult.then(nextAction).catch(nextAction);
7121
+ umdHookUnmountResult
7122
+ .then(nextAction)
7123
+ .catch((e) => {
7124
+ logError('An error occurred in window.unmount \n', this.name, e);
7125
+ nextAction();
7126
+ });
6678
7127
  }
6679
7128
  else {
6680
7129
  nextAction();
@@ -6687,7 +7136,7 @@ class CreateApp {
6687
7136
  * @param keepRouteState keep route state when unmount, default is false
6688
7137
  * @param unmountcb callback of unmount
6689
7138
  */
6690
- actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
7139
+ actionsAfterUnmounted({ destroy, clearData, keepRouteState, unmountcb, }) {
6691
7140
  var _a;
6692
7141
  if (this.umdMode && this.container && !destroy) {
6693
7142
  this.cloneContainer(this.source.html, this.container, false);
@@ -6704,20 +7153,33 @@ class CreateApp {
6704
7153
  destroy,
6705
7154
  clearData: clearData || destroy,
6706
7155
  });
6707
- this.setLifeCycleState(lifeCycles.UNMOUNT);
6708
7156
  // dispatch unmount event to base app
6709
7157
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
6710
7158
  this.clearOptions(destroy);
6711
7159
  unmountcb === null || unmountcb === void 0 ? void 0 : unmountcb();
6712
7160
  }
6713
7161
  clearOptions(destroy) {
6714
- this.container.innerHTML = '';
6715
- this.container = null;
7162
+ var _a, _b;
6716
7163
  this.isPrerender = false;
6717
7164
  this.preRenderEvents = null;
6718
7165
  this.setKeepAliveState(null);
7166
+ if (this.container) {
7167
+ this.container.innerHTML = '';
7168
+ this.container = null;
7169
+ }
7170
+ else if (!this.umdMode) {
7171
+ /**
7172
+ * this.container is null means sandBox.start has not exec, so sandBox.stop won't exec either
7173
+ * we should remove iframeElement in default mode manually
7174
+ */
7175
+ (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.deleteIframeElement) === null || _b === void 0 ? void 0 : _b.call(_a);
7176
+ }
6719
7177
  // in iframe sandbox & default mode, delete the sandbox & iframeElement
6720
- // TODO: with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
7178
+ /**
7179
+ * TODO:
7180
+ * 1. with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
7181
+ * 2. 接1.0,this.sandBox置空,还需要注意后续app.sandBox相关操作,比如 scripts.ts --> app.iframe ? app.sandBox!.microBody : app.querySelector('micro-app-body'),如果是fiber或者预加载,会存在卸载后js还在处理的情况
7182
+ */
6721
7183
  if (this.iframe && !this.umdMode)
6722
7184
  this.sandBox = null;
6723
7185
  if (destroy)
@@ -6746,7 +7208,6 @@ class CreateApp {
6746
7208
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
6747
7209
  appState: 'afterhidden',
6748
7210
  });
6749
- this.setLifeCycleState(lifeCycles.AFTERHIDDEN);
6750
7211
  // dispatch afterHidden event to base app
6751
7212
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
6752
7213
  if (isRouterModeSearch(this.name)) {
@@ -6768,6 +7229,14 @@ class CreateApp {
6768
7229
  // show app when connectedCallback called with keep-alive
6769
7230
  showKeepAliveApp(container) {
6770
7231
  var _a, _b;
7232
+ /**
7233
+ * NOTE:
7234
+ * 1. this.container must set to container(micro-app element) before exec rebuildEffectSnapshot
7235
+ * ISSUE: https://github.com/micro-zoe/micro-app/issues/1115
7236
+ * 2. rebuildEffectSnapshot must exec before dispatch beforeshow event
7237
+ */
7238
+ const oldContainer = this.container;
7239
+ this.container = container;
6771
7240
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
6772
7241
  // dispatch beforeShow event to micro-app
6773
7242
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
@@ -6776,11 +7245,11 @@ class CreateApp {
6776
7245
  // dispatch beforeShow event to base app
6777
7246
  dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
6778
7247
  this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
6779
- this.container = this.cloneContainer(container, this.container, false);
7248
+ this.cloneContainer(this.container, oldContainer, false);
6780
7249
  /**
6781
7250
  * TODO:
6782
7251
  * 问题:当路由模式为custom时,keep-alive应用在重新展示,是否需要根据子应用location信息更新浏览器地址?
6783
- * 暂时不这么做吧,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
7252
+ * 暂时不这么做,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
6784
7253
  */
6785
7254
  if (isRouterModeSearch(this.name)) {
6786
7255
  // called before lifeCyclesEvent
@@ -6790,7 +7259,6 @@ class CreateApp {
6790
7259
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
6791
7260
  appState: 'aftershow',
6792
7261
  });
6793
- this.setLifeCycleState(lifeCycles.AFTERSHOW);
6794
7262
  // dispatch afterShow event to base app
6795
7263
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
6796
7264
  }
@@ -6799,7 +7267,6 @@ class CreateApp {
6799
7267
  * @param e Error
6800
7268
  */
6801
7269
  onerror(e) {
6802
- this.setLifeCycleState(lifeCycles.ERROR);
6803
7270
  // dispatch state event to micro app
6804
7271
  dispatchCustomEventToMicroApp(this, 'statechange', {
6805
7272
  appState: appStates.LOAD_FAILED
@@ -6820,13 +7287,13 @@ class CreateApp {
6820
7287
  }
6821
7288
  /**
6822
7289
  * clone origin elements to target
6823
- * @param origin Cloned element
6824
7290
  * @param target Accept cloned elements
7291
+ * @param origin Cloned element
6825
7292
  * @param deep deep clone or transfer dom
6826
7293
  */
6827
7294
  cloneContainer(target, origin, deep) {
6828
7295
  // 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
6829
- if (origin) {
7296
+ if (origin && target) {
6830
7297
  target.innerHTML = '';
6831
7298
  Array.from(deep ? this.parseHtmlString(origin.innerHTML).childNodes : origin.childNodes).forEach((node) => {
6832
7299
  target.appendChild(node);
@@ -6856,14 +7323,6 @@ class CreateApp {
6856
7323
  getAppState() {
6857
7324
  return this.state;
6858
7325
  }
6859
- // set app lifeCycleState
6860
- setLifeCycleState(state) {
6861
- this.lifeCycleState = state;
6862
- }
6863
- // get app lifeCycleState
6864
- getLifeCycleState() {
6865
- return this.lifeCycleState || '';
6866
- }
6867
7326
  // set keep-alive state
6868
7327
  setKeepAliveState(state) {
6869
7328
  this.keepAliveState = state;
@@ -6880,23 +7339,6 @@ class CreateApp {
6880
7339
  isHidden() {
6881
7340
  return keepAliveStates.KEEP_ALIVE_HIDDEN === this.keepAliveState;
6882
7341
  }
6883
- // get umd library, if it not exist, return empty object
6884
- getUmdLibraryHooks() {
6885
- // after execScripts, the app maybe unmounted
6886
- if (!this.isUnmounted() && this.sandBox) {
6887
- const libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
6888
- const proxyWindow = this.sandBox.proxyWindow;
6889
- // compatible with pre versions
6890
- if (isObject(proxyWindow[libraryName])) {
6891
- return proxyWindow[libraryName];
6892
- }
6893
- return {
6894
- mount: proxyWindow.mount,
6895
- unmount: proxyWindow.unmount,
6896
- };
6897
- }
6898
- return {};
6899
- }
6900
7342
  getMicroAppGlobalHook(eventName) {
6901
7343
  var _a, _b;
6902
7344
  const listener = (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) === null || _b === void 0 ? void 0 : _b[eventName];
@@ -7002,11 +7444,11 @@ function handleNewNode(child, app) {
7002
7444
  * @param app app
7003
7445
  * @param method raw method
7004
7446
  * @param parent parent node
7005
- * @param targetChild target node
7006
- * @param passiveChild second param of insertBefore and replaceChild
7447
+ * @param targetNode target node
7448
+ * @param passiveNode second param of insertBefore and replaceChild
7007
7449
  */
7008
- function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
7009
- const hijackParent = getHijackParent(parent, targetChild, app);
7450
+ function invokePrototypeMethod(app, rawMethod, parent, targetNode, passiveNode) {
7451
+ const hijackParent = getHijackParent(parent, targetNode, app);
7010
7452
  if (hijackParent) {
7011
7453
  /**
7012
7454
  * If parentNode is <micro-app-body>, return rawDocument.body
@@ -7023,9 +7465,9 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
7023
7465
  if (!isIframeSandbox(app.name) &&
7024
7466
  isMicroAppBody(hijackParent) &&
7025
7467
  rawMethod !== globalEnv.rawRemoveChild) {
7026
- const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
7027
- if ((!descriptor || descriptor.configurable) && !targetChild.__MICRO_APP_HAS_DPN__) {
7028
- rawDefineProperties(targetChild, {
7468
+ const descriptor = Object.getOwnPropertyDescriptor(targetNode, 'parentNode');
7469
+ if ((!descriptor || descriptor.configurable) && !targetNode.__MICRO_APP_HAS_DPN__) {
7470
+ rawDefineProperties(targetNode, {
7029
7471
  parentNode: {
7030
7472
  configurable: true,
7031
7473
  get() {
@@ -7046,68 +7488,84 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
7046
7488
  }
7047
7489
  }
7048
7490
  if ((process.env.NODE_ENV !== 'production') &&
7049
- isIFrameElement(targetChild) &&
7491
+ isIFrameElement(targetNode) &&
7050
7492
  rawMethod === globalEnv.rawAppendChild) {
7051
7493
  fixReactHMRConflict(app);
7052
7494
  }
7053
7495
  /**
7054
- * 1. If passiveChild exists, it must be insertBefore or replaceChild
7055
- * 2. When removeChild, targetChild may not be in microAppHead or head
7496
+ * 1. If passiveNode exists, it must be insertBefore or replaceChild
7497
+ * 2. When removeChild, targetNode may not be in microAppHead or head
7056
7498
  * 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])
7499
+ * 1. If passiveNode not in hijackParent, insertBefore replaceChild will be degraded to appendChild
7500
+ * E.g: document.head.replaceChild(targetNode, document.scripts[0])
7501
+ * 2. If passiveNode not in hijackParent but in parent and method is insertBefore, try insert it into the position corresponding to hijackParent
7502
+ * E.g: document.head.insertBefore(targetNode, document.head.childNodes[0])
7061
7503
  * ISSUE: https://github.com/micro-zoe/micro-app/issues/1071
7062
7504
  */
7063
- if (passiveChild && !hijackParent.contains(passiveChild)) {
7064
- if (rawMethod === globalEnv.rawInsertBefore && parent.contains(passiveChild)) {
7065
- const indexOfParent = Array.from(parent.childNodes).indexOf(passiveChild);
7505
+ if (passiveNode && !hijackParent.contains(passiveNode)) {
7506
+ if (rawMethod === globalEnv.rawInsertBefore && parent.contains(passiveNode)) {
7507
+ const indexOfParent = Array.from(parent.childNodes).indexOf(passiveNode);
7066
7508
  if (hijackParent.childNodes[indexOfParent]) {
7067
- return invokeRawMethod(rawMethod, hijackParent, targetChild, hijackParent.childNodes[indexOfParent]);
7509
+ return invokeRawMethod(rawMethod, hijackParent, targetNode, hijackParent.childNodes[indexOfParent], app);
7068
7510
  }
7069
7511
  }
7070
- return globalEnv.rawAppendChild.call(hijackParent, targetChild);
7512
+ return globalEnv.rawAppendChild.call(hijackParent, targetNode);
7071
7513
  }
7072
- else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
7073
- if (parent.contains(targetChild)) {
7074
- return rawMethod.call(parent, targetChild);
7514
+ else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetNode)) {
7515
+ if (parent.contains(targetNode)) {
7516
+ return rawMethod.call(parent, targetNode);
7075
7517
  }
7076
- return targetChild;
7518
+ return targetNode;
7077
7519
  }
7078
- return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
7520
+ return invokeRawMethod(rawMethod, hijackParent, targetNode, passiveNode, app);
7079
7521
  }
7080
- return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
7522
+ return invokeRawMethod(rawMethod, parent, targetNode, passiveNode, app);
7081
7523
  }
7082
7524
  // head/body map to micro-app-head/micro-app-body
7083
- function getHijackParent(parent, targetChild, app) {
7525
+ function getHijackParent(parent, targetNode, app) {
7084
7526
  if (app) {
7085
7527
  if (parent === document.head) {
7086
- if (app.iframe && isScriptElement(targetChild)) {
7528
+ if (app.iframe && isScriptElement(targetNode)) {
7087
7529
  return app.sandBox.microHead;
7088
7530
  }
7089
7531
  return app.querySelector('micro-app-head');
7090
7532
  }
7091
7533
  if (parent === document.body || parent === document.body.parentNode) {
7092
- if (app.iframe && isScriptElement(targetChild)) {
7534
+ if (app.iframe && isScriptElement(targetNode)) {
7093
7535
  return app.sandBox.microBody;
7094
7536
  }
7095
7537
  return app.querySelector('micro-app-body');
7096
7538
  }
7097
- if (app.iframe && isScriptElement(targetChild)) {
7539
+ if (app.iframe && isScriptElement(targetNode)) {
7098
7540
  return app.sandBox.microBody;
7099
7541
  }
7100
7542
  }
7101
7543
  return null;
7102
7544
  }
7103
- function invokeRawMethod(rawMethod, parent, targetChild, passiveChild) {
7545
+ function invokeRawMethod(rawMethod, parent, targetNode, passiveNode, app) {
7104
7546
  if (isPendMethod(rawMethod)) {
7105
- return rawMethod.call(parent, targetChild);
7547
+ /**
7548
+ * In iframe sandbox, script will pend to iframe.body, so we should reset rawMethod, because:
7549
+ * Element.prototype.append === DocumentFragment.prototype.append ==> false
7550
+ * Element.prototype.prepend === DocumentFragment.prototype.prepend ==> false
7551
+ */
7552
+ if ((app === null || app === void 0 ? void 0 : app.iframe) && isScriptElement(targetNode)) {
7553
+ if (rawMethod === globalEnv.rawFragmentAppend) {
7554
+ rawMethod = globalEnv.rawAppend;
7555
+ }
7556
+ else if (rawMethod === globalEnv.rawFragmentPrepend) {
7557
+ rawMethod = globalEnv.rawPrepend;
7558
+ }
7559
+ }
7560
+ return rawMethod.call(parent, targetNode);
7106
7561
  }
7107
- return rawMethod.call(parent, targetChild, passiveChild);
7562
+ return rawMethod.call(parent, targetNode, passiveNode);
7108
7563
  }
7109
7564
  function isPendMethod(method) {
7110
- return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
7565
+ return (method === globalEnv.rawAppend ||
7566
+ method === globalEnv.rawPrepend ||
7567
+ method === globalEnv.rawFragmentAppend ||
7568
+ method === globalEnv.rawFragmentPrepend);
7111
7569
  }
7112
7570
  /**
7113
7571
  * Attempt to complete the static resource address again before insert the node
@@ -7124,7 +7582,7 @@ function completePathDynamic(app, newChild) {
7124
7582
  globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
7125
7583
  }
7126
7584
  }
7127
- else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
7585
+ else if (/^(link|image)$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
7128
7586
  globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
7129
7587
  }
7130
7588
  }
@@ -7133,31 +7591,26 @@ function completePathDynamic(app, newChild) {
7133
7591
  * method of handle new node
7134
7592
  * @param parent parent node
7135
7593
  * @param newChild new node
7136
- * @param passiveChild passive node
7594
+ * @param passiveNode passive node
7137
7595
  * @param rawMethod method
7138
7596
  */
7139
- function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
7597
+ function commonElementHandler(parent, newChild, passiveNode, rawMethod) {
7140
7598
  const currentAppName = getCurrentAppName();
7141
7599
  if (isNode(newChild) &&
7142
7600
  !newChild.__PURE_ELEMENT__ &&
7143
7601
  (newChild.__MICRO_APP_NAME__ ||
7144
7602
  currentAppName)) {
7145
- newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
7603
+ updateElementInfo(newChild, newChild.__MICRO_APP_NAME__ || currentAppName);
7146
7604
  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
- }
7152
7605
  if (app === null || app === void 0 ? void 0 : app.container) {
7606
+ if (isStyleElement(newChild)) {
7607
+ parent.getRootNode() instanceof ShadowRoot && newChild.setAttribute('ignore', 'true');
7608
+ }
7153
7609
  completePathDynamic(app, newChild);
7154
- return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
7610
+ return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveNode && getMappingNode(passiveNode));
7155
7611
  }
7156
7612
  }
7157
- if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
7158
- return rawMethod.call(parent, newChild);
7159
- }
7160
- return rawMethod.call(parent, newChild, passiveChild);
7613
+ return invokeRawMethod(rawMethod, parent, newChild, passiveNode);
7161
7614
  }
7162
7615
  /**
7163
7616
  * Rewrite element prototype method
@@ -7166,36 +7619,19 @@ function patchElementAndDocument() {
7166
7619
  patchDocument$2();
7167
7620
  const rawRootElement = globalEnv.rawRootElement;
7168
7621
  const rawRootNode = globalEnv.rawRootNode;
7622
+ const rawDocumentFragment = globalEnv.rawDocumentFragment;
7169
7623
  // prototype methods of add element👇
7170
- rawRootElement.prototype.appendChild = function appendChild(newChild) {
7624
+ rawRootNode.prototype.appendChild = function appendChild(newChild) {
7171
7625
  return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
7172
7626
  };
7173
- rawRootElement.prototype.insertBefore = function insertBefore(newChild, refChild) {
7627
+ rawRootNode.prototype.insertBefore = function insertBefore(newChild, refChild) {
7174
7628
  return commonElementHandler(this, newChild, refChild, globalEnv.rawInsertBefore);
7175
7629
  };
7176
- rawRootElement.prototype.replaceChild = function replaceChild(newChild, oldChild) {
7630
+ rawRootNode.prototype.replaceChild = function replaceChild(newChild, oldChild) {
7177
7631
  return commonElementHandler(this, newChild, oldChild, globalEnv.rawReplaceChild);
7178
7632
  };
7179
- rawRootElement.prototype.append = function append(...nodes) {
7180
- let i = 0;
7181
- while (i < nodes.length) {
7182
- let node = nodes[i];
7183
- node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
7184
- commonElementHandler(this, markElement(node), null, globalEnv.rawAppend);
7185
- i++;
7186
- }
7187
- };
7188
- rawRootElement.prototype.prepend = function prepend(...nodes) {
7189
- let i = nodes.length;
7190
- while (i > 0) {
7191
- let node = nodes[i - 1];
7192
- node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
7193
- commonElementHandler(this, markElement(node), null, globalEnv.rawPrepend);
7194
- i--;
7195
- }
7196
- };
7197
7633
  // prototype methods of delete element👇
7198
- rawRootElement.prototype.removeChild = function removeChild(oldChild) {
7634
+ rawRootNode.prototype.removeChild = function removeChild(oldChild) {
7199
7635
  if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
7200
7636
  const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
7201
7637
  if (app === null || app === void 0 ? void 0 : app.container) {
@@ -7210,6 +7646,24 @@ function patchElementAndDocument() {
7210
7646
  }
7211
7647
  return globalEnv.rawRemoveChild.call(this, oldChild);
7212
7648
  };
7649
+ rawDocumentFragment.prototype.append = rawRootElement.prototype.append = function append(...nodes) {
7650
+ let i = 0;
7651
+ while (i < nodes.length) {
7652
+ let node = nodes[i];
7653
+ node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
7654
+ commonElementHandler(this, markElement(node), null, isDocumentFragment(this) ? globalEnv.rawFragmentAppend : globalEnv.rawAppend);
7655
+ i++;
7656
+ }
7657
+ };
7658
+ rawDocumentFragment.prototype.prepend = rawRootElement.prototype.prepend = function prepend(...nodes) {
7659
+ let i = nodes.length;
7660
+ while (i > 0) {
7661
+ let node = nodes[i - 1];
7662
+ node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
7663
+ commonElementHandler(this, markElement(node), null, isDocumentFragment(this) ? globalEnv.rawFragmentPrepend : globalEnv.rawPrepend);
7664
+ i--;
7665
+ }
7666
+ };
7213
7667
  /**
7214
7668
  * The insertAdjacentElement method of the Element interface inserts a given element node at a given position relative to the element it is invoked upon.
7215
7669
  * NOTE:
@@ -7229,52 +7683,81 @@ function patchElementAndDocument() {
7229
7683
  }
7230
7684
  return globalEnv.rawInsertAdjacentElement.call(this, where, element);
7231
7685
  };
7232
- // patch cloneNode
7233
- rawRootElement.prototype.cloneNode = function cloneNode(deep) {
7234
- const clonedNode = globalEnv.rawCloneNode.call(this, deep);
7235
- this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
7236
- return clonedNode;
7237
- };
7238
7686
  /**
7239
7687
  * document.body(head).querySelector(querySelectorAll) hijack to microAppBody(microAppHead).querySelector(querySelectorAll)
7240
7688
  * NOTE:
7241
7689
  * 1. May cause some problems!
7242
7690
  * 2. Add config options?
7243
7691
  */
7244
- function getQueryTarget(target) {
7245
- const currentAppName = getCurrentAppName();
7246
- if ((target === document.body || target === document.head) && currentAppName) {
7692
+ function getElementQueryTarget(targetNode) {
7693
+ const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
7694
+ if ((targetNode === document.body || targetNode === document.head) && currentAppName) {
7247
7695
  const app = appInstanceMap.get(currentAppName);
7248
7696
  if (app === null || app === void 0 ? void 0 : app.container) {
7249
- if (target === document.body) {
7697
+ if (targetNode === document.body) {
7250
7698
  return app.querySelector('micro-app-body');
7251
7699
  }
7252
- else if (target === document.head) {
7700
+ else if (targetNode === document.head) {
7253
7701
  return app.querySelector('micro-app-head');
7254
7702
  }
7255
7703
  }
7256
7704
  }
7257
- return target;
7705
+ return targetNode;
7706
+ }
7707
+ /**
7708
+ * In iframe sandbox, script will render to iframe instead of micro-app-body
7709
+ * So when query elements, we need to search both micro-app and iframe
7710
+ * @param isEmpty get empty result
7711
+ * @param targetNode targetNode element
7712
+ * @param result origin result
7713
+ * @param selectors selectors
7714
+ * @param methodName querySelector or querySelectorAll
7715
+ */
7716
+ function getElementQueryResult(isEmpty, targetNode, result, selectors, methodName) {
7717
+ if (isEmpty) {
7718
+ const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
7719
+ if (currentAppName && isIframeSandbox(currentAppName)) {
7720
+ const app = appInstanceMap.get(currentAppName);
7721
+ if (isMicroAppHead(targetNode)) {
7722
+ return app.sandBox.microHead[methodName](selectors);
7723
+ }
7724
+ if (isMicroAppBody(targetNode)) {
7725
+ return app.sandBox.microBody[methodName](selectors);
7726
+ }
7727
+ }
7728
+ }
7729
+ return result;
7258
7730
  }
7259
7731
  rawRootElement.prototype.querySelector = function querySelector(selectors) {
7260
7732
  var _a;
7261
- return globalEnv.rawElementQuerySelector.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
7733
+ const _this = (_a = getElementQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
7734
+ const result = globalEnv.rawElementQuerySelector.call(_this, selectors);
7735
+ return getElementQueryResult(isNull(result) && _this !== this, _this, result, selectors, 'querySelector');
7262
7736
  };
7263
7737
  rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
7264
7738
  var _a;
7265
- return globalEnv.rawElementQuerySelectorAll.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
7739
+ const _this = (_a = getElementQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
7740
+ const result = globalEnv.rawElementQuerySelectorAll.call(_this, selectors);
7741
+ return getElementQueryResult(!result.length && _this !== this, _this, result, selectors, 'querySelectorAll');
7266
7742
  };
7267
7743
  // rewrite setAttribute, complete resource address
7268
7744
  rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
7269
- const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
7270
- if (appName &&
7271
- appInstanceMap.has(appName) &&
7272
- (((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
7273
- (key === 'href' && /^link$/i.test(this.tagName)))) {
7274
- const app = appInstanceMap.get(appName);
7275
- value = CompletionPath(value, app.url);
7745
+ if (/^micro-app(-\S+)?/i.test(this.tagName) &&
7746
+ key === 'data' &&
7747
+ this.setAttribute !== rawRootElement.prototype.setAttribute) {
7748
+ this.setAttribute(key, value);
7749
+ }
7750
+ else {
7751
+ const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
7752
+ if (appName &&
7753
+ appInstanceMap.has(appName) &&
7754
+ (((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
7755
+ (key === 'href' && /^(link|image)$/i.test(this.tagName)))) {
7756
+ const app = appInstanceMap.get(appName);
7757
+ value = CompletionPath(value, app.url);
7758
+ }
7759
+ globalEnv.rawSetAttribute.call(this, key, value);
7276
7760
  }
7277
- globalEnv.rawSetAttribute.call(this, key, value);
7278
7761
  };
7279
7762
  /**
7280
7763
  * TODO: 兼容直接通过img.src等操作设置的资源
@@ -7301,7 +7784,7 @@ function patchElementAndDocument() {
7301
7784
  // return get?.call(this)
7302
7785
  // },
7303
7786
  // set: function (value) {
7304
- // const currentAppName = getCurrentAppName()
7787
+ // const currentAppName = this.__MICRO_APP_NAME__ || getCurrentAppName()
7305
7788
  // if (currentAppName && appInstanceMap.has(currentAppName)) {
7306
7789
  // const app = appInstanceMap.get(currentAppName)
7307
7790
  // value = CompletionPath(value, app!.url)
@@ -7310,41 +7793,25 @@ function patchElementAndDocument() {
7310
7793
  // },
7311
7794
  // })
7312
7795
  // })
7313
- rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
7314
- configurable: true,
7315
- enumerable: true,
7316
- get() {
7317
- return globalEnv.rawInnerHTMLDesc.get.call(this);
7318
- },
7319
- set(code) {
7320
- globalEnv.rawInnerHTMLDesc.set.call(this, code);
7321
- const currentAppName = getCurrentAppName();
7322
- Array.from(this.children).forEach((child) => {
7323
- if (isElement(child) && currentAppName) {
7324
- // TODO: 使用updateElementInfo进行更新
7325
- child.__MICRO_APP_NAME__ = currentAppName;
7326
- }
7327
- });
7328
- }
7329
- });
7330
7796
  rawDefineProperty(rawRootNode.prototype, 'parentNode', {
7331
7797
  configurable: true,
7332
7798
  enumerable: true,
7333
7799
  get() {
7334
7800
  var _a, _b, _c;
7335
7801
  /**
7336
- * hijack parentNode of html
7802
+ * hijack parentNode of html for with sandbox
7337
7803
  * Scenes:
7338
7804
  * 1. element-ui@2/lib/utils/popper.js
7339
7805
  * // root is child app window, so root.document is proxyDocument or microDocument
7340
7806
  * if (element.parentNode === root.document) ...
7341
7807
  */
7342
- const currentAppName = getCurrentAppName();
7808
+ const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
7343
7809
  if (currentAppName && this === globalEnv.rawDocument.firstElementChild) {
7344
7810
  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;
7345
7811
  if (microDocument)
7346
7812
  return microDocument;
7347
7813
  }
7814
+ // NOTE: run after hijack html.parentNode
7348
7815
  const result = globalEnv.rawParentNodeDesc.get.call(this);
7349
7816
  /**
7350
7817
  * If parentNode is <micro-app-body>, return rawDocument.body
@@ -7363,16 +7830,34 @@ function patchElementAndDocument() {
7363
7830
  return result;
7364
7831
  },
7365
7832
  });
7833
+ rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
7834
+ configurable: true,
7835
+ enumerable: true,
7836
+ get() {
7837
+ return globalEnv.rawInnerHTMLDesc.get.call(this);
7838
+ },
7839
+ set(code) {
7840
+ globalEnv.rawInnerHTMLDesc.set.call(this, code);
7841
+ const currentAppName = this.__MICRO_APP_NAME__ || getCurrentAppName();
7842
+ Array.from(this.children).forEach((child) => {
7843
+ if (isElement(child) && currentAppName) {
7844
+ updateElementInfo(child, currentAppName);
7845
+ }
7846
+ });
7847
+ }
7848
+ });
7849
+ // patch cloneNode
7850
+ rawRootNode.prototype.cloneNode = function cloneNode(deep) {
7851
+ const clonedNode = globalEnv.rawCloneNode.call(this, deep);
7852
+ return updateElementInfo(clonedNode, this.__MICRO_APP_NAME__);
7853
+ };
7366
7854
  }
7367
7855
  /**
7368
7856
  * Mark the newly created element in the micro application
7369
7857
  * @param element new element
7370
7858
  */
7371
7859
  function markElement(element) {
7372
- const currentAppName = getCurrentAppName();
7373
- if (currentAppName)
7374
- element.__MICRO_APP_NAME__ = currentAppName;
7375
- return element;
7860
+ return updateElementInfo(element, getCurrentAppName());
7376
7861
  }
7377
7862
  // methods of document
7378
7863
  function patchDocument$2() {
@@ -7503,18 +7988,18 @@ function releasePatchElementAndDocument() {
7503
7988
  releasePatchDocument();
7504
7989
  const rawRootElement = globalEnv.rawRootElement;
7505
7990
  const rawRootNode = globalEnv.rawRootNode;
7506
- rawRootElement.prototype.appendChild = globalEnv.rawAppendChild;
7507
- rawRootElement.prototype.insertBefore = globalEnv.rawInsertBefore;
7508
- rawRootElement.prototype.replaceChild = globalEnv.rawReplaceChild;
7509
- rawRootElement.prototype.removeChild = globalEnv.rawRemoveChild;
7991
+ rawRootNode.prototype.appendChild = globalEnv.rawAppendChild;
7992
+ rawRootNode.prototype.insertBefore = globalEnv.rawInsertBefore;
7993
+ rawRootNode.prototype.replaceChild = globalEnv.rawReplaceChild;
7994
+ rawRootNode.prototype.removeChild = globalEnv.rawRemoveChild;
7995
+ rawRootNode.prototype.cloneNode = globalEnv.rawCloneNode;
7510
7996
  rawRootElement.prototype.append = globalEnv.rawAppend;
7511
7997
  rawRootElement.prototype.prepend = globalEnv.rawPrepend;
7512
- rawRootElement.prototype.cloneNode = globalEnv.rawCloneNode;
7513
7998
  rawRootElement.prototype.querySelector = globalEnv.rawElementQuerySelector;
7514
7999
  rawRootElement.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
7515
8000
  rawRootElement.prototype.setAttribute = globalEnv.rawSetAttribute;
7516
- rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
7517
8001
  rawDefineProperty(rawRootNode.prototype, 'parentNode', globalEnv.rawParentNodeDesc);
8002
+ rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
7518
8003
  }
7519
8004
  // Set the style of micro-app-head and micro-app-body
7520
8005
  let hasRejectMicroAppStyle = false;
@@ -7544,15 +8029,18 @@ function initGlobalEnv() {
7544
8029
  const rawRootElement = rawWindow.Element;
7545
8030
  const rawRootNode = rawWindow.Node;
7546
8031
  const rawRootEventTarget = rawWindow.EventTarget;
8032
+ const rawDocumentFragment = rawWindow.DocumentFragment;
7547
8033
  // save patch raw methods, pay attention to this binding
8034
+ const rawAppendChild = rawRootNode.prototype.appendChild;
8035
+ const rawInsertBefore = rawRootNode.prototype.insertBefore;
8036
+ const rawReplaceChild = rawRootNode.prototype.replaceChild;
8037
+ const rawRemoveChild = rawRootNode.prototype.removeChild;
7548
8038
  const rawSetAttribute = rawRootElement.prototype.setAttribute;
7549
- const rawAppendChild = rawRootElement.prototype.appendChild;
7550
- const rawInsertBefore = rawRootElement.prototype.insertBefore;
7551
- const rawReplaceChild = rawRootElement.prototype.replaceChild;
7552
- const rawRemoveChild = rawRootElement.prototype.removeChild;
7553
8039
  const rawAppend = rawRootElement.prototype.append;
7554
8040
  const rawPrepend = rawRootElement.prototype.prepend;
7555
- const rawCloneNode = rawRootElement.prototype.cloneNode;
8041
+ const rawFragmentAppend = rawDocumentFragment.prototype.append;
8042
+ const rawFragmentPrepend = rawDocumentFragment.prototype.prepend;
8043
+ const rawCloneNode = rawRootNode.prototype.cloneNode;
7556
8044
  const rawElementQuerySelector = rawRootElement.prototype.querySelector;
7557
8045
  const rawElementQuerySelectorAll = rawRootElement.prototype.querySelectorAll;
7558
8046
  const rawInsertAdjacentElement = rawRootElement.prototype.insertAdjacentElement;
@@ -7570,13 +8058,10 @@ function initGlobalEnv() {
7570
8058
  const rawGetElementsByClassName = rawRootDocument.prototype.getElementsByClassName;
7571
8059
  const rawGetElementsByTagName = rawRootDocument.prototype.getElementsByTagName;
7572
8060
  const rawGetElementsByName = rawRootDocument.prototype.getElementsByName;
7573
- const ImageProxy = new Proxy(Image, {
8061
+ // TODO: 将ImageProxy移出去
8062
+ const ImageProxy = new Proxy(rawWindow.Image, {
7574
8063
  construct(Target, args) {
7575
- const elementImage = new Target(...args);
7576
- const currentAppName = getCurrentAppName();
7577
- if (currentAppName)
7578
- elementImage.__MICRO_APP_NAME__ = currentAppName;
7579
- return elementImage;
8064
+ return updateElementInfo(new Target(...args), getCurrentAppName());
7580
8065
  },
7581
8066
  });
7582
8067
  /**
@@ -7602,6 +8087,7 @@ function initGlobalEnv() {
7602
8087
  rawRootDocument,
7603
8088
  rawRootElement,
7604
8089
  rawRootNode,
8090
+ rawDocumentFragment,
7605
8091
  // source/patch
7606
8092
  rawSetAttribute,
7607
8093
  rawAppendChild,
@@ -7610,6 +8096,8 @@ function initGlobalEnv() {
7610
8096
  rawRemoveChild,
7611
8097
  rawAppend,
7612
8098
  rawPrepend,
8099
+ rawFragmentAppend,
8100
+ rawFragmentPrepend,
7613
8101
  rawCloneNode,
7614
8102
  rawElementQuerySelector,
7615
8103
  rawElementQuerySelectorAll,
@@ -7649,7 +8137,7 @@ function initGlobalEnv() {
7649
8137
  * @param tagName element name
7650
8138
  */
7651
8139
  function defineElement(tagName) {
7652
- class MicroAppElement extends getBaseHTMLElement() {
8140
+ class MicroAppElement extends HTMLElement {
7653
8141
  constructor() {
7654
8142
  super(...arguments);
7655
8143
  this.isWaiting = false;
@@ -7714,6 +8202,13 @@ function defineElement(tagName) {
7714
8202
  // baseRoute: route prefix, default is ''
7715
8203
  // keep-alive: open keep-alive mode
7716
8204
  connectedCallback() {
8205
+ /**
8206
+ * In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
8207
+ * If <micro-app>.prototype is not MicroAppElement.prototype, we should reset it
8208
+ */
8209
+ if (Object.getPrototypeOf(this) !== MicroAppElement.prototype) {
8210
+ Object.setPrototypeOf(this, MicroAppElement.prototype);
8211
+ }
7717
8212
  const cacheCount = ++this.connectedCount;
7718
8213
  this.connectStateMap.set(cacheCount, true);
7719
8214
  /**
@@ -7846,12 +8341,12 @@ function defineElement(tagName) {
7846
8341
  /**
7847
8342
  * url is different & old app is unmounted or prefetch, create new app to replace old one
7848
8343
  */
7849
- logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${oldAppUrl} replaced by a new app with url: ${targetUrl}`, this.appName);
8344
+ logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url ${oldAppUrl} replaced by a new app with url ${targetUrl}`, this.appName);
7850
8345
  }
7851
8346
  this.handleCreateApp();
7852
8347
  }
7853
8348
  else {
7854
- logError(`app name conflict, an app named: ${this.appName} with url: ${oldAppUrl} is running`);
8349
+ logError(`app name conflict, an app named ${this.appName} with url ${oldAppUrl} is running`);
7855
8350
  }
7856
8351
  }
7857
8352
  else {
@@ -8095,6 +8590,7 @@ function defineElement(tagName) {
8095
8590
  }
8096
8591
  else {
8097
8592
  // get path from browser URL
8593
+ // TODO: 新版本路由系统要重新兼容ssr
8098
8594
  let targetPath = getNoHashMicroPathFromURL(this.appName, baseUrl);
8099
8595
  const defaultPagePath = this.getDefaultPage();
8100
8596
  if (!targetPath && defaultPagePath) {
@@ -8122,8 +8618,9 @@ function defineElement(tagName) {
8122
8618
  * @returns router-mode
8123
8619
  */
8124
8620
  getMemoryRouterMode() {
8125
- return getRouterMode(this.getAttribute('router-mode'),
8621
+ return initRouterMode(this.getAttribute('router-mode'),
8126
8622
  // is micro-app element set disable-memory-router, like <micro-app disable-memory-router></micro-app>
8623
+ // or <micro-app disable-memory-router='false'></micro-app>
8127
8624
  this.compatibleProperties('disable-memory-router') && this.compatibleDisableProperties('disable-memory-router'));
8128
8625
  }
8129
8626
  /**
@@ -8150,6 +8647,17 @@ function defineElement(tagName) {
8150
8647
  globalEnv.rawSetAttribute.call(this, key, value);
8151
8648
  }
8152
8649
  }
8650
+ /**
8651
+ * get delay time of router event
8652
+ * @returns delay time
8653
+ */
8654
+ getRouterEventDelay() {
8655
+ let delay = parseInt(this.getAttribute('router-event-delay'));
8656
+ if (isNaN(delay)) {
8657
+ delay = parseInt((isFunction(microApp.options['router-event-delay']) ? microApp.options['router-event-delay'](this.appName) : microApp.options['router-event-delay']));
8658
+ }
8659
+ return !isNaN(delay) ? delay : 0;
8660
+ }
8153
8661
  /**
8154
8662
  * Data from the base application
8155
8663
  */
@@ -8186,7 +8694,7 @@ function defineElement(tagName) {
8186
8694
  return this.getBaseRouteCompatible();
8187
8695
  }
8188
8696
  }
8189
- globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
8697
+ window.customElements.define(tagName, MicroAppElement);
8190
8698
  }
8191
8699
 
8192
8700
  /**
@@ -8218,7 +8726,7 @@ function preFetch(apps, delay) {
8218
8726
  const delayTime = isNumber(delay) ? delay : microApp.options.prefetchDelay;
8219
8727
  /**
8220
8728
  * TODO: remove setTimeout
8221
- * Is there a better way?
8729
+ * 如果要保留setTimeout,则需要考虑清空定时器的情况
8222
8730
  */
8223
8731
  setTimeout(() => {
8224
8732
  // releasePrefetchEffect()
@@ -8272,7 +8780,7 @@ function preFetchAction(options) {
8272
8780
  * 问题:
8273
8781
  * 1、如何确保子应用进行跳转时不影响到浏览器地址??pure??
8274
8782
  */
8275
- routerMode: getRouterMode(options['router-mode']),
8783
+ routerMode: initRouterMode(options['router-mode']),
8276
8784
  baseroute: options.baseroute,
8277
8785
  disablePatchRequest: options['disable-patch-request'],
8278
8786
  });
@@ -8309,7 +8817,7 @@ function getGlobalAssets(assets) {
8309
8817
  // TODO: requestIdleCallback for every file
8310
8818
  function fetchGlobalResources(resources, suffix, sourceHandler) {
8311
8819
  if (isArray(resources)) {
8312
- const effectiveResource = resources.filter((path) => isString(path) && path.includes(`.${suffix}`) && !sourceHandler.hasInfo(path));
8820
+ const effectiveResource = resources.filter((path) => isString(path) && isTargetExtension(path, suffix) && !sourceHandler.hasInfo(path));
8313
8821
  const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
8314
8822
  // fetch resource with stream
8315
8823
  promiseStream(fetchResourcePromise, (res) => {
@@ -8453,7 +8961,7 @@ function unmountApp(appName, options) {
8453
8961
  }
8454
8962
  }
8455
8963
  else {
8456
- logWarn(`app ${appName} does not exist`);
8964
+ logWarn(`app ${appName} does not exist when unmountApp`);
8457
8965
  resolve(false);
8458
8966
  }
8459
8967
  });
@@ -8483,7 +8991,7 @@ function reload(appName, destroy) {
8483
8991
  }
8484
8992
  }
8485
8993
  else {
8486
- logWarn(`app ${appName} does not exist`);
8994
+ logWarn(`app ${appName} does not exist when reload app`);
8487
8995
  resolve(false);
8488
8996
  }
8489
8997
  });
@@ -8538,20 +9046,6 @@ function renderApp(options) {
8538
9046
  container.appendChild(microAppElement);
8539
9047
  });
8540
9048
  }
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
- }
8555
9049
  class MicroApp extends EventCenterForBaseApp {
8556
9050
  constructor() {
8557
9051
  super(...arguments);
@@ -8566,7 +9060,6 @@ class MicroApp extends EventCenterForBaseApp {
8566
9060
  this.getAllApps = getAllApps;
8567
9061
  this.reload = reload;
8568
9062
  this.renderApp = renderApp;
8569
- this.getAppStatus = getAppStatus;
8570
9063
  }
8571
9064
  start(options) {
8572
9065
  var _a, _b;
@@ -8591,7 +9084,7 @@ class MicroApp extends EventCenterForBaseApp {
8591
9084
  }
8592
9085
  }
8593
9086
  initGlobalEnv();
8594
- if (globalEnv.rawWindow.customElements.get(this.tagName)) {
9087
+ if (window.customElements.get(this.tagName)) {
8595
9088
  return logWarn(`element ${this.tagName} is already defined`);
8596
9089
  }
8597
9090
  if (isPlainObject(options)) {
@@ -8622,5 +9115,5 @@ class MicroApp extends EventCenterForBaseApp {
8622
9115
  const microApp = new MicroApp();
8623
9116
 
8624
9117
  export default microApp;
8625
- export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, getAppStatus, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
9118
+ export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
8626
9119
  //# sourceMappingURL=index.esm.js.map