@micro-zoe/micro-app 1.0.0-alpha.6 → 1.0.0-alpha.7

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-alpha.6';
1
+ const version = '1.0.0-alpha.7';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -72,6 +72,12 @@ function isShadowRoot(target) {
72
72
  function isURL(target) {
73
73
  return target instanceof URL;
74
74
  }
75
+ function isElement(target) {
76
+ return target instanceof Element;
77
+ }
78
+ function isNode(target) {
79
+ return target instanceof Node;
80
+ }
75
81
  // is ProxyDocument
76
82
  function isProxyDocument(target) {
77
83
  return toString.call(target) === '[object ProxyDocument]';
@@ -483,6 +489,20 @@ function serialExecFiberTasks(tasks) {
483
489
  function isInlineScript(address) {
484
490
  return address.startsWith('inline-');
485
491
  }
492
+ /**
493
+ * call function with try catch
494
+ * @param fn target function
495
+ * @param appName app.name
496
+ * @param args arguments
497
+ */
498
+ function callFnWithTryCatch(fn, appName, msgSuffix, ...args) {
499
+ try {
500
+ isFunction(fn) && fn(...args);
501
+ }
502
+ catch (e) {
503
+ logError(`an error occurred in app ${appName} ${msgSuffix} \n`, null, e);
504
+ }
505
+ }
486
506
 
487
507
  var ObservedAttrName;
488
508
  (function (ObservedAttrName) {
@@ -513,12 +533,38 @@ var lifeCycles;
513
533
  lifeCycles["AFTERSHOW"] = "aftershow";
514
534
  lifeCycles["AFTERHIDDEN"] = "afterhidden";
515
535
  })(lifeCycles || (lifeCycles = {}));
536
+ // global event of child app
537
+ var microGlobalEvent;
538
+ (function (microGlobalEvent) {
539
+ microGlobalEvent["ONMOUNT"] = "onmount";
540
+ microGlobalEvent["ONUNMOUNT"] = "onunmount";
541
+ })(microGlobalEvent || (microGlobalEvent = {}));
516
542
  // keep-alive status
517
543
  var keepAliveStates;
518
544
  (function (keepAliveStates) {
519
545
  keepAliveStates["KEEP_ALIVE_SHOW"] = "keep_alive_show";
520
546
  keepAliveStates["KEEP_ALIVE_HIDDEN"] = "keep_alive_hidden";
521
547
  })(keepAliveStates || (keepAliveStates = {}));
548
+ // micro-app config
549
+ var MicroAppConfig;
550
+ (function (MicroAppConfig) {
551
+ MicroAppConfig["DESTROY"] = "destroy";
552
+ MicroAppConfig["DESTORY"] = "destory";
553
+ MicroAppConfig["INLINE"] = "inline";
554
+ MicroAppConfig["DISABLESCOPECSS"] = "disableScopecss";
555
+ MicroAppConfig["DISABLESANDBOX"] = "disableSandbox";
556
+ MicroAppConfig["DISABLE_SCOPECSS"] = "disable-scopecss";
557
+ MicroAppConfig["DISABLE_SANDBOX"] = "disable-sandbox";
558
+ MicroAppConfig["DISABLE_MEMORY_ROUTER"] = "disable-memory-router";
559
+ MicroAppConfig["DISABLE_PATCH_REQUEST"] = "disable-patch-request";
560
+ MicroAppConfig["KEEP_ROUTER_STATE"] = "keep-router-state";
561
+ MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
562
+ MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
563
+ MicroAppConfig["CLEAR_DATA"] = "clear-data";
564
+ MicroAppConfig["ESMODULE"] = "esmodule";
565
+ MicroAppConfig["SSR"] = "ssr";
566
+ MicroAppConfig["FIBER"] = "fiber";
567
+ })(MicroAppConfig || (MicroAppConfig = {}));
522
568
  /**
523
569
  * global key must be static key, they can not rewrite
524
570
  * e.g.
@@ -1366,16 +1412,21 @@ function fixReactHMRConflict(app) {
1366
1412
  function throttleDeferForParentNode(proxyDocument) {
1367
1413
  const html = globalEnv.rawDocument.firstElementChild;
1368
1414
  if (html && html.parentNode !== proxyDocument) {
1369
- setRootParentNode(html, proxyDocument);
1415
+ setParentNode(html, proxyDocument);
1370
1416
  defer(() => {
1371
- setRootParentNode(html, globalEnv.rawDocument);
1417
+ setParentNode(html, globalEnv.rawDocument);
1372
1418
  });
1373
1419
  }
1374
1420
  }
1375
- function setRootParentNode(root, value) {
1376
- const descriptor = Object.getOwnPropertyDescriptor(root, 'parentNode');
1421
+ /**
1422
+ * Modify the point of parentNode
1423
+ * @param target target Node
1424
+ * @param value parentNode
1425
+ */
1426
+ function setParentNode(target, value) {
1427
+ const descriptor = Object.getOwnPropertyDescriptor(target, 'parentNode');
1377
1428
  if (!descriptor || descriptor.configurable) {
1378
- Object.defineProperty(root, 'parentNode', {
1429
+ rawDefineProperty(target, 'parentNode', {
1379
1430
  value,
1380
1431
  configurable: true,
1381
1432
  });
@@ -1457,20 +1508,40 @@ function handleNewNode(parent, child, app) {
1457
1508
  * @param passiveChild second param of insertBefore and replaceChild
1458
1509
  */
1459
1510
  function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
1460
- const hijackElement = getHijackElement(parent, app);
1511
+ const hijackParent = getHijackParent(parent, app);
1461
1512
  /**
1462
1513
  * If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
1463
1514
  * E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
1464
1515
  */
1465
- if (hijackElement) {
1516
+ if (hijackParent) {
1517
+ /**
1518
+ * WARNING:
1519
+ * Verifying that the parentNode of the targetChild points to document.body will cause other problems ?
1520
+ */
1521
+ if (hijackParent.tagName === 'MICRO-APP-BODY' && rawMethod !== globalEnv.rawRemoveChild) {
1522
+ const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
1523
+ if (!descriptor || descriptor.configurable) {
1524
+ rawDefineProperty(targetChild, 'parentNode', {
1525
+ configurable: true,
1526
+ get() {
1527
+ /**
1528
+ * When operate child from parentNode async, Element.prototype may reset
1529
+ * e.g.
1530
+ * target.parentNode.remove(target)
1531
+ */
1532
+ return Element.prototype.removeChild === globalEnv.rawRemoveChild ? hijackParent : document.body;
1533
+ },
1534
+ });
1535
+ }
1536
+ }
1466
1537
  /**
1467
1538
  * 1. If passiveChild exists, it must be insertBefore or replaceChild
1468
1539
  * 2. When removeChild, targetChild may not be in microAppHead or head
1469
1540
  */
1470
- if (passiveChild && !hijackElement.contains(passiveChild)) {
1471
- return globalEnv.rawAppendChild.call(hijackElement, targetChild);
1541
+ if (passiveChild && !hijackParent.contains(passiveChild)) {
1542
+ return globalEnv.rawAppendChild.call(hijackParent, targetChild);
1472
1543
  }
1473
- else if (rawMethod === globalEnv.rawRemoveChild && !hijackElement.contains(targetChild)) {
1544
+ else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
1474
1545
  if (parent.contains(targetChild)) {
1475
1546
  return rawMethod.call(parent, targetChild);
1476
1547
  }
@@ -1482,12 +1553,12 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
1482
1553
  rawMethod === globalEnv.rawAppendChild) {
1483
1554
  fixReactHMRConflict(app);
1484
1555
  }
1485
- return invokeRawMethod(rawMethod, hijackElement, targetChild, passiveChild);
1556
+ return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
1486
1557
  }
1487
1558
  return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
1488
1559
  }
1489
1560
  // head/body map to micro-app-head/micro-app-body
1490
- function getHijackElement(node, app) {
1561
+ function getHijackParent(node, app) {
1491
1562
  var _a, _b;
1492
1563
  if (node === document.head) {
1493
1564
  return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
@@ -1520,13 +1591,13 @@ function getMappingNode(node) {
1520
1591
  */
1521
1592
  function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1522
1593
  const currentAppName = getCurrentAppName();
1523
- if (newChild instanceof Node &&
1594
+ if (isNode(newChild) &&
1524
1595
  (newChild.__MICRO_APP_NAME__ ||
1525
1596
  (currentAppName && !newChild.__PURE_ELEMENT__))) {
1526
1597
  newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
1527
1598
  const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
1528
1599
  if (app === null || app === void 0 ? void 0 : app.container) {
1529
- if (newChild instanceof Element) {
1600
+ if (isElement(newChild)) {
1530
1601
  if (/^(img|script)$/i.test(newChild.tagName)) {
1531
1602
  if (newChild.hasAttribute('src')) {
1532
1603
  globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
@@ -1546,7 +1617,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
1546
1617
  }
1547
1618
  }
1548
1619
  else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
1549
- if (!(newChild instanceof Node) && currentAppName) {
1620
+ if (!isNode(newChild) && currentAppName) {
1550
1621
  const app = appInstanceMap.get(currentAppName);
1551
1622
  if (app === null || app === void 0 ? void 0 : app.container) {
1552
1623
  if (parent === document.head) {
@@ -2551,6 +2622,37 @@ function extractSourceDom(htmlStr, app) {
2551
2622
  class EventCenter {
2552
2623
  constructor() {
2553
2624
  this.eventList = new Map();
2625
+ this.queue = [];
2626
+ this.recordStep = {};
2627
+ // run task
2628
+ this.process = () => {
2629
+ var _a, _b;
2630
+ let name;
2631
+ const temRecordStep = this.recordStep;
2632
+ const queue = this.queue;
2633
+ this.recordStep = {};
2634
+ this.queue = [];
2635
+ while (name = queue.shift()) {
2636
+ const eventInfo = this.eventList.get(name);
2637
+ // clear tempData, force before exec nextStep
2638
+ const tempData = eventInfo.tempData;
2639
+ const force = eventInfo.force;
2640
+ eventInfo.tempData = null;
2641
+ eventInfo.force = false;
2642
+ if (force || !this.isEqual(eventInfo.data, tempData)) {
2643
+ eventInfo.data = tempData || eventInfo.data;
2644
+ for (const f of eventInfo.callbacks) {
2645
+ f(eventInfo.data);
2646
+ }
2647
+ (_b = (_a = temRecordStep[name]).dispatchDataEvent) === null || _b === void 0 ? void 0 : _b.call(_a);
2648
+ /**
2649
+ * WARING:
2650
+ * If data of other app is sent in nextStep, it may cause confusion of tempData and force
2651
+ */
2652
+ temRecordStep[name].nextStepList.forEach((nextStep) => nextStep());
2653
+ }
2654
+ }
2655
+ };
2554
2656
  }
2555
2657
  // whether the name is legal
2556
2658
  isLegalName(name) {
@@ -2560,6 +2662,39 @@ class EventCenter {
2560
2662
  }
2561
2663
  return true;
2562
2664
  }
2665
+ // add appName to queue
2666
+ enqueue(name, nextStep, dispatchDataEvent) {
2667
+ // this.nextStepList.push(nextStep)
2668
+ if (this.recordStep[name]) {
2669
+ this.recordStep[name].nextStepList.push(nextStep);
2670
+ dispatchDataEvent && (this.recordStep[name].dispatchDataEvent = dispatchDataEvent);
2671
+ }
2672
+ else {
2673
+ this.recordStep[name] = {
2674
+ nextStepList: [nextStep],
2675
+ dispatchDataEvent,
2676
+ };
2677
+ }
2678
+ /**
2679
+ * The micro task is executed async when the second render of child.
2680
+ * We should ensure that the data changes are executed before binding the listening function
2681
+ */
2682
+ (!this.queue.includes(name) && this.queue.push(name) === 1) && defer(this.process);
2683
+ }
2684
+ /**
2685
+ * In react, each setState will trigger setData, so we need a filter operation to avoid repeated trigger
2686
+ */
2687
+ isEqual(oldData, newData) {
2688
+ if (!newData || Object.keys(oldData).length !== Object.keys(newData).length)
2689
+ return false;
2690
+ for (const key in oldData) {
2691
+ if (Object.prototype.hasOwnProperty.call(oldData, key)) {
2692
+ if (oldData[key] !== newData[key])
2693
+ return false;
2694
+ }
2695
+ }
2696
+ return true;
2697
+ }
2563
2698
  /**
2564
2699
  * add listener
2565
2700
  * @param name event name
@@ -2579,7 +2714,10 @@ class EventCenter {
2579
2714
  };
2580
2715
  this.eventList.set(name, eventInfo);
2581
2716
  }
2582
- else if (autoTrigger && Object.getOwnPropertyNames(eventInfo.data).length) {
2717
+ else if (autoTrigger &&
2718
+ Object.keys(eventInfo.data).length &&
2719
+ (!this.queue.includes(name) ||
2720
+ this.isEqual(eventInfo.data, eventInfo.tempData))) {
2583
2721
  // auto trigger when data not null
2584
2722
  f(eventInfo.data);
2585
2723
  }
@@ -2600,21 +2738,27 @@ class EventCenter {
2600
2738
  }
2601
2739
  }
2602
2740
  }
2741
+ /**
2742
+ * clearData
2743
+ */
2744
+ clearData(name) {
2745
+ if (this.isLegalName(name)) {
2746
+ const eventInfo = this.eventList.get(name);
2747
+ if (eventInfo) {
2748
+ eventInfo.data = {};
2749
+ }
2750
+ }
2751
+ }
2603
2752
  // dispatch data
2604
- dispatch(name, data) {
2753
+ dispatch(name, data, nextStep, force, dispatchDataEvent) {
2605
2754
  if (this.isLegalName(name)) {
2606
2755
  if (!isPlainObject(data)) {
2607
2756
  return logError('event-center: data must be object');
2608
2757
  }
2609
2758
  let eventInfo = this.eventList.get(name);
2610
2759
  if (eventInfo) {
2611
- // Update when the data is not equal
2612
- if (eventInfo.data !== data) {
2613
- eventInfo.data = data;
2614
- for (const f of eventInfo.callbacks) {
2615
- f(data);
2616
- }
2617
- }
2760
+ eventInfo.tempData = assign({}, eventInfo.tempData || eventInfo.data, data);
2761
+ !eventInfo.force && (eventInfo.force = !!force);
2618
2762
  }
2619
2763
  else {
2620
2764
  eventInfo = {
@@ -2622,7 +2766,13 @@ class EventCenter {
2622
2766
  callbacks: new Set(),
2623
2767
  };
2624
2768
  this.eventList.set(name, eventInfo);
2769
+ /**
2770
+ * When sent data to parent, eventInfo probably does not exist, because parent may listen to datachange
2771
+ */
2772
+ eventInfo.force = true;
2625
2773
  }
2774
+ // add to queue, event eventInfo is null
2775
+ this.enqueue(name, nextStep, dispatchDataEvent);
2626
2776
  }
2627
2777
  }
2628
2778
  // get data
@@ -2671,10 +2821,13 @@ class EventCenterForGlobal {
2671
2821
  * dispatch global data
2672
2822
  * @param data data
2673
2823
  */
2674
- setGlobalData(data) {
2824
+ setGlobalData(data, nextStep, force) {
2675
2825
  // clear dom scope before dispatch global data, apply to micro app
2676
2826
  removeDomScope();
2677
- eventCenter.dispatch('global', data);
2827
+ eventCenter.dispatch('global', data, () => isFunction(nextStep) && nextStep(), force);
2828
+ }
2829
+ forceSetGlobalData(data, nextStep) {
2830
+ this.setGlobalData(data, nextStep, true);
2678
2831
  }
2679
2832
  /**
2680
2833
  * get global data
@@ -2682,6 +2835,12 @@ class EventCenterForGlobal {
2682
2835
  getGlobalData() {
2683
2836
  return eventCenter.getData('global');
2684
2837
  }
2838
+ /**
2839
+ * clear global data
2840
+ */
2841
+ clearGlobalData() {
2842
+ eventCenter.clearData('global');
2843
+ }
2685
2844
  /**
2686
2845
  * clear all listener of global data
2687
2846
  * if appName exists, only the specified functions is cleared
@@ -2732,8 +2891,19 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
2732
2891
  * @param appName app.name
2733
2892
  * @param data data
2734
2893
  */
2735
- setData(appName, data) {
2736
- eventCenter.dispatch(formatEventName(formatAppName(appName), true), data);
2894
+ setData(appName, data, nextStep, force) {
2895
+ eventCenter.dispatch(formatEventName(formatAppName(appName), true), data, () => isFunction(nextStep) && nextStep(), force);
2896
+ }
2897
+ forceSetData(appName, data, nextStep) {
2898
+ this.setData(appName, data, nextStep, true);
2899
+ }
2900
+ /**
2901
+ * clear data from base app
2902
+ * @param appName app.name
2903
+ * @param fromBaseApp whether clear data from child app, default is true
2904
+ */
2905
+ clearData(appName, fromBaseApp = true) {
2906
+ eventCenter.clearData(formatEventName(formatAppName(appName), fromBaseApp));
2737
2907
  }
2738
2908
  /**
2739
2909
  * clear all listener for specified micro app
@@ -2769,25 +2939,36 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
2769
2939
  /**
2770
2940
  * get data from base app
2771
2941
  */
2772
- getData() {
2773
- return eventCenter.getData(formatEventName(this.appName, true));
2942
+ getData(fromBaseApp = true) {
2943
+ return eventCenter.getData(formatEventName(this.appName, fromBaseApp));
2774
2944
  }
2775
2945
  /**
2776
2946
  * dispatch data to base app
2777
2947
  * @param data data
2778
2948
  */
2779
- dispatch(data) {
2949
+ dispatch(data, nextStep, force) {
2780
2950
  removeDomScope();
2781
- eventCenter.dispatch(formatEventName(this.appName, false), data);
2782
- const app = appInstanceMap.get(this.appName);
2783
- if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
2784
- const event = new CustomEvent('datachange', {
2785
- detail: {
2786
- data,
2787
- }
2788
- });
2789
- getRootContainer(app.container).dispatchEvent(event);
2790
- }
2951
+ eventCenter.dispatch(formatEventName(this.appName, false), data, () => isFunction(nextStep) && nextStep(), force, () => {
2952
+ const app = appInstanceMap.get(this.appName);
2953
+ if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
2954
+ const event = new CustomEvent('datachange', {
2955
+ detail: {
2956
+ data: eventCenter.getData(formatEventName(this.appName, false))
2957
+ }
2958
+ });
2959
+ getRootContainer(app.container).dispatchEvent(event);
2960
+ }
2961
+ });
2962
+ }
2963
+ forceDispatch(data, nextStep) {
2964
+ this.dispatch(data, nextStep, true);
2965
+ }
2966
+ /**
2967
+ * clear data from child app
2968
+ * @param fromBaseApp whether clear data from base app, default is false
2969
+ */
2970
+ clearData(fromBaseApp = false) {
2971
+ eventCenter.clearData(formatEventName(this.appName, fromBaseApp));
2791
2972
  }
2792
2973
  /**
2793
2974
  * clear all listeners
@@ -4235,12 +4416,14 @@ class SandBox {
4235
4416
  * @param umdMode is umd mode
4236
4417
  * @param keepRouteState prevent reset route
4237
4418
  * @param clearEventSource clear MicroEventSource when destroy
4419
+ * @param clearData clear data from base app
4238
4420
  */
4239
- stop({ umdMode, keepRouteState, clearEventSource, }) {
4421
+ stop({ umdMode, keepRouteState, clearEventSource, clearData, }) {
4240
4422
  if (this.active) {
4241
4423
  this.releaseEffect();
4242
4424
  this.microAppWindow.microApp.clearDataListener();
4243
4425
  this.microAppWindow.microApp.clearGlobalDataListener();
4426
+ clearData && this.microAppWindow.microApp.clearData();
4244
4427
  if (this.removeHistoryListener) {
4245
4428
  this.clearRouteState(keepRouteState);
4246
4429
  // release listener of popstate
@@ -4846,7 +5029,7 @@ class CreateApp {
4846
5029
  this.sandBox.proxyWindow.__MICRO_APP_UMD_MODE__ = true;
4847
5030
  // this.sandBox?.recordUmdSnapshot()
4848
5031
  try {
4849
- umdHookMountResult = this.umdHookMount();
5032
+ umdHookMountResult = this.umdHookMount(microApp.getData(this.name, true));
4850
5033
  }
4851
5034
  catch (e) {
4852
5035
  logError('an error occurred in the mount function \n', this.name, e);
@@ -4890,6 +5073,9 @@ class CreateApp {
4890
5073
  dispatchMountedEvent() {
4891
5074
  if (appStates.UNMOUNT !== this.state) {
4892
5075
  this.state = appStates.MOUNTED;
5076
+ // call window.onmount of child app
5077
+ callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONMOUNT), this.name, `window.${microGlobalEvent.ONMOUNT}`, microApp.getData(this.name, true));
5078
+ // dispatch event mounted to parent
4893
5079
  dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
4894
5080
  }
4895
5081
  }
@@ -4899,7 +5085,7 @@ class CreateApp {
4899
5085
  * @param destroy completely destroy, delete cache resources
4900
5086
  * @param unmountcb callback of unmount
4901
5087
  */
4902
- unmount(destroy, unmountcb) {
5088
+ unmount({ destroy, clearData, unmountcb, }) {
4903
5089
  if (this.state === appStates.LOAD_FAILED) {
4904
5090
  destroy = true;
4905
5091
  }
@@ -4914,15 +5100,17 @@ class CreateApp {
4914
5100
  */
4915
5101
  if (isFunction(this.umdHookUnmount)) {
4916
5102
  try {
4917
- umdHookUnmountResult = this.umdHookUnmount();
5103
+ umdHookUnmountResult = this.umdHookUnmount(microApp.getData(this.name, true));
4918
5104
  }
4919
5105
  catch (e) {
4920
5106
  logError('an error occurred in the unmount function \n', this.name, e);
4921
5107
  }
4922
5108
  }
5109
+ // call window.onunmount of child app
5110
+ callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONUNMOUNT), this.name, `window.${microGlobalEvent.ONUNMOUNT}`);
4923
5111
  // dispatch unmount event to micro app
4924
5112
  dispatchCustomEventToMicroApp('unmount', this.name);
4925
- this.handleUnmounted(destroy, umdHookUnmountResult, unmountcb);
5113
+ this.handleUnmounted(destroy, clearData, umdHookUnmountResult, unmountcb);
4926
5114
  }
4927
5115
  /**
4928
5116
  * handle for promise umdHookUnmount
@@ -4930,14 +5118,14 @@ class CreateApp {
4930
5118
  * @param umdHookUnmountResult result of umdHookUnmount
4931
5119
  * @param unmountcb callback of unmount
4932
5120
  */
4933
- handleUnmounted(destroy, umdHookUnmountResult, unmountcb) {
5121
+ handleUnmounted(destroy, clearData, umdHookUnmountResult, unmountcb) {
4934
5122
  if (isPromise(umdHookUnmountResult)) {
4935
5123
  umdHookUnmountResult
4936
- .then(() => this.actionsForUnmount(destroy, unmountcb))
4937
- .catch(() => this.actionsForUnmount(destroy, unmountcb));
5124
+ .then(() => this.actionsForUnmount(destroy, clearData, unmountcb))
5125
+ .catch(() => this.actionsForUnmount(destroy, clearData, unmountcb));
4938
5126
  }
4939
5127
  else {
4940
- this.actionsForUnmount(destroy, unmountcb);
5128
+ this.actionsForUnmount(destroy, clearData, unmountcb);
4941
5129
  }
4942
5130
  }
4943
5131
  /**
@@ -4945,7 +5133,7 @@ class CreateApp {
4945
5133
  * @param destroy completely destroy, delete cache resources
4946
5134
  * @param unmountcb callback of unmount
4947
5135
  */
4948
- actionsForUnmount(destroy, unmountcb) {
5136
+ actionsForUnmount(destroy, clearData, unmountcb) {
4949
5137
  var _a, _b;
4950
5138
  if (destroy) {
4951
5139
  this.actionsForCompletelyDestroy();
@@ -4956,6 +5144,9 @@ class CreateApp {
4956
5144
  if (this.umdMode) {
4957
5145
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordUmdSnapshot();
4958
5146
  }
5147
+ if (clearData || destroy) {
5148
+ microApp.clearData(this.name);
5149
+ }
4959
5150
  /**
4960
5151
  * this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
4961
5152
  * NOTE:
@@ -4966,6 +5157,7 @@ class CreateApp {
4966
5157
  umdMode: this.umdMode,
4967
5158
  keepRouteState: this.keepRouteState && !destroy,
4968
5159
  clearEventSource: !this.umdMode || destroy,
5160
+ clearData: clearData || destroy,
4969
5161
  });
4970
5162
  if (!getActiveApps().length) {
4971
5163
  releasePatchSetAttribute();
@@ -4981,10 +5173,11 @@ class CreateApp {
4981
5173
  if (!this.useSandbox && this.umdMode) {
4982
5174
  delete window[this.libraryName];
4983
5175
  }
5176
+ sourceCenter.script.deleteInlineInfo(this.source.scripts);
4984
5177
  appInstanceMap.delete(this.name);
4985
5178
  }
4986
5179
  // hidden app when disconnectedCallback called with keep-alive
4987
- hiddenKeepAliveApp() {
5180
+ hiddenKeepAliveApp(callback) {
4988
5181
  var _a;
4989
5182
  const oldContainer = this.container;
4990
5183
  cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
@@ -4999,6 +5192,7 @@ class CreateApp {
4999
5192
  dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
5000
5193
  // called after lifeCyclesEvent
5001
5194
  (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
5195
+ callback && callback();
5002
5196
  }
5003
5197
  // show app when connectedCallback called with keep-alive
5004
5198
  showKeepAliveApp(container) {
@@ -5053,6 +5247,12 @@ class CreateApp {
5053
5247
  }
5054
5248
  return {};
5055
5249
  }
5250
+ getGlobalEventListener(eventName) {
5251
+ var _a;
5252
+ // @ts-ignore
5253
+ const listener = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow[eventName];
5254
+ return isFunction(listener) ? listener : null;
5255
+ }
5056
5256
  }
5057
5257
 
5058
5258
  /**
@@ -5088,7 +5288,7 @@ function defineElement(tagName) {
5088
5288
  keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
5089
5289
  !existApp.isPrefetch) {
5090
5290
  this.setAttribute('name', this.appName);
5091
- return logError(`app name conflict, an app named ${formatAttrName} is running`, this.appName);
5291
+ return logError(`app name conflict, an app named ${formatAttrName} is running`);
5092
5292
  }
5093
5293
  }
5094
5294
  if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
@@ -5138,22 +5338,47 @@ function defineElement(tagName) {
5138
5338
  defer(() => {
5139
5339
  if (this.connectStateMap.get(cacheCount)) {
5140
5340
  dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED);
5141
- this.initialMount();
5341
+ this.handleConnected();
5142
5342
  }
5143
5343
  });
5144
5344
  }
5145
5345
  disconnectedCallback() {
5146
5346
  this.connectStateMap.set(this.connectedCount, false);
5347
+ this.handleDisconnected();
5348
+ }
5349
+ /**
5350
+ * Re render app from the command line
5351
+ * MicroAppElement.reload(destroy)
5352
+ */
5353
+ reload(destroy) {
5354
+ return new Promise((resolve) => {
5355
+ const handleAfterReload = () => {
5356
+ this.removeEventListener(lifeCycles.MOUNTED, handleAfterReload);
5357
+ this.removeEventListener(lifeCycles.AFTERSHOW, handleAfterReload);
5358
+ resolve(true);
5359
+ };
5360
+ this.addEventListener(lifeCycles.MOUNTED, handleAfterReload);
5361
+ this.addEventListener(lifeCycles.AFTERSHOW, handleAfterReload);
5362
+ this.handleDisconnected(destroy, () => {
5363
+ this.handleConnected();
5364
+ });
5365
+ });
5366
+ }
5367
+ /**
5368
+ * common action for unmount
5369
+ * @param destroy reload param
5370
+ */
5371
+ handleDisconnected(destroy = false, callback) {
5147
5372
  const app = appInstanceMap.get(this.appName);
5148
5373
  if (app &&
5149
5374
  app.getAppState() !== appStates.UNMOUNT &&
5150
5375
  app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
5151
5376
  // keep-alive
5152
- if (this.getKeepAliveModeResult()) {
5153
- this.handleHiddenKeepAliveApp();
5377
+ if (this.getKeepAliveModeResult() && !destroy) {
5378
+ this.handleHiddenKeepAliveApp(callback);
5154
5379
  }
5155
5380
  else {
5156
- this.handleUnmount(this.getDestroyCompatibleResult());
5381
+ this.handleUnmount(destroy || this.getDestroyCompatibleResult(), callback);
5157
5382
  }
5158
5383
  }
5159
5384
  }
@@ -5191,12 +5416,12 @@ function defineElement(tagName) {
5191
5416
  }
5192
5417
  // handle for connectedCallback run before attributeChangedCallback
5193
5418
  handleInitialNameAndUrl() {
5194
- this.connectStateMap.get(this.connectedCount) && this.initialMount();
5419
+ this.connectStateMap.get(this.connectedCount) && this.handleConnected();
5195
5420
  }
5196
5421
  /**
5197
5422
  * first mount of this app
5198
5423
  */
5199
- initialMount() {
5424
+ handleConnected() {
5200
5425
  if (!this.appName || !this.appUrl)
5201
5426
  return;
5202
5427
  if (this.getDisposeResult('shadowDOM') && !this.shadowRoot && isFunction(this.attachShadow)) {
@@ -5234,7 +5459,7 @@ function defineElement(tagName) {
5234
5459
  this.handleCreateApp();
5235
5460
  }
5236
5461
  else {
5237
- logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running`, this.appName);
5462
+ logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running`);
5238
5463
  }
5239
5464
  }
5240
5465
  else {
@@ -5269,7 +5494,7 @@ function defineElement(tagName) {
5269
5494
  }
5270
5495
  else {
5271
5496
  // the hidden keep-alive app is still active
5272
- logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
5497
+ logError(`app name conflict, an app named ${this.appName} is running`);
5273
5498
  }
5274
5499
  }
5275
5500
  else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
@@ -5296,6 +5521,27 @@ function defineElement(tagName) {
5296
5521
  }
5297
5522
  return true;
5298
5523
  }
5524
+ // create app instance
5525
+ handleCreateApp() {
5526
+ var _a;
5527
+ /**
5528
+ * actions for destroy old app
5529
+ * fix of unmounted umd app with disableSandbox
5530
+ */
5531
+ if (appInstanceMap.has(this.appName)) {
5532
+ appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
5533
+ }
5534
+ new CreateApp({
5535
+ name: this.appName,
5536
+ url: this.appUrl,
5537
+ scopecss: this.isScopecss(),
5538
+ useSandbox: this.isSandbox(),
5539
+ inline: this.getDisposeResult('inline'),
5540
+ esmodule: this.getDisposeResult('esmodule'),
5541
+ container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
5542
+ ssrUrl: this.ssrUrl,
5543
+ });
5544
+ }
5299
5545
  /**
5300
5546
  * mount app
5301
5547
  * some serious note before mount:
@@ -5325,45 +5571,29 @@ function defineElement(tagName) {
5325
5571
  fiber: this.getDisposeResult('fiber'),
5326
5572
  });
5327
5573
  }
5328
- // create app instance
5329
- handleCreateApp() {
5330
- var _a;
5331
- /**
5332
- * actions for destroy old app
5333
- * fix of unmounted umd app with disableSandbox
5334
- */
5335
- if (appInstanceMap.has(this.appName)) {
5336
- appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
5337
- }
5338
- new CreateApp({
5339
- name: this.appName,
5340
- url: this.appUrl,
5341
- scopecss: this.isScopecss(),
5342
- useSandbox: this.isSandbox(),
5343
- inline: this.getDisposeResult('inline'),
5344
- esmodule: this.getDisposeResult('esmodule'),
5345
- container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
5346
- ssrUrl: this.ssrUrl,
5347
- });
5348
- }
5349
5574
  /**
5350
5575
  * unmount app
5351
5576
  * @param destroy delete cache resources when unmount
5352
5577
  */
5353
- handleUnmount(destroy, unmountCb) {
5578
+ handleUnmount(destroy, unmountcb) {
5354
5579
  const app = appInstanceMap.get(this.appName);
5355
5580
  if (app &&
5356
5581
  app.getAppState() !== appStates.UNMOUNT) {
5357
- app.unmount(destroy, unmountCb);
5582
+ app.unmount({
5583
+ destroy,
5584
+ clearData: this.getDisposeResult('clear-data'),
5585
+ unmountcb,
5586
+ });
5358
5587
  }
5359
5588
  }
5360
5589
  // hidden app when disconnectedCallback called with keep-alive
5361
- handleHiddenKeepAliveApp() {
5590
+ handleHiddenKeepAliveApp(callback) {
5362
5591
  const app = appInstanceMap.get(this.appName);
5363
5592
  if (app &&
5364
5593
  app.getAppState() !== appStates.UNMOUNT &&
5365
- app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN)
5366
- app.hiddenKeepAliveApp();
5594
+ app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
5595
+ app.hiddenKeepAliveApp(callback);
5596
+ }
5367
5597
  }
5368
5598
  // show app when connectedCallback called with keep-alive
5369
5599
  handleShowKeepAliveApp(app) {
@@ -5480,7 +5710,7 @@ function defineElement(tagName) {
5480
5710
  return null;
5481
5711
  }
5482
5712
  }
5483
- window.customElements.define(tagName, MicroAppElement);
5713
+ globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
5484
5714
  }
5485
5715
 
5486
5716
  /**
@@ -5625,33 +5855,41 @@ function unmountApp(appName, options) {
5625
5855
  if (options === null || options === void 0 ? void 0 : options.destroy) {
5626
5856
  app.actionsForCompletelyDestroy();
5627
5857
  }
5628
- resolve();
5858
+ resolve(true);
5629
5859
  }
5630
5860
  else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
5631
5861
  if (options === null || options === void 0 ? void 0 : options.destroy) {
5632
- app.unmount(true, resolve);
5862
+ app.unmount({
5863
+ destroy: true,
5864
+ clearData: true,
5865
+ unmountcb: resolve.bind(null, true)
5866
+ });
5633
5867
  }
5634
5868
  else if (options === null || options === void 0 ? void 0 : options.clearAliveState) {
5635
- app.unmount(false, resolve);
5869
+ app.unmount({
5870
+ destroy: false,
5871
+ clearData: !!options.clearData,
5872
+ unmountcb: resolve.bind(null, true)
5873
+ });
5636
5874
  }
5637
5875
  else {
5638
- resolve();
5876
+ resolve(true);
5639
5877
  }
5640
5878
  }
5641
5879
  else {
5642
5880
  const container = getRootContainer(app.container);
5643
5881
  const unmountHandler = () => {
5644
- container.removeEventListener('unmount', unmountHandler);
5645
- container.removeEventListener('afterhidden', afterhiddenHandler);
5646
- resolve();
5882
+ container.removeEventListener(lifeCycles.UNMOUNT, unmountHandler);
5883
+ container.removeEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
5884
+ resolve(true);
5647
5885
  };
5648
5886
  const afterhiddenHandler = () => {
5649
- container.removeEventListener('unmount', unmountHandler);
5650
- container.removeEventListener('afterhidden', afterhiddenHandler);
5651
- resolve();
5887
+ container.removeEventListener(lifeCycles.UNMOUNT, unmountHandler);
5888
+ container.removeEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
5889
+ resolve(true);
5652
5890
  };
5653
- container.addEventListener('unmount', unmountHandler);
5654
- container.addEventListener('afterhidden', afterhiddenHandler);
5891
+ container.addEventListener(lifeCycles.UNMOUNT, unmountHandler);
5892
+ container.addEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
5655
5893
  if (options === null || options === void 0 ? void 0 : options.destroy) {
5656
5894
  let destroyAttrValue, destoryAttrValue;
5657
5895
  container.hasAttribute('destroy') && (destroyAttrValue = container.getAttribute('destroy'));
@@ -5659,37 +5897,131 @@ function unmountApp(appName, options) {
5659
5897
  container.setAttribute('destroy', 'true');
5660
5898
  container.parentNode.removeChild(container);
5661
5899
  container.removeAttribute('destroy');
5662
- typeof destroyAttrValue === 'string' && container.setAttribute('destroy', destroyAttrValue);
5663
- typeof destoryAttrValue === 'string' && container.setAttribute('destory', destoryAttrValue);
5900
+ isString(destroyAttrValue) && container.setAttribute('destroy', destroyAttrValue);
5901
+ isString(destoryAttrValue) && container.setAttribute('destory', destoryAttrValue);
5664
5902
  }
5665
5903
  else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
5666
5904
  const keepAliveAttrValue = container.getAttribute('keep-alive');
5667
5905
  container.removeAttribute('keep-alive');
5906
+ let clearDataAttrValue;
5907
+ if (options.clearData) {
5908
+ clearDataAttrValue = container.getAttribute('clear-data');
5909
+ container.setAttribute('clear-data', 'true');
5910
+ }
5668
5911
  container.parentNode.removeChild(container);
5669
5912
  container.setAttribute('keep-alive', keepAliveAttrValue);
5913
+ isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
5670
5914
  }
5671
5915
  else {
5916
+ let clearDataAttrValue;
5917
+ if (options === null || options === void 0 ? void 0 : options.clearData) {
5918
+ clearDataAttrValue = container.getAttribute('clear-data');
5919
+ container.setAttribute('clear-data', 'true');
5920
+ }
5672
5921
  container.parentNode.removeChild(container);
5922
+ isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
5673
5923
  }
5674
5924
  }
5675
5925
  }
5676
5926
  else {
5677
5927
  logWarn(`app ${appName} does not exist`);
5678
- resolve();
5928
+ resolve(false);
5679
5929
  }
5680
5930
  });
5681
5931
  }
5682
5932
  // unmount all apps in turn
5683
5933
  function unmountAllApps(options) {
5684
- return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve());
5934
+ return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve(true));
5935
+ }
5936
+ /**
5937
+ * Re render app from the command line
5938
+ * microApp.reload(destroy)
5939
+ * @param appName app.name
5940
+ * @param destroy unmount app with destroy mode
5941
+ * @returns Promise<boolean>
5942
+ */
5943
+ function reload(appName, destroy) {
5944
+ return new Promise((resolve) => {
5945
+ const app = appInstanceMap.get(formatAppName(appName));
5946
+ if (app) {
5947
+ const rootContainer = app.container && getRootContainer(app.container);
5948
+ if (rootContainer) {
5949
+ resolve(rootContainer.reload(destroy));
5950
+ }
5951
+ else {
5952
+ logWarn(`app ${appName} is not rendered, cannot use reload`);
5953
+ resolve(false);
5954
+ }
5955
+ }
5956
+ else {
5957
+ logWarn(`app ${appName} does not exist`);
5958
+ resolve(false);
5959
+ }
5960
+ });
5961
+ }
5962
+ /**
5963
+ * Manually render app
5964
+ * @param options RenderAppOptions
5965
+ * @returns Promise<boolean>
5966
+ */
5967
+ function renderApp(options) {
5968
+ return new Promise((resolve) => {
5969
+ if (!isPlainObject(options))
5970
+ return logError('renderApp options must be an object');
5971
+ const container = isElement(options.container) ? options.container : isString(options.container) ? document.querySelector(options.container) : null;
5972
+ if (!isElement(container))
5973
+ return logError('Target container is not a DOM element.');
5974
+ const microAppElement = pureCreateElement(microApp.tagName);
5975
+ for (const attr in options) {
5976
+ if (attr === 'onDataChange') {
5977
+ if (isFunction(options[attr])) {
5978
+ microAppElement.addEventListener('datachange', options[attr]);
5979
+ }
5980
+ }
5981
+ else if (attr === 'lifeCycles') {
5982
+ const lifeCycleConfig = options[attr];
5983
+ if (isPlainObject(lifeCycleConfig)) {
5984
+ for (const lifeName in lifeCycleConfig) {
5985
+ if (lifeName.toUpperCase() in lifeCycles && isFunction(lifeCycleConfig[lifeName])) {
5986
+ microAppElement.addEventListener(lifeName.toLowerCase(), lifeCycleConfig[lifeName]);
5987
+ }
5988
+ }
5989
+ }
5990
+ }
5991
+ else if (attr !== 'container') {
5992
+ microAppElement.setAttribute(attr, options[attr]);
5993
+ }
5994
+ }
5995
+ const handleMount = () => {
5996
+ releaseListener();
5997
+ resolve(true);
5998
+ };
5999
+ const handleError = () => {
6000
+ releaseListener();
6001
+ resolve(false);
6002
+ };
6003
+ const releaseListener = () => {
6004
+ microAppElement.removeEventListener(lifeCycles.MOUNTED, handleMount);
6005
+ microAppElement.removeEventListener(lifeCycles.ERROR, handleError);
6006
+ };
6007
+ microAppElement.addEventListener(lifeCycles.MOUNTED, handleMount);
6008
+ microAppElement.addEventListener(lifeCycles.ERROR, handleError);
6009
+ container.appendChild(microAppElement);
6010
+ });
5685
6011
  }
5686
6012
  class MicroApp extends EventCenterForBaseApp {
5687
6013
  constructor() {
5688
6014
  super(...arguments);
5689
6015
  this.tagName = 'micro-app';
5690
6016
  this.options = {};
5691
- this.preFetch = preFetch;
5692
6017
  this.router = router;
6018
+ this.preFetch = preFetch;
6019
+ this.unmountApp = unmountApp;
6020
+ this.unmountAllApps = unmountAllApps;
6021
+ this.getActiveApps = getActiveApps;
6022
+ this.getAllApps = getAllApps;
6023
+ this.reload = reload;
6024
+ this.renderApp = renderApp;
5693
6025
  }
5694
6026
  start(options) {
5695
6027
  var _a, _b;
@@ -5733,8 +6065,8 @@ class MicroApp extends EventCenterForBaseApp {
5733
6065
  defineElement(this.tagName);
5734
6066
  }
5735
6067
  }
5736
- var microApp = new MicroApp();
6068
+ const microApp = new MicroApp();
5737
6069
 
5738
6070
  export default microApp;
5739
- export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, unmountAllApps, unmountApp, version };
6071
+ export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
5740
6072
  //# sourceMappingURL=index.esm.js.map