@micro-zoe/micro-app 1.0.0-rc.1 → 1.0.0-rc.3

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.1';
1
+ const version = '1.0.0-rc.3';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -15,7 +15,9 @@ const assign = Object.assign;
15
15
  // Object prototype methods
16
16
  const rawDefineProperty = Object.defineProperty;
17
17
  const rawDefineProperties = Object.defineProperties;
18
+ const rawToString = Object.prototype.toString;
18
19
  const rawHasOwnProperty = Object.prototype.hasOwnProperty;
20
+ const toTypeString = (value) => rawToString.call(value);
19
21
  // is Undefined
20
22
  function isUndefined(target) {
21
23
  return target === undefined;
@@ -42,15 +44,15 @@ function isFunction(target) {
42
44
  }
43
45
  // is PlainObject
44
46
  function isPlainObject(target) {
45
- return toString.call(target) === '[object Object]';
47
+ return toTypeString(target) === '[object Object]';
46
48
  }
47
49
  // is Object
48
50
  function isObject(target) {
49
- return typeof target === 'object';
51
+ return !isNull(target) && typeof target === 'object';
50
52
  }
51
53
  // is Promise
52
54
  function isPromise(target) {
53
- return toString.call(target) === '[object Promise]';
55
+ return toTypeString(target) === '[object Promise]';
54
56
  }
55
57
  // is bind function
56
58
  function isBoundFunction(target) {
@@ -87,40 +89,32 @@ function isNode(target) {
87
89
  return target instanceof Node || isNumber((_a = target) === null || _a === void 0 ? void 0 : _a.nodeType);
88
90
  }
89
91
  function isLinkElement(target) {
90
- var _a, _b;
91
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'LINK';
92
+ return toTypeString(target) === '[object HTMLLinkElement]';
92
93
  }
93
94
  function isStyleElement(target) {
94
- var _a, _b;
95
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'STYLE';
95
+ return toTypeString(target) === '[object HTMLStyleElement]';
96
96
  }
97
97
  function isScriptElement(target) {
98
- var _a, _b;
99
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'SCRIPT';
98
+ return toTypeString(target) === '[object HTMLScriptElement]';
100
99
  }
101
100
  function isIFrameElement(target) {
102
- var _a, _b;
103
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IFRAME';
101
+ return toTypeString(target) === '[object HTMLIFrameElement]';
104
102
  }
105
103
  function isDivElement(target) {
106
- var _a, _b;
107
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'DIV';
104
+ return toTypeString(target) === '[object HTMLDivElement]';
108
105
  }
109
106
  function isImageElement(target) {
110
- var _a, _b;
111
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IMG';
107
+ return toTypeString(target) === '[object HTMLImageElement]';
112
108
  }
113
109
  function isBaseElement(target) {
114
- var _a, _b;
115
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'BASE';
110
+ return toTypeString(target) === '[object HTMLBaseElement]';
116
111
  }
117
112
  function isMicroAppBody(target) {
118
- var _a, _b;
119
- return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'MICRO-APP-BODY';
113
+ return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-BODY';
120
114
  }
121
115
  // is ProxyDocument
122
116
  function isProxyDocument(target) {
123
- return toString.call(target) === '[object ProxyDocument]';
117
+ return toTypeString(target) === '[object ProxyDocument]';
124
118
  }
125
119
  /**
126
120
  * format error log
@@ -344,7 +338,7 @@ function removeDomScope() {
344
338
  * Create pure elements
345
339
  */
346
340
  function pureCreateElement(tagName, options) {
347
- const element = document.createElement(tagName, options);
341
+ const element = (window.rawDocument || document).createElement(tagName, options);
348
342
  if (element.__MICRO_APP_NAME__)
349
343
  delete element.__MICRO_APP_NAME__;
350
344
  element.__PURE_ELEMENT__ = true;
@@ -550,11 +544,23 @@ function execMicroAppGlobalHook(fn, appName, hookName, ...args) {
550
544
  logError(`An error occurred in app ${appName} window.${hookName} \n`, null, e);
551
545
  }
552
546
  }
547
+ /**
548
+ * remove all childNode from target node
549
+ * @param $dom target node
550
+ */
553
551
  function clearDOM($dom) {
554
552
  while ($dom === null || $dom === void 0 ? void 0 : $dom.firstChild) {
555
553
  $dom.removeChild($dom.firstChild);
556
554
  }
557
555
  }
556
+ /**
557
+ * get HTMLElement from base app
558
+ * @returns HTMLElement
559
+ */
560
+ function getBaseHTMLElement() {
561
+ var _a;
562
+ return (((_a = window.rawWindow) === null || _a === void 0 ? void 0 : _a.HTMLElement) || window.HTMLElement);
563
+ }
558
564
 
559
565
  function formatEventInfo(event, element) {
560
566
  Object.defineProperties(event, {
@@ -654,7 +660,10 @@ class HTMLLoader {
654
660
  run(app, successCb) {
655
661
  const appName = app.name;
656
662
  const htmlUrl = app.ssrUrl || app.url;
657
- fetchSource(htmlUrl, appName, { cache: 'no-cache' }).then((htmlStr) => {
663
+ const htmlPromise = htmlUrl.includes('.js')
664
+ ? Promise.resolve(`<micro-app-head><script src='${htmlUrl}'></script></micro-app-head><micro-app-body></micro-app-body>`)
665
+ : fetchSource(htmlUrl, appName, { cache: 'no-cache' });
666
+ htmlPromise.then((htmlStr) => {
658
667
  if (!htmlStr) {
659
668
  const msg = 'html is empty, please check in detail';
660
669
  app.onerror(new Error(msg));
@@ -809,8 +818,8 @@ class CSSParser {
809
818
  return parseError("Declaration missing '}'", this.linkPath);
810
819
  return true;
811
820
  }
812
- matchAllDeclarations() {
813
- let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^}/])*/, true)[0];
821
+ matchAllDeclarations(nesting = 1) {
822
+ let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^{}/])*/, true)[0];
814
823
  if (cssValue) {
815
824
  if (!this.scopecssDisableNextLine &&
816
825
  (!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
@@ -829,16 +838,30 @@ class CSSParser {
829
838
  }
830
839
  // reset scopecssDisableNextLine
831
840
  this.scopecssDisableNextLine = false;
832
- if (!this.cssText || this.cssText.charAt(0) === '}')
841
+ if (!this.cssText)
833
842
  return;
843
+ if (this.cssText.charAt(0) === '}') {
844
+ if (!nesting)
845
+ return;
846
+ if (nesting > 1) {
847
+ this.commonMatch(/}+/);
848
+ }
849
+ return this.matchAllDeclarations(nesting - 1);
850
+ }
834
851
  // extract comments in declarations
835
- if (this.cssText.charAt(0) === '/' && this.cssText.charAt(1) === '*') {
836
- this.matchComments();
852
+ if (this.cssText.charAt(0) === '/') {
853
+ if (this.cssText.charAt(1) === '*') {
854
+ this.matchComments();
855
+ }
856
+ else {
857
+ this.commonMatch(/\/+/);
858
+ }
837
859
  }
838
- else {
839
- this.commonMatch(/\/+/);
860
+ if (this.cssText.charAt(0) === '{') {
861
+ this.commonMatch(/{+\s*/);
862
+ nesting++;
840
863
  }
841
- return this.matchAllDeclarations();
864
+ return this.matchAllDeclarations(nesting);
842
865
  }
843
866
  matchAtRule() {
844
867
  if (this.cssText[0] !== '@')
@@ -1467,6 +1490,8 @@ const SCOPE_WINDOW_EVENT = [
1467
1490
  'unload',
1468
1491
  'unmount',
1469
1492
  'appstate-change',
1493
+ 'statechange',
1494
+ 'mounted',
1470
1495
  ];
1471
1496
  // on event bound to child app window
1472
1497
  const SCOPE_WINDOW_ON_EVENT = [
@@ -1475,6 +1500,7 @@ const SCOPE_WINDOW_ON_EVENT = [
1475
1500
  'onload',
1476
1501
  'onbeforeunload',
1477
1502
  'onunload',
1503
+ 'onerror'
1478
1504
  ];
1479
1505
  // event bound to child app document
1480
1506
  const SCOPE_DOCUMENT_EVENT = [
@@ -1524,8 +1550,7 @@ function isInlineMode(app, scriptInfo) {
1524
1550
  return (app.inline ||
1525
1551
  scriptInfo.appSpace[app.name].inline ||
1526
1552
  isTypeModule(app, scriptInfo) ||
1527
- isSpecialScript(app, scriptInfo) ||
1528
- app.iframe);
1553
+ isSpecialScript(app, scriptInfo));
1529
1554
  }
1530
1555
  // TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
1531
1556
  function getEffectWindow(app) {
@@ -1941,6 +1966,8 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
1941
1966
  }
1942
1967
  catch (e) {
1943
1968
  console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
1969
+ // throw error in with sandbox to parent app
1970
+ throw e;
1944
1971
  }
1945
1972
  }
1946
1973
  /**
@@ -2687,148 +2714,6 @@ function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
2687
2714
  return value;
2688
2715
  }
2689
2716
 
2690
- class Adapter {
2691
- constructor() {
2692
- // keys that can only assigned to rawWindow
2693
- this.escapeSetterKeyList = [
2694
- 'location',
2695
- ];
2696
- // keys that can escape to rawWindow
2697
- this.staticEscapeProperties = [
2698
- 'System',
2699
- '__cjsWrapper',
2700
- ];
2701
- // keys that scoped in child app
2702
- this.staticScopeProperties = [
2703
- 'webpackJsonp',
2704
- 'webpackHotUpdate',
2705
- 'Vue',
2706
- ];
2707
- this.injectReactHMRProperty();
2708
- }
2709
- // adapter for react
2710
- injectReactHMRProperty() {
2711
- if ((process.env.NODE_ENV !== 'production')) {
2712
- // react child in non-react env
2713
- this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
2714
- // in react parent
2715
- if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
2716
- this.staticScopeProperties = this.staticScopeProperties.concat([
2717
- '__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
2718
- '__reactRefreshInjected',
2719
- ]);
2720
- }
2721
- }
2722
- }
2723
- }
2724
- // Fix conflict of babel-polyfill@6.x
2725
- function fixBabelPolyfill6() {
2726
- if (globalEnv.rawWindow._babelPolyfill)
2727
- globalEnv.rawWindow._babelPolyfill = false;
2728
- }
2729
- /**
2730
- * Fix error of hot reload when parent&child created by create-react-app in development environment
2731
- * Issue: https://github.com/micro-zoe/micro-app/issues/382
2732
- */
2733
- function fixReactHMRConflict(app) {
2734
- var _a;
2735
- if ((process.env.NODE_ENV !== 'production')) {
2736
- const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
2737
- const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
2738
- if (rawReactErrorHook && childReactErrorHook) {
2739
- globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
2740
- defer(() => {
2741
- globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
2742
- });
2743
- }
2744
- }
2745
- }
2746
- /**
2747
- * reDefine parentNode of html
2748
- * Scenes:
2749
- * 1. element-ui@2/lib/utils/popper.js
2750
- * var parent = element.parentNode;
2751
- * // root is child app window
2752
- * if (parent === root.document) ...
2753
- */
2754
- function throttleDeferForParentNode(microDocument) {
2755
- const html = globalEnv.rawDocument.firstElementChild;
2756
- if ((html === null || html === void 0 ? void 0 : html.parentNode) === globalEnv.rawDocument) {
2757
- setParentNode(html, microDocument);
2758
- defer(() => {
2759
- setParentNode(html, globalEnv.rawDocument);
2760
- });
2761
- }
2762
- }
2763
- /**
2764
- * Modify the point of parentNode
2765
- * @param target target Node
2766
- * @param value parentNode
2767
- */
2768
- function setParentNode(target, value) {
2769
- const descriptor = Object.getOwnPropertyDescriptor(target, 'parentNode');
2770
- if (!descriptor || descriptor.configurable) {
2771
- rawDefineProperty(target, 'parentNode', {
2772
- value,
2773
- configurable: true,
2774
- });
2775
- }
2776
- }
2777
- /**
2778
- * update dom tree of target dom
2779
- * @param container target dom
2780
- * @param appName app name
2781
- */
2782
- function patchElementTree(container, appName) {
2783
- const children = Array.from(container.children);
2784
- children.length && children.forEach((child) => {
2785
- patchElementTree(child, appName);
2786
- });
2787
- for (const child of children) {
2788
- updateElementInfo(child, appName);
2789
- }
2790
- }
2791
- /**
2792
- * rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
2793
- * @param node target node
2794
- * @param appName app name
2795
- * @returns target node
2796
- */
2797
- function updateElementInfo(node, appName) {
2798
- var _a, _b;
2799
- const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
2800
- if (isNode(node) &&
2801
- !node.__MICRO_APP_NAME__ &&
2802
- !node.__PURE_ELEMENT__ &&
2803
- proxyWindow) {
2804
- /**
2805
- * TODO:
2806
- * 1. 测试baseURI和ownerDocument在with沙箱中是否正确
2807
- * 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
2808
- * 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
2809
- * 3. 性能: defineProperty的性能肯定不如直接设置
2810
- */
2811
- rawDefineProperties(node, {
2812
- baseURI: {
2813
- configurable: true,
2814
- get: () => proxyWindow.location.href,
2815
- },
2816
- __MICRO_APP_NAME__: {
2817
- configurable: true,
2818
- writable: true,
2819
- value: appName,
2820
- },
2821
- });
2822
- if (isIframeSandbox(appName)) {
2823
- rawDefineProperty(node, 'ownerDocument', {
2824
- configurable: true,
2825
- get: () => proxyWindow.document,
2826
- });
2827
- }
2828
- }
2829
- return node;
2830
- }
2831
-
2832
2717
  /**
2833
2718
  * create proxyDocument and MicroDocument, rewrite document of child app
2834
2719
  * @param appName app name
@@ -2955,11 +2840,36 @@ function createProxyDocument(appName, sandbox) {
2955
2840
  eventListenerMap.clear();
2956
2841
  }
2957
2842
  };
2843
+ const genProxyDocumentProps = () => {
2844
+ var _a;
2845
+ // microApp framework built-in Proxy
2846
+ const builtInProxyProps = new Map([
2847
+ ['onclick', (value) => {
2848
+ if (isFunction(onClickHandler)) {
2849
+ rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
2850
+ }
2851
+ // TODO: listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
2852
+ if (isFunction(value)) {
2853
+ rawAddEventListener.call(rawDocument, 'click', value, false);
2854
+ }
2855
+ onClickHandler = value;
2856
+ }]
2857
+ ]);
2858
+ // external custom proxy
2859
+ const customProxyDocumentProps = ((_a = microApp.options) === null || _a === void 0 ? void 0 : _a.customProxyDocumentProps) || new Map();
2860
+ // External has higher priority than built-in
2861
+ const mergedProxyDocumentProps = new Map([
2862
+ ...builtInProxyProps,
2863
+ ...customProxyDocumentProps,
2864
+ ]);
2865
+ return mergedProxyDocumentProps;
2866
+ };
2867
+ const mergedProxyDocumentProps = genProxyDocumentProps();
2958
2868
  const proxyDocument = new Proxy(rawDocument, {
2959
2869
  get: (target, key) => {
2960
2870
  var _a;
2961
2871
  throttleDeferForSetAppName(appName);
2962
- throttleDeferForParentNode(proxyDocument);
2872
+ // TODO: 转换成数据形式,类似iframe的方式
2963
2873
  if (key === 'createElement')
2964
2874
  return createElement;
2965
2875
  if (key === Symbol.toStringTag)
@@ -2974,18 +2884,14 @@ function createProxyDocument(appName, sandbox) {
2974
2884
  return removeEventListener;
2975
2885
  if (key === 'microAppElement')
2976
2886
  return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container;
2887
+ if (key === '__MICRO_APP_NAME__')
2888
+ return appName;
2977
2889
  return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
2978
2890
  },
2979
2891
  set: (target, key, value) => {
2980
- if (key === 'onclick') {
2981
- if (isFunction(onClickHandler)) {
2982
- rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
2983
- }
2984
- // TODO: listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
2985
- if (isFunction(value)) {
2986
- rawAddEventListener.call(rawDocument, 'click', value, false);
2987
- }
2988
- onClickHandler = value;
2892
+ if (mergedProxyDocumentProps.has(key)) {
2893
+ const proxyCallback = mergedProxyDocumentProps.get(key);
2894
+ proxyCallback(value);
2989
2895
  }
2990
2896
  else if (key !== 'microAppElement') {
2991
2897
  /**
@@ -3018,7 +2924,8 @@ function createMicroDocument(appName, proxyDocument) {
3018
2924
  class MicroDocument {
3019
2925
  static [Symbol.hasInstance](target) {
3020
2926
  let proto = target;
3021
- while (proto = Object.getPrototypeOf(proto)) {
2927
+ while (proto) {
2928
+ proto = Object.getPrototypeOf(proto);
3022
2929
  if (proto === MicroDocument.prototype) {
3023
2930
  return true;
3024
2931
  }
@@ -3784,7 +3691,11 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
3784
3691
  const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
3785
3692
  // navigate with native history method
3786
3693
  nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
3787
- // TODO: 如果所有模式统一发送popstate事件,则!isRouterModeCustom(appName)要去掉
3694
+ /**
3695
+ * TODO:
3696
+ * 1. 如果所有模式统一发送popstate事件,则!isRouterModeCustom(appName)要去掉
3697
+ * 2. 如果发送事件,则会导致vue router-view :key='router.path'绑定,无限卸载应用,死循环
3698
+ */
3788
3699
  if (oldFullPath !== result.fullPath && !isRouterModeCustom(appName)) {
3789
3700
  dispatchNativeEvent(appName, onlyForBrowser, oldHref);
3790
3701
  }
@@ -3913,52 +3824,53 @@ function createRouterApi() {
3913
3824
  */
3914
3825
  function createNavigationMethod(replace) {
3915
3826
  return function (to) {
3916
- const appName = formatAppName(to.name);
3917
- if (appName && isString(to.path)) {
3918
- /**
3919
- * active apps, exclude prerender app or hidden keep-alive app
3920
- * NOTE:
3921
- * 1. prerender app or hidden keep-alive app clear and record popstate event, so we cannot control app jump through the API
3922
- * 2. disable memory-router
3923
- */
3924
- /**
3925
- * TODO: 子应用开始渲染但是还没渲染完成
3926
- * 1、调用跳转改如何处理
3927
- * 2、iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
3928
- * 3hidden app 是否支持跳转
3929
- */
3930
- if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
3931
- const app = appInstanceMap.get(appName);
3932
- const navigateAction = () => handleNavigate(appName, app, to, replace);
3933
- app.iframe ? app.sandBox.sandboxReady.then(navigateAction) : navigateAction();
3827
+ return new Promise((resolve, reject) => {
3828
+ const appName = formatAppName(to.name);
3829
+ if (appName && isString(to.path)) {
3830
+ /**
3831
+ * active apps, exclude prerender app or hidden keep-alive app
3832
+ * NOTE:
3833
+ * 1. prerender app or hidden keep-alive app clear and record popstate event, so we cannot control app jump through the API
3834
+ * 2. disable memory-router
3835
+ */
3836
+ /**
3837
+ * TODO: 子应用开始渲染但是还没渲染完成
3838
+ * 1、调用跳转改如何处理
3839
+ * 2iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
3840
+ * 3、hidden app 是否支持跳转
3841
+ */
3842
+ if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
3843
+ const app = appInstanceMap.get(appName);
3844
+ resolve(app.sandBox.sandboxReady.then(() => handleNavigate(appName, app, to, replace)));
3845
+ }
3846
+ else {
3847
+ reject(logError('navigation failed, app does not exist or is inactive'));
3848
+ }
3849
+ // /**
3850
+ // * app not exit or unmounted, update browser URL with replaceState
3851
+ // * use base app location.origin as baseURL
3852
+ // * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
3853
+ // */
3854
+ // /**
3855
+ // * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
3856
+ // * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
3857
+ // */
3858
+ // const rawLocation = globalEnv.rawWindow.location
3859
+ // const targetLocation = createURL(to.path, rawLocation.origin)
3860
+ // const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
3861
+ // if (getMicroPathFromURL(appName) !== targetFullPath) {
3862
+ // navigateWithRawHistory(
3863
+ // appName,
3864
+ // to.replace === false ? 'pushState' : 'replaceState',
3865
+ // targetLocation,
3866
+ // to.state,
3867
+ // )
3868
+ // }
3934
3869
  }
3935
3870
  else {
3936
- logWarn('navigation failed, app does not exist or is inactive');
3871
+ reject(logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`));
3937
3872
  }
3938
- // /**
3939
- // * app not exit or unmounted, update browser URL with replaceState
3940
- // * use base app location.origin as baseURL
3941
- // * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
3942
- // */
3943
- // /**
3944
- // * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
3945
- // * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
3946
- // */
3947
- // const rawLocation = globalEnv.rawWindow.location
3948
- // const targetLocation = createURL(to.path, rawLocation.origin)
3949
- // const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
3950
- // if (getMicroPathFromURL(appName) !== targetFullPath) {
3951
- // navigateWithRawHistory(
3952
- // appName,
3953
- // to.replace === false ? 'pushState' : 'replaceState',
3954
- // targetLocation,
3955
- // to.state,
3956
- // )
3957
- // }
3958
- }
3959
- else {
3960
- logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`);
3961
- }
3873
+ });
3962
3874
  };
3963
3875
  }
3964
3876
  // create method of router.go/back/forward
@@ -4540,6 +4452,159 @@ function removePathFromBrowser(appName) {
4540
4452
  attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
4541
4453
  }
4542
4454
 
4455
+ class Adapter {
4456
+ constructor() {
4457
+ // keys that can only assigned to rawWindow
4458
+ this.escapeSetterKeyList = [
4459
+ 'location',
4460
+ ];
4461
+ // keys that can escape to rawWindow
4462
+ this.staticEscapeProperties = [
4463
+ 'System',
4464
+ '__cjsWrapper',
4465
+ ];
4466
+ // keys that scoped in child app
4467
+ this.staticScopeProperties = [
4468
+ 'webpackJsonp',
4469
+ 'webpackHotUpdate',
4470
+ 'Vue',
4471
+ ];
4472
+ this.injectReactHMRProperty();
4473
+ }
4474
+ // adapter for react
4475
+ injectReactHMRProperty() {
4476
+ if ((process.env.NODE_ENV !== 'production')) {
4477
+ // react child in non-react env
4478
+ this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
4479
+ // in react parent
4480
+ if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
4481
+ this.staticScopeProperties = this.staticScopeProperties.concat([
4482
+ '__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
4483
+ '__reactRefreshInjected',
4484
+ ]);
4485
+ }
4486
+ }
4487
+ }
4488
+ }
4489
+ // Fix conflict of babel-polyfill@6.x
4490
+ function fixBabelPolyfill6() {
4491
+ if (globalEnv.rawWindow._babelPolyfill)
4492
+ globalEnv.rawWindow._babelPolyfill = false;
4493
+ }
4494
+ /**
4495
+ * Fix error of hot reload when parent&child created by create-react-app in development environment
4496
+ * Issue: https://github.com/micro-zoe/micro-app/issues/382
4497
+ */
4498
+ function fixReactHMRConflict(app) {
4499
+ var _a;
4500
+ if ((process.env.NODE_ENV !== 'production')) {
4501
+ const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
4502
+ const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
4503
+ if (rawReactErrorHook && childReactErrorHook) {
4504
+ globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
4505
+ defer(() => {
4506
+ globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
4507
+ });
4508
+ }
4509
+ }
4510
+ }
4511
+ /**
4512
+ * update dom tree of target dom
4513
+ * @param container target dom
4514
+ * @param appName app name
4515
+ */
4516
+ function patchElementTree(container, appName) {
4517
+ const children = Array.from(container.children);
4518
+ children.length && children.forEach((child) => {
4519
+ patchElementTree(child, appName);
4520
+ });
4521
+ for (const child of children) {
4522
+ updateElementInfo(child, appName);
4523
+ }
4524
+ }
4525
+ /**
4526
+ * rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
4527
+ * @param node target node
4528
+ * @param appName app name
4529
+ * @returns target node
4530
+ */
4531
+ function updateElementInfo(node, appName) {
4532
+ var _a, _b;
4533
+ const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
4534
+ if (isNode(node) &&
4535
+ !node.__MICRO_APP_NAME__ &&
4536
+ !node.__PURE_ELEMENT__ &&
4537
+ proxyWindow) {
4538
+ /**
4539
+ * TODO:
4540
+ * 1. 测试baseURI和ownerDocument在with沙箱中是否正确
4541
+ * 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
4542
+ * 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
4543
+ */
4544
+ rawDefineProperties(node, {
4545
+ baseURI: {
4546
+ configurable: true,
4547
+ get: () => proxyWindow.location.href,
4548
+ },
4549
+ __MICRO_APP_NAME__: {
4550
+ configurable: true,
4551
+ writable: true,
4552
+ value: appName,
4553
+ },
4554
+ });
4555
+ if (isIframeSandbox(appName)) {
4556
+ /**
4557
+ * If HTML built-in node belongs to base app, it needs to be handled separately for parentNode
4558
+ * Fix error for nuxt@2.x + ElementUI@2.x
4559
+ */
4560
+ if (node instanceof globalEnv.rawRootNode) {
4561
+ rawDefineProperty(node, 'parentNode', {
4562
+ configurable: true,
4563
+ get: createGetterForIframeParentNode(appName, globalEnv.rawParentNodeDesc, true)
4564
+ });
4565
+ }
4566
+ }
4567
+ }
4568
+ return node;
4569
+ }
4570
+ /**
4571
+ * patch iframe node parentNode
4572
+ * Scenes:
4573
+ * 1. iframe common node: patch Node.prototype.parentNode to hijack parentNode
4574
+ * 2. iframe HTML built-in node: belongs to base app, we should rewrite parentNode for every built-in node
4575
+ * NOTE:
4576
+ * 1. HTML built-in node parentNode cannot point to raw body, otherwise Vue2 will render failed
4577
+ * @param appName app name
4578
+ * @param parentNode parentNode Descriptor of iframe or browser
4579
+ * @param HTMLBuildInNode is HTML built-in node
4580
+ */
4581
+ function createGetterForIframeParentNode(appName, parentNodeDesc, HTMLBuildInNode) {
4582
+ return function () {
4583
+ var _a, _b, _c;
4584
+ /**
4585
+ * set current appName for hijack parentNode of html
4586
+ * NOTE:
4587
+ * 1. Is there a problem with setting the current appName in iframe mode
4588
+ */
4589
+ throttleDeferForSetAppName(appName);
4590
+ const result = parentNodeDesc.get.call(this);
4591
+ /**
4592
+ * If parentNode is <micro-app-body>, return rawDocument.body
4593
+ * Scenes:
4594
+ * 1. element-ui@2/lib/utils/vue-popper.js
4595
+ * if (this.popperElm.parentNode === document.body) ...
4596
+ * WARNING:
4597
+ * Will it cause other problems ?
4598
+ * e.g. target.parentNode.remove(target)
4599
+ */
4600
+ if (!HTMLBuildInNode &&
4601
+ isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
4602
+ return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
4603
+ }
4604
+ return result;
4605
+ };
4606
+ }
4607
+
4543
4608
  /**
4544
4609
  * https://developer.mozilla.org/en-US/docs/Web/API/fetch
4545
4610
  * Promise<Response> fetch(input[, init])
@@ -4657,17 +4722,20 @@ class WithSandBox {
4657
4722
  // Properties newly added to microAppWindow
4658
4723
  this.injectedKeys = new Set();
4659
4724
  this.microAppWindow = new EventTarget(); // Proxy target
4660
- this.adapter = new Adapter();
4661
- // get scopeProperties and escapeProperties from plugins
4662
- this.getSpecialProperties(appName);
4663
- // create location, history for child app
4664
- this.patchRouter(appName, url, this.microAppWindow);
4665
- // patch window of child app
4666
- this.windowEffect = patchWindow(appName, this.microAppWindow, this);
4667
- // patch document of child app
4668
- this.documentEffect = patchDocument(appName, this.microAppWindow, this);
4669
- // inject global properties
4670
- this.initStaticGlobalKeys(appName, url, this.microAppWindow);
4725
+ this.patchWith((resolve) => {
4726
+ this.adapter = new Adapter();
4727
+ // get scopeProperties and escapeProperties from plugins
4728
+ this.getSpecialProperties(appName);
4729
+ // create location, history for child app
4730
+ this.patchRouter(appName, url, this.microAppWindow);
4731
+ // patch window of child app
4732
+ this.windowEffect = patchWindow(appName, this.microAppWindow, this);
4733
+ // patch document of child app
4734
+ this.documentEffect = patchDocument(appName, this.microAppWindow, this);
4735
+ // inject global properties
4736
+ this.initStaticGlobalKeys(appName, url, this.microAppWindow);
4737
+ resolve();
4738
+ });
4671
4739
  }
4672
4740
  /**
4673
4741
  * open sandbox and perform some initial actions
@@ -4685,7 +4753,9 @@ class WithSandBox {
4685
4753
  this.initRouteState(defaultPage);
4686
4754
  // unique listener of popstate event for sub app
4687
4755
  this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
4688
- this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
4756
+ if (isRouterModeCustom(this.microAppWindow.__MICRO_APP_NAME__)) {
4757
+ this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
4758
+ }
4689
4759
  /* --- memory router part --- end */
4690
4760
  /**
4691
4761
  * Target: Ensure default mode action exactly same to first time when render again
@@ -4883,6 +4953,9 @@ class WithSandBox {
4883
4953
  markUmdMode(state) {
4884
4954
  this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
4885
4955
  }
4956
+ patchWith(cb) {
4957
+ this.sandboxReady = new Promise((resolve) => cb(resolve));
4958
+ }
4886
4959
  // properties associated with the native window
4887
4960
  setMappingPropertiesWithRawDescriptor(microAppWindow) {
4888
4961
  let topValue, parentValue;
@@ -4934,7 +5007,7 @@ class WithSandBox {
4934
5007
  enumerable: false,
4935
5008
  get() {
4936
5009
  throttleDeferForSetAppName(appName);
4937
- return modifiedEval || eval;
5010
+ return modifiedEval || globalEnv.rawWindow.eval;
4938
5011
  },
4939
5012
  set: (value) => {
4940
5013
  modifiedEval = value;
@@ -5054,6 +5127,9 @@ class WithSandBox {
5054
5127
  actionBeforeExecScripts(container) {
5055
5128
  this.patchStaticElement(container);
5056
5129
  }
5130
+ setStaticAppState(state) {
5131
+ this.microAppWindow.__MICRO_APP_STATE__ = state;
5132
+ }
5057
5133
  }
5058
5134
  WithSandBox.activeCount = 0; // number of active sandbox
5059
5135
 
@@ -5368,17 +5444,18 @@ function patchDocumentPrototype(appName, microAppWindow) {
5368
5444
  }
5369
5445
  };
5370
5446
  microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
5371
- var _a;
5372
5447
  const _this = getDefaultRawTarget(this);
5373
5448
  if (isUniqueElement(key) ||
5374
- isInvalidQuerySelectorKey(key) ||
5375
- (!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
5449
+ isInvalidQuerySelectorKey(key)) {
5376
5450
  return rawMicroGetElementsByTagName.call(_this, key);
5377
5451
  }
5452
+ else if (/^script|base$/i.test(key)) {
5453
+ return rawMicroGetElementsByTagName.call(microDocument, key);
5454
+ }
5378
5455
  try {
5379
5456
  return querySelectorAll.call(this, key);
5380
5457
  }
5381
- catch (_b) {
5458
+ catch (_a) {
5382
5459
  return rawMicroGetElementsByTagName.call(_this, key);
5383
5460
  }
5384
5461
  };
@@ -5421,6 +5498,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5421
5498
  ['links', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'a')],
5422
5499
  // unique keys of micro-app
5423
5500
  ['microAppElement', () => { var _a; return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container; }],
5501
+ ['__MICRO_APP_NAME__', () => appName],
5424
5502
  ];
5425
5503
  descList.forEach((desc) => {
5426
5504
  result[desc[0]] = getCommonDescriptor(desc[0], desc[1]);
@@ -5447,7 +5525,10 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
5447
5525
  rawDefineProperty(microDocument, tagName, {
5448
5526
  enumerable: true,
5449
5527
  configurable: true,
5450
- get: () => rawDocument[tagName],
5528
+ get: () => {
5529
+ throttleDeferForSetAppName(appName);
5530
+ return rawDocument[tagName];
5531
+ },
5451
5532
  set: (value) => { rawDocument[tagName] = value; },
5452
5533
  });
5453
5534
  });
@@ -5619,7 +5700,8 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5619
5700
  const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
5620
5701
  const rawMicroCloneNode = microRootNode.prototype.cloneNode;
5621
5702
  const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
5622
- const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
5703
+ const rawParentNodeDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
5704
+ const rawOwnerDocumentDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'ownerDocument');
5623
5705
  const isPureNode = (target) => {
5624
5706
  return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
5625
5707
  };
@@ -5711,6 +5793,15 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5711
5793
  const clonedNode = rawMicroCloneNode.call(this, deep);
5712
5794
  return updateElementInfo(clonedNode, appName);
5713
5795
  };
5796
+ rawDefineProperty(microRootNode.prototype, 'ownerDocument', {
5797
+ configurable: true,
5798
+ enumerable: true,
5799
+ get() {
5800
+ return this.__PURE_ELEMENT__
5801
+ ? rawOwnerDocumentDesc.get.call(this)
5802
+ : microDocument;
5803
+ },
5804
+ });
5714
5805
  rawDefineProperty(microRootElement.prototype, 'innerHTML', {
5715
5806
  configurable: true,
5716
5807
  enumerable: true,
@@ -5730,25 +5821,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
5730
5821
  rawDefineProperty(microRootNode.prototype, 'parentNode', {
5731
5822
  configurable: true,
5732
5823
  enumerable: true,
5733
- get() {
5734
- var _a, _b, _c;
5735
- // set html.parentNode to microDocument
5736
- throttleDeferForParentNode(microDocument);
5737
- const result = rawParentNodeLDesc.get.call(this);
5738
- /**
5739
- * If parentNode is <micro-app-body>, return rawDocument.body
5740
- * Scenes:
5741
- * 1. element-ui@2/lib/utils/vue-popper.js
5742
- * if (this.popperElm.parentNode === document.body) ...
5743
- * WARNING:
5744
- * Will it cause other problems ?
5745
- * e.g. target.parentNode.remove(target)
5746
- */
5747
- if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
5748
- return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || rawDocument.body;
5749
- }
5750
- return result;
5751
- },
5824
+ get: createGetterForIframeParentNode(appName, rawParentNodeDesc),
5752
5825
  });
5753
5826
  // Adapt to new image(...) scene
5754
5827
  const ImageProxy = new Proxy(microAppWindow.Image, {
@@ -5899,7 +5972,9 @@ class IframeSandbox {
5899
5972
  this.initRouteState(defaultPage);
5900
5973
  // unique listener of popstate event for child app
5901
5974
  this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
5902
- this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
5975
+ if (isRouterModeCustom(this.microAppWindow.__MICRO_APP_NAME__)) {
5976
+ this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
5977
+ }
5903
5978
  /* --- memory router part --- end */
5904
5979
  /**
5905
5980
  * create base element to iframe
@@ -6152,6 +6227,9 @@ class IframeSandbox {
6152
6227
  actionBeforeExecScripts(container) {
6153
6228
  this.patchStaticElement(container);
6154
6229
  }
6230
+ setStaticAppState(state) {
6231
+ this.microAppWindow.__MICRO_APP_STATE__ = state;
6232
+ }
6155
6233
  }
6156
6234
  IframeSandbox.activeCount = 0; // number of active sandbox
6157
6235
 
@@ -6164,6 +6242,7 @@ class CreateApp {
6164
6242
  this.loadSourceLevel = 0;
6165
6243
  this.umdHookMount = null;
6166
6244
  this.umdHookUnmount = null;
6245
+ this.lifeCycleState = null;
6167
6246
  this.umdMode = false;
6168
6247
  // TODO: 类型优化,加上iframe沙箱
6169
6248
  this.sandBox = null;
@@ -6174,8 +6253,9 @@ class CreateApp {
6174
6253
  this.url = url;
6175
6254
  this.useSandbox = useSandbox;
6176
6255
  this.scopecss = this.useSandbox && scopecss;
6177
- this.inline = inline !== null && inline !== void 0 ? inline : false;
6256
+ // exec before getInlineModeState
6178
6257
  this.iframe = iframe !== null && iframe !== void 0 ? iframe : false;
6258
+ this.inline = this.getInlineModeState(inline);
6179
6259
  /**
6180
6260
  * NOTE:
6181
6261
  * 1. Navigate after micro-app created, before mount
@@ -6272,6 +6352,10 @@ class CreateApp {
6272
6352
  this.container = container;
6273
6353
  // mount before prerender exec mount (loading source), set isPrerender to false
6274
6354
  this.isPrerender = false;
6355
+ // dispatch state event to micro app
6356
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6357
+ appState: appStates.LOADING
6358
+ });
6275
6359
  // reset app state to LOADING
6276
6360
  return this.setAppState(appStates.LOADING);
6277
6361
  }
@@ -6318,10 +6402,13 @@ class CreateApp {
6318
6402
  }
6319
6403
  else {
6320
6404
  this.container = container;
6321
- this.inline = inline;
6405
+ this.inline = this.getInlineModeState(inline);
6322
6406
  this.fiber = fiber;
6323
6407
  this.routerMode = routerMode;
6324
- const dispatchBeforeMount = () => dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
6408
+ const dispatchBeforeMount = () => {
6409
+ this.setLifeCycleState(lifeCycles.BEFOREMOUNT);
6410
+ dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
6411
+ };
6325
6412
  if (this.isPrerender) {
6326
6413
  ((_d = this.preRenderEvents) !== null && _d !== void 0 ? _d : (this.preRenderEvents = [])).push(dispatchBeforeMount);
6327
6414
  }
@@ -6329,6 +6416,10 @@ class CreateApp {
6329
6416
  dispatchBeforeMount();
6330
6417
  }
6331
6418
  this.setAppState(appStates.MOUNTING);
6419
+ // dispatch state event to micro app
6420
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6421
+ appState: appStates.MOUNTING
6422
+ });
6332
6423
  // TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
6333
6424
  cloneContainer(this.container, this.source.html, !this.umdMode);
6334
6425
  (_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
@@ -6383,8 +6474,8 @@ class CreateApp {
6383
6474
  }
6384
6475
  }
6385
6476
  };
6386
- // TODO: any替换为iframe沙箱类型
6387
- this.iframe ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
6477
+ // TODO: 可优化?
6478
+ this.sandBox ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
6388
6479
  }
6389
6480
  /**
6390
6481
  * handle for promise umdHookMount
@@ -6422,6 +6513,13 @@ class CreateApp {
6422
6513
  this.setAppState(appStates.MOUNTED);
6423
6514
  // call window.onmount of child app
6424
6515
  execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONMOUNT), this.name, microGlobalEvent.ONMOUNT, microApp.getData(this.name, true));
6516
+ // dispatch state event to micro app
6517
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6518
+ appState: appStates.MOUNTED
6519
+ });
6520
+ // dispatch mounted event to micro app
6521
+ dispatchCustomEventToMicroApp(this, 'mounted');
6522
+ this.setLifeCycleState(lifeCycles.MOUNTED);
6425
6523
  // dispatch event mounted to parent
6426
6524
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
6427
6525
  /**
@@ -6461,6 +6559,10 @@ class CreateApp {
6461
6559
  catch (e) {
6462
6560
  logError('An error occurred in window.unmount \n', this.name, e);
6463
6561
  }
6562
+ // dispatch state event to micro app
6563
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6564
+ appState: appStates.UNMOUNT
6565
+ });
6464
6566
  // dispatch unmount event to micro app
6465
6567
  dispatchCustomEventToMicroApp(this, 'unmount');
6466
6568
  // call window.onunmount of child app
@@ -6521,6 +6623,7 @@ class CreateApp {
6521
6623
  destroy,
6522
6624
  clearData: clearData || destroy,
6523
6625
  });
6626
+ this.setLifeCycleState(lifeCycles.UNMOUNT);
6524
6627
  // dispatch unmount event to base app
6525
6628
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
6526
6629
  this.clearOptions(destroy);
@@ -6561,6 +6664,7 @@ class CreateApp {
6561
6664
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
6562
6665
  appState: 'afterhidden',
6563
6666
  });
6667
+ this.setLifeCycleState(lifeCycles.AFTERHIDDEN);
6564
6668
  // dispatch afterHidden event to base app
6565
6669
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
6566
6670
  if (this.routerMode !== ROUTER_MODE_CUSTOM) {
@@ -6604,6 +6708,7 @@ class CreateApp {
6604
6708
  dispatchCustomEventToMicroApp(this, 'appstate-change', {
6605
6709
  appState: 'aftershow',
6606
6710
  });
6711
+ this.setLifeCycleState(lifeCycles.AFTERSHOW);
6607
6712
  // dispatch afterShow event to base app
6608
6713
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
6609
6714
  }
@@ -6612,6 +6717,11 @@ class CreateApp {
6612
6717
  * @param e Error
6613
6718
  */
6614
6719
  onerror(e) {
6720
+ this.setLifeCycleState(lifeCycles.ERROR);
6721
+ // dispatch state event to micro app
6722
+ dispatchCustomEventToMicroApp(this, 'statechange', {
6723
+ appState: appStates.LOAD_FAILED
6724
+ });
6615
6725
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
6616
6726
  }
6617
6727
  /**
@@ -6632,12 +6742,23 @@ class CreateApp {
6632
6742
  }
6633
6743
  // set app state
6634
6744
  setAppState(state) {
6745
+ var _a;
6635
6746
  this.state = state;
6747
+ // set window.__MICRO_APP_STATE__
6748
+ (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setStaticAppState(state);
6636
6749
  }
6637
6750
  // get app state
6638
6751
  getAppState() {
6639
6752
  return this.state;
6640
6753
  }
6754
+ // set app lifeCycleState
6755
+ setLifeCycleState(state) {
6756
+ this.lifeCycleState = state;
6757
+ }
6758
+ // get app lifeCycleState
6759
+ getLifeCycleState() {
6760
+ return this.lifeCycleState || '';
6761
+ }
6641
6762
  // set keep-alive state
6642
6763
  setKeepAliveState(state) {
6643
6764
  this.keepAliveState = state;
@@ -6682,6 +6803,15 @@ class CreateApp {
6682
6803
  querySelectorAll(selectors) {
6683
6804
  return this.container ? globalEnv.rawElementQuerySelectorAll.call(this.container, selectors) : [];
6684
6805
  }
6806
+ /**
6807
+ * NOTE:
6808
+ * 1. If the iframe sandbox no longer enforces the use of inline mode in the future, the way getElementsByTagName retrieves the script from the iframe by default needs to be changed, because in non inline mode, the script in the iframe may be empty
6809
+ * @param inline inline mode config
6810
+ */
6811
+ getInlineModeState(inline) {
6812
+ var _a;
6813
+ return (_a = (this.iframe || inline)) !== null && _a !== void 0 ? _a : false;
6814
+ }
6685
6815
  }
6686
6816
  // iframe route mode
6687
6817
  function isIframeSandbox(appName) {
@@ -6917,6 +7047,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
6917
7047
  function patchElementAndDocument() {
6918
7048
  patchDocument$2();
6919
7049
  const rawRootElement = globalEnv.rawRootElement;
7050
+ const rawRootNode = globalEnv.rawRootNode;
6920
7051
  // prototype methods of add element👇
6921
7052
  rawRootElement.prototype.appendChild = function appendChild(newChild) {
6922
7053
  return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
@@ -7068,37 +7199,48 @@ function patchElementAndDocument() {
7068
7199
  const currentAppName = getCurrentAppName();
7069
7200
  Array.from(this.children).forEach((child) => {
7070
7201
  if (isElement(child) && currentAppName) {
7202
+ // TODO: 使用updateElementInfo进行更新
7071
7203
  child.__MICRO_APP_NAME__ = currentAppName;
7072
7204
  }
7073
7205
  });
7074
7206
  }
7075
7207
  });
7076
- /**
7077
- * NOTE:Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
7078
- */
7079
- // rawDefineProperty(Node.prototype, 'parentNode', {
7080
- // configurable: true,
7081
- // enumerable: true,
7082
- // get () {
7083
- // const result = globalEnv.rawParentNodeDesc.get.call(this)
7084
- // /**
7085
- // * If parentNode is <micro-app-body>, return rawDocument.body
7086
- // * Scenes:
7087
- // * 1. element-ui@2/lib/utils/vue-popper.js
7088
- // * if (this.popperElm.parentNode === document.body) ...
7089
- // * WARNING:
7090
- // * Will it cause other problems ?
7091
- // * e.g. target.parentNode.remove(target)
7092
- // * BUG:
7093
- // * 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again )
7094
- // */
7095
- // if (isMicroAppBody(result) && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
7096
- // return document.body
7097
- // }
7098
- // return result
7099
- // },
7100
- // set: undefined,
7101
- // })
7208
+ rawDefineProperty(rawRootNode.prototype, 'parentNode', {
7209
+ configurable: true,
7210
+ enumerable: true,
7211
+ get() {
7212
+ var _a, _b, _c;
7213
+ /**
7214
+ * hijack parentNode of html
7215
+ * Scenes:
7216
+ * 1. element-ui@2/lib/utils/popper.js
7217
+ * // root is child app window, so root.document is proxyDocument or microDocument
7218
+ * if (element.parentNode === root.document) ...
7219
+ */
7220
+ const currentAppName = getCurrentAppName();
7221
+ if (currentAppName && this === globalEnv.rawDocument.firstElementChild) {
7222
+ 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;
7223
+ if (microDocument)
7224
+ return microDocument;
7225
+ }
7226
+ const result = globalEnv.rawParentNodeDesc.get.call(this);
7227
+ /**
7228
+ * If parentNode is <micro-app-body>, return rawDocument.body
7229
+ * Scenes:
7230
+ * 1. element-ui@2/lib/utils/vue-popper.js
7231
+ * if (this.popperElm.parentNode === document.body) ...
7232
+ * WARNING:
7233
+ * Will it cause other problems ?
7234
+ * e.g. target.parentNode.remove(target)
7235
+ * BUG:
7236
+ * 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again ) -- Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
7237
+ */
7238
+ // if (isMicroAppBody(result) && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
7239
+ // return document.body
7240
+ // }
7241
+ return result;
7242
+ },
7243
+ });
7102
7244
  }
7103
7245
  /**
7104
7246
  * Mark the newly created element in the micro application
@@ -7237,6 +7379,7 @@ function releasePatchElementAndDocument() {
7237
7379
  removeDomScope();
7238
7380
  releasePatchDocument();
7239
7381
  const rawRootElement = globalEnv.rawRootElement;
7382
+ const rawRootNode = globalEnv.rawRootNode;
7240
7383
  rawRootElement.prototype.appendChild = globalEnv.rawAppendChild;
7241
7384
  rawRootElement.prototype.insertBefore = globalEnv.rawInsertBefore;
7242
7385
  rawRootElement.prototype.replaceChild = globalEnv.rawReplaceChild;
@@ -7248,6 +7391,7 @@ function releasePatchElementAndDocument() {
7248
7391
  rawRootElement.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
7249
7392
  rawRootElement.prototype.setAttribute = globalEnv.rawSetAttribute;
7250
7393
  rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
7394
+ rawDefineProperty(rawRootNode.prototype, 'parentNode', globalEnv.rawParentNodeDesc);
7251
7395
  }
7252
7396
  // Set the style of micro-app-head and micro-app-body
7253
7397
  let hasRejectMicroAppStyle = false;
@@ -7380,9 +7524,9 @@ function initGlobalEnv() {
7380
7524
  /**
7381
7525
  * define element
7382
7526
  * @param tagName element name
7383
- */
7527
+ */
7384
7528
  function defineElement(tagName) {
7385
- class MicroAppElement extends HTMLElement {
7529
+ class MicroAppElement extends getBaseHTMLElement() {
7386
7530
  constructor() {
7387
7531
  super(...arguments);
7388
7532
  this.isWaiting = false;
@@ -8244,6 +8388,20 @@ function renderApp(options) {
8244
8388
  container.appendChild(microAppElement);
8245
8389
  });
8246
8390
  }
8391
+ /**
8392
+ * get app state
8393
+ * @param appName app.name
8394
+ * @returns app.state
8395
+ */
8396
+ function getAppStatus(appName) {
8397
+ const app = appInstanceMap.get(formatAppName(appName));
8398
+ if (app) {
8399
+ return app.getLifeCycleState();
8400
+ }
8401
+ else {
8402
+ logWarn(`app ${appName} does not exist`);
8403
+ }
8404
+ }
8247
8405
  class MicroApp extends EventCenterForBaseApp {
8248
8406
  constructor() {
8249
8407
  super(...arguments);
@@ -8258,6 +8416,7 @@ class MicroApp extends EventCenterForBaseApp {
8258
8416
  this.getAllApps = getAllApps;
8259
8417
  this.reload = reload;
8260
8418
  this.renderApp = renderApp;
8419
+ this.getAppStatus = getAppStatus;
8261
8420
  }
8262
8421
  start(options) {
8263
8422
  var _a, _b;
@@ -8313,5 +8472,5 @@ class MicroApp extends EventCenterForBaseApp {
8313
8472
  const microApp = new MicroApp();
8314
8473
 
8315
8474
  export default microApp;
8316
- export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
8475
+ export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, getAppStatus, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
8317
8476
  //# sourceMappingURL=index.esm.js.map