@micro-zoe/micro-app 1.0.0-alpha.5 → 1.0.0-alpha.8
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/README.md +0 -4
- package/README.zh-cn.md +1 -1
- package/lib/index.d.ts +101 -30
- package/lib/index.esm.js +1672 -639
- package/lib/index.esm.js.map +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.min.js.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/typings/global.d.ts +158 -90
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-alpha.
|
|
1
|
+
const version = '1.0.0-alpha.8';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -33,6 +33,10 @@ function isString(target) {
|
|
|
33
33
|
function isBoolean(target) {
|
|
34
34
|
return typeof target === 'boolean';
|
|
35
35
|
}
|
|
36
|
+
// is Number
|
|
37
|
+
function isNumber(target) {
|
|
38
|
+
return typeof target === 'number';
|
|
39
|
+
}
|
|
36
40
|
// is function
|
|
37
41
|
function isFunction(target) {
|
|
38
42
|
return typeof target === 'function';
|
|
@@ -72,6 +76,12 @@ function isShadowRoot(target) {
|
|
|
72
76
|
function isURL(target) {
|
|
73
77
|
return target instanceof URL;
|
|
74
78
|
}
|
|
79
|
+
function isElement(target) {
|
|
80
|
+
return target instanceof Element;
|
|
81
|
+
}
|
|
82
|
+
function isNode(target) {
|
|
83
|
+
return target instanceof Node;
|
|
84
|
+
}
|
|
75
85
|
// is ProxyDocument
|
|
76
86
|
function isProxyDocument(target) {
|
|
77
87
|
return toString.call(target) === '[object ProxyDocument]';
|
|
@@ -258,8 +268,19 @@ const requestIdleCallback = globalThis.requestIdleCallback ||
|
|
|
258
268
|
return Math.max(0, 50 - (Date.now() - lastTime));
|
|
259
269
|
},
|
|
260
270
|
});
|
|
261
|
-
},
|
|
271
|
+
}, 1);
|
|
262
272
|
};
|
|
273
|
+
/**
|
|
274
|
+
* Wrap requestIdleCallback with promise
|
|
275
|
+
* Exec callback when browser idle
|
|
276
|
+
*/
|
|
277
|
+
function promiseRequestIdle(callback) {
|
|
278
|
+
return new Promise((resolve) => {
|
|
279
|
+
requestIdleCallback(() => {
|
|
280
|
+
callback(resolve);
|
|
281
|
+
});
|
|
282
|
+
});
|
|
283
|
+
}
|
|
263
284
|
/**
|
|
264
285
|
* Record the currently running app.name
|
|
265
286
|
*/
|
|
@@ -433,6 +454,59 @@ function useMapRecord() {
|
|
|
433
454
|
}
|
|
434
455
|
};
|
|
435
456
|
}
|
|
457
|
+
function getAttributes(element) {
|
|
458
|
+
const attr = element.attributes;
|
|
459
|
+
const attrMap = new Map();
|
|
460
|
+
for (let i = 0; i < attr.length; i++) {
|
|
461
|
+
attrMap.set(attr[i].name, attr[i].value);
|
|
462
|
+
}
|
|
463
|
+
return attrMap;
|
|
464
|
+
}
|
|
465
|
+
/**
|
|
466
|
+
* if fiberTasks exist, wrap callback with promiseRequestIdle
|
|
467
|
+
* if not, execute callback
|
|
468
|
+
* @param fiberTasks fiber task list
|
|
469
|
+
* @param callback action callback
|
|
470
|
+
*/
|
|
471
|
+
function injectFiberTask(fiberTasks, callback) {
|
|
472
|
+
if (fiberTasks) {
|
|
473
|
+
fiberTasks.push(() => promiseRequestIdle((resolve) => {
|
|
474
|
+
callback();
|
|
475
|
+
resolve();
|
|
476
|
+
}));
|
|
477
|
+
}
|
|
478
|
+
else {
|
|
479
|
+
callback();
|
|
480
|
+
}
|
|
481
|
+
}
|
|
482
|
+
/**
|
|
483
|
+
* serial exec fiber task of link, style, script
|
|
484
|
+
* @param tasks task array or null
|
|
485
|
+
*/
|
|
486
|
+
function serialExecFiberTasks(tasks) {
|
|
487
|
+
return (tasks === null || tasks === void 0 ? void 0 : tasks.reduce((pre, next) => pre.then(next), Promise.resolve())) || null;
|
|
488
|
+
}
|
|
489
|
+
/**
|
|
490
|
+
* inline script start with inline-xxx
|
|
491
|
+
* @param address source address
|
|
492
|
+
*/
|
|
493
|
+
function isInlineScript(address) {
|
|
494
|
+
return address.startsWith('inline-');
|
|
495
|
+
}
|
|
496
|
+
/**
|
|
497
|
+
* call function with try catch
|
|
498
|
+
* @param fn target function
|
|
499
|
+
* @param appName app.name
|
|
500
|
+
* @param args arguments
|
|
501
|
+
*/
|
|
502
|
+
function callFnWithTryCatch(fn, appName, msgSuffix, ...args) {
|
|
503
|
+
try {
|
|
504
|
+
isFunction(fn) && fn(...args);
|
|
505
|
+
}
|
|
506
|
+
catch (e) {
|
|
507
|
+
logError(`an error occurred in app ${appName} ${msgSuffix} \n`, null, e);
|
|
508
|
+
}
|
|
509
|
+
}
|
|
436
510
|
|
|
437
511
|
var ObservedAttrName;
|
|
438
512
|
(function (ObservedAttrName) {
|
|
@@ -463,12 +537,39 @@ var lifeCycles;
|
|
|
463
537
|
lifeCycles["AFTERSHOW"] = "aftershow";
|
|
464
538
|
lifeCycles["AFTERHIDDEN"] = "afterhidden";
|
|
465
539
|
})(lifeCycles || (lifeCycles = {}));
|
|
540
|
+
// global event of child app
|
|
541
|
+
var microGlobalEvent;
|
|
542
|
+
(function (microGlobalEvent) {
|
|
543
|
+
microGlobalEvent["ONMOUNT"] = "onmount";
|
|
544
|
+
microGlobalEvent["ONUNMOUNT"] = "onunmount";
|
|
545
|
+
})(microGlobalEvent || (microGlobalEvent = {}));
|
|
466
546
|
// keep-alive status
|
|
467
547
|
var keepAliveStates;
|
|
468
548
|
(function (keepAliveStates) {
|
|
469
549
|
keepAliveStates["KEEP_ALIVE_SHOW"] = "keep_alive_show";
|
|
470
550
|
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "keep_alive_hidden";
|
|
471
551
|
})(keepAliveStates || (keepAliveStates = {}));
|
|
552
|
+
// micro-app config
|
|
553
|
+
var MicroAppConfig;
|
|
554
|
+
(function (MicroAppConfig) {
|
|
555
|
+
MicroAppConfig["DESTROY"] = "destroy";
|
|
556
|
+
MicroAppConfig["DESTORY"] = "destory";
|
|
557
|
+
MicroAppConfig["INLINE"] = "inline";
|
|
558
|
+
MicroAppConfig["DISABLESCOPECSS"] = "disableScopecss";
|
|
559
|
+
MicroAppConfig["DISABLESANDBOX"] = "disableSandbox";
|
|
560
|
+
MicroAppConfig["DISABLE_SCOPECSS"] = "disable-scopecss";
|
|
561
|
+
MicroAppConfig["DISABLE_SANDBOX"] = "disable-sandbox";
|
|
562
|
+
MicroAppConfig["DISABLE_MEMORY_ROUTER"] = "disable-memory-router";
|
|
563
|
+
MicroAppConfig["DISABLE_PATCH_REQUEST"] = "disable-patch-request";
|
|
564
|
+
MicroAppConfig["KEEP_ROUTER_STATE"] = "keep-router-state";
|
|
565
|
+
MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
|
|
566
|
+
MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
|
|
567
|
+
MicroAppConfig["CLEAR_DATA"] = "clear-data";
|
|
568
|
+
MicroAppConfig["ESMODULE"] = "esmodule";
|
|
569
|
+
MicroAppConfig["SSR"] = "ssr";
|
|
570
|
+
MicroAppConfig["FIBER"] = "fiber";
|
|
571
|
+
})(MicroAppConfig || (MicroAppConfig = {}));
|
|
572
|
+
const PREFETCH_LEVEL = [1, 2, 3];
|
|
472
573
|
/**
|
|
473
574
|
* global key must be static key, they can not rewrite
|
|
474
575
|
* e.g.
|
|
@@ -493,8 +594,8 @@ function fetchSource(url, appName = null, options = {}) {
|
|
|
493
594
|
* baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
|
|
494
595
|
*/
|
|
495
596
|
removeDomScope();
|
|
496
|
-
if (isFunction(microApp.fetch)) {
|
|
497
|
-
return microApp.fetch(url, options, appName);
|
|
597
|
+
if (isFunction(microApp.options.fetch)) {
|
|
598
|
+
return microApp.options.fetch(url, options, appName);
|
|
498
599
|
}
|
|
499
600
|
// Don’t use globalEnv.rawWindow.fetch, will cause sgm-2.8.0.js throw error in nest app
|
|
500
601
|
return window.fetch(url, options).then((res) => {
|
|
@@ -531,7 +632,7 @@ class HTMLLoader {
|
|
|
531
632
|
});
|
|
532
633
|
}
|
|
533
634
|
formatHTML(htmlUrl, htmlStr, appName) {
|
|
534
|
-
return this.processHtml(htmlUrl, htmlStr, appName, microApp.plugins)
|
|
635
|
+
return this.processHtml(htmlUrl, htmlStr, appName, microApp.options.plugins)
|
|
535
636
|
.replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
|
|
536
637
|
return match
|
|
537
638
|
.replace(/<head/i, '<micro-app-head')
|
|
@@ -553,7 +654,7 @@ class HTMLLoader {
|
|
|
553
654
|
if (mergedPlugins.length > 0) {
|
|
554
655
|
return mergedPlugins.reduce((preCode, plugin) => {
|
|
555
656
|
if (isPlainObject(plugin) && isFunction(plugin.processHtml)) {
|
|
556
|
-
return plugin.processHtml(preCode, url
|
|
657
|
+
return plugin.processHtml(preCode, url);
|
|
557
658
|
}
|
|
558
659
|
return preCode;
|
|
559
660
|
}, code);
|
|
@@ -591,11 +692,13 @@ class CSSParser {
|
|
|
591
692
|
this.scopecssDisableSelectors = []; // disable or enable scopecss for specific selectors
|
|
592
693
|
this.scopecssDisableNextLine = false; // use block comments /* scopecss-disable-next-line */ to disable scopecss on a specific line
|
|
593
694
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSMediaRule
|
|
594
|
-
this.mediaRule = this.
|
|
695
|
+
this.mediaRule = this.createMatcherForRuleWithChildRule(/^@media *([^{]+)/, '@media');
|
|
595
696
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSSupportsRule
|
|
596
|
-
this.supportsRule = this.
|
|
597
|
-
this.documentRule = this.
|
|
598
|
-
this.hostRule = this.
|
|
697
|
+
this.supportsRule = this.createMatcherForRuleWithChildRule(/^@supports *([^{]+)/, '@supports');
|
|
698
|
+
this.documentRule = this.createMatcherForRuleWithChildRule(/^@([-\w]+)?document *([^{]+)/, '@document');
|
|
699
|
+
this.hostRule = this.createMatcherForRuleWithChildRule(/^@host\s*/, '@host');
|
|
700
|
+
// :global is CSS Modules rule, it will be converted to normal syntax
|
|
701
|
+
// private globalRule = this.createMatcherForRuleWithChildRule(/^:global([^{]*)/, ':global')
|
|
599
702
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSImportRule
|
|
600
703
|
this.importRule = this.createMatcherForNoneBraceAtRule('import');
|
|
601
704
|
// Removed in most browsers
|
|
@@ -716,6 +819,13 @@ class CSSParser {
|
|
|
716
819
|
this.hostRule() ||
|
|
717
820
|
this.fontFaceRule();
|
|
718
821
|
}
|
|
822
|
+
// :global is CSS Modules rule, it will be converted to normal syntax
|
|
823
|
+
// private matchGlobalRule (): boolean | void {
|
|
824
|
+
// if (this.cssText[0] !== ':') return false
|
|
825
|
+
// // reset scopecssDisableNextLine
|
|
826
|
+
// this.scopecssDisableNextLine = false
|
|
827
|
+
// return this.globalRule()
|
|
828
|
+
// }
|
|
719
829
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSKeyframesRule
|
|
720
830
|
keyframesRule() {
|
|
721
831
|
if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
|
|
@@ -769,17 +879,17 @@ class CSSParser {
|
|
|
769
879
|
return false;
|
|
770
880
|
return this.commonHandlerForAtRuleWithSelfRule('font-face');
|
|
771
881
|
}
|
|
772
|
-
// common matcher for @media, @supports, @document, @host
|
|
773
|
-
|
|
882
|
+
// common matcher for @media, @supports, @document, @host, :global
|
|
883
|
+
createMatcherForRuleWithChildRule(reg, name) {
|
|
774
884
|
return () => {
|
|
775
885
|
if (!this.commonMatch(reg))
|
|
776
886
|
return false;
|
|
777
887
|
if (!this.matchOpenBrace())
|
|
778
|
-
return parseError(
|
|
888
|
+
return parseError(`${name} missing '{'`, this.linkPath);
|
|
779
889
|
this.matchComments();
|
|
780
890
|
this.matchRules();
|
|
781
891
|
if (!this.matchCloseBrace())
|
|
782
|
-
return parseError(
|
|
892
|
+
return parseError(`${name} missing '}'`, this.linkPath);
|
|
783
893
|
this.matchLeadingSpaces();
|
|
784
894
|
return true;
|
|
785
895
|
};
|
|
@@ -906,20 +1016,20 @@ let parser;
|
|
|
906
1016
|
* @param styleElement target style element
|
|
907
1017
|
* @param appName app name
|
|
908
1018
|
*/
|
|
909
|
-
function scopedCSS(styleElement, app) {
|
|
1019
|
+
function scopedCSS(styleElement, app, linkPath) {
|
|
910
1020
|
if (app.scopecss) {
|
|
911
|
-
const prefix =
|
|
1021
|
+
const prefix = createPrefix(app.name);
|
|
912
1022
|
if (!parser)
|
|
913
1023
|
parser = new CSSParser();
|
|
914
1024
|
if (styleElement.textContent) {
|
|
915
|
-
commonAction(styleElement, app.name, prefix, app.url,
|
|
1025
|
+
commonAction(styleElement, app.name, prefix, app.url, linkPath);
|
|
916
1026
|
}
|
|
917
1027
|
else {
|
|
918
1028
|
const observer = new MutationObserver(function () {
|
|
919
1029
|
observer.disconnect();
|
|
920
1030
|
// styled-component will be ignore
|
|
921
1031
|
if (styleElement.textContent && !styleElement.hasAttribute('data-styled')) {
|
|
922
|
-
commonAction(styleElement, app.name, prefix, app.url,
|
|
1032
|
+
commonAction(styleElement, app.name, prefix, app.url, linkPath);
|
|
923
1033
|
}
|
|
924
1034
|
});
|
|
925
1035
|
observer.observe(styleElement, { childList: true });
|
|
@@ -927,6 +1037,10 @@ function scopedCSS(styleElement, app) {
|
|
|
927
1037
|
}
|
|
928
1038
|
return styleElement;
|
|
929
1039
|
}
|
|
1040
|
+
function createPrefix(appName, reg = false) {
|
|
1041
|
+
const regCharacter = reg ? '\\' : '';
|
|
1042
|
+
return `${microApp.tagName}${regCharacter}[name=${appName}${regCharacter}]`;
|
|
1043
|
+
}
|
|
930
1044
|
|
|
931
1045
|
function eventHandler(event, element) {
|
|
932
1046
|
Object.defineProperties(event, {
|
|
@@ -968,8 +1082,76 @@ function dispatchOnErrorEvent(element) {
|
|
|
968
1082
|
}
|
|
969
1083
|
}
|
|
970
1084
|
|
|
971
|
-
|
|
972
|
-
|
|
1085
|
+
/**
|
|
1086
|
+
* SourceCenter is a resource management center
|
|
1087
|
+
* All html, js, css will be recorded and processed here
|
|
1088
|
+
* NOTE:
|
|
1089
|
+
* 1. All resources are global and shared between apps
|
|
1090
|
+
* 2. Pay attention to the case of html with parameters
|
|
1091
|
+
* 3. The resource is first processed by the plugin
|
|
1092
|
+
*/
|
|
1093
|
+
function createSourceCenter() {
|
|
1094
|
+
const linkList = new Map();
|
|
1095
|
+
const scriptList = new Map();
|
|
1096
|
+
// setInterval(() => {
|
|
1097
|
+
// console.log(linkList, scriptList)
|
|
1098
|
+
// }, 10000);
|
|
1099
|
+
function createSourceHandler(targetList) {
|
|
1100
|
+
return {
|
|
1101
|
+
setInfo(address, info) {
|
|
1102
|
+
targetList.set(address, info);
|
|
1103
|
+
},
|
|
1104
|
+
getInfo(address) {
|
|
1105
|
+
var _a;
|
|
1106
|
+
return (_a = targetList.get(address)) !== null && _a !== void 0 ? _a : null;
|
|
1107
|
+
},
|
|
1108
|
+
hasInfo(address) {
|
|
1109
|
+
return targetList.has(address);
|
|
1110
|
+
},
|
|
1111
|
+
deleteInfo(address) {
|
|
1112
|
+
return targetList.delete(address);
|
|
1113
|
+
}
|
|
1114
|
+
};
|
|
1115
|
+
}
|
|
1116
|
+
return {
|
|
1117
|
+
link: createSourceHandler(linkList),
|
|
1118
|
+
script: Object.assign(Object.assign({}, createSourceHandler(scriptList)), { deleteInlineInfo(addressList) {
|
|
1119
|
+
addressList.forEach((address) => {
|
|
1120
|
+
if (isInlineScript(address)) {
|
|
1121
|
+
scriptList.delete(address);
|
|
1122
|
+
}
|
|
1123
|
+
});
|
|
1124
|
+
} }),
|
|
1125
|
+
};
|
|
1126
|
+
}
|
|
1127
|
+
var sourceCenter = createSourceCenter();
|
|
1128
|
+
|
|
1129
|
+
/**
|
|
1130
|
+
*
|
|
1131
|
+
* @param appName app.name
|
|
1132
|
+
* @param linkInfo linkInfo of current address
|
|
1133
|
+
*/
|
|
1134
|
+
function getExistParseCode(appName, prefix, linkInfo) {
|
|
1135
|
+
const appSpace = linkInfo.appSpace;
|
|
1136
|
+
for (const item in appSpace) {
|
|
1137
|
+
if (item !== appName) {
|
|
1138
|
+
const appSpaceData = appSpace[item];
|
|
1139
|
+
if (appSpaceData.parsedCode) {
|
|
1140
|
+
return appSpaceData.parsedCode.replaceAll(new RegExp(createPrefix(item, true), 'g'), prefix);
|
|
1141
|
+
}
|
|
1142
|
+
}
|
|
1143
|
+
}
|
|
1144
|
+
}
|
|
1145
|
+
// transfer the attributes on the link to convertStyle
|
|
1146
|
+
function setConvertStyleAttr(convertStyle, attrs) {
|
|
1147
|
+
attrs.forEach((value, key) => {
|
|
1148
|
+
if (key === 'rel')
|
|
1149
|
+
return;
|
|
1150
|
+
if (key === 'href')
|
|
1151
|
+
key = 'data-origin-href';
|
|
1152
|
+
convertStyle.setAttribute(key, value);
|
|
1153
|
+
});
|
|
1154
|
+
}
|
|
973
1155
|
/**
|
|
974
1156
|
* Extract link elements
|
|
975
1157
|
* @param link link element
|
|
@@ -984,22 +1166,29 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
984
1166
|
let replaceComment = null;
|
|
985
1167
|
if (rel === 'stylesheet' && href) {
|
|
986
1168
|
href = CompletionPath(href, app.url);
|
|
1169
|
+
let linkInfo = sourceCenter.link.getInfo(href);
|
|
1170
|
+
const appSpaceData = {
|
|
1171
|
+
attrs: getAttributes(link),
|
|
1172
|
+
};
|
|
1173
|
+
if (!linkInfo) {
|
|
1174
|
+
linkInfo = {
|
|
1175
|
+
code: '',
|
|
1176
|
+
appSpace: {
|
|
1177
|
+
[app.name]: appSpaceData,
|
|
1178
|
+
}
|
|
1179
|
+
};
|
|
1180
|
+
}
|
|
1181
|
+
else {
|
|
1182
|
+
linkInfo.appSpace[app.name] = linkInfo.appSpace[app.name] || appSpaceData;
|
|
1183
|
+
}
|
|
1184
|
+
sourceCenter.link.setInfo(href, linkInfo);
|
|
987
1185
|
if (!isDynamic) {
|
|
1186
|
+
app.source.links.add(href);
|
|
988
1187
|
replaceComment = document.createComment(`link element with href=${href} move to micro-app-head as style element`);
|
|
989
|
-
app.
|
|
990
|
-
code: '',
|
|
991
|
-
placeholder: replaceComment,
|
|
992
|
-
isGlobal: link.hasAttribute('global'),
|
|
993
|
-
});
|
|
1188
|
+
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
994
1189
|
}
|
|
995
1190
|
else {
|
|
996
|
-
return {
|
|
997
|
-
url: href,
|
|
998
|
-
info: {
|
|
999
|
-
code: '',
|
|
1000
|
-
isGlobal: link.hasAttribute('global'),
|
|
1001
|
-
}
|
|
1002
|
-
};
|
|
1191
|
+
return { address: href, linkInfo };
|
|
1003
1192
|
}
|
|
1004
1193
|
}
|
|
1005
1194
|
else if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
|
|
@@ -1028,79 +1217,138 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
1028
1217
|
* @param app app
|
|
1029
1218
|
* @param microAppHead micro-app-head
|
|
1030
1219
|
*/
|
|
1031
|
-
function fetchLinksFromHtml(wrapElement, app, microAppHead) {
|
|
1032
|
-
const
|
|
1033
|
-
const fetchLinkPromise =
|
|
1034
|
-
|
|
1220
|
+
function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
1221
|
+
const styleList = Array.from(app.source.links);
|
|
1222
|
+
const fetchLinkPromise = styleList.map((address) => {
|
|
1223
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
1224
|
+
return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
|
|
1035
1225
|
});
|
|
1226
|
+
const fiberLinkTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
1036
1227
|
promiseStream(fetchLinkPromise, (res) => {
|
|
1037
|
-
|
|
1228
|
+
injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
|
|
1038
1229
|
}, (err) => {
|
|
1039
1230
|
logError(err, app.name);
|
|
1040
1231
|
}, () => {
|
|
1041
|
-
|
|
1232
|
+
if (fiberLinkTasks) {
|
|
1233
|
+
/**
|
|
1234
|
+
* 1. If fiberLinkTasks is not null, fiberStyleResult is not null
|
|
1235
|
+
* 2. Download link source while processing style
|
|
1236
|
+
* 3. Process style first, and then process link
|
|
1237
|
+
*/
|
|
1238
|
+
fiberStyleResult.then(() => {
|
|
1239
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1240
|
+
serialExecFiberTasks(fiberLinkTasks);
|
|
1241
|
+
});
|
|
1242
|
+
}
|
|
1243
|
+
else {
|
|
1244
|
+
app.onLoad(wrapElement);
|
|
1245
|
+
}
|
|
1042
1246
|
});
|
|
1043
1247
|
}
|
|
1044
1248
|
/**
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1249
|
+
* Fetch link succeeded, replace placeholder with style tag
|
|
1250
|
+
* NOTE:
|
|
1251
|
+
* 1. Only exec when init, no longer exec when remount
|
|
1252
|
+
* 2. Only handler html link element, not dynamic link or style
|
|
1253
|
+
* 3. The same prefix can reuse parsedCode
|
|
1254
|
+
* 4. Async exec with requestIdleCallback in prefetch or fiber
|
|
1255
|
+
* 5. appSpace[app.name].placeholder/attrs must exist
|
|
1256
|
+
* @param address resource address
|
|
1257
|
+
* @param code link source code
|
|
1049
1258
|
* @param microAppHead micro-app-head
|
|
1050
|
-
* @param app app
|
|
1259
|
+
* @param app app instance
|
|
1051
1260
|
*/
|
|
1052
|
-
function fetchLinkSuccess(
|
|
1053
|
-
|
|
1054
|
-
|
|
1261
|
+
function fetchLinkSuccess(address, code, microAppHead, app) {
|
|
1262
|
+
/**
|
|
1263
|
+
* linkInfo must exist, but linkInfo.code not
|
|
1264
|
+
* so we set code to linkInfo.code
|
|
1265
|
+
*/
|
|
1266
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
1267
|
+
linkInfo.code = code;
|
|
1268
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
1269
|
+
const placeholder = appSpaceData.placeholder;
|
|
1270
|
+
/**
|
|
1271
|
+
* When prefetch app is replaced by a new app in the processing phase, since the linkInfo is common, when the linkInfo of the prefetch app is processed, it may have already been processed.
|
|
1272
|
+
* This causes placeholder to be possibly null
|
|
1273
|
+
* e.g.
|
|
1274
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
1275
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
1276
|
+
*/
|
|
1277
|
+
if (placeholder) {
|
|
1278
|
+
const convertStyle = pureCreateElement('style');
|
|
1279
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, appSpaceData.attrs);
|
|
1280
|
+
if (placeholder.parentNode) {
|
|
1281
|
+
placeholder.parentNode.replaceChild(convertStyle, placeholder);
|
|
1282
|
+
}
|
|
1283
|
+
else {
|
|
1284
|
+
microAppHead.appendChild(convertStyle);
|
|
1285
|
+
}
|
|
1286
|
+
// clear placeholder
|
|
1287
|
+
appSpaceData.placeholder = null;
|
|
1055
1288
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1289
|
+
}
|
|
1290
|
+
/**
|
|
1291
|
+
* Get parsedCode, update convertStyle
|
|
1292
|
+
* Actions:
|
|
1293
|
+
* 1. get scope css (through scopedCSS or oldData)
|
|
1294
|
+
* 2. record parsedCode
|
|
1295
|
+
* 3. set parsedCode to convertStyle if need
|
|
1296
|
+
* @param app app instance
|
|
1297
|
+
* @param address resource address
|
|
1298
|
+
* @param convertStyle converted style
|
|
1299
|
+
* @param linkInfo linkInfo in sourceCenter
|
|
1300
|
+
* @param attrs attrs of link
|
|
1301
|
+
*/
|
|
1302
|
+
function handleConvertStyle(app, address, convertStyle, linkInfo, attrs) {
|
|
1303
|
+
if (app.scopecss) {
|
|
1304
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
1305
|
+
appSpaceData.prefix = appSpaceData.prefix || createPrefix(app.name);
|
|
1306
|
+
if (!appSpaceData.parsedCode) {
|
|
1307
|
+
const existParsedCode = getExistParseCode(app.name, appSpaceData.prefix, linkInfo);
|
|
1308
|
+
if (!existParsedCode) {
|
|
1309
|
+
convertStyle.textContent = linkInfo.code;
|
|
1310
|
+
scopedCSS(convertStyle, app, address);
|
|
1311
|
+
}
|
|
1312
|
+
else {
|
|
1313
|
+
convertStyle.textContent = existParsedCode;
|
|
1314
|
+
}
|
|
1315
|
+
appSpaceData.parsedCode = convertStyle.textContent;
|
|
1316
|
+
}
|
|
1317
|
+
else {
|
|
1318
|
+
convertStyle.textContent = appSpaceData.parsedCode;
|
|
1319
|
+
}
|
|
1062
1320
|
}
|
|
1063
1321
|
else {
|
|
1064
|
-
|
|
1322
|
+
convertStyle.textContent = linkInfo.code;
|
|
1065
1323
|
}
|
|
1066
|
-
|
|
1067
|
-
info.code = data;
|
|
1324
|
+
setConvertStyleAttr(convertStyle, attrs);
|
|
1068
1325
|
}
|
|
1069
1326
|
/**
|
|
1070
|
-
*
|
|
1071
|
-
* @param
|
|
1072
|
-
* @param info info
|
|
1327
|
+
* Handle css of dynamic link
|
|
1328
|
+
* @param address link address
|
|
1073
1329
|
* @param app app
|
|
1330
|
+
* @param linkInfo linkInfo
|
|
1074
1331
|
* @param originLink origin link element
|
|
1075
|
-
* @param replaceStyle style element which replaced origin link
|
|
1076
1332
|
*/
|
|
1077
|
-
function formatDynamicLink(
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1333
|
+
function formatDynamicLink(address, app, linkInfo, originLink) {
|
|
1334
|
+
const convertStyle = pureCreateElement('style');
|
|
1335
|
+
const handleDynamicLink = () => {
|
|
1336
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, linkInfo.appSpace[app.name].attrs);
|
|
1337
|
+
dispatchOnLoadEvent(originLink);
|
|
1338
|
+
};
|
|
1339
|
+
if (linkInfo.code) {
|
|
1340
|
+
defer(handleDynamicLink);
|
|
1083
1341
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1342
|
+
else {
|
|
1343
|
+
fetchSource(address, app.name).then((data) => {
|
|
1344
|
+
linkInfo.code = data;
|
|
1345
|
+
handleDynamicLink();
|
|
1346
|
+
}).catch((err) => {
|
|
1347
|
+
logError(err, app.name);
|
|
1348
|
+
dispatchOnErrorEvent(originLink);
|
|
1349
|
+
});
|
|
1092
1350
|
}
|
|
1093
|
-
|
|
1094
|
-
info.code = data;
|
|
1095
|
-
app.source.links.set(url, info);
|
|
1096
|
-
info.isGlobal && globalLinks.set(url, data);
|
|
1097
|
-
replaceStyle.textContent = data;
|
|
1098
|
-
scopedCSS(replaceStyle, app);
|
|
1099
|
-
dispatchOnLoadEvent(originLink);
|
|
1100
|
-
}).catch((err) => {
|
|
1101
|
-
logError(err, app.name);
|
|
1102
|
-
dispatchOnErrorEvent(originLink);
|
|
1103
|
-
});
|
|
1351
|
+
return convertStyle;
|
|
1104
1352
|
}
|
|
1105
1353
|
|
|
1106
1354
|
class Adapter {
|
|
@@ -1122,10 +1370,9 @@ class Adapter {
|
|
|
1122
1370
|
];
|
|
1123
1371
|
this.injectReactHRMProperty();
|
|
1124
1372
|
}
|
|
1125
|
-
// TODO: __DEV__ process.env.NODE_ENV !== 'production'
|
|
1126
1373
|
// adapter for react
|
|
1127
1374
|
injectReactHRMProperty() {
|
|
1128
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1375
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
1129
1376
|
// react child in non-react env
|
|
1130
1377
|
this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
|
|
1131
1378
|
// in react parent
|
|
@@ -1149,7 +1396,7 @@ function fixBabelPolyfill6() {
|
|
|
1149
1396
|
*/
|
|
1150
1397
|
function fixReactHMRConflict(app) {
|
|
1151
1398
|
var _a;
|
|
1152
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
1399
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
1153
1400
|
const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
1154
1401
|
const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
1155
1402
|
if (rawReactErrorHook && childReactErrorHook) {
|
|
@@ -1169,17 +1416,25 @@ function fixReactHMRConflict(app) {
|
|
|
1169
1416
|
function throttleDeferForParentNode(proxyDocument) {
|
|
1170
1417
|
const html = globalEnv.rawDocument.firstElementChild;
|
|
1171
1418
|
if (html && html.parentNode !== proxyDocument) {
|
|
1172
|
-
|
|
1419
|
+
setParentNode(html, proxyDocument);
|
|
1173
1420
|
defer(() => {
|
|
1174
|
-
|
|
1421
|
+
setParentNode(html, globalEnv.rawDocument);
|
|
1175
1422
|
});
|
|
1176
1423
|
}
|
|
1177
1424
|
}
|
|
1178
|
-
|
|
1179
|
-
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1425
|
+
/**
|
|
1426
|
+
* Modify the point of parentNode
|
|
1427
|
+
* @param target target Node
|
|
1428
|
+
* @param value parentNode
|
|
1429
|
+
*/
|
|
1430
|
+
function setParentNode(target, value) {
|
|
1431
|
+
const descriptor = Object.getOwnPropertyDescriptor(target, 'parentNode');
|
|
1432
|
+
if (!descriptor || descriptor.configurable) {
|
|
1433
|
+
rawDefineProperty(target, 'parentNode', {
|
|
1434
|
+
value,
|
|
1435
|
+
configurable: true,
|
|
1436
|
+
});
|
|
1437
|
+
}
|
|
1183
1438
|
}
|
|
1184
1439
|
|
|
1185
1440
|
// Record element and map element
|
|
@@ -1208,14 +1463,16 @@ function handleNewNode(parent, child, app) {
|
|
|
1208
1463
|
dynamicElementInMicroAppMap.set(child, linkReplaceComment);
|
|
1209
1464
|
return linkReplaceComment;
|
|
1210
1465
|
}
|
|
1211
|
-
else if (child.hasAttribute('ignore') ||
|
|
1466
|
+
else if (child.hasAttribute('ignore') ||
|
|
1467
|
+
checkIgnoreUrl(child.getAttribute('href'), app.name) ||
|
|
1468
|
+
(child.href &&
|
|
1469
|
+
isFunction(microApp.options.excludeAssetFilter) &&
|
|
1470
|
+
microApp.options.excludeAssetFilter(child.href))) {
|
|
1212
1471
|
return child;
|
|
1213
1472
|
}
|
|
1214
|
-
const {
|
|
1215
|
-
if (
|
|
1216
|
-
const replaceStyle =
|
|
1217
|
-
replaceStyle.__MICRO_APP_LINK_PATH__ = url;
|
|
1218
|
-
formatDynamicLink(url, info, app, child, replaceStyle);
|
|
1473
|
+
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child, parent, app, true);
|
|
1474
|
+
if (address && linkInfo) {
|
|
1475
|
+
const replaceStyle = formatDynamicLink(address, app, linkInfo, child);
|
|
1219
1476
|
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
1220
1477
|
return replaceStyle;
|
|
1221
1478
|
}
|
|
@@ -1226,18 +1483,17 @@ function handleNewNode(parent, child, app) {
|
|
|
1226
1483
|
return child;
|
|
1227
1484
|
}
|
|
1228
1485
|
else if (child instanceof HTMLScriptElement) {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1486
|
+
if (child.src &&
|
|
1487
|
+
isFunction(microApp.options.excludeAssetFilter) &&
|
|
1488
|
+
microApp.options.excludeAssetFilter(child.src)) {
|
|
1489
|
+
return child;
|
|
1490
|
+
}
|
|
1491
|
+
const { replaceComment, address, scriptInfo } = extractScriptElement(child, parent, app, true) || {};
|
|
1492
|
+
if (address && scriptInfo) {
|
|
1493
|
+
// remote script or inline script
|
|
1494
|
+
const replaceElement = scriptInfo.isExternal ? runDynamicRemoteScript(address, app, scriptInfo, child) : runDynamicInlineScript(address, app, scriptInfo);
|
|
1495
|
+
dynamicElementInMicroAppMap.set(child, replaceElement);
|
|
1496
|
+
return replaceElement;
|
|
1241
1497
|
}
|
|
1242
1498
|
else if (replaceComment) {
|
|
1243
1499
|
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
@@ -1256,37 +1512,56 @@ function handleNewNode(parent, child, app) {
|
|
|
1256
1512
|
* @param passiveChild second param of insertBefore and replaceChild
|
|
1257
1513
|
*/
|
|
1258
1514
|
function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
|
|
1259
|
-
const
|
|
1515
|
+
const hijackParent = getHijackParent(parent, app);
|
|
1260
1516
|
/**
|
|
1261
1517
|
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
1262
1518
|
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
1263
1519
|
*/
|
|
1264
|
-
if (
|
|
1520
|
+
if (hijackParent) {
|
|
1521
|
+
/**
|
|
1522
|
+
* WARNING:
|
|
1523
|
+
* Verifying that the parentNode of the targetChild points to document.body will cause other problems ?
|
|
1524
|
+
*/
|
|
1525
|
+
if (hijackParent.tagName === 'MICRO-APP-BODY' && rawMethod !== globalEnv.rawRemoveChild) {
|
|
1526
|
+
const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
|
|
1527
|
+
if (!descriptor || descriptor.configurable) {
|
|
1528
|
+
rawDefineProperty(targetChild, 'parentNode', {
|
|
1529
|
+
configurable: true,
|
|
1530
|
+
get() {
|
|
1531
|
+
/**
|
|
1532
|
+
* When operate child from parentNode async, may have been unmount
|
|
1533
|
+
* e.g.
|
|
1534
|
+
* target.parentNode.remove(target)
|
|
1535
|
+
*/
|
|
1536
|
+
return !app.container ? hijackParent : document.body;
|
|
1537
|
+
},
|
|
1538
|
+
});
|
|
1539
|
+
}
|
|
1540
|
+
}
|
|
1265
1541
|
/**
|
|
1266
1542
|
* 1. If passiveChild exists, it must be insertBefore or replaceChild
|
|
1267
1543
|
* 2. When removeChild, targetChild may not be in microAppHead or head
|
|
1268
1544
|
*/
|
|
1269
|
-
if (passiveChild && !
|
|
1270
|
-
return globalEnv.rawAppendChild.call(
|
|
1545
|
+
if (passiveChild && !hijackParent.contains(passiveChild)) {
|
|
1546
|
+
return globalEnv.rawAppendChild.call(hijackParent, targetChild);
|
|
1271
1547
|
}
|
|
1272
|
-
else if (rawMethod === globalEnv.rawRemoveChild && !
|
|
1548
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
|
|
1273
1549
|
if (parent.contains(targetChild)) {
|
|
1274
1550
|
return rawMethod.call(parent, targetChild);
|
|
1275
1551
|
}
|
|
1276
1552
|
return targetChild;
|
|
1277
1553
|
}
|
|
1278
|
-
|
|
1279
|
-
if (process.env.NODE_ENV !== 'production' &&
|
|
1554
|
+
if ((process.env.NODE_ENV !== 'production') &&
|
|
1280
1555
|
targetChild instanceof HTMLIFrameElement &&
|
|
1281
1556
|
rawMethod === globalEnv.rawAppendChild) {
|
|
1282
1557
|
fixReactHMRConflict(app);
|
|
1283
1558
|
}
|
|
1284
|
-
return invokeRawMethod(rawMethod,
|
|
1559
|
+
return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
|
|
1285
1560
|
}
|
|
1286
1561
|
return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
|
|
1287
1562
|
}
|
|
1288
1563
|
// head/body map to micro-app-head/micro-app-body
|
|
1289
|
-
function
|
|
1564
|
+
function getHijackParent(node, app) {
|
|
1290
1565
|
var _a, _b;
|
|
1291
1566
|
if (node === document.head) {
|
|
1292
1567
|
return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
|
|
@@ -1319,13 +1594,13 @@ function getMappingNode(node) {
|
|
|
1319
1594
|
*/
|
|
1320
1595
|
function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
1321
1596
|
const currentAppName = getCurrentAppName();
|
|
1322
|
-
if (newChild
|
|
1597
|
+
if (isNode(newChild) &&
|
|
1323
1598
|
(newChild.__MICRO_APP_NAME__ ||
|
|
1324
1599
|
(currentAppName && !newChild.__PURE_ELEMENT__))) {
|
|
1325
1600
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1326
1601
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1327
1602
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1328
|
-
if (newChild
|
|
1603
|
+
if (isElement(newChild)) {
|
|
1329
1604
|
if (/^(img|script)$/i.test(newChild.tagName)) {
|
|
1330
1605
|
if (newChild.hasAttribute('src')) {
|
|
1331
1606
|
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
@@ -1345,7 +1620,7 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1345
1620
|
}
|
|
1346
1621
|
}
|
|
1347
1622
|
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1348
|
-
if (!(newChild
|
|
1623
|
+
if (!isNode(newChild) && currentAppName) {
|
|
1349
1624
|
const app = appInstanceMap.get(currentAppName);
|
|
1350
1625
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1351
1626
|
if (parent === document.head) {
|
|
@@ -1392,7 +1667,6 @@ function patchElementPrototypeMethods() {
|
|
|
1392
1667
|
};
|
|
1393
1668
|
// prototype methods of delete element👇
|
|
1394
1669
|
Element.prototype.removeChild = function removeChild(oldChild) {
|
|
1395
|
-
var _a;
|
|
1396
1670
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1397
1671
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1398
1672
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -1401,8 +1675,8 @@ function patchElementPrototypeMethods() {
|
|
|
1401
1675
|
try {
|
|
1402
1676
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1403
1677
|
}
|
|
1404
|
-
catch (
|
|
1405
|
-
return (
|
|
1678
|
+
catch (_a) {
|
|
1679
|
+
return ((oldChild === null || oldChild === void 0 ? void 0 : oldChild.parentNode) && globalEnv.rawRemoveChild.call(oldChild.parentNode, oldChild));
|
|
1406
1680
|
}
|
|
1407
1681
|
}
|
|
1408
1682
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
@@ -1705,8 +1979,80 @@ function initGlobalEnv() {
|
|
|
1705
1979
|
}
|
|
1706
1980
|
}
|
|
1707
1981
|
|
|
1708
|
-
|
|
1709
|
-
|
|
1982
|
+
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1983
|
+
// whether use type='module' script
|
|
1984
|
+
function isTypeModule(app, scriptInfo) {
|
|
1985
|
+
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.esmodule);
|
|
1986
|
+
}
|
|
1987
|
+
// special script element
|
|
1988
|
+
function isSpecialScript(app, scriptInfo) {
|
|
1989
|
+
const attrs = scriptInfo.appSpace[app.name].attrs;
|
|
1990
|
+
return attrs.has('id');
|
|
1991
|
+
}
|
|
1992
|
+
/**
|
|
1993
|
+
* whether to run js in inline mode
|
|
1994
|
+
* scene:
|
|
1995
|
+
* 1. inline config for app
|
|
1996
|
+
* 2. inline attr in script element
|
|
1997
|
+
* 3. module script
|
|
1998
|
+
* 4. script with special attr
|
|
1999
|
+
*/
|
|
2000
|
+
function isInlineMode(app, scriptInfo) {
|
|
2001
|
+
return (app.inline ||
|
|
2002
|
+
scriptInfo.appSpace[app.name].inline ||
|
|
2003
|
+
isTypeModule(app, scriptInfo) ||
|
|
2004
|
+
isSpecialScript(app, scriptInfo));
|
|
2005
|
+
}
|
|
2006
|
+
// Convert string code to function
|
|
2007
|
+
function code2Function(code) {
|
|
2008
|
+
return new Function(code);
|
|
2009
|
+
}
|
|
2010
|
+
/**
|
|
2011
|
+
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
2012
|
+
* @param appName app.name
|
|
2013
|
+
* @param scriptInfo scriptInfo of current address
|
|
2014
|
+
* @param currentCode pure code of current address
|
|
2015
|
+
*/
|
|
2016
|
+
function getExistParseResult(appName, scriptInfo, currentCode) {
|
|
2017
|
+
const appSpace = scriptInfo.appSpace;
|
|
2018
|
+
for (const item in appSpace) {
|
|
2019
|
+
if (item !== appName) {
|
|
2020
|
+
const appSpaceData = appSpace[item];
|
|
2021
|
+
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
2022
|
+
return appSpaceData.parsedFunction;
|
|
2023
|
+
}
|
|
2024
|
+
}
|
|
2025
|
+
}
|
|
2026
|
+
}
|
|
2027
|
+
/**
|
|
2028
|
+
* get parsedFunction from exist data or parsedCode
|
|
2029
|
+
* @returns parsedFunction
|
|
2030
|
+
*/
|
|
2031
|
+
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
2032
|
+
return getExistParseResult(app.name, scriptInfo, parsedCode) || code2Function(parsedCode);
|
|
2033
|
+
}
|
|
2034
|
+
// Prevent randomly created strings from repeating
|
|
2035
|
+
function getUniqueNonceSrc() {
|
|
2036
|
+
const nonceStr = createNonceSrc();
|
|
2037
|
+
if (sourceCenter.script.hasInfo(nonceStr)) {
|
|
2038
|
+
return getUniqueNonceSrc();
|
|
2039
|
+
}
|
|
2040
|
+
return nonceStr;
|
|
2041
|
+
}
|
|
2042
|
+
// transfer the attributes on the script to convertScript
|
|
2043
|
+
function setConvertScriptAttr(convertScript, attrs) {
|
|
2044
|
+
attrs.forEach((value, key) => {
|
|
2045
|
+
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
2046
|
+
return;
|
|
2047
|
+
if (key === 'src')
|
|
2048
|
+
key = 'data-origin-src';
|
|
2049
|
+
convertScript.setAttribute(key, value);
|
|
2050
|
+
});
|
|
2051
|
+
}
|
|
2052
|
+
// wrap code in sandbox
|
|
2053
|
+
function isWrapInSandBox(app, scriptInfo) {
|
|
2054
|
+
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
2055
|
+
}
|
|
1710
2056
|
/**
|
|
1711
2057
|
* Extract script elements
|
|
1712
2058
|
* @param script script element
|
|
@@ -1717,14 +2063,15 @@ const globalScripts = new Map();
|
|
|
1717
2063
|
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
1718
2064
|
let replaceComment = null;
|
|
1719
2065
|
let src = script.getAttribute('src');
|
|
1720
|
-
if (src)
|
|
2066
|
+
if (src)
|
|
1721
2067
|
src = CompletionPath(src, app.url);
|
|
1722
|
-
}
|
|
1723
2068
|
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
1724
2069
|
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
1725
2070
|
}
|
|
1726
|
-
else if ((script.type &&
|
|
1727
|
-
|
|
2071
|
+
else if ((script.type &&
|
|
2072
|
+
!scriptTypes.includes(script.type)) ||
|
|
2073
|
+
script.hasAttribute('ignore') ||
|
|
2074
|
+
checkIgnoreUrl(src, app.name)) {
|
|
1728
2075
|
return null;
|
|
1729
2076
|
}
|
|
1730
2077
|
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
@@ -1732,39 +2079,74 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
1732
2079
|
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
1733
2080
|
}
|
|
1734
2081
|
else if (src) { // remote script
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
isExternal: true,
|
|
1738
|
-
isDynamic: isDynamic,
|
|
2082
|
+
let scriptInfo = sourceCenter.script.getInfo(src);
|
|
2083
|
+
const appSpaceData = {
|
|
1739
2084
|
async: script.hasAttribute('async'),
|
|
1740
2085
|
defer: script.defer || script.type === 'module',
|
|
1741
2086
|
module: script.type === 'module',
|
|
1742
|
-
|
|
2087
|
+
inline: script.hasAttribute('inline'),
|
|
2088
|
+
pure: script.hasAttribute('pure'),
|
|
2089
|
+
attrs: getAttributes(script),
|
|
1743
2090
|
};
|
|
2091
|
+
if (!scriptInfo) {
|
|
2092
|
+
scriptInfo = {
|
|
2093
|
+
code: '',
|
|
2094
|
+
isExternal: true,
|
|
2095
|
+
appSpace: {
|
|
2096
|
+
[app.name]: appSpaceData,
|
|
2097
|
+
}
|
|
2098
|
+
};
|
|
2099
|
+
}
|
|
2100
|
+
else {
|
|
2101
|
+
/**
|
|
2102
|
+
* Reuse when appSpace exists
|
|
2103
|
+
* NOTE:
|
|
2104
|
+
* 1. The same static script, appSpace must be the same (in fact, it may be different when url change)
|
|
2105
|
+
* 2. The same dynamic script, appSpace may be the same, but we still reuse appSpace, which should pay attention
|
|
2106
|
+
*/
|
|
2107
|
+
scriptInfo.appSpace[app.name] = scriptInfo.appSpace[app.name] || appSpaceData;
|
|
2108
|
+
}
|
|
2109
|
+
sourceCenter.script.setInfo(src, scriptInfo);
|
|
1744
2110
|
if (!isDynamic) {
|
|
1745
|
-
app.source.scripts.
|
|
2111
|
+
app.source.scripts.add(src);
|
|
1746
2112
|
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
1747
2113
|
}
|
|
1748
2114
|
else {
|
|
1749
|
-
return {
|
|
2115
|
+
return { address: src, scriptInfo };
|
|
1750
2116
|
}
|
|
1751
2117
|
}
|
|
1752
2118
|
else if (script.textContent) { // inline script
|
|
1753
|
-
|
|
1754
|
-
|
|
2119
|
+
/**
|
|
2120
|
+
* NOTE:
|
|
2121
|
+
* 1. Each inline script is unique
|
|
2122
|
+
* 2. Every dynamic created inline script will be re-executed
|
|
2123
|
+
* ACTION:
|
|
2124
|
+
* 1. Delete dynamic inline script info after exec
|
|
2125
|
+
* 2. Delete static inline script info when destroy
|
|
2126
|
+
*/
|
|
2127
|
+
const nonceStr = getUniqueNonceSrc();
|
|
2128
|
+
const scriptInfo = {
|
|
1755
2129
|
code: script.textContent,
|
|
1756
2130
|
isExternal: false,
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
2131
|
+
appSpace: {
|
|
2132
|
+
[app.name]: {
|
|
2133
|
+
async: false,
|
|
2134
|
+
defer: script.type === 'module',
|
|
2135
|
+
module: script.type === 'module',
|
|
2136
|
+
inline: script.hasAttribute('inline'),
|
|
2137
|
+
pure: script.hasAttribute('pure'),
|
|
2138
|
+
attrs: getAttributes(script),
|
|
2139
|
+
}
|
|
2140
|
+
}
|
|
1761
2141
|
};
|
|
1762
2142
|
if (!isDynamic) {
|
|
1763
|
-
app.source.scripts.
|
|
2143
|
+
app.source.scripts.add(nonceStr);
|
|
2144
|
+
sourceCenter.script.setInfo(nonceStr, scriptInfo);
|
|
1764
2145
|
replaceComment = document.createComment('inline script extract by micro-app');
|
|
1765
2146
|
}
|
|
1766
2147
|
else {
|
|
1767
|
-
|
|
2148
|
+
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
2149
|
+
return { address: nonceStr, scriptInfo };
|
|
1768
2150
|
}
|
|
1769
2151
|
}
|
|
1770
2152
|
else if (!isDynamic) {
|
|
@@ -1787,38 +2169,38 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
1787
2169
|
*/
|
|
1788
2170
|
function getAssetsPlugins(appName) {
|
|
1789
2171
|
var _a, _b, _c;
|
|
1790
|
-
const globalPlugins = ((_a = microApp.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
1791
|
-
const modulePlugins = ((_c = (_b = microApp.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
2172
|
+
const globalPlugins = ((_a = microApp.options.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
2173
|
+
const modulePlugins = ((_c = (_b = microApp.options.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
1792
2174
|
return [...globalPlugins, ...modulePlugins];
|
|
1793
2175
|
}
|
|
1794
2176
|
/**
|
|
1795
|
-
* whether the
|
|
1796
|
-
* @param
|
|
2177
|
+
* whether the address needs to be excluded
|
|
2178
|
+
* @param address css or js link
|
|
1797
2179
|
* @param plugins microApp plugins
|
|
1798
2180
|
*/
|
|
1799
|
-
function checkExcludeUrl(
|
|
1800
|
-
if (!
|
|
2181
|
+
function checkExcludeUrl(address, appName) {
|
|
2182
|
+
if (!address)
|
|
1801
2183
|
return false;
|
|
1802
2184
|
const plugins = getAssetsPlugins(appName) || [];
|
|
1803
2185
|
return plugins.some(plugin => {
|
|
1804
2186
|
if (!plugin.excludeChecker)
|
|
1805
2187
|
return false;
|
|
1806
|
-
return plugin.excludeChecker(
|
|
2188
|
+
return plugin.excludeChecker(address);
|
|
1807
2189
|
});
|
|
1808
2190
|
}
|
|
1809
2191
|
/**
|
|
1810
|
-
* whether the
|
|
1811
|
-
* @param
|
|
2192
|
+
* whether the address needs to be ignore
|
|
2193
|
+
* @param address css or js link
|
|
1812
2194
|
* @param plugins microApp plugins
|
|
1813
2195
|
*/
|
|
1814
|
-
function checkIgnoreUrl(
|
|
1815
|
-
if (!
|
|
2196
|
+
function checkIgnoreUrl(address, appName) {
|
|
2197
|
+
if (!address)
|
|
1816
2198
|
return false;
|
|
1817
2199
|
const plugins = getAssetsPlugins(appName) || [];
|
|
1818
2200
|
return plugins.some(plugin => {
|
|
1819
2201
|
if (!plugin.ignoreChecker)
|
|
1820
2202
|
return false;
|
|
1821
|
-
return plugin.ignoreChecker(
|
|
2203
|
+
return plugin.ignoreChecker(address);
|
|
1822
2204
|
});
|
|
1823
2205
|
}
|
|
1824
2206
|
/**
|
|
@@ -1827,28 +2209,31 @@ function checkIgnoreUrl(url, appName) {
|
|
|
1827
2209
|
* @param app app
|
|
1828
2210
|
*/
|
|
1829
2211
|
function fetchScriptsFromHtml(wrapElement, app) {
|
|
1830
|
-
const
|
|
2212
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1831
2213
|
const fetchScriptPromise = [];
|
|
1832
2214
|
const fetchScriptPromiseInfo = [];
|
|
1833
|
-
for (const
|
|
1834
|
-
|
|
1835
|
-
|
|
1836
|
-
|
|
1837
|
-
|
|
1838
|
-
|
|
1839
|
-
else if ((!info.defer && !info.async) || app.isPrefetch) {
|
|
1840
|
-
fetchScriptPromise.push(fetchSource(url, app.name));
|
|
1841
|
-
fetchScriptPromiseInfo.push([url, info]);
|
|
1842
|
-
}
|
|
2215
|
+
for (const address of scriptList) {
|
|
2216
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2217
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2218
|
+
if ((!appSpaceData.defer && !appSpaceData.async) || (app.isPrefetch && !app.isPrerender)) {
|
|
2219
|
+
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
2220
|
+
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
1843
2221
|
}
|
|
1844
2222
|
}
|
|
2223
|
+
const fiberScriptTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
1845
2224
|
if (fetchScriptPromise.length) {
|
|
1846
2225
|
promiseStream(fetchScriptPromise, (res) => {
|
|
1847
|
-
fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data);
|
|
2226
|
+
injectFiberTask(fiberScriptTasks, () => fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data, app));
|
|
1848
2227
|
}, (err) => {
|
|
1849
2228
|
logError(err, app.name);
|
|
1850
2229
|
}, () => {
|
|
1851
|
-
|
|
2230
|
+
if (fiberScriptTasks) {
|
|
2231
|
+
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2232
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
2233
|
+
}
|
|
2234
|
+
else {
|
|
2235
|
+
app.onLoad(wrapElement);
|
|
2236
|
+
}
|
|
1852
2237
|
});
|
|
1853
2238
|
}
|
|
1854
2239
|
else {
|
|
@@ -1857,169 +2242,224 @@ function fetchScriptsFromHtml(wrapElement, app) {
|
|
|
1857
2242
|
}
|
|
1858
2243
|
/**
|
|
1859
2244
|
* fetch js succeeded, record the code value
|
|
1860
|
-
* @param
|
|
1861
|
-
* @param
|
|
2245
|
+
* @param address script address
|
|
2246
|
+
* @param scriptInfo resource script info
|
|
1862
2247
|
* @param data code
|
|
1863
2248
|
*/
|
|
1864
|
-
function fetchScriptSuccess(
|
|
1865
|
-
|
|
1866
|
-
|
|
2249
|
+
function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
2250
|
+
// reset scriptInfo.code
|
|
2251
|
+
scriptInfo.code = code;
|
|
2252
|
+
/**
|
|
2253
|
+
* Pre parse script for prefetch, improve rendering performance
|
|
2254
|
+
* NOTE:
|
|
2255
|
+
* 1. if global parseResult exist, skip this step
|
|
2256
|
+
* 2. if app is inline or script is esmodule, skip this step
|
|
2257
|
+
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
2258
|
+
*/
|
|
2259
|
+
if (app.isPrefetch && app.prefetchLevel === 2) {
|
|
2260
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2261
|
+
/**
|
|
2262
|
+
* When prefetch app is replaced by a new app in the processing phase, since the scriptInfo is common, when the scriptInfo of the prefetch app is processed, it may have already been processed.
|
|
2263
|
+
* This causes parsedCode to already exist when preloading ends
|
|
2264
|
+
* e.g.
|
|
2265
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
2266
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
2267
|
+
*/
|
|
2268
|
+
if (!appSpaceData.parsedCode) {
|
|
2269
|
+
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
2270
|
+
appSpaceData.wrapInSandBox = isWrapInSandBox(app, scriptInfo);
|
|
2271
|
+
if (!isInlineMode(app, scriptInfo)) {
|
|
2272
|
+
try {
|
|
2273
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2274
|
+
}
|
|
2275
|
+
catch (err) {
|
|
2276
|
+
logWarn('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
2277
|
+
}
|
|
2278
|
+
}
|
|
2279
|
+
}
|
|
1867
2280
|
}
|
|
1868
|
-
info.code = data;
|
|
1869
2281
|
}
|
|
1870
2282
|
/**
|
|
1871
2283
|
* Execute js in the mount lifecycle
|
|
1872
|
-
* @param scriptList script list
|
|
1873
2284
|
* @param app app
|
|
1874
2285
|
* @param initHook callback for umd mode
|
|
1875
2286
|
*/
|
|
1876
|
-
function execScripts(
|
|
1877
|
-
const
|
|
2287
|
+
function execScripts(app, initHook) {
|
|
2288
|
+
const fiberScriptTasks = app.fiber ? [] : null;
|
|
2289
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1878
2290
|
const deferScriptPromise = [];
|
|
1879
2291
|
const deferScriptInfo = [];
|
|
1880
|
-
for (const
|
|
1881
|
-
|
|
1882
|
-
|
|
1883
|
-
|
|
1884
|
-
|
|
1885
|
-
|
|
1886
|
-
|
|
1887
|
-
else {
|
|
1888
|
-
deferScriptPromise.push(info.code);
|
|
1889
|
-
}
|
|
1890
|
-
deferScriptInfo.push([url, info]);
|
|
1891
|
-
info.module && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
2292
|
+
for (const address of scriptList) {
|
|
2293
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2294
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2295
|
+
// Notice the second render
|
|
2296
|
+
if (appSpaceData.defer || appSpaceData.async) {
|
|
2297
|
+
if (scriptInfo.isExternal && !scriptInfo.code) {
|
|
2298
|
+
deferScriptPromise.push(fetchSource(address, app.name));
|
|
1892
2299
|
}
|
|
1893
2300
|
else {
|
|
1894
|
-
|
|
1895
|
-
initHook(false);
|
|
2301
|
+
deferScriptPromise.push(scriptInfo.code);
|
|
1896
2302
|
}
|
|
2303
|
+
deferScriptInfo.push([address, scriptInfo]);
|
|
2304
|
+
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
2305
|
+
}
|
|
2306
|
+
else {
|
|
2307
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
2308
|
+
runScript(address, app, scriptInfo);
|
|
2309
|
+
initHook(false);
|
|
2310
|
+
});
|
|
1897
2311
|
}
|
|
1898
2312
|
}
|
|
1899
2313
|
if (deferScriptPromise.length) {
|
|
1900
2314
|
promiseStream(deferScriptPromise, (res) => {
|
|
1901
|
-
const
|
|
1902
|
-
|
|
2315
|
+
const scriptInfo = deferScriptInfo[res.index][1];
|
|
2316
|
+
scriptInfo.code = scriptInfo.code || res.data;
|
|
1903
2317
|
}, (err) => {
|
|
1904
2318
|
initHook.errorCount = initHook.errorCount ? ++initHook.errorCount : 1;
|
|
1905
2319
|
logError(err, app.name);
|
|
1906
2320
|
}, () => {
|
|
1907
|
-
deferScriptInfo.forEach(([
|
|
1908
|
-
if (
|
|
1909
|
-
|
|
1910
|
-
|
|
2321
|
+
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
2322
|
+
if (scriptInfo.code) {
|
|
2323
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
2324
|
+
runScript(address, app, scriptInfo, initHook);
|
|
2325
|
+
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
2326
|
+
});
|
|
1911
2327
|
}
|
|
1912
2328
|
});
|
|
1913
|
-
|
|
1914
|
-
|
|
2329
|
+
/**
|
|
2330
|
+
* Fiber wraps js in requestIdleCallback and executes it in sequence
|
|
2331
|
+
* NOTE:
|
|
2332
|
+
* 1. In order to ensure the execution order, wait for all js loaded and then execute
|
|
2333
|
+
* 2. If js create a dynamic script, it may be errors in the execution order, because the subsequent js is wrapped in requestIdleCallback, even putting dynamic script in requestIdleCallback doesn't solve it
|
|
2334
|
+
*
|
|
2335
|
+
* BUG: NOTE.2 - execution order problem
|
|
2336
|
+
*/
|
|
2337
|
+
if (fiberScriptTasks) {
|
|
2338
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(isUndefined(initHook.moduleCount) ||
|
|
2339
|
+
initHook.errorCount === deferScriptPromise.length)));
|
|
2340
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
2341
|
+
}
|
|
2342
|
+
else {
|
|
2343
|
+
initHook(isUndefined(initHook.moduleCount) ||
|
|
2344
|
+
initHook.errorCount === deferScriptPromise.length);
|
|
2345
|
+
}
|
|
1915
2346
|
});
|
|
1916
2347
|
}
|
|
1917
2348
|
else {
|
|
1918
|
-
|
|
2349
|
+
if (fiberScriptTasks) {
|
|
2350
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
2351
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
2352
|
+
}
|
|
2353
|
+
else {
|
|
2354
|
+
initHook(true);
|
|
2355
|
+
}
|
|
1919
2356
|
}
|
|
1920
2357
|
}
|
|
1921
2358
|
/**
|
|
1922
2359
|
* run code
|
|
1923
|
-
* @param
|
|
2360
|
+
* @param address script address
|
|
1924
2361
|
* @param app app
|
|
1925
|
-
* @param
|
|
1926
|
-
* @param isDynamic dynamically created script
|
|
2362
|
+
* @param scriptInfo script info
|
|
1927
2363
|
* @param callback callback of module script
|
|
1928
2364
|
*/
|
|
1929
|
-
function runScript(
|
|
2365
|
+
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
1930
2366
|
var _a;
|
|
1931
2367
|
try {
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2368
|
+
actionsBeforeRunScript(app);
|
|
2369
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2370
|
+
const wrapInSandBox = isWrapInSandBox(app, scriptInfo);
|
|
2371
|
+
/**
|
|
2372
|
+
* NOTE:
|
|
2373
|
+
* 1. plugins and wrapCode will only be executed once
|
|
2374
|
+
* 2. if parsedCode not exist, parsedFunction is not exist
|
|
2375
|
+
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
2376
|
+
*/
|
|
2377
|
+
if (!appSpaceData.parsedCode || appSpaceData.wrapInSandBox !== wrapInSandBox) {
|
|
2378
|
+
appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
|
|
2379
|
+
appSpaceData.wrapInSandBox = wrapInSandBox;
|
|
2380
|
+
appSpaceData.parsedFunction = null;
|
|
2381
|
+
}
|
|
2382
|
+
if (isInlineMode(app, scriptInfo)) {
|
|
2383
|
+
const scriptElement = replaceElement || pureCreateElement('script');
|
|
2384
|
+
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
2385
|
+
if (!replaceElement) {
|
|
2386
|
+
// TEST IGNORE
|
|
2387
|
+
(_a = app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-body').appendChild(scriptElement);
|
|
2388
|
+
}
|
|
1940
2389
|
}
|
|
1941
2390
|
else {
|
|
1942
|
-
|
|
1943
|
-
if (isDynamic)
|
|
1944
|
-
return document.createComment('dynamic script extract by micro-app');
|
|
2391
|
+
runParsedFunction(app, scriptInfo);
|
|
1945
2392
|
}
|
|
1946
2393
|
}
|
|
1947
2394
|
catch (e) {
|
|
1948
|
-
console.error(`[micro-app from runScript] app ${app.name}: `, e);
|
|
2395
|
+
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
1949
2396
|
}
|
|
1950
2397
|
}
|
|
1951
2398
|
/**
|
|
1952
2399
|
* Get dynamically created remote script
|
|
1953
|
-
* @param
|
|
1954
|
-
* @param
|
|
1955
|
-
* @param
|
|
2400
|
+
* @param address script address
|
|
2401
|
+
* @param app app instance
|
|
2402
|
+
* @param scriptInfo scriptInfo
|
|
1956
2403
|
* @param originScript origin script element
|
|
1957
2404
|
*/
|
|
1958
|
-
function runDynamicRemoteScript(
|
|
2405
|
+
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
2406
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
1959
2407
|
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
1960
|
-
|
|
1961
|
-
|
|
1962
|
-
|
|
1963
|
-
|
|
1964
|
-
|
|
1965
|
-
|
|
1966
|
-
|
|
1967
|
-
|
|
1968
|
-
|
|
1969
|
-
|
|
1970
|
-
|
|
1971
|
-
|
|
1972
|
-
|
|
1973
|
-
if (globalScripts.has(url)) {
|
|
1974
|
-
const code = globalScripts.get(url);
|
|
1975
|
-
info.code = code;
|
|
1976
|
-
app.source.scripts.set(url, info);
|
|
1977
|
-
!info.module && defer(dispatchScriptOnLoadEvent);
|
|
1978
|
-
return runScript(url, app, info, true, dispatchScriptOnLoadEvent);
|
|
1979
|
-
}
|
|
1980
|
-
let replaceElement;
|
|
1981
|
-
if (app.inline || info.module) {
|
|
1982
|
-
replaceElement = pureCreateElement('script');
|
|
2408
|
+
const runDynamicScript = () => {
|
|
2409
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
2410
|
+
if (!descriptor || descriptor.configurable) {
|
|
2411
|
+
Object.defineProperty(globalEnv.rawDocument, 'currentScript', {
|
|
2412
|
+
value: originScript,
|
|
2413
|
+
configurable: true,
|
|
2414
|
+
});
|
|
2415
|
+
}
|
|
2416
|
+
runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
|
|
2417
|
+
!isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
|
|
2418
|
+
};
|
|
2419
|
+
if (scriptInfo.code) {
|
|
2420
|
+
defer(runDynamicScript);
|
|
1983
2421
|
}
|
|
1984
2422
|
else {
|
|
1985
|
-
|
|
2423
|
+
fetchSource(address, app.name).then((code) => {
|
|
2424
|
+
scriptInfo.code = code;
|
|
2425
|
+
runDynamicScript();
|
|
2426
|
+
}).catch((err) => {
|
|
2427
|
+
logError(err, app.name);
|
|
2428
|
+
dispatchOnErrorEvent(originScript);
|
|
2429
|
+
});
|
|
1986
2430
|
}
|
|
1987
|
-
|
|
1988
|
-
|
|
1989
|
-
|
|
1990
|
-
|
|
1991
|
-
|
|
1992
|
-
|
|
1993
|
-
|
|
1994
|
-
|
|
1995
|
-
|
|
1996
|
-
|
|
1997
|
-
|
|
1998
|
-
}
|
|
1999
|
-
}
|
|
2000
|
-
catch (e) {
|
|
2001
|
-
console.error(`[micro-app from runDynamicScript] app ${app.name}: `, e, url);
|
|
2002
|
-
}
|
|
2003
|
-
!info.module && dispatchScriptOnLoadEvent();
|
|
2004
|
-
}).catch((err) => {
|
|
2005
|
-
logError(err, app.name);
|
|
2006
|
-
dispatchOnErrorEvent(originScript);
|
|
2007
|
-
});
|
|
2431
|
+
return replaceElement;
|
|
2432
|
+
}
|
|
2433
|
+
/**
|
|
2434
|
+
* Get dynamically created inline script
|
|
2435
|
+
* @param address script address
|
|
2436
|
+
* @param app app instance
|
|
2437
|
+
* @param scriptInfo scriptInfo
|
|
2438
|
+
*/
|
|
2439
|
+
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
2440
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
2441
|
+
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
2008
2442
|
return replaceElement;
|
|
2009
2443
|
}
|
|
2010
2444
|
/**
|
|
2011
2445
|
* common handle for inline script
|
|
2012
|
-
* @param
|
|
2446
|
+
* @param address script address
|
|
2013
2447
|
* @param code bound code
|
|
2014
2448
|
* @param module type='module' of script
|
|
2015
2449
|
* @param scriptElement target script element
|
|
2450
|
+
* @param attrs attributes of script element
|
|
2016
2451
|
* @param callback callback of module script
|
|
2017
2452
|
*/
|
|
2018
|
-
function runCode2InlineScript(
|
|
2453
|
+
function runCode2InlineScript(address, code, module, scriptElement, attrs, callback) {
|
|
2019
2454
|
if (module) {
|
|
2020
2455
|
// module script is async, transform it to a blob for subsequent operations
|
|
2021
|
-
|
|
2022
|
-
|
|
2456
|
+
if (isInlineScript(address)) {
|
|
2457
|
+
const blob = new Blob([code], { type: 'text/javascript' });
|
|
2458
|
+
scriptElement.src = URL.createObjectURL(blob);
|
|
2459
|
+
}
|
|
2460
|
+
else {
|
|
2461
|
+
scriptElement.src = address;
|
|
2462
|
+
}
|
|
2023
2463
|
scriptElement.setAttribute('type', 'module');
|
|
2024
2464
|
if (callback) {
|
|
2025
2465
|
callback.moduleCount && callback.moduleCount--;
|
|
@@ -2029,55 +2469,65 @@ function runCode2InlineScript(url, code, module, scriptElement, callback) {
|
|
|
2029
2469
|
else {
|
|
2030
2470
|
scriptElement.textContent = code;
|
|
2031
2471
|
}
|
|
2032
|
-
|
|
2033
|
-
scriptElement.setAttribute('data-origin-src', url);
|
|
2034
|
-
}
|
|
2472
|
+
setConvertScriptAttr(scriptElement, attrs);
|
|
2035
2473
|
}
|
|
2036
2474
|
// init & run code2Function
|
|
2037
|
-
function
|
|
2038
|
-
|
|
2039
|
-
|
|
2475
|
+
function runParsedFunction(app, scriptInfo) {
|
|
2476
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2477
|
+
if (!appSpaceData.parsedFunction) {
|
|
2478
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2040
2479
|
}
|
|
2041
|
-
|
|
2480
|
+
appSpaceData.parsedFunction.call(window);
|
|
2042
2481
|
}
|
|
2043
2482
|
/**
|
|
2044
2483
|
* bind js scope
|
|
2045
|
-
* @param url script address
|
|
2046
2484
|
* @param app app
|
|
2047
2485
|
* @param code code
|
|
2048
|
-
* @param
|
|
2486
|
+
* @param scriptInfo source script info
|
|
2049
2487
|
*/
|
|
2050
|
-
function bindScope(
|
|
2051
|
-
// TODO:
|
|
2052
|
-
if (isPlainObject(microApp.plugins)) {
|
|
2053
|
-
code = usePlugins(
|
|
2488
|
+
function bindScope(address, app, code, scriptInfo) {
|
|
2489
|
+
// TODO: cache
|
|
2490
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
2491
|
+
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
2054
2492
|
}
|
|
2055
|
-
if (app
|
|
2056
|
-
|
|
2057
|
-
return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
2493
|
+
if (isWrapInSandBox(app, scriptInfo)) {
|
|
2494
|
+
return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
2058
2495
|
}
|
|
2059
2496
|
return code;
|
|
2060
2497
|
}
|
|
2498
|
+
/**
|
|
2499
|
+
* actions before run script
|
|
2500
|
+
*/
|
|
2501
|
+
function actionsBeforeRunScript(app) {
|
|
2502
|
+
setActiveProxyWindow(app);
|
|
2503
|
+
}
|
|
2504
|
+
/**
|
|
2505
|
+
* set active sandBox.proxyWindow to window.__MICRO_APP_PROXY_WINDOW__
|
|
2506
|
+
*/
|
|
2507
|
+
function setActiveProxyWindow(app) {
|
|
2508
|
+
if (app.sandBox) {
|
|
2509
|
+
globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2061
2512
|
/**
|
|
2062
2513
|
* Call the plugin to process the file
|
|
2063
|
-
* @param
|
|
2514
|
+
* @param address script address
|
|
2064
2515
|
* @param code code
|
|
2065
2516
|
* @param appName app name
|
|
2066
2517
|
* @param plugins plugin list
|
|
2067
|
-
* @param info source script info
|
|
2068
2518
|
*/
|
|
2069
|
-
function usePlugins(
|
|
2519
|
+
function usePlugins(address, code, appName, plugins) {
|
|
2070
2520
|
var _a;
|
|
2071
|
-
const newCode = processCode(plugins.global, code,
|
|
2072
|
-
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode,
|
|
2521
|
+
const newCode = processCode(plugins.global, code, address);
|
|
2522
|
+
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, address);
|
|
2073
2523
|
}
|
|
2074
|
-
function processCode(configs, code,
|
|
2524
|
+
function processCode(configs, code, address) {
|
|
2075
2525
|
if (!isArray(configs)) {
|
|
2076
2526
|
return code;
|
|
2077
2527
|
}
|
|
2078
2528
|
return configs.reduce((preCode, config) => {
|
|
2079
2529
|
if (isPlainObject(config) && isFunction(config.loader)) {
|
|
2080
|
-
return config.loader(preCode,
|
|
2530
|
+
return config.loader(preCode, address);
|
|
2081
2531
|
}
|
|
2082
2532
|
return preCode;
|
|
2083
2533
|
}, code);
|
|
@@ -2098,10 +2548,10 @@ function getWrapElement(str) {
|
|
|
2098
2548
|
* @param app app
|
|
2099
2549
|
* @param microAppHead micro-app-head element
|
|
2100
2550
|
*/
|
|
2101
|
-
function flatChildren(parent, app, microAppHead) {
|
|
2551
|
+
function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
2102
2552
|
const children = Array.from(parent.children);
|
|
2103
2553
|
children.length && children.forEach((child) => {
|
|
2104
|
-
flatChildren(child, app);
|
|
2554
|
+
flatChildren(child, app, microAppHead, fiberStyleTasks);
|
|
2105
2555
|
});
|
|
2106
2556
|
for (const dom of children) {
|
|
2107
2557
|
if (dom instanceof HTMLLinkElement) {
|
|
@@ -2120,7 +2570,7 @@ function flatChildren(parent, app, microAppHead) {
|
|
|
2120
2570
|
parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
|
|
2121
2571
|
}
|
|
2122
2572
|
else if (app.scopecss && !dom.hasAttribute('ignore')) {
|
|
2123
|
-
scopedCSS(dom, app);
|
|
2573
|
+
injectFiberTask(fiberStyleTasks, () => scopedCSS(dom, app));
|
|
2124
2574
|
}
|
|
2125
2575
|
}
|
|
2126
2576
|
else if (dom instanceof HTMLScriptElement) {
|
|
@@ -2148,9 +2598,17 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2148
2598
|
app.onerror(new Error(msg));
|
|
2149
2599
|
return logError(msg, app.name);
|
|
2150
2600
|
}
|
|
2151
|
-
|
|
2601
|
+
const fiberStyleTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
2602
|
+
flatChildren(wrapElement, app, microAppHead, fiberStyleTasks);
|
|
2603
|
+
/**
|
|
2604
|
+
* 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.
|
|
2605
|
+
*/
|
|
2606
|
+
const fiberStyleResult = serialExecFiberTasks(fiberStyleTasks);
|
|
2152
2607
|
if (app.source.links.size) {
|
|
2153
|
-
fetchLinksFromHtml(wrapElement, app, microAppHead);
|
|
2608
|
+
fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult);
|
|
2609
|
+
}
|
|
2610
|
+
else if (fiberStyleResult) {
|
|
2611
|
+
fiberStyleResult.then(() => app.onLoad(wrapElement));
|
|
2154
2612
|
}
|
|
2155
2613
|
else {
|
|
2156
2614
|
app.onLoad(wrapElement);
|
|
@@ -2166,6 +2624,39 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2166
2624
|
class EventCenter {
|
|
2167
2625
|
constructor() {
|
|
2168
2626
|
this.eventList = new Map();
|
|
2627
|
+
this.queue = [];
|
|
2628
|
+
this.recordStep = {};
|
|
2629
|
+
// run task
|
|
2630
|
+
this.process = () => {
|
|
2631
|
+
var _a, _b;
|
|
2632
|
+
let name;
|
|
2633
|
+
const temRecordStep = this.recordStep;
|
|
2634
|
+
const queue = this.queue;
|
|
2635
|
+
this.recordStep = {};
|
|
2636
|
+
this.queue = [];
|
|
2637
|
+
while (name = queue.shift()) {
|
|
2638
|
+
const eventInfo = this.eventList.get(name);
|
|
2639
|
+
// clear tempData, force before exec nextStep
|
|
2640
|
+
const tempData = eventInfo.tempData;
|
|
2641
|
+
const force = eventInfo.force;
|
|
2642
|
+
eventInfo.tempData = null;
|
|
2643
|
+
eventInfo.force = false;
|
|
2644
|
+
let resArr;
|
|
2645
|
+
if (force || !this.isEqual(eventInfo.data, tempData)) {
|
|
2646
|
+
eventInfo.data = tempData || eventInfo.data;
|
|
2647
|
+
for (const f of eventInfo.callbacks) {
|
|
2648
|
+
const res = f(eventInfo.data);
|
|
2649
|
+
res && (resArr !== null && resArr !== void 0 ? resArr : (resArr = [])).push(res);
|
|
2650
|
+
}
|
|
2651
|
+
(_b = (_a = temRecordStep[name]).dispatchDataEvent) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
2652
|
+
/**
|
|
2653
|
+
* WARING:
|
|
2654
|
+
* If data of other app is sent in nextStep, it may cause confusion of tempData and force
|
|
2655
|
+
*/
|
|
2656
|
+
temRecordStep[name].nextStepList.forEach((nextStep) => nextStep(resArr));
|
|
2657
|
+
}
|
|
2658
|
+
}
|
|
2659
|
+
};
|
|
2169
2660
|
}
|
|
2170
2661
|
// whether the name is legal
|
|
2171
2662
|
isLegalName(name) {
|
|
@@ -2175,6 +2666,39 @@ class EventCenter {
|
|
|
2175
2666
|
}
|
|
2176
2667
|
return true;
|
|
2177
2668
|
}
|
|
2669
|
+
// add appName to queue
|
|
2670
|
+
enqueue(name, nextStep, dispatchDataEvent) {
|
|
2671
|
+
// this.nextStepList.push(nextStep)
|
|
2672
|
+
if (this.recordStep[name]) {
|
|
2673
|
+
this.recordStep[name].nextStepList.push(nextStep);
|
|
2674
|
+
dispatchDataEvent && (this.recordStep[name].dispatchDataEvent = dispatchDataEvent);
|
|
2675
|
+
}
|
|
2676
|
+
else {
|
|
2677
|
+
this.recordStep[name] = {
|
|
2678
|
+
nextStepList: [nextStep],
|
|
2679
|
+
dispatchDataEvent,
|
|
2680
|
+
};
|
|
2681
|
+
}
|
|
2682
|
+
/**
|
|
2683
|
+
* The micro task is executed async when the second render of child.
|
|
2684
|
+
* We should ensure that the data changes are executed before binding the listening function
|
|
2685
|
+
*/
|
|
2686
|
+
(!this.queue.includes(name) && this.queue.push(name) === 1) && defer(this.process);
|
|
2687
|
+
}
|
|
2688
|
+
/**
|
|
2689
|
+
* In react, each setState will trigger setData, so we need a filter operation to avoid repeated trigger
|
|
2690
|
+
*/
|
|
2691
|
+
isEqual(oldData, newData) {
|
|
2692
|
+
if (!newData || Object.keys(oldData).length !== Object.keys(newData).length)
|
|
2693
|
+
return false;
|
|
2694
|
+
for (const key in oldData) {
|
|
2695
|
+
if (Object.prototype.hasOwnProperty.call(oldData, key)) {
|
|
2696
|
+
if (oldData[key] !== newData[key])
|
|
2697
|
+
return false;
|
|
2698
|
+
}
|
|
2699
|
+
}
|
|
2700
|
+
return true;
|
|
2701
|
+
}
|
|
2178
2702
|
/**
|
|
2179
2703
|
* add listener
|
|
2180
2704
|
* @param name event name
|
|
@@ -2194,7 +2718,10 @@ class EventCenter {
|
|
|
2194
2718
|
};
|
|
2195
2719
|
this.eventList.set(name, eventInfo);
|
|
2196
2720
|
}
|
|
2197
|
-
else if (autoTrigger &&
|
|
2721
|
+
else if (autoTrigger &&
|
|
2722
|
+
Object.keys(eventInfo.data).length &&
|
|
2723
|
+
(!this.queue.includes(name) ||
|
|
2724
|
+
this.isEqual(eventInfo.data, eventInfo.tempData))) {
|
|
2198
2725
|
// auto trigger when data not null
|
|
2199
2726
|
f(eventInfo.data);
|
|
2200
2727
|
}
|
|
@@ -2215,21 +2742,27 @@ class EventCenter {
|
|
|
2215
2742
|
}
|
|
2216
2743
|
}
|
|
2217
2744
|
}
|
|
2745
|
+
/**
|
|
2746
|
+
* clearData
|
|
2747
|
+
*/
|
|
2748
|
+
clearData(name) {
|
|
2749
|
+
if (this.isLegalName(name)) {
|
|
2750
|
+
const eventInfo = this.eventList.get(name);
|
|
2751
|
+
if (eventInfo) {
|
|
2752
|
+
eventInfo.data = {};
|
|
2753
|
+
}
|
|
2754
|
+
}
|
|
2755
|
+
}
|
|
2218
2756
|
// dispatch data
|
|
2219
|
-
dispatch(name, data) {
|
|
2757
|
+
dispatch(name, data, nextStep, force, dispatchDataEvent) {
|
|
2220
2758
|
if (this.isLegalName(name)) {
|
|
2221
2759
|
if (!isPlainObject(data)) {
|
|
2222
2760
|
return logError('event-center: data must be object');
|
|
2223
2761
|
}
|
|
2224
2762
|
let eventInfo = this.eventList.get(name);
|
|
2225
2763
|
if (eventInfo) {
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
eventInfo.data = data;
|
|
2229
|
-
for (const f of eventInfo.callbacks) {
|
|
2230
|
-
f(data);
|
|
2231
|
-
}
|
|
2232
|
-
}
|
|
2764
|
+
eventInfo.tempData = assign({}, eventInfo.tempData || eventInfo.data, data);
|
|
2765
|
+
!eventInfo.force && (eventInfo.force = !!force);
|
|
2233
2766
|
}
|
|
2234
2767
|
else {
|
|
2235
2768
|
eventInfo = {
|
|
@@ -2237,7 +2770,13 @@ class EventCenter {
|
|
|
2237
2770
|
callbacks: new Set(),
|
|
2238
2771
|
};
|
|
2239
2772
|
this.eventList.set(name, eventInfo);
|
|
2773
|
+
/**
|
|
2774
|
+
* When sent data to parent, eventInfo probably does not exist, because parent may listen to datachange
|
|
2775
|
+
*/
|
|
2776
|
+
eventInfo.force = true;
|
|
2240
2777
|
}
|
|
2778
|
+
// add to queue, event eventInfo is null
|
|
2779
|
+
this.enqueue(name, nextStep, dispatchDataEvent);
|
|
2241
2780
|
}
|
|
2242
2781
|
}
|
|
2243
2782
|
// get data
|
|
@@ -2286,10 +2825,13 @@ class EventCenterForGlobal {
|
|
|
2286
2825
|
* dispatch global data
|
|
2287
2826
|
* @param data data
|
|
2288
2827
|
*/
|
|
2289
|
-
setGlobalData(data) {
|
|
2828
|
+
setGlobalData(data, nextStep, force) {
|
|
2290
2829
|
// clear dom scope before dispatch global data, apply to micro app
|
|
2291
2830
|
removeDomScope();
|
|
2292
|
-
eventCenter.dispatch('global', data);
|
|
2831
|
+
eventCenter.dispatch('global', data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
|
|
2832
|
+
}
|
|
2833
|
+
forceSetGlobalData(data, nextStep) {
|
|
2834
|
+
this.setGlobalData(data, nextStep, true);
|
|
2293
2835
|
}
|
|
2294
2836
|
/**
|
|
2295
2837
|
* get global data
|
|
@@ -2297,6 +2839,12 @@ class EventCenterForGlobal {
|
|
|
2297
2839
|
getGlobalData() {
|
|
2298
2840
|
return eventCenter.getData('global');
|
|
2299
2841
|
}
|
|
2842
|
+
/**
|
|
2843
|
+
* clear global data
|
|
2844
|
+
*/
|
|
2845
|
+
clearGlobalData() {
|
|
2846
|
+
eventCenter.clearData('global');
|
|
2847
|
+
}
|
|
2300
2848
|
/**
|
|
2301
2849
|
* clear all listener of global data
|
|
2302
2850
|
* if appName exists, only the specified functions is cleared
|
|
@@ -2347,8 +2895,19 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
2347
2895
|
* @param appName app.name
|
|
2348
2896
|
* @param data data
|
|
2349
2897
|
*/
|
|
2350
|
-
setData(appName, data) {
|
|
2351
|
-
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data);
|
|
2898
|
+
setData(appName, data, nextStep, force) {
|
|
2899
|
+
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force);
|
|
2900
|
+
}
|
|
2901
|
+
forceSetData(appName, data, nextStep) {
|
|
2902
|
+
this.setData(appName, data, nextStep, true);
|
|
2903
|
+
}
|
|
2904
|
+
/**
|
|
2905
|
+
* clear data from base app
|
|
2906
|
+
* @param appName app.name
|
|
2907
|
+
* @param fromBaseApp whether clear data from child app, default is true
|
|
2908
|
+
*/
|
|
2909
|
+
clearData(appName, fromBaseApp = true) {
|
|
2910
|
+
eventCenter.clearData(formatEventName(formatAppName(appName), fromBaseApp));
|
|
2352
2911
|
}
|
|
2353
2912
|
/**
|
|
2354
2913
|
* clear all listener for specified micro app
|
|
@@ -2384,25 +2943,36 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
2384
2943
|
/**
|
|
2385
2944
|
* get data from base app
|
|
2386
2945
|
*/
|
|
2387
|
-
getData() {
|
|
2388
|
-
return eventCenter.getData(formatEventName(this.appName,
|
|
2946
|
+
getData(fromBaseApp = true) {
|
|
2947
|
+
return eventCenter.getData(formatEventName(this.appName, fromBaseApp));
|
|
2389
2948
|
}
|
|
2390
2949
|
/**
|
|
2391
2950
|
* dispatch data to base app
|
|
2392
2951
|
* @param data data
|
|
2393
2952
|
*/
|
|
2394
|
-
dispatch(data) {
|
|
2953
|
+
dispatch(data, nextStep, force) {
|
|
2395
2954
|
removeDomScope();
|
|
2396
|
-
eventCenter.dispatch(formatEventName(this.appName, false), data)
|
|
2397
|
-
|
|
2398
|
-
|
|
2399
|
-
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2955
|
+
eventCenter.dispatch(formatEventName(this.appName, false), data, (resArr) => isFunction(nextStep) && nextStep(resArr), force, () => {
|
|
2956
|
+
const app = appInstanceMap.get(this.appName);
|
|
2957
|
+
if ((app === null || app === void 0 ? void 0 : app.container) && isPlainObject(data)) {
|
|
2958
|
+
const event = new CustomEvent('datachange', {
|
|
2959
|
+
detail: {
|
|
2960
|
+
data: eventCenter.getData(formatEventName(this.appName, false))
|
|
2961
|
+
}
|
|
2962
|
+
});
|
|
2963
|
+
getRootContainer(app.container).dispatchEvent(event);
|
|
2964
|
+
}
|
|
2965
|
+
});
|
|
2966
|
+
}
|
|
2967
|
+
forceDispatch(data, nextStep) {
|
|
2968
|
+
this.dispatch(data, nextStep, true);
|
|
2969
|
+
}
|
|
2970
|
+
/**
|
|
2971
|
+
* clear data from child app
|
|
2972
|
+
* @param fromBaseApp whether clear data from base app, default is false
|
|
2973
|
+
*/
|
|
2974
|
+
clearData(fromBaseApp = false) {
|
|
2975
|
+
eventCenter.clearData(formatEventName(this.appName, fromBaseApp));
|
|
2406
2976
|
}
|
|
2407
2977
|
/**
|
|
2408
2978
|
* clear all listeners
|
|
@@ -2592,12 +3162,14 @@ function effectDocumentEvent() {
|
|
|
2592
3162
|
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
2593
3163
|
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
2594
3164
|
document.addEventListener = function (type, listener, options) {
|
|
2595
|
-
var _a;
|
|
2596
3165
|
const appName = getCurrentAppName();
|
|
2597
3166
|
/**
|
|
2598
3167
|
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
3168
|
+
* update in 2022-09-02:
|
|
3169
|
+
* boundFunction is no longer exclude, because events in UMD mode will not cleared from v1.0.0-alpha.4
|
|
3170
|
+
* if (appName && !(appInstanceMap.get(appName)?.umdMode && isBoundFunction(listener))) {
|
|
2599
3171
|
*/
|
|
2600
|
-
if (appName
|
|
3172
|
+
if (appName) {
|
|
2601
3173
|
const appListenersMap = documentEventListenerMap.get(appName);
|
|
2602
3174
|
if (appListenersMap) {
|
|
2603
3175
|
const appListenerList = appListenersMap.get(type);
|
|
@@ -2616,9 +3188,13 @@ function effectDocumentEvent() {
|
|
|
2616
3188
|
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
2617
3189
|
};
|
|
2618
3190
|
document.removeEventListener = function (type, listener, options) {
|
|
2619
|
-
var _a;
|
|
2620
3191
|
const appName = getCurrentAppName();
|
|
2621
|
-
|
|
3192
|
+
/**
|
|
3193
|
+
* update in 2022-09-02:
|
|
3194
|
+
* boundFunction is no longer exclude, because events in UMD mode will not cleared from v1.0.0-alpha.4
|
|
3195
|
+
* if (appName && !(appInstanceMap.get(appName)?.umdMode && isBoundFunction(listener))) {
|
|
3196
|
+
*/
|
|
3197
|
+
if (appName) {
|
|
2622
3198
|
const appListenersMap = documentEventListenerMap.get(appName);
|
|
2623
3199
|
if (appListenersMap) {
|
|
2624
3200
|
const appListenerList = appListenersMap.get(type);
|
|
@@ -2683,69 +3259,80 @@ function effect(appName, microAppWindow) {
|
|
|
2683
3259
|
timeoutIdMap.delete(timeoutId);
|
|
2684
3260
|
rawClearTimeout.call(rawWindow, timeoutId);
|
|
2685
3261
|
};
|
|
2686
|
-
const
|
|
2687
|
-
const
|
|
2688
|
-
let
|
|
2689
|
-
let
|
|
2690
|
-
let
|
|
2691
|
-
const
|
|
2692
|
-
|
|
2693
|
-
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
3262
|
+
const sstWindowListenerMap = new Map();
|
|
3263
|
+
const sstDocumentListenerMap = new Map();
|
|
3264
|
+
let sstIntervalIdMap = new Map();
|
|
3265
|
+
let sstTimeoutIdMap = new Map();
|
|
3266
|
+
let sstOnClickHandler;
|
|
3267
|
+
const clearSnapshotData = () => {
|
|
3268
|
+
sstWindowListenerMap.clear();
|
|
3269
|
+
sstIntervalIdMap.clear();
|
|
3270
|
+
sstTimeoutIdMap.clear();
|
|
3271
|
+
sstDocumentListenerMap.clear();
|
|
3272
|
+
sstOnClickHandler = null;
|
|
2697
3273
|
};
|
|
2698
|
-
|
|
2699
|
-
|
|
3274
|
+
/**
|
|
3275
|
+
* record event and timer
|
|
3276
|
+
* Scenes:
|
|
3277
|
+
* 1. exec umdMountHook in umd mode
|
|
3278
|
+
* 2. hidden keep-alive app
|
|
3279
|
+
* 3. after init prerender app
|
|
3280
|
+
*/
|
|
3281
|
+
const recordEffect = () => {
|
|
2700
3282
|
// record window event
|
|
2701
3283
|
eventListenerMap.forEach((listenerList, type) => {
|
|
2702
3284
|
if (listenerList.size) {
|
|
2703
|
-
|
|
3285
|
+
sstWindowListenerMap.set(type, new Set(listenerList));
|
|
2704
3286
|
}
|
|
2705
3287
|
});
|
|
2706
3288
|
// record timers
|
|
2707
3289
|
if (intervalIdMap.size) {
|
|
2708
|
-
|
|
3290
|
+
sstIntervalIdMap = new Map(intervalIdMap);
|
|
2709
3291
|
}
|
|
2710
3292
|
if (timeoutIdMap.size) {
|
|
2711
|
-
|
|
3293
|
+
sstTimeoutIdMap = new Map(timeoutIdMap);
|
|
2712
3294
|
}
|
|
2713
3295
|
// record onclick handler
|
|
2714
|
-
|
|
3296
|
+
sstOnClickHandler = documentClickListMap.get(appName);
|
|
2715
3297
|
// record document event
|
|
2716
3298
|
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
2717
3299
|
if (documentAppListenersMap) {
|
|
2718
3300
|
documentAppListenersMap.forEach((listenerList, type) => {
|
|
2719
3301
|
if (listenerList.size) {
|
|
2720
|
-
|
|
3302
|
+
sstDocumentListenerMap.set(type, new Set(listenerList));
|
|
2721
3303
|
}
|
|
2722
3304
|
});
|
|
2723
3305
|
}
|
|
2724
3306
|
};
|
|
2725
|
-
// rebuild event and timer before remount
|
|
2726
|
-
const
|
|
3307
|
+
// rebuild event and timer before remount app
|
|
3308
|
+
const rebuildEffect = () => {
|
|
2727
3309
|
// rebuild window event
|
|
2728
|
-
|
|
3310
|
+
sstWindowListenerMap.forEach((listenerList, type) => {
|
|
2729
3311
|
for (const listener of listenerList) {
|
|
2730
3312
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
2731
3313
|
}
|
|
2732
3314
|
});
|
|
2733
3315
|
// rebuild timer
|
|
2734
|
-
|
|
3316
|
+
sstIntervalIdMap.forEach((info) => {
|
|
2735
3317
|
microAppWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
2736
3318
|
});
|
|
2737
|
-
|
|
3319
|
+
sstTimeoutIdMap.forEach((info) => {
|
|
2738
3320
|
microAppWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
2739
3321
|
});
|
|
2740
3322
|
// rebuild onclick event
|
|
2741
|
-
|
|
2742
|
-
|
|
2743
|
-
|
|
3323
|
+
sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
|
|
3324
|
+
/**
|
|
3325
|
+
* rebuild document event
|
|
3326
|
+
* WARNING!!: do not delete setCurrentAppName & removeDomScope
|
|
3327
|
+
*/
|
|
3328
|
+
setCurrentAppName(appName);
|
|
3329
|
+
sstDocumentListenerMap.forEach((listenerList, type) => {
|
|
2744
3330
|
for (const listener of listenerList) {
|
|
2745
3331
|
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
2746
3332
|
}
|
|
2747
3333
|
});
|
|
2748
|
-
|
|
3334
|
+
removeDomScope();
|
|
3335
|
+
clearSnapshotData();
|
|
2749
3336
|
};
|
|
2750
3337
|
// release all event listener & interval & timeout when unmount app
|
|
2751
3338
|
const releaseEffect = () => {
|
|
@@ -2785,8 +3372,8 @@ function effect(appName, microAppWindow) {
|
|
|
2785
3372
|
}
|
|
2786
3373
|
};
|
|
2787
3374
|
return {
|
|
2788
|
-
|
|
2789
|
-
|
|
3375
|
+
recordEffect,
|
|
3376
|
+
rebuildEffect,
|
|
2790
3377
|
releaseEffect,
|
|
2791
3378
|
};
|
|
2792
3379
|
}
|
|
@@ -2812,7 +3399,6 @@ function removeMicroState(appName, rawState) {
|
|
|
2812
3399
|
delete rawState.microAppState;
|
|
2813
3400
|
}
|
|
2814
3401
|
}
|
|
2815
|
-
// 生成新的state对象
|
|
2816
3402
|
return assign({}, rawState);
|
|
2817
3403
|
}
|
|
2818
3404
|
// get micro app state form origin state
|
|
@@ -2824,12 +3410,15 @@ const ENC_AD_RE = /&/g; // %M1
|
|
|
2824
3410
|
const ENC_EQ_RE = /=/g; // %M2
|
|
2825
3411
|
const DEC_AD_RE = /%M1/g; // &
|
|
2826
3412
|
const DEC_EQ_RE = /%M2/g; // =
|
|
3413
|
+
// encode path with special symbol
|
|
2827
3414
|
function encodeMicroPath(path) {
|
|
2828
3415
|
return encodeURIComponent(commonDecode(path).replace(ENC_AD_RE, '%M1').replace(ENC_EQ_RE, '%M2'));
|
|
2829
3416
|
}
|
|
3417
|
+
// decode path
|
|
2830
3418
|
function decodeMicroPath(path) {
|
|
2831
3419
|
return commonDecode(path).replace(DEC_AD_RE, '&').replace(DEC_EQ_RE, '=');
|
|
2832
3420
|
}
|
|
3421
|
+
// Recursively resolve address
|
|
2833
3422
|
function commonDecode(path) {
|
|
2834
3423
|
try {
|
|
2835
3424
|
const decPath = decodeURIComponent(path);
|
|
@@ -2841,12 +3430,15 @@ function commonDecode(path) {
|
|
|
2841
3430
|
return path;
|
|
2842
3431
|
}
|
|
2843
3432
|
}
|
|
2844
|
-
//
|
|
3433
|
+
// Format the query parameter key to prevent conflicts with the original parameters
|
|
2845
3434
|
function formatQueryAppName(appName) {
|
|
2846
3435
|
// return `app-${appName}`
|
|
2847
3436
|
return appName;
|
|
2848
3437
|
}
|
|
2849
|
-
|
|
3438
|
+
/**
|
|
3439
|
+
* Get app fullPath from browser url
|
|
3440
|
+
* @param appName app.name
|
|
3441
|
+
*/
|
|
2850
3442
|
function getMicroPathFromURL(appName) {
|
|
2851
3443
|
var _a, _b;
|
|
2852
3444
|
const rawLocation = globalEnv.rawWindow.location;
|
|
@@ -2854,15 +3446,23 @@ function getMicroPathFromURL(appName) {
|
|
|
2854
3446
|
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)]);
|
|
2855
3447
|
return isString(microPath) ? decodeMicroPath(microPath) : null;
|
|
2856
3448
|
}
|
|
2857
|
-
|
|
3449
|
+
/**
|
|
3450
|
+
* Attach child app fullPath to browser url
|
|
3451
|
+
* @param appName app.name
|
|
3452
|
+
* @param microLocation location of child app
|
|
3453
|
+
*/
|
|
2858
3454
|
function setMicroPathToURL(appName, microLocation) {
|
|
2859
3455
|
let { pathname, search, hash } = globalEnv.rawWindow.location;
|
|
2860
3456
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
2861
3457
|
const encodedMicroPath = encodeMicroPath(microLocation.pathname +
|
|
2862
3458
|
microLocation.search +
|
|
2863
3459
|
microLocation.hash);
|
|
2864
|
-
|
|
2865
|
-
|
|
3460
|
+
/**
|
|
3461
|
+
* Is parent is hash router
|
|
3462
|
+
* In fact, this is not true. It just means that the parameter is added to the hash
|
|
3463
|
+
*/
|
|
3464
|
+
let isAttach2Hash = false;
|
|
3465
|
+
// If hash exists and search does not exist, it is considered as a hash route
|
|
2866
3466
|
if (hash && !search) {
|
|
2867
3467
|
isAttach2Hash = true;
|
|
2868
3468
|
if (queryObject.hashQuery) {
|
|
@@ -2892,7 +3492,11 @@ function setMicroPathToURL(appName, microLocation) {
|
|
|
2892
3492
|
isAttach2Hash,
|
|
2893
3493
|
};
|
|
2894
3494
|
}
|
|
2895
|
-
|
|
3495
|
+
/**
|
|
3496
|
+
* Delete child app fullPath from browser url
|
|
3497
|
+
* @param appName app.name
|
|
3498
|
+
* @param targetLocation target Location, default is rawLocation
|
|
3499
|
+
*/
|
|
2896
3500
|
function removeMicroPathFromURL(appName, targetLocation) {
|
|
2897
3501
|
var _a, _b, _c, _d;
|
|
2898
3502
|
let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
|
|
@@ -2915,7 +3519,7 @@ function removeMicroPathFromURL(appName, targetLocation) {
|
|
|
2915
3519
|
};
|
|
2916
3520
|
}
|
|
2917
3521
|
/**
|
|
2918
|
-
*
|
|
3522
|
+
* Format search, hash to object
|
|
2919
3523
|
*/
|
|
2920
3524
|
function getQueryObjectFromURL(search, hash) {
|
|
2921
3525
|
const queryObject = {};
|
|
@@ -2937,6 +3541,18 @@ function getNoHashMicroPathFromURL(appName, baseUrl) {
|
|
|
2937
3541
|
const formatLocation = createURL(microPath, baseUrl);
|
|
2938
3542
|
return formatLocation.origin + formatLocation.pathname + formatLocation.search;
|
|
2939
3543
|
}
|
|
3544
|
+
/**
|
|
3545
|
+
* Effect app is an app that can perform route navigation
|
|
3546
|
+
* NOTE: Invalid app action
|
|
3547
|
+
* 1. prevent update browser url, dispatch popStateEvent, reload browser
|
|
3548
|
+
* 2. It can update path with pushState/replaceState
|
|
3549
|
+
* 3. Can not update path outside (with router api)
|
|
3550
|
+
* 3. Can not update path by location
|
|
3551
|
+
*/
|
|
3552
|
+
function isEffectiveApp(appName) {
|
|
3553
|
+
const app = appInstanceMap.get(appName);
|
|
3554
|
+
return !!(app && !app.isPrefetch);
|
|
3555
|
+
}
|
|
2940
3556
|
|
|
2941
3557
|
/**
|
|
2942
3558
|
* dispatch PopStateEvent & HashChangeEvent to child app
|
|
@@ -2953,7 +3569,8 @@ function addHistoryListener(appName) {
|
|
|
2953
3569
|
* 1. unmount app & hidden keep-alive app will not receive popstate event
|
|
2954
3570
|
* 2. filter out onlyForBrowser
|
|
2955
3571
|
*/
|
|
2956
|
-
if (getActiveApps(true).includes(appName) &&
|
|
3572
|
+
if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName) &&
|
|
3573
|
+
!e.onlyForBrowser) {
|
|
2957
3574
|
const microPath = getMicroPathFromURL(appName);
|
|
2958
3575
|
const app = appInstanceMap.get(appName);
|
|
2959
3576
|
const proxyWindow = app.sandBox.proxyWindow;
|
|
@@ -2989,9 +3606,19 @@ function addHistoryListener(appName) {
|
|
|
2989
3606
|
function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
|
|
2990
3607
|
// create PopStateEvent named popstate-appName with sub app state
|
|
2991
3608
|
const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName) });
|
|
3609
|
+
/**
|
|
3610
|
+
* angular14 takes e.type as type judgment
|
|
3611
|
+
* when e.type is popstate-appName popstate event will be invalid
|
|
3612
|
+
*/
|
|
3613
|
+
// Object.defineProperty(newPopStateEvent, 'type', {
|
|
3614
|
+
// value: 'popstate',
|
|
3615
|
+
// writable: true,
|
|
3616
|
+
// configurable: true,
|
|
3617
|
+
// enumerable: true,
|
|
3618
|
+
// })
|
|
2992
3619
|
globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
|
|
2993
3620
|
// call function window.onpopstate if it exists
|
|
2994
|
-
|
|
3621
|
+
isFunction(proxyWindow.onpopstate) && proxyWindow.onpopstate(newPopStateEvent);
|
|
2995
3622
|
}
|
|
2996
3623
|
/**
|
|
2997
3624
|
* dispatch formatted hashchange event to microApp
|
|
@@ -3006,7 +3633,7 @@ function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
|
|
|
3006
3633
|
});
|
|
3007
3634
|
globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
|
|
3008
3635
|
// call function window.onhashchange if it exists
|
|
3009
|
-
|
|
3636
|
+
isFunction(proxyWindow.onhashchange) && proxyWindow.onhashchange(newHashChangeEvent);
|
|
3010
3637
|
}
|
|
3011
3638
|
/**
|
|
3012
3639
|
* dispatch native PopStateEvent, simulate location behavior
|
|
@@ -3031,15 +3658,18 @@ function dispatchNativeHashChangeEvent(oldHref) {
|
|
|
3031
3658
|
}
|
|
3032
3659
|
/**
|
|
3033
3660
|
* dispatch popstate & hashchange event to browser
|
|
3661
|
+
* @param appName app.name
|
|
3034
3662
|
* @param onlyForBrowser only dispatch event to browser
|
|
3035
3663
|
* @param oldHref old href of rawWindow.location
|
|
3036
3664
|
*/
|
|
3037
|
-
function dispatchNativeEvent(onlyForBrowser, oldHref) {
|
|
3665
|
+
function dispatchNativeEvent(appName, onlyForBrowser, oldHref) {
|
|
3038
3666
|
// clear element scope before dispatch global event
|
|
3039
3667
|
removeDomScope();
|
|
3040
|
-
|
|
3041
|
-
|
|
3042
|
-
|
|
3668
|
+
if (isEffectiveApp(appName)) {
|
|
3669
|
+
dispatchNativePopStateEvent(onlyForBrowser);
|
|
3670
|
+
if (oldHref) {
|
|
3671
|
+
dispatchNativeHashChangeEvent(oldHref);
|
|
3672
|
+
}
|
|
3043
3673
|
}
|
|
3044
3674
|
}
|
|
3045
3675
|
|
|
@@ -3056,7 +3686,7 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3056
3686
|
if (isString(rests[2]) || isURL(rests[2])) {
|
|
3057
3687
|
const targetLocation = createURL(rests[2], microLocation.href);
|
|
3058
3688
|
if (targetLocation.origin === microLocation.origin) {
|
|
3059
|
-
navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
|
|
3689
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0]), rests[1]);
|
|
3060
3690
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3061
3691
|
if (targetFullPath !== microLocation.fullPath) {
|
|
3062
3692
|
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
@@ -3064,7 +3694,7 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3064
3694
|
return void 0;
|
|
3065
3695
|
}
|
|
3066
3696
|
}
|
|
3067
|
-
nativeHistoryNavigate(methodName, rests[2], rests[0], rests[1]);
|
|
3697
|
+
nativeHistoryNavigate(appName, methodName, rests[2], rests[0], rests[1]);
|
|
3068
3698
|
};
|
|
3069
3699
|
}
|
|
3070
3700
|
const pushState = getMicroHistoryMethod('pushState');
|
|
@@ -3096,14 +3726,17 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3096
3726
|
}
|
|
3097
3727
|
/**
|
|
3098
3728
|
* navigate to new path base on native method of history
|
|
3729
|
+
* @param appName app.name
|
|
3099
3730
|
* @param methodName pushState/replaceState
|
|
3100
3731
|
* @param fullPath full path
|
|
3101
3732
|
* @param state history.state, default is null
|
|
3102
3733
|
* @param title history.title, default is ''
|
|
3103
3734
|
*/
|
|
3104
|
-
function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
|
|
3105
|
-
|
|
3106
|
-
|
|
3735
|
+
function nativeHistoryNavigate(appName, methodName, fullPath, state = null, title = '') {
|
|
3736
|
+
if (isEffectiveApp(appName)) {
|
|
3737
|
+
const method = methodName === 'pushState' ? globalEnv.rawPushState : globalEnv.rawReplaceState;
|
|
3738
|
+
method.call(globalEnv.rawWindow.history, state, title, fullPath);
|
|
3739
|
+
}
|
|
3107
3740
|
}
|
|
3108
3741
|
/**
|
|
3109
3742
|
* Navigate to new path, and dispatch native popStateEvent/hashChangeEvent to browser
|
|
@@ -3112,29 +3745,33 @@ function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
|
|
|
3112
3745
|
* 2. proxyHistory.pushState/replaceState with limited popstateEvent
|
|
3113
3746
|
* 3. api microApp.router.push/replace
|
|
3114
3747
|
* 4. proxyLocation.hash = xxx
|
|
3748
|
+
* @param appName app.name
|
|
3115
3749
|
* @param methodName pushState/replaceState
|
|
3116
3750
|
* @param result result of add/remove microApp path on browser url
|
|
3117
3751
|
* @param onlyForBrowser only dispatch event to browser
|
|
3118
3752
|
* @param state history.state, not required
|
|
3119
3753
|
* @param title history.title, not required
|
|
3120
3754
|
*/
|
|
3121
|
-
function navigateWithNativeEvent(methodName, result, onlyForBrowser, state, title) {
|
|
3122
|
-
|
|
3123
|
-
|
|
3124
|
-
|
|
3125
|
-
|
|
3126
|
-
|
|
3127
|
-
|
|
3128
|
-
|
|
3755
|
+
function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, state, title) {
|
|
3756
|
+
if (isEffectiveApp(appName)) {
|
|
3757
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
3758
|
+
const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
3759
|
+
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
3760
|
+
// navigate with native history method
|
|
3761
|
+
nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
|
|
3762
|
+
if (oldFullPath !== result.fullPath)
|
|
3763
|
+
dispatchNativeEvent(appName, onlyForBrowser, oldHref);
|
|
3764
|
+
}
|
|
3129
3765
|
}
|
|
3130
3766
|
/**
|
|
3131
3767
|
* update browser url when mount/unmount/hidden/show/attachToURL/attachAllToURL
|
|
3132
3768
|
* just attach microRoute info to browser, dispatch event to base app(exclude child)
|
|
3769
|
+
* @param appName app.name
|
|
3133
3770
|
* @param result result of add/remove microApp path on browser url
|
|
3134
3771
|
* @param state history.state
|
|
3135
3772
|
*/
|
|
3136
|
-
function attachRouteToBrowserURL(result, state) {
|
|
3137
|
-
navigateWithNativeEvent('replaceState', result, true, state);
|
|
3773
|
+
function attachRouteToBrowserURL(appName, result, state) {
|
|
3774
|
+
navigateWithNativeEvent(appName, 'replaceState', result, true, state);
|
|
3138
3775
|
}
|
|
3139
3776
|
/**
|
|
3140
3777
|
* When path is same, keep the microAppState in history.state
|
|
@@ -3163,12 +3800,14 @@ function reWriteHistoryMethod(method) {
|
|
|
3163
3800
|
* 1. Exec after apply pushState/replaceState
|
|
3164
3801
|
* 2. Unable to catch when base app navigate with location
|
|
3165
3802
|
* 3. When in nest app, rawPushState/rawReplaceState has been modified by parent
|
|
3166
|
-
* 4.
|
|
3167
3803
|
*/
|
|
3168
|
-
getActiveApps(
|
|
3804
|
+
getActiveApps({
|
|
3805
|
+
excludeHiddenApp: true,
|
|
3806
|
+
excludePreRender: true,
|
|
3807
|
+
}).forEach(appName => {
|
|
3169
3808
|
const app = appInstanceMap.get(appName);
|
|
3170
3809
|
if (app.sandBox && app.useMemoryRouter && !getMicroPathFromURL(appName)) {
|
|
3171
|
-
attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3810
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3172
3811
|
}
|
|
3173
3812
|
});
|
|
3174
3813
|
// fix bug for nest app
|
|
@@ -3200,7 +3839,7 @@ function createRouterApi() {
|
|
|
3200
3839
|
* @param state to.state
|
|
3201
3840
|
*/
|
|
3202
3841
|
function navigateWithRawHistory(appName, methodName, targetLocation, state) {
|
|
3203
|
-
navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
3842
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
3204
3843
|
// clear element scope after navigate
|
|
3205
3844
|
removeDomScope();
|
|
3206
3845
|
}
|
|
@@ -3221,7 +3860,7 @@ function createRouterApi() {
|
|
|
3221
3860
|
return logError(`navigation failed, memory router of app ${appName} is closed`);
|
|
3222
3861
|
}
|
|
3223
3862
|
// active apps, include hidden keep-alive app
|
|
3224
|
-
if (getActiveApps().includes(appName)) {
|
|
3863
|
+
if (getActiveApps({ excludePreRender: true }).includes(appName)) {
|
|
3225
3864
|
const microLocation = app.sandBox.proxyWindow.location;
|
|
3226
3865
|
const targetLocation = createURL(to.path, microLocation.href);
|
|
3227
3866
|
// Only get path data, even if the origin is different from microApp
|
|
@@ -3273,7 +3912,7 @@ function createRouterApi() {
|
|
|
3273
3912
|
removeDomScope();
|
|
3274
3913
|
for (const guard of guards) {
|
|
3275
3914
|
if (isFunction(guard)) {
|
|
3276
|
-
guard(
|
|
3915
|
+
guard(to, from, appName);
|
|
3277
3916
|
}
|
|
3278
3917
|
else if (isPlainObject(guard) && isFunction(guard[appName])) {
|
|
3279
3918
|
guard[appName](to, from);
|
|
@@ -3304,7 +3943,7 @@ function createRouterApi() {
|
|
|
3304
3943
|
function commonHandlerForAttachToURL(appName) {
|
|
3305
3944
|
const app = appInstanceMap.get(appName);
|
|
3306
3945
|
if (app.sandBox && app.useMemoryRouter) {
|
|
3307
|
-
attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3946
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3308
3947
|
}
|
|
3309
3948
|
}
|
|
3310
3949
|
/**
|
|
@@ -3319,10 +3958,14 @@ function createRouterApi() {
|
|
|
3319
3958
|
}
|
|
3320
3959
|
/**
|
|
3321
3960
|
* Attach all active app router info to browser url
|
|
3322
|
-
*
|
|
3961
|
+
* @param includeHiddenApp include hidden keep-alive app
|
|
3962
|
+
* @param includePreRender include preRender app
|
|
3323
3963
|
*/
|
|
3324
|
-
function attachAllToURL(includeHiddenApp = false) {
|
|
3325
|
-
getActiveApps(
|
|
3964
|
+
function attachAllToURL({ includeHiddenApp = false, includePreRender = false, }) {
|
|
3965
|
+
getActiveApps({
|
|
3966
|
+
excludeHiddenApp: !includeHiddenApp,
|
|
3967
|
+
excludePreRender: !includePreRender,
|
|
3968
|
+
}).forEach(appName => commonHandlerForAttachToURL(appName));
|
|
3326
3969
|
}
|
|
3327
3970
|
function createDefaultPageApi() {
|
|
3328
3971
|
// defaultPage data
|
|
@@ -3337,7 +3980,7 @@ function createRouterApi() {
|
|
|
3337
3980
|
function setDefaultPage(options) {
|
|
3338
3981
|
const appName = formatAppName(options.name);
|
|
3339
3982
|
if (!appName || !options.path) {
|
|
3340
|
-
if (process.env.NODE_ENV !== 'production') {
|
|
3983
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
3341
3984
|
if (!appName) {
|
|
3342
3985
|
logWarn(`setDefaultPage: invalid appName "${appName}"`);
|
|
3343
3986
|
}
|
|
@@ -3380,7 +4023,7 @@ function createRouterApi() {
|
|
|
3380
4023
|
}
|
|
3381
4024
|
});
|
|
3382
4025
|
}
|
|
3383
|
-
else if (process.env.NODE_ENV !== 'production') {
|
|
4026
|
+
else if ((process.env.NODE_ENV !== 'production')) {
|
|
3384
4027
|
logWarn('setBaseAppRouter: Invalid base router');
|
|
3385
4028
|
}
|
|
3386
4029
|
}
|
|
@@ -3448,13 +4091,13 @@ function createMicroLocation(appName, url) {
|
|
|
3448
4091
|
if (targetLocation.hash !== shadowLocation.hash) {
|
|
3449
4092
|
if (setMicroPathResult.isAttach2Hash)
|
|
3450
4093
|
oldHref = rawLocation.href;
|
|
3451
|
-
nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
|
|
4094
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
3452
4095
|
}
|
|
3453
4096
|
if (targetLocation.hash) {
|
|
3454
|
-
dispatchNativeEvent(false, oldHref);
|
|
4097
|
+
dispatchNativeEvent(appName, false, oldHref);
|
|
3455
4098
|
}
|
|
3456
4099
|
else {
|
|
3457
|
-
|
|
4100
|
+
rawReload();
|
|
3458
4101
|
}
|
|
3459
4102
|
return void 0;
|
|
3460
4103
|
/**
|
|
@@ -3463,8 +4106,8 @@ function createMicroLocation(appName, url) {
|
|
|
3463
4106
|
*/
|
|
3464
4107
|
}
|
|
3465
4108
|
else if (setMicroPathResult.isAttach2Hash) {
|
|
3466
|
-
nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
|
|
3467
|
-
|
|
4109
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
4110
|
+
rawReload();
|
|
3468
4111
|
return void 0;
|
|
3469
4112
|
}
|
|
3470
4113
|
value = setMicroPathResult.fullPath;
|
|
@@ -3494,7 +4137,7 @@ function createMicroLocation(appName, url) {
|
|
|
3494
4137
|
// When the browser url has a hash value, the same pathname/search will not refresh browser
|
|
3495
4138
|
if (targetLocation[key] === shadowLocation[key] && shadowLocation.hash) {
|
|
3496
4139
|
// The href has not changed, not need to dispatch hashchange event
|
|
3497
|
-
dispatchNativeEvent(false);
|
|
4140
|
+
dispatchNativeEvent(appName, false);
|
|
3498
4141
|
}
|
|
3499
4142
|
else {
|
|
3500
4143
|
/**
|
|
@@ -3503,19 +4146,24 @@ function createMicroLocation(appName, url) {
|
|
|
3503
4146
|
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
3504
4147
|
* search: ?query ==> ?query#hash
|
|
3505
4148
|
*/
|
|
3506
|
-
nativeHistoryNavigate(targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
|
|
3507
|
-
|
|
4149
|
+
nativeHistoryNavigate(appName, targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
|
|
4150
|
+
rawReload();
|
|
3508
4151
|
}
|
|
3509
4152
|
}
|
|
4153
|
+
function rawReload() {
|
|
4154
|
+
isEffectiveApp(appName) && rawLocation.reload();
|
|
4155
|
+
}
|
|
3510
4156
|
/**
|
|
3511
4157
|
* Special processing for four keys: href, pathname, search and hash
|
|
3512
4158
|
* They take values from shadowLocation, and require special operations when assigning values
|
|
3513
4159
|
*/
|
|
3514
4160
|
rawDefineProperties(microLocation, {
|
|
3515
4161
|
href: createPropertyDescriptor(() => shadowLocation.href, (value) => {
|
|
3516
|
-
|
|
3517
|
-
|
|
3518
|
-
|
|
4162
|
+
if (isEffectiveApp(appName)) {
|
|
4163
|
+
const targetPath = commonHandler(value, 'pushState');
|
|
4164
|
+
if (targetPath)
|
|
4165
|
+
rawLocation.href = targetPath;
|
|
4166
|
+
}
|
|
3519
4167
|
}),
|
|
3520
4168
|
pathname: createPropertyDescriptor(() => shadowLocation.pathname, (value) => {
|
|
3521
4169
|
const targetPath = ('/' + value).replace(/^\/+/, '/') + shadowLocation.search + shadowLocation.hash;
|
|
@@ -3530,16 +4178,18 @@ function createMicroLocation(appName, url) {
|
|
|
3530
4178
|
const targetLocation = createURL(targetPath, url);
|
|
3531
4179
|
// The same hash will not trigger popStateEvent
|
|
3532
4180
|
if (targetLocation.hash !== shadowLocation.hash) {
|
|
3533
|
-
navigateWithNativeEvent('pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
4181
|
+
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
3534
4182
|
}
|
|
3535
4183
|
}),
|
|
3536
4184
|
fullPath: createPropertyDescriptor(() => shadowLocation.pathname + shadowLocation.search + shadowLocation.hash, noop),
|
|
3537
4185
|
});
|
|
3538
4186
|
const createLocationMethod = (locationMethodName) => {
|
|
3539
4187
|
return function (value) {
|
|
3540
|
-
|
|
3541
|
-
|
|
3542
|
-
|
|
4188
|
+
if (isEffectiveApp(appName)) {
|
|
4189
|
+
const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
|
|
4190
|
+
if (targetPath)
|
|
4191
|
+
rawLocation[locationMethodName](targetPath);
|
|
4192
|
+
}
|
|
3543
4193
|
};
|
|
3544
4194
|
};
|
|
3545
4195
|
return assign(microLocation, {
|
|
@@ -3614,7 +4264,12 @@ function createMicroRouter(appName, url) {
|
|
|
3614
4264
|
microHistory: createMicroHistory(appName, microLocation),
|
|
3615
4265
|
};
|
|
3616
4266
|
}
|
|
3617
|
-
|
|
4267
|
+
/**
|
|
4268
|
+
* When the sandbox executes start, or the hidden keep-alive application is re-rendered, the location is updated according to the browser url or attach router info to browser url
|
|
4269
|
+
* @param appName app.name
|
|
4270
|
+
* @param microLocation MicroLocation for sandbox
|
|
4271
|
+
* @param defaultPage default page
|
|
4272
|
+
*/
|
|
3618
4273
|
function initRouteStateWithURL(appName, microLocation, defaultPage) {
|
|
3619
4274
|
const microPath = getMicroPathFromURL(appName);
|
|
3620
4275
|
if (microPath) {
|
|
@@ -3633,7 +4288,7 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
3633
4288
|
if (defaultPage)
|
|
3634
4289
|
updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
|
|
3635
4290
|
// attach microApp route info to browser URL
|
|
3636
|
-
attachRouteToBrowserURL(setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
|
|
4291
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
|
|
3637
4292
|
// trigger guards after change browser URL
|
|
3638
4293
|
autoTriggerNavigationGuard(appName, microLocation);
|
|
3639
4294
|
}
|
|
@@ -3657,7 +4312,7 @@ function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
|
|
|
3657
4312
|
* called on sandbox.stop or hidden of keep-alive app
|
|
3658
4313
|
*/
|
|
3659
4314
|
function removeStateAndPathFromBrowser(appName) {
|
|
3660
|
-
attachRouteToBrowserURL(removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
4315
|
+
attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
3661
4316
|
}
|
|
3662
4317
|
|
|
3663
4318
|
/**
|
|
@@ -3766,7 +4421,7 @@ function useMicroEventSource() {
|
|
|
3766
4421
|
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
3767
4422
|
const globalPropertyList = ['window', 'self', 'globalThis'];
|
|
3768
4423
|
class SandBox {
|
|
3769
|
-
constructor(appName, url
|
|
4424
|
+
constructor(appName, url) {
|
|
3770
4425
|
/**
|
|
3771
4426
|
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
3772
4427
|
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
@@ -3789,28 +4444,38 @@ class SandBox {
|
|
|
3789
4444
|
// create proxyWindow with Proxy(microAppWindow)
|
|
3790
4445
|
this.proxyWindow = this.createProxyWindow(appName);
|
|
3791
4446
|
// Rewrite global event listener & timeout
|
|
3792
|
-
|
|
4447
|
+
this.effectController = effect(appName, this.microAppWindow);
|
|
3793
4448
|
// inject global properties
|
|
3794
|
-
this.initStaticGlobalKeys(this.microAppWindow, appName, url
|
|
4449
|
+
this.initStaticGlobalKeys(this.microAppWindow, appName, url);
|
|
3795
4450
|
}
|
|
3796
|
-
|
|
3797
|
-
|
|
4451
|
+
/**
|
|
4452
|
+
* open sandbox and perform some initial actions
|
|
4453
|
+
* @param umdMode is umd mode
|
|
4454
|
+
* @param baseroute base route for child
|
|
4455
|
+
* @param useMemoryRouter use virtual router
|
|
4456
|
+
* @param defaultPage default page when mount child base on virtual router
|
|
4457
|
+
* @param disablePatchRequest prevent patchRequestApi
|
|
4458
|
+
*/
|
|
4459
|
+
start({ umdMode, baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
3798
4460
|
if (!this.active) {
|
|
3799
4461
|
this.active = true;
|
|
3800
4462
|
if (useMemoryRouter) {
|
|
4463
|
+
if (isUndefined(this.microAppWindow.location)) {
|
|
4464
|
+
this.setMicroAppRouter(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__);
|
|
4465
|
+
}
|
|
3801
4466
|
this.initRouteState(defaultPage);
|
|
3802
4467
|
// unique listener of popstate event for sub app
|
|
3803
|
-
this.removeHistoryListener = addHistoryListener(this.
|
|
4468
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
3804
4469
|
}
|
|
3805
4470
|
else {
|
|
3806
|
-
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ =
|
|
4471
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
3807
4472
|
}
|
|
3808
4473
|
/**
|
|
3809
4474
|
* 1. prevent the key deleted during sandBox.stop after rewrite
|
|
3810
4475
|
* 2. umd mode will not delete any keys during sandBox.stop
|
|
3811
4476
|
*/
|
|
3812
4477
|
if (!umdMode) {
|
|
3813
|
-
this.initGlobalKeysWhenStart(this.microAppWindow, this.
|
|
4478
|
+
this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
|
|
3814
4479
|
}
|
|
3815
4480
|
if (++SandBox.activeCount === 1) {
|
|
3816
4481
|
effectDocumentEvent();
|
|
@@ -3821,18 +4486,24 @@ class SandBox {
|
|
|
3821
4486
|
fixBabelPolyfill6();
|
|
3822
4487
|
}
|
|
3823
4488
|
}
|
|
3824
|
-
|
|
4489
|
+
/**
|
|
4490
|
+
* close sandbox and perform some clean up actions
|
|
4491
|
+
* @param umdMode is umd mode
|
|
4492
|
+
* @param keepRouteState prevent reset route
|
|
4493
|
+
* @param clearEventSource clear MicroEventSource when destroy
|
|
4494
|
+
* @param clearData clear data from base app
|
|
4495
|
+
*/
|
|
4496
|
+
stop({ umdMode, keepRouteState, clearEventSource, clearData, }) {
|
|
3825
4497
|
if (this.active) {
|
|
3826
|
-
|
|
3827
|
-
this.
|
|
3828
|
-
this.microAppWindow.microApp.clearGlobalDataListener();
|
|
4498
|
+
// clear global event, timeout, data listener
|
|
4499
|
+
this.releaseGlobalEffect(clearData);
|
|
3829
4500
|
if (this.removeHistoryListener) {
|
|
3830
4501
|
this.clearRouteState(keepRouteState);
|
|
3831
4502
|
// release listener of popstate
|
|
3832
4503
|
this.removeHistoryListener();
|
|
3833
4504
|
}
|
|
3834
4505
|
if (clearEventSource) {
|
|
3835
|
-
clearMicroEventSource(this.
|
|
4506
|
+
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
3836
4507
|
}
|
|
3837
4508
|
/**
|
|
3838
4509
|
* NOTE:
|
|
@@ -3858,10 +4529,33 @@ class SandBox {
|
|
|
3858
4529
|
this.active = false;
|
|
3859
4530
|
}
|
|
3860
4531
|
}
|
|
3861
|
-
|
|
3862
|
-
|
|
4532
|
+
/**
|
|
4533
|
+
* clear global event, timeout, data listener
|
|
4534
|
+
* Scenes:
|
|
4535
|
+
* 1. unmount of normal/umd app
|
|
4536
|
+
* 2. hidden keep-alive app
|
|
4537
|
+
* 3. after init prerender app
|
|
4538
|
+
* @param clearData clear data from base app
|
|
4539
|
+
*/
|
|
4540
|
+
releaseGlobalEffect(clearData = false) {
|
|
4541
|
+
this.effectController.releaseEffect();
|
|
4542
|
+
this.microAppWindow.microApp.clearDataListener();
|
|
4543
|
+
this.microAppWindow.microApp.clearGlobalDataListener();
|
|
4544
|
+
if (clearData) {
|
|
4545
|
+
microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4546
|
+
this.microAppWindow.microApp.clearData();
|
|
4547
|
+
}
|
|
4548
|
+
}
|
|
4549
|
+
/**
|
|
4550
|
+
* record umd snapshot before the first execution of umdHookMount
|
|
4551
|
+
* Scenes:
|
|
4552
|
+
* 1. exec umdMountHook in umd mode
|
|
4553
|
+
* 2. hidden keep-alive app
|
|
4554
|
+
* 3. after init prerender app
|
|
4555
|
+
*/
|
|
4556
|
+
recordEffectSnapshot() {
|
|
3863
4557
|
// this.microAppWindow.__MICRO_APP_UMD_MODE__ = true
|
|
3864
|
-
this.
|
|
4558
|
+
this.effectController.recordEffect();
|
|
3865
4559
|
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
3866
4560
|
// this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
|
|
3867
4561
|
// this.injectedKeys.forEach((key: PropertyKey) => {
|
|
@@ -3869,13 +4563,17 @@ class SandBox {
|
|
|
3869
4563
|
// })
|
|
3870
4564
|
}
|
|
3871
4565
|
// rebuild umd snapshot before remount umd app
|
|
3872
|
-
|
|
4566
|
+
rebuildEffectSnapshot() {
|
|
3873
4567
|
// this.recordUmdInjectedValues!.forEach((value: unknown, key: PropertyKey) => {
|
|
3874
4568
|
// Reflect.set(this.proxyWindow, key, value)
|
|
3875
4569
|
// })
|
|
3876
|
-
this.
|
|
4570
|
+
this.effectController.rebuildEffect();
|
|
3877
4571
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
3878
4572
|
}
|
|
4573
|
+
// set __MICRO_APP_PRE_RENDER__ state
|
|
4574
|
+
setPreRenderState(state) {
|
|
4575
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
4576
|
+
}
|
|
3879
4577
|
/**
|
|
3880
4578
|
* get scopeProperties and escapeProperties from plugins & adapter
|
|
3881
4579
|
* @param appName app name
|
|
@@ -3883,9 +4581,9 @@ class SandBox {
|
|
|
3883
4581
|
getSpecialProperties(appName) {
|
|
3884
4582
|
var _a;
|
|
3885
4583
|
this.scopeProperties = this.scopeProperties.concat(this.adapter.staticScopeProperties);
|
|
3886
|
-
if (isPlainObject(microApp.plugins)) {
|
|
3887
|
-
this.commonActionForSpecialProperties(microApp.plugins.global);
|
|
3888
|
-
this.commonActionForSpecialProperties((_a = microApp.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
4584
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
4585
|
+
this.commonActionForSpecialProperties(microApp.options.plugins.global);
|
|
4586
|
+
this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
3889
4587
|
}
|
|
3890
4588
|
}
|
|
3891
4589
|
// common action for global plugins and module plugins
|
|
@@ -4003,12 +4701,13 @@ class SandBox {
|
|
|
4003
4701
|
* @param url app url
|
|
4004
4702
|
* @param useMemoryRouter whether use memory router
|
|
4005
4703
|
*/
|
|
4006
|
-
initStaticGlobalKeys(microAppWindow, appName, url
|
|
4704
|
+
initStaticGlobalKeys(microAppWindow, appName, url) {
|
|
4007
4705
|
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
4008
4706
|
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
4009
4707
|
microAppWindow.__MICRO_APP_URL__ = url;
|
|
4010
4708
|
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
4011
4709
|
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
4710
|
+
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
4012
4711
|
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
4013
4712
|
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
4014
4713
|
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
@@ -4018,8 +4717,6 @@ class SandBox {
|
|
|
4018
4717
|
});
|
|
4019
4718
|
this.setProxyDocument(microAppWindow, appName);
|
|
4020
4719
|
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
4021
|
-
if (useMemoryRouter)
|
|
4022
|
-
this.setMicroAppRouter(microAppWindow, appName, url);
|
|
4023
4720
|
}
|
|
4024
4721
|
setProxyDocument(microAppWindow, appName) {
|
|
4025
4722
|
const { proxyDocument, MicroDocument } = this.createProxyDocument(appName);
|
|
@@ -4197,17 +4894,19 @@ class SandBox {
|
|
|
4197
4894
|
return element;
|
|
4198
4895
|
};
|
|
4199
4896
|
const proxyDocument = new Proxy(rawDocument, {
|
|
4200
|
-
get(target, key) {
|
|
4897
|
+
get: (target, key) => {
|
|
4201
4898
|
throttleDeferForSetAppName(appName);
|
|
4202
4899
|
throttleDeferForParentNode(proxyDocument);
|
|
4203
4900
|
if (key === 'createElement')
|
|
4204
4901
|
return createElement;
|
|
4205
4902
|
if (key === Symbol.toStringTag)
|
|
4206
4903
|
return 'ProxyDocument';
|
|
4904
|
+
if (key === 'defaultView')
|
|
4905
|
+
return this.proxyWindow;
|
|
4207
4906
|
const rawValue = Reflect.get(target, key);
|
|
4208
4907
|
return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
|
|
4209
4908
|
},
|
|
4210
|
-
set(target, key, value) {
|
|
4909
|
+
set: (target, key, value) => {
|
|
4211
4910
|
// Fix TypeError: Illegal invocation when set document.title
|
|
4212
4911
|
Reflect.set(target, key, value);
|
|
4213
4912
|
/**
|
|
@@ -4299,10 +4998,8 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
4299
4998
|
});
|
|
4300
4999
|
formatEventInfo(event, element);
|
|
4301
5000
|
// global hooks
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
// @ts-ignore
|
|
4305
|
-
microApp.lifeCycles[lifecycleName](event);
|
|
5001
|
+
if (isFunction((_a = microApp.options.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
5002
|
+
microApp.options.lifeCycles[lifecycleName](event);
|
|
4306
5003
|
}
|
|
4307
5004
|
element.dispatchEvent(event);
|
|
4308
5005
|
}
|
|
@@ -4322,7 +5019,7 @@ function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
|
4322
5019
|
// micro app instances
|
|
4323
5020
|
const appInstanceMap = new Map();
|
|
4324
5021
|
class CreateApp {
|
|
4325
|
-
constructor({ name, url,
|
|
5022
|
+
constructor({ name, url, container, scopecss, useSandbox, inline, esmodule, ssrUrl, isPrefetch, prefetchLevel, }) {
|
|
4326
5023
|
this.state = appStates.CREATED;
|
|
4327
5024
|
this.keepAliveState = null;
|
|
4328
5025
|
this.keepAliveContainer = null;
|
|
@@ -4331,30 +5028,27 @@ class CreateApp {
|
|
|
4331
5028
|
this.umdHookUnmount = null;
|
|
4332
5029
|
this.libraryName = null;
|
|
4333
5030
|
this.umdMode = false;
|
|
4334
|
-
this.isPrefetch = false;
|
|
4335
|
-
this.prefetchResolve = null;
|
|
4336
|
-
this.container = null;
|
|
4337
5031
|
this.sandBox = null;
|
|
5032
|
+
this.fiber = false;
|
|
5033
|
+
this.useMemoryRouter = true;
|
|
4338
5034
|
this.name = name;
|
|
4339
5035
|
this.url = url;
|
|
4340
5036
|
this.useSandbox = useSandbox;
|
|
4341
5037
|
this.scopecss = this.useSandbox && scopecss;
|
|
4342
|
-
this.
|
|
4343
|
-
|
|
5038
|
+
this.inline = inline !== null && inline !== void 0 ? inline : false;
|
|
5039
|
+
this.esmodule = esmodule !== null && esmodule !== void 0 ? esmodule : false;
|
|
5040
|
+
// not exist when prefetch 👇
|
|
4344
5041
|
this.container = container !== null && container !== void 0 ? container : null;
|
|
4345
5042
|
this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
|
|
4346
|
-
|
|
4347
|
-
this.
|
|
4348
|
-
this.
|
|
4349
|
-
this.
|
|
4350
|
-
|
|
4351
|
-
this.
|
|
4352
|
-
this.source = {
|
|
4353
|
-
links: new Map(),
|
|
4354
|
-
scripts: new Map(),
|
|
4355
|
-
};
|
|
5043
|
+
// exist only prefetch 👇
|
|
5044
|
+
this.isPrefetch = isPrefetch !== null && isPrefetch !== void 0 ? isPrefetch : false;
|
|
5045
|
+
this.isPrerender = prefetchLevel === 3;
|
|
5046
|
+
this.prefetchLevel = prefetchLevel;
|
|
5047
|
+
// init actions
|
|
5048
|
+
appInstanceMap.set(this.name, this);
|
|
5049
|
+
this.source = { html: null, links: new Set(), scripts: new Set() };
|
|
4356
5050
|
this.loadSourceCode();
|
|
4357
|
-
this.useSandbox && (this.sandBox = new SandBox(name, url
|
|
5051
|
+
this.useSandbox && (this.sandBox = new SandBox(name, url));
|
|
4358
5052
|
}
|
|
4359
5053
|
// Load resources
|
|
4360
5054
|
loadSourceCode() {
|
|
@@ -4364,17 +5058,45 @@ class CreateApp {
|
|
|
4364
5058
|
/**
|
|
4365
5059
|
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
4366
5060
|
*/
|
|
4367
|
-
onLoad(html) {
|
|
5061
|
+
onLoad(html, defaultPage, disablePatchRequest) {
|
|
4368
5062
|
var _a;
|
|
4369
5063
|
if (++this.loadSourceLevel === 2) {
|
|
4370
5064
|
this.source.html = html;
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
this.
|
|
5065
|
+
this.state = appStates.LOADED;
|
|
5066
|
+
if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
|
|
5067
|
+
getRootContainer(this.container).mount(this);
|
|
4374
5068
|
}
|
|
4375
|
-
else if (
|
|
4376
|
-
|
|
4377
|
-
|
|
5069
|
+
else if (this.isPrerender) {
|
|
5070
|
+
/**
|
|
5071
|
+
* PreRender is an option of prefetch, it will render app during prefetch
|
|
5072
|
+
* Limit:
|
|
5073
|
+
* 1. fiber forced on
|
|
5074
|
+
* 2. only virtual router support
|
|
5075
|
+
*
|
|
5076
|
+
* NOTE: (4P: not - update browser url, dispatch popstateEvent, reload window, dispatch lifecycle event)
|
|
5077
|
+
* 1. pushState/replaceState in child can update microLocation, but will not attach router info to browser url
|
|
5078
|
+
* 2. prevent dispatch popstate/hashchange event to browser
|
|
5079
|
+
* 3. all navigation actions of location are invalid (In the future, we can consider update microLocation without trigger browser reload)
|
|
5080
|
+
* 4. lifecycle event will not trigger when prerender
|
|
5081
|
+
*
|
|
5082
|
+
* Special scenes
|
|
5083
|
+
* 1. unmount prerender app when loading
|
|
5084
|
+
* 2. unmount prerender app when exec js
|
|
5085
|
+
* 2. unmount prerender app after exec js
|
|
5086
|
+
*/
|
|
5087
|
+
const container = pureCreateElement('div');
|
|
5088
|
+
container.setAttribute('prerender', 'true');
|
|
5089
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setPreRenderState(true);
|
|
5090
|
+
this.mount({
|
|
5091
|
+
container,
|
|
5092
|
+
inline: this.inline,
|
|
5093
|
+
useMemoryRouter: true,
|
|
5094
|
+
baseroute: '',
|
|
5095
|
+
fiber: true,
|
|
5096
|
+
esmodule: this.esmodule,
|
|
5097
|
+
defaultPage: defaultPage !== null && defaultPage !== void 0 ? defaultPage : '',
|
|
5098
|
+
disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
|
|
5099
|
+
});
|
|
4378
5100
|
}
|
|
4379
5101
|
}
|
|
4380
5102
|
}
|
|
@@ -4384,10 +5106,6 @@ class CreateApp {
|
|
|
4384
5106
|
*/
|
|
4385
5107
|
onLoadError(e) {
|
|
4386
5108
|
this.loadSourceLevel = -1;
|
|
4387
|
-
if (this.prefetchResolve) {
|
|
4388
|
-
this.prefetchResolve();
|
|
4389
|
-
this.prefetchResolve = null;
|
|
4390
|
-
}
|
|
4391
5109
|
if (appStates.UNMOUNT !== this.state) {
|
|
4392
5110
|
this.onerror(e);
|
|
4393
5111
|
this.state = appStates.LOAD_FAILED;
|
|
@@ -4396,33 +5114,98 @@ class CreateApp {
|
|
|
4396
5114
|
/**
|
|
4397
5115
|
* mount app
|
|
4398
5116
|
* @param container app container
|
|
4399
|
-
* @param inline js
|
|
5117
|
+
* @param inline run js in inline mode
|
|
5118
|
+
* @param useMemoryRouter use virtual router
|
|
5119
|
+
* @param defaultPage default page of virtual router
|
|
4400
5120
|
* @param baseroute route prefix, default is ''
|
|
4401
|
-
* @param keepRouteState keep route state when unmount, default is false
|
|
4402
5121
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
5122
|
+
* @param fiber run js in fiber mode
|
|
5123
|
+
* @param esmodule support type='module' script
|
|
4403
5124
|
*/
|
|
4404
|
-
mount(container, inline, baseroute,
|
|
4405
|
-
var _a, _b, _c;
|
|
4406
|
-
this.inline = inline !== null && inline !== void 0 ? inline : this.inline;
|
|
4407
|
-
this.keepRouteState = keepRouteState !== null && keepRouteState !== void 0 ? keepRouteState : this.keepRouteState;
|
|
4408
|
-
this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
|
|
4409
|
-
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
|
|
4410
|
-
this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : this.defaultPage;
|
|
4411
|
-
this.hiddenRouter = hiddenRouter !== null && hiddenRouter !== void 0 ? hiddenRouter : this.hiddenRouter;
|
|
4412
|
-
this.disablePatchRequest = disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : this.disablePatchRequest;
|
|
5125
|
+
mount({ container, inline, useMemoryRouter, defaultPage, baseroute, disablePatchRequest, fiber, esmodule, }) {
|
|
5126
|
+
var _a, _b, _c, _d, _e, _f;
|
|
4413
5127
|
if (this.loadSourceLevel !== 2) {
|
|
5128
|
+
/**
|
|
5129
|
+
* unmount prefetch app when loading source, when mount again before loading end,
|
|
5130
|
+
* isPrefetch & isPrerender will be reset, and this.container sill be null
|
|
5131
|
+
* so we should set this.container
|
|
5132
|
+
*/
|
|
5133
|
+
this.container = container;
|
|
5134
|
+
// mount before prerender exec mount (loading source), set isPrerender to false
|
|
5135
|
+
this.isPrerender = false;
|
|
5136
|
+
// reset app state to LOADING
|
|
4414
5137
|
this.state = appStates.LOADING;
|
|
4415
5138
|
return;
|
|
4416
5139
|
}
|
|
4417
|
-
|
|
5140
|
+
/**
|
|
5141
|
+
* Mount app with prerender, this.container is empty
|
|
5142
|
+
* When rendering again, identify prerender by this.container
|
|
5143
|
+
* Transfer the contents of div to the <micro-app> tag
|
|
5144
|
+
*
|
|
5145
|
+
* Special scenes:
|
|
5146
|
+
* 1. mount before prerender exec mount (loading source)
|
|
5147
|
+
* 2. mount when prerender js executing
|
|
5148
|
+
* 3. mount after prerender js exec end
|
|
5149
|
+
*
|
|
5150
|
+
* TODO: test shadowDOM
|
|
5151
|
+
*/
|
|
5152
|
+
if (this.container instanceof HTMLDivElement &&
|
|
5153
|
+
this.container.hasAttribute('prerender')) {
|
|
5154
|
+
/**
|
|
5155
|
+
* rebuild effect event of window, document, data center
|
|
5156
|
+
* explain:
|
|
5157
|
+
* 1. rebuild before exec mount, do nothing
|
|
5158
|
+
* 2. rebuild when js executing, recovery recorded effect event, because prerender fiber mode
|
|
5159
|
+
* 3. rebuild after js exec end, normal recovery effect event
|
|
5160
|
+
*/
|
|
5161
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
5162
|
+
// current this.container is <div prerender='true'></div>
|
|
5163
|
+
cloneContainer(this.container, container, false);
|
|
5164
|
+
/**
|
|
5165
|
+
* set this.container to <micro-app></micro-app>
|
|
5166
|
+
* NOTE:
|
|
5167
|
+
* must before exec this.preRenderEvent?.forEach((cb) => cb())
|
|
5168
|
+
*/
|
|
5169
|
+
this.container = container;
|
|
5170
|
+
(_b = this.preRenderEvent) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
|
|
5171
|
+
// reset isPrerender config
|
|
5172
|
+
this.isPrerender = false;
|
|
5173
|
+
this.preRenderEvent = undefined;
|
|
5174
|
+
// attach router info to browser url
|
|
5175
|
+
router.attachToURL(this.name);
|
|
5176
|
+
return (_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.setPreRenderState(false);
|
|
5177
|
+
}
|
|
5178
|
+
this.container = container;
|
|
5179
|
+
this.inline = inline;
|
|
5180
|
+
this.esmodule = esmodule;
|
|
5181
|
+
this.fiber = fiber;
|
|
5182
|
+
// use in sandbox/effect
|
|
5183
|
+
this.useMemoryRouter = useMemoryRouter;
|
|
5184
|
+
// this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
|
|
5185
|
+
const dispatchBeforeMount = () => {
|
|
5186
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
5187
|
+
};
|
|
5188
|
+
if (this.isPrerender) {
|
|
5189
|
+
((_d = this.preRenderEvent) !== null && _d !== void 0 ? _d : (this.preRenderEvent = [])).push(dispatchBeforeMount);
|
|
5190
|
+
}
|
|
5191
|
+
else {
|
|
5192
|
+
dispatchBeforeMount();
|
|
5193
|
+
}
|
|
4418
5194
|
this.state = appStates.MOUNTING;
|
|
4419
5195
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
4420
|
-
(
|
|
5196
|
+
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
5197
|
+
umdMode: this.umdMode,
|
|
5198
|
+
baseroute,
|
|
5199
|
+
useMemoryRouter,
|
|
5200
|
+
defaultPage,
|
|
5201
|
+
disablePatchRequest,
|
|
5202
|
+
});
|
|
4421
5203
|
let umdHookMountResult; // result of mount function
|
|
4422
5204
|
if (!this.umdMode) {
|
|
4423
5205
|
let hasDispatchMountedEvent = false;
|
|
4424
5206
|
// if all js are executed, param isFinished will be true
|
|
4425
|
-
execScripts(this
|
|
5207
|
+
execScripts(this, (isFinished) => {
|
|
5208
|
+
var _a;
|
|
4426
5209
|
if (!this.umdMode) {
|
|
4427
5210
|
const { mount, unmount } = this.getUmdLibraryHooks();
|
|
4428
5211
|
/**
|
|
@@ -4436,9 +5219,9 @@ class CreateApp {
|
|
|
4436
5219
|
this.umdMode = true;
|
|
4437
5220
|
if (this.sandBox)
|
|
4438
5221
|
this.sandBox.proxyWindow.__MICRO_APP_UMD_MODE__ = true;
|
|
4439
|
-
// this.sandBox?.
|
|
5222
|
+
// this.sandBox?.recordEffectSnapshot()
|
|
4440
5223
|
try {
|
|
4441
|
-
umdHookMountResult = this.umdHookMount();
|
|
5224
|
+
umdHookMountResult = this.umdHookMount(microApp.getData(this.name, true));
|
|
4442
5225
|
}
|
|
4443
5226
|
catch (e) {
|
|
4444
5227
|
logError('an error occurred in the mount function \n', this.name, e);
|
|
@@ -4447,12 +5230,19 @@ class CreateApp {
|
|
|
4447
5230
|
}
|
|
4448
5231
|
if (!hasDispatchMountedEvent && (isFinished === true || this.umdMode)) {
|
|
4449
5232
|
hasDispatchMountedEvent = true;
|
|
4450
|
-
this.handleMounted(umdHookMountResult);
|
|
5233
|
+
const dispatchMounted = () => this.handleMounted(umdHookMountResult);
|
|
5234
|
+
if (this.isPrerender) {
|
|
5235
|
+
((_a = this.preRenderEvent) !== null && _a !== void 0 ? _a : (this.preRenderEvent = [])).push(dispatchMounted);
|
|
5236
|
+
this.recordAndReleaseEffect();
|
|
5237
|
+
}
|
|
5238
|
+
else {
|
|
5239
|
+
dispatchMounted();
|
|
5240
|
+
}
|
|
4451
5241
|
}
|
|
4452
5242
|
});
|
|
4453
5243
|
}
|
|
4454
5244
|
else {
|
|
4455
|
-
(
|
|
5245
|
+
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.rebuildEffectSnapshot();
|
|
4456
5246
|
try {
|
|
4457
5247
|
umdHookMountResult = this.umdHookMount();
|
|
4458
5248
|
}
|
|
@@ -4482,6 +5272,9 @@ class CreateApp {
|
|
|
4482
5272
|
dispatchMountedEvent() {
|
|
4483
5273
|
if (appStates.UNMOUNT !== this.state) {
|
|
4484
5274
|
this.state = appStates.MOUNTED;
|
|
5275
|
+
// call window.onmount of child app
|
|
5276
|
+
callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONMOUNT), this.name, `window.${microGlobalEvent.ONMOUNT}`, microApp.getData(this.name, true));
|
|
5277
|
+
// dispatch event mounted to parent
|
|
4485
5278
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
4486
5279
|
}
|
|
4487
5280
|
}
|
|
@@ -4489,9 +5282,11 @@ class CreateApp {
|
|
|
4489
5282
|
* unmount app
|
|
4490
5283
|
* NOTE: Do not add any params on account of unmountApp
|
|
4491
5284
|
* @param destroy completely destroy, delete cache resources
|
|
5285
|
+
* @param clearData clear data of dateCenter
|
|
5286
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
4492
5287
|
* @param unmountcb callback of unmount
|
|
4493
5288
|
*/
|
|
4494
|
-
unmount(destroy, unmountcb) {
|
|
5289
|
+
unmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
4495
5290
|
if (this.state === appStates.LOAD_FAILED) {
|
|
4496
5291
|
destroy = true;
|
|
4497
5292
|
}
|
|
@@ -4506,38 +5301,50 @@ class CreateApp {
|
|
|
4506
5301
|
*/
|
|
4507
5302
|
if (isFunction(this.umdHookUnmount)) {
|
|
4508
5303
|
try {
|
|
4509
|
-
umdHookUnmountResult = this.umdHookUnmount();
|
|
5304
|
+
umdHookUnmountResult = this.umdHookUnmount(microApp.getData(this.name, true));
|
|
4510
5305
|
}
|
|
4511
5306
|
catch (e) {
|
|
4512
5307
|
logError('an error occurred in the unmount function \n', this.name, e);
|
|
4513
5308
|
}
|
|
4514
5309
|
}
|
|
5310
|
+
// call window.onunmount of child app
|
|
5311
|
+
callFnWithTryCatch(this.getGlobalEventListener(microGlobalEvent.ONUNMOUNT), this.name, `window.${microGlobalEvent.ONUNMOUNT}`);
|
|
4515
5312
|
// dispatch unmount event to micro app
|
|
4516
5313
|
dispatchCustomEventToMicroApp('unmount', this.name);
|
|
4517
|
-
this.handleUnmounted(destroy, umdHookUnmountResult, unmountcb);
|
|
5314
|
+
this.handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb);
|
|
4518
5315
|
}
|
|
4519
5316
|
/**
|
|
4520
5317
|
* handle for promise umdHookUnmount
|
|
4521
5318
|
* @param destroy completely destroy, delete cache resources
|
|
5319
|
+
* @param clearData clear data of dateCenter
|
|
5320
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
4522
5321
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
4523
5322
|
* @param unmountcb callback of unmount
|
|
4524
5323
|
*/
|
|
4525
|
-
handleUnmounted(destroy, umdHookUnmountResult, unmountcb) {
|
|
5324
|
+
handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult, unmountcb) {
|
|
5325
|
+
const unmountParam = {
|
|
5326
|
+
destroy,
|
|
5327
|
+
clearData,
|
|
5328
|
+
keepRouteState,
|
|
5329
|
+
unmountcb,
|
|
5330
|
+
};
|
|
4526
5331
|
if (isPromise(umdHookUnmountResult)) {
|
|
4527
5332
|
umdHookUnmountResult
|
|
4528
|
-
.then(() => this.actionsForUnmount(
|
|
4529
|
-
.catch(() => this.actionsForUnmount(
|
|
5333
|
+
.then(() => this.actionsForUnmount(unmountParam))
|
|
5334
|
+
.catch(() => this.actionsForUnmount(unmountParam));
|
|
4530
5335
|
}
|
|
4531
5336
|
else {
|
|
4532
|
-
this.actionsForUnmount(
|
|
5337
|
+
this.actionsForUnmount(unmountParam);
|
|
4533
5338
|
}
|
|
4534
5339
|
}
|
|
4535
5340
|
/**
|
|
4536
5341
|
* actions for unmount app
|
|
4537
5342
|
* @param destroy completely destroy, delete cache resources
|
|
5343
|
+
* @param clearData clear data of dateCenter
|
|
5344
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
4538
5345
|
* @param unmountcb callback of unmount
|
|
4539
5346
|
*/
|
|
4540
|
-
actionsForUnmount(destroy, unmountcb) {
|
|
5347
|
+
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
|
|
4541
5348
|
var _a, _b;
|
|
4542
5349
|
if (destroy) {
|
|
4543
5350
|
this.actionsForCompletelyDestroy();
|
|
@@ -4546,7 +5353,7 @@ class CreateApp {
|
|
|
4546
5353
|
cloneContainer(this.container, this.source.html, false);
|
|
4547
5354
|
}
|
|
4548
5355
|
if (this.umdMode) {
|
|
4549
|
-
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.
|
|
5356
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
|
|
4550
5357
|
}
|
|
4551
5358
|
/**
|
|
4552
5359
|
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
@@ -4554,25 +5361,36 @@ class CreateApp {
|
|
|
4554
5361
|
* 1. if destroy is true, clear route state
|
|
4555
5362
|
* 2. umd mode and keep-alive will not clear EventSource
|
|
4556
5363
|
*/
|
|
4557
|
-
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop(
|
|
5364
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop({
|
|
5365
|
+
umdMode: this.umdMode,
|
|
5366
|
+
keepRouteState: keepRouteState && !destroy,
|
|
5367
|
+
clearEventSource: !this.umdMode || destroy,
|
|
5368
|
+
clearData: clearData || destroy,
|
|
5369
|
+
});
|
|
4558
5370
|
if (!getActiveApps().length) {
|
|
4559
5371
|
releasePatchSetAttribute();
|
|
4560
5372
|
}
|
|
4561
5373
|
// dispatch unmount event to base app
|
|
4562
5374
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
5375
|
+
this.resetConfig();
|
|
5376
|
+
unmountcb && unmountcb();
|
|
5377
|
+
}
|
|
5378
|
+
resetConfig() {
|
|
4563
5379
|
this.container.innerHTML = '';
|
|
4564
5380
|
this.container = null;
|
|
4565
|
-
|
|
5381
|
+
this.isPrerender = false;
|
|
5382
|
+
this.preRenderEvent = undefined;
|
|
4566
5383
|
}
|
|
4567
5384
|
// actions for completely destroy
|
|
4568
5385
|
actionsForCompletelyDestroy() {
|
|
4569
5386
|
if (!this.useSandbox && this.umdMode) {
|
|
4570
5387
|
delete window[this.libraryName];
|
|
4571
5388
|
}
|
|
5389
|
+
sourceCenter.script.deleteInlineInfo(this.source.scripts);
|
|
4572
5390
|
appInstanceMap.delete(this.name);
|
|
4573
5391
|
}
|
|
4574
5392
|
// hidden app when disconnectedCallback called with keep-alive
|
|
4575
|
-
hiddenKeepAliveApp() {
|
|
5393
|
+
hiddenKeepAliveApp(callback) {
|
|
4576
5394
|
var _a;
|
|
4577
5395
|
const oldContainer = this.container;
|
|
4578
5396
|
cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
|
|
@@ -4587,10 +5405,13 @@ class CreateApp {
|
|
|
4587
5405
|
dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
|
|
4588
5406
|
// called after lifeCyclesEvent
|
|
4589
5407
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
5408
|
+
this.recordAndReleaseEffect();
|
|
5409
|
+
callback && callback();
|
|
4590
5410
|
}
|
|
4591
5411
|
// show app when connectedCallback called with keep-alive
|
|
4592
5412
|
showKeepAliveApp(container) {
|
|
4593
|
-
var _a;
|
|
5413
|
+
var _a, _b;
|
|
5414
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
4594
5415
|
// dispatch beforeShow event to micro-app
|
|
4595
5416
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
4596
5417
|
appState: 'beforeshow',
|
|
@@ -4601,7 +5422,7 @@ class CreateApp {
|
|
|
4601
5422
|
this.container = container;
|
|
4602
5423
|
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
4603
5424
|
// called before lifeCyclesEvent
|
|
4604
|
-
(
|
|
5425
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
|
|
4605
5426
|
// dispatch afterShow event to micro-app
|
|
4606
5427
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
4607
5428
|
appState: 'aftershow',
|
|
@@ -4641,6 +5462,23 @@ class CreateApp {
|
|
|
4641
5462
|
}
|
|
4642
5463
|
return {};
|
|
4643
5464
|
}
|
|
5465
|
+
getGlobalEventListener(eventName) {
|
|
5466
|
+
var _a;
|
|
5467
|
+
// @ts-ignore
|
|
5468
|
+
const listener = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow[eventName];
|
|
5469
|
+
return isFunction(listener) ? listener : null;
|
|
5470
|
+
}
|
|
5471
|
+
/**
|
|
5472
|
+
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
5473
|
+
* Scenes:
|
|
5474
|
+
* 1. hidden keep-alive app
|
|
5475
|
+
* 2. after init prerender app
|
|
5476
|
+
*/
|
|
5477
|
+
recordAndReleaseEffect() {
|
|
5478
|
+
var _a, _b;
|
|
5479
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordEffectSnapshot();
|
|
5480
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.releaseGlobalEffect();
|
|
5481
|
+
}
|
|
4644
5482
|
}
|
|
4645
5483
|
|
|
4646
5484
|
/**
|
|
@@ -4653,7 +5491,8 @@ function defineElement(tagName) {
|
|
|
4653
5491
|
super();
|
|
4654
5492
|
this.isWaiting = false;
|
|
4655
5493
|
this.cacheData = null;
|
|
4656
|
-
this.
|
|
5494
|
+
this.connectedCount = 0;
|
|
5495
|
+
this.connectStateMap = new Map();
|
|
4657
5496
|
this.appName = ''; // app name
|
|
4658
5497
|
this.appUrl = ''; // app url
|
|
4659
5498
|
this.ssrUrl = ''; // html path in ssr mode
|
|
@@ -4663,6 +5502,8 @@ function defineElement(tagName) {
|
|
|
4663
5502
|
*/
|
|
4664
5503
|
this.handleAttributeUpdate = () => {
|
|
4665
5504
|
this.isWaiting = false;
|
|
5505
|
+
if (!this.connectStateMap.get(this.connectedCount))
|
|
5506
|
+
return;
|
|
4666
5507
|
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
4667
5508
|
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
4668
5509
|
if (this.legalAttribute('name', formatAttrName) && this.legalAttribute('url', formatAttrUrl)) {
|
|
@@ -4673,7 +5514,7 @@ function defineElement(tagName) {
|
|
|
4673
5514
|
keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
|
|
4674
5515
|
!existApp.isPrefetch) {
|
|
4675
5516
|
this.setAttribute('name', this.appName);
|
|
4676
|
-
return logError(`app name conflict, an app named ${formatAttrName} is running
|
|
5517
|
+
return logError(`app name conflict, an app named ${formatAttrName} is running`);
|
|
4677
5518
|
}
|
|
4678
5519
|
}
|
|
4679
5520
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
@@ -4714,22 +5555,56 @@ function defineElement(tagName) {
|
|
|
4714
5555
|
// baseRoute: route prefix, default is ''
|
|
4715
5556
|
// keep-alive: open keep-alive mode
|
|
4716
5557
|
connectedCallback() {
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
5558
|
+
const cacheCount = ++this.connectedCount;
|
|
5559
|
+
this.connectStateMap.set(cacheCount, true);
|
|
5560
|
+
/**
|
|
5561
|
+
* In some special scenes, such as vue's keep-alive, the micro-app will be inserted and deleted twice in an instant
|
|
5562
|
+
* So we execute the mount method async and record connectState to prevent repeated rendering
|
|
5563
|
+
*/
|
|
5564
|
+
defer(() => {
|
|
5565
|
+
if (this.connectStateMap.get(cacheCount)) {
|
|
5566
|
+
dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED);
|
|
5567
|
+
this.handleConnected();
|
|
5568
|
+
}
|
|
5569
|
+
});
|
|
4720
5570
|
}
|
|
4721
5571
|
disconnectedCallback() {
|
|
4722
|
-
this.
|
|
5572
|
+
this.connectStateMap.set(this.connectedCount, false);
|
|
5573
|
+
this.handleDisconnected();
|
|
5574
|
+
}
|
|
5575
|
+
/**
|
|
5576
|
+
* Re render app from the command line
|
|
5577
|
+
* MicroAppElement.reload(destroy)
|
|
5578
|
+
*/
|
|
5579
|
+
reload(destroy) {
|
|
5580
|
+
return new Promise((resolve) => {
|
|
5581
|
+
const handleAfterReload = () => {
|
|
5582
|
+
this.removeEventListener(lifeCycles.MOUNTED, handleAfterReload);
|
|
5583
|
+
this.removeEventListener(lifeCycles.AFTERSHOW, handleAfterReload);
|
|
5584
|
+
resolve(true);
|
|
5585
|
+
};
|
|
5586
|
+
this.addEventListener(lifeCycles.MOUNTED, handleAfterReload);
|
|
5587
|
+
this.addEventListener(lifeCycles.AFTERSHOW, handleAfterReload);
|
|
5588
|
+
this.handleDisconnected(destroy, () => {
|
|
5589
|
+
this.handleConnected();
|
|
5590
|
+
});
|
|
5591
|
+
});
|
|
5592
|
+
}
|
|
5593
|
+
/**
|
|
5594
|
+
* common action for unmount
|
|
5595
|
+
* @param destroy reload param
|
|
5596
|
+
*/
|
|
5597
|
+
handleDisconnected(destroy = false, callback) {
|
|
4723
5598
|
const app = appInstanceMap.get(this.appName);
|
|
4724
5599
|
if (app &&
|
|
4725
5600
|
app.getAppState() !== appStates.UNMOUNT &&
|
|
4726
5601
|
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
4727
5602
|
// keep-alive
|
|
4728
|
-
if (this.getKeepAliveModeResult()) {
|
|
4729
|
-
this.handleHiddenKeepAliveApp();
|
|
5603
|
+
if (this.getKeepAliveModeResult() && !destroy) {
|
|
5604
|
+
this.handleHiddenKeepAliveApp(callback);
|
|
4730
5605
|
}
|
|
4731
5606
|
else {
|
|
4732
|
-
this.handleUnmount(this.getDestroyCompatibleResult());
|
|
5607
|
+
this.handleUnmount(destroy || this.getDestroyCompatibleResult(), callback);
|
|
4733
5608
|
}
|
|
4734
5609
|
}
|
|
4735
5610
|
}
|
|
@@ -4767,12 +5642,12 @@ function defineElement(tagName) {
|
|
|
4767
5642
|
}
|
|
4768
5643
|
// handle for connectedCallback run before attributeChangedCallback
|
|
4769
5644
|
handleInitialNameAndUrl() {
|
|
4770
|
-
this.
|
|
5645
|
+
this.connectStateMap.get(this.connectedCount) && this.handleConnected();
|
|
4771
5646
|
}
|
|
4772
5647
|
/**
|
|
4773
5648
|
* first mount of this app
|
|
4774
5649
|
*/
|
|
4775
|
-
|
|
5650
|
+
handleConnected() {
|
|
4776
5651
|
if (!this.appName || !this.appUrl)
|
|
4777
5652
|
return;
|
|
4778
5653
|
if (this.getDisposeResult('shadowDOM') && !this.shadowRoot && isFunction(this.attachShadow)) {
|
|
@@ -4782,26 +5657,35 @@ function defineElement(tagName) {
|
|
|
4782
5657
|
if (appInstanceMap.has(this.appName)) {
|
|
4783
5658
|
const app = appInstanceMap.get(this.appName);
|
|
4784
5659
|
const existAppUrl = app.ssrUrl || app.url;
|
|
4785
|
-
const
|
|
4786
|
-
|
|
4787
|
-
|
|
5660
|
+
const targetAppUrl = this.ssrUrl || this.appUrl;
|
|
5661
|
+
/**
|
|
5662
|
+
* NOTE:
|
|
5663
|
+
* 1. keep-alive don't care about ssrUrl
|
|
5664
|
+
* 2. Even if the keep-alive app is pushed into the background, it is still active and cannot be replaced. Otherwise, it is difficult for developers to troubleshoot in case of conflict and will leave developers at a loss
|
|
5665
|
+
* 3. When scopecss, useSandbox of prefetch app different from target app, delete prefetch app and create new one
|
|
5666
|
+
*/
|
|
4788
5667
|
if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
4789
5668
|
app.url === this.appUrl) {
|
|
4790
5669
|
this.handleShowKeepAliveApp(app);
|
|
4791
5670
|
}
|
|
4792
|
-
else if (existAppUrl ===
|
|
4793
|
-
app.
|
|
5671
|
+
else if (existAppUrl === targetAppUrl && (app.getAppState() === appStates.UNMOUNT ||
|
|
5672
|
+
(app.isPrefetch && (app.scopecss === this.isScopecss() &&
|
|
5673
|
+
app.useSandbox === this.isSandbox())))) {
|
|
4794
5674
|
this.handleAppMount(app);
|
|
4795
5675
|
}
|
|
4796
5676
|
else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
5677
|
+
if ((process.env.NODE_ENV !== 'production') &&
|
|
5678
|
+
app.scopecss === this.isScopecss() &&
|
|
5679
|
+
app.useSandbox === this.isSandbox()) {
|
|
5680
|
+
/**
|
|
5681
|
+
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
5682
|
+
*/
|
|
5683
|
+
logWarn(`the ${app.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${existAppUrl} replaced by a new app with url: ${targetAppUrl}`, this.appName);
|
|
5684
|
+
}
|
|
4801
5685
|
this.handleCreateApp();
|
|
4802
5686
|
}
|
|
4803
5687
|
else {
|
|
4804
|
-
logError(`app name conflict, an app named ${this.appName} is running
|
|
5688
|
+
logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running`);
|
|
4805
5689
|
}
|
|
4806
5690
|
}
|
|
4807
5691
|
else {
|
|
@@ -4836,7 +5720,7 @@ function defineElement(tagName) {
|
|
|
4836
5720
|
}
|
|
4837
5721
|
else {
|
|
4838
5722
|
// the hidden keep-alive app is still active
|
|
4839
|
-
logError(`app name conflict, an app named ${this.appName} is running
|
|
5723
|
+
logError(`app name conflict, an app named ${this.appName} is running`);
|
|
4840
5724
|
}
|
|
4841
5725
|
}
|
|
4842
5726
|
else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
|
|
@@ -4863,20 +5747,6 @@ function defineElement(tagName) {
|
|
|
4863
5747
|
}
|
|
4864
5748
|
return true;
|
|
4865
5749
|
}
|
|
4866
|
-
/**
|
|
4867
|
-
* mount app
|
|
4868
|
-
* some serious note before mount:
|
|
4869
|
-
* 1. is prefetch ?
|
|
4870
|
-
* 2. is remount in another container ?
|
|
4871
|
-
* 3. is remount with change properties of the container ?
|
|
4872
|
-
*/
|
|
4873
|
-
handleAppMount(app) {
|
|
4874
|
-
app.isPrefetch = false;
|
|
4875
|
-
defer(() => {
|
|
4876
|
-
var _a;
|
|
4877
|
-
return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible(), this.getDisposeResult('keep-router-state'), this.getDefaultPageValue(), this.getDisposeResult('hidden-router'), this.getDisposeResult('disable-patch-request'));
|
|
4878
|
-
});
|
|
4879
|
-
}
|
|
4880
5750
|
// create app instance
|
|
4881
5751
|
handleCreateApp() {
|
|
4882
5752
|
var _a;
|
|
@@ -4887,41 +5757,68 @@ function defineElement(tagName) {
|
|
|
4887
5757
|
if (appInstanceMap.has(this.appName)) {
|
|
4888
5758
|
appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
|
|
4889
5759
|
}
|
|
4890
|
-
|
|
5760
|
+
new CreateApp({
|
|
4891
5761
|
name: this.appName,
|
|
4892
5762
|
url: this.appUrl,
|
|
5763
|
+
scopecss: this.isScopecss(),
|
|
5764
|
+
useSandbox: this.isSandbox(),
|
|
5765
|
+
inline: this.getDisposeResult('inline'),
|
|
5766
|
+
esmodule: this.getDisposeResult('esmodule'),
|
|
5767
|
+
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
4893
5768
|
ssrUrl: this.ssrUrl,
|
|
5769
|
+
});
|
|
5770
|
+
}
|
|
5771
|
+
/**
|
|
5772
|
+
* mount app
|
|
5773
|
+
* some serious note before mount:
|
|
5774
|
+
* 1. is prefetch ?
|
|
5775
|
+
* 2. is remount in another container ?
|
|
5776
|
+
* 3. is remount with change properties of the container ?
|
|
5777
|
+
*/
|
|
5778
|
+
handleAppMount(app) {
|
|
5779
|
+
app.isPrefetch = false;
|
|
5780
|
+
defer(() => this.mount(app));
|
|
5781
|
+
}
|
|
5782
|
+
/**
|
|
5783
|
+
* public mount action for micro_app_element & create_app
|
|
5784
|
+
*/
|
|
5785
|
+
mount(app) {
|
|
5786
|
+
var _a;
|
|
5787
|
+
app.mount({
|
|
4894
5788
|
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
4895
5789
|
inline: this.getDisposeResult('inline'),
|
|
4896
|
-
scopecss: !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM')),
|
|
4897
|
-
useSandbox: !this.getDisposeResult('disable-sandbox'),
|
|
4898
5790
|
useMemoryRouter: !this.getDisposeResult('disable-memory-router'),
|
|
4899
|
-
baseroute: this.getBaseRouteCompatible(),
|
|
4900
|
-
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
4901
5791
|
defaultPage: this.getDefaultPageValue(),
|
|
4902
|
-
|
|
5792
|
+
baseroute: this.getBaseRouteCompatible(),
|
|
4903
5793
|
disablePatchRequest: this.getDisposeResult('disable-patch-request'),
|
|
5794
|
+
fiber: this.getDisposeResult('fiber'),
|
|
5795
|
+
esmodule: this.getDisposeResult('esmodule'),
|
|
4904
5796
|
});
|
|
4905
|
-
appInstanceMap.set(this.appName, instance);
|
|
4906
5797
|
}
|
|
4907
5798
|
/**
|
|
4908
5799
|
* unmount app
|
|
4909
5800
|
* @param destroy delete cache resources when unmount
|
|
4910
5801
|
*/
|
|
4911
|
-
handleUnmount(destroy,
|
|
5802
|
+
handleUnmount(destroy, unmountcb) {
|
|
4912
5803
|
const app = appInstanceMap.get(this.appName);
|
|
4913
5804
|
if (app &&
|
|
4914
5805
|
app.getAppState() !== appStates.UNMOUNT) {
|
|
4915
|
-
app.unmount(
|
|
5806
|
+
app.unmount({
|
|
5807
|
+
destroy,
|
|
5808
|
+
clearData: this.getDisposeResult('clear-data'),
|
|
5809
|
+
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
5810
|
+
unmountcb,
|
|
5811
|
+
});
|
|
4916
5812
|
}
|
|
4917
5813
|
}
|
|
4918
5814
|
// hidden app when disconnectedCallback called with keep-alive
|
|
4919
|
-
handleHiddenKeepAliveApp() {
|
|
5815
|
+
handleHiddenKeepAliveApp(callback) {
|
|
4920
5816
|
const app = appInstanceMap.get(this.appName);
|
|
4921
5817
|
if (app &&
|
|
4922
5818
|
app.getAppState() !== appStates.UNMOUNT &&
|
|
4923
|
-
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN)
|
|
4924
|
-
app.hiddenKeepAliveApp();
|
|
5819
|
+
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
5820
|
+
app.hiddenKeepAliveApp(callback);
|
|
5821
|
+
}
|
|
4925
5822
|
}
|
|
4926
5823
|
// show app when connectedCallback called with keep-alive
|
|
4927
5824
|
handleShowKeepAliveApp(app) {
|
|
@@ -4934,8 +5831,7 @@ function defineElement(tagName) {
|
|
|
4934
5831
|
* @param name Configuration item name
|
|
4935
5832
|
*/
|
|
4936
5833
|
getDisposeResult(name) {
|
|
4937
|
-
|
|
4938
|
-
return (this.compatibleSpecialProperties(name) || !!microApp[name]) && this.compatibleDisableSpecialProperties(name);
|
|
5834
|
+
return (this.compatibleSpecialProperties(name) || !!microApp.options[name]) && this.compatibleDisableSpecialProperties(name);
|
|
4939
5835
|
}
|
|
4940
5836
|
// compatible of disableScopecss & disableSandbox
|
|
4941
5837
|
compatibleSpecialProperties(name) {
|
|
@@ -4957,6 +5853,12 @@ function defineElement(tagName) {
|
|
|
4957
5853
|
}
|
|
4958
5854
|
return this.getAttribute(name) !== 'false';
|
|
4959
5855
|
}
|
|
5856
|
+
isScopecss() {
|
|
5857
|
+
return !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM'));
|
|
5858
|
+
}
|
|
5859
|
+
isSandbox() {
|
|
5860
|
+
return !this.getDisposeResult('disable-sandbox');
|
|
5861
|
+
}
|
|
4960
5862
|
/**
|
|
4961
5863
|
* 2021-09-08
|
|
4962
5864
|
* get baseRoute
|
|
@@ -5004,8 +5906,10 @@ function defineElement(tagName) {
|
|
|
5004
5906
|
* get config of default page
|
|
5005
5907
|
*/
|
|
5006
5908
|
getDefaultPageValue() {
|
|
5007
|
-
|
|
5008
|
-
|
|
5909
|
+
return (router.getDefaultPage(this.appName) ||
|
|
5910
|
+
this.getAttribute('default-page') ||
|
|
5911
|
+
this.getAttribute('defaultPage') ||
|
|
5912
|
+
'');
|
|
5009
5913
|
}
|
|
5010
5914
|
/**
|
|
5011
5915
|
* Data from the base application
|
|
@@ -5031,7 +5935,7 @@ function defineElement(tagName) {
|
|
|
5031
5935
|
return null;
|
|
5032
5936
|
}
|
|
5033
5937
|
}
|
|
5034
|
-
|
|
5938
|
+
globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
|
|
5035
5939
|
}
|
|
5036
5940
|
|
|
5037
5941
|
/**
|
|
@@ -5050,45 +5954,71 @@ function defineElement(tagName) {
|
|
|
5050
5954
|
* 2: disableScopecss, disableSandbox, disableMemoryRouter must be same with micro-app element, if conflict, the one who executes first shall prevail
|
|
5051
5955
|
* @param apps micro apps
|
|
5052
5956
|
*/
|
|
5053
|
-
function preFetch(apps) {
|
|
5957
|
+
function preFetch(apps, delay) {
|
|
5054
5958
|
if (!isBrowser) {
|
|
5055
5959
|
return logError('preFetch is only supported in browser environment');
|
|
5056
5960
|
}
|
|
5057
5961
|
requestIdleCallback(() => {
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5962
|
+
const delayTime = delay !== null && delay !== void 0 ? delay : microApp.options.prefetchDelay;
|
|
5963
|
+
setTimeout(() => {
|
|
5964
|
+
// releasePrefetchEffect()
|
|
5965
|
+
preFetchInSerial(apps);
|
|
5966
|
+
}, isNumber(delayTime) ? delayTime : 3000);
|
|
5062
5967
|
});
|
|
5968
|
+
// const handleOnLoad = (): void => {
|
|
5969
|
+
// releasePrefetchEffect()
|
|
5970
|
+
// requestIdleCallback(() => {
|
|
5971
|
+
// preFetchInSerial(apps)
|
|
5972
|
+
// })
|
|
5973
|
+
// }
|
|
5974
|
+
// const releasePrefetchEffect = (): void => {
|
|
5975
|
+
// window.removeEventListener('load', handleOnLoad)
|
|
5976
|
+
// clearTimeout(preFetchTime)
|
|
5977
|
+
// }
|
|
5978
|
+
// window.addEventListener('load', handleOnLoad)
|
|
5979
|
+
}
|
|
5980
|
+
function preFetchInSerial(apps) {
|
|
5981
|
+
isFunction(apps) && (apps = apps());
|
|
5982
|
+
if (isArray(apps)) {
|
|
5983
|
+
apps.reduce((pre, next) => pre.then(() => preFetchAction(next)), Promise.resolve());
|
|
5984
|
+
}
|
|
5063
5985
|
}
|
|
5064
5986
|
// sequential preload app
|
|
5065
|
-
function
|
|
5066
|
-
return
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
|
|
5987
|
+
function preFetchAction(options) {
|
|
5988
|
+
return promiseRequestIdle((resolve) => {
|
|
5989
|
+
var _a, _b, _c, _d, _e, _f;
|
|
5990
|
+
if (isPlainObject(options) && navigator.onLine) {
|
|
5991
|
+
options.name = formatAppName(options.name);
|
|
5992
|
+
options.url = formatAppURL(options.url, options.name);
|
|
5993
|
+
if (options.name && options.url && !appInstanceMap.has(options.name)) {
|
|
5994
|
+
const app = new CreateApp({
|
|
5995
|
+
name: options.name,
|
|
5996
|
+
url: options.url,
|
|
5997
|
+
isPrefetch: true,
|
|
5998
|
+
scopecss: !((_b = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss) !== null && _b !== void 0 ? _b : microApp.options['disable-scopecss']),
|
|
5999
|
+
useSandbox: !((_d = (_c = options['disable-sandbox']) !== null && _c !== void 0 ? _c : options.disableSandbox) !== null && _d !== void 0 ? _d : microApp.options['disable-sandbox']),
|
|
6000
|
+
inline: (_e = options.inline) !== null && _e !== void 0 ? _e : microApp.options.inline,
|
|
6001
|
+
esmodule: (_f = options.esmodule) !== null && _f !== void 0 ? _f : microApp.options.esmodule,
|
|
6002
|
+
prefetchLevel: options.level && PREFETCH_LEVEL.includes(options.level) ? options.level : microApp.options.prefetchLevel && PREFETCH_LEVEL.includes(microApp.options.prefetchLevel) ? microApp.options.prefetchLevel : 2,
|
|
6003
|
+
});
|
|
6004
|
+
const oldOnload = app.onLoad;
|
|
6005
|
+
const oldOnLoadError = app.onLoadError;
|
|
6006
|
+
app.onLoad = (html) => {
|
|
5085
6007
|
resolve();
|
|
5086
|
-
|
|
6008
|
+
oldOnload.call(app, html, options['default-page'], options['disable-patch-request']);
|
|
6009
|
+
};
|
|
6010
|
+
app.onLoadError = (...rests) => {
|
|
6011
|
+
resolve();
|
|
6012
|
+
oldOnLoadError.call(app, ...rests);
|
|
6013
|
+
};
|
|
5087
6014
|
}
|
|
5088
6015
|
else {
|
|
5089
6016
|
resolve();
|
|
5090
6017
|
}
|
|
5091
|
-
}
|
|
6018
|
+
}
|
|
6019
|
+
else {
|
|
6020
|
+
resolve();
|
|
6021
|
+
}
|
|
5092
6022
|
});
|
|
5093
6023
|
}
|
|
5094
6024
|
/**
|
|
@@ -5098,21 +6028,35 @@ function preFetchInSerial(prefetchApp) {
|
|
|
5098
6028
|
function getGlobalAssets(assets) {
|
|
5099
6029
|
if (isPlainObject(assets)) {
|
|
5100
6030
|
requestIdleCallback(() => {
|
|
5101
|
-
fetchGlobalResources(assets.js, 'js',
|
|
5102
|
-
fetchGlobalResources(assets.css, 'css',
|
|
6031
|
+
fetchGlobalResources(assets.js, 'js', sourceCenter.script);
|
|
6032
|
+
fetchGlobalResources(assets.css, 'css', sourceCenter.link);
|
|
5103
6033
|
});
|
|
5104
6034
|
}
|
|
5105
6035
|
}
|
|
5106
6036
|
// TODO: requestIdleCallback for every file
|
|
5107
|
-
function fetchGlobalResources(resources, suffix,
|
|
6037
|
+
function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
5108
6038
|
if (isArray(resources)) {
|
|
5109
|
-
const effectiveResource = resources.filter((path) => isString(path) && path.includes(`.${suffix}`) && !
|
|
6039
|
+
const effectiveResource = resources.filter((path) => isString(path) && path.includes(`.${suffix}`) && !sourceHandler.hasInfo(path));
|
|
5110
6040
|
const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
|
|
5111
6041
|
// fetch resource with stream
|
|
5112
6042
|
promiseStream(fetchResourcePromise, (res) => {
|
|
5113
6043
|
const path = effectiveResource[res.index];
|
|
5114
|
-
if (
|
|
5115
|
-
|
|
6044
|
+
if (suffix === 'js') {
|
|
6045
|
+
if (!sourceHandler.hasInfo(path)) {
|
|
6046
|
+
sourceHandler.setInfo(path, {
|
|
6047
|
+
code: res.data,
|
|
6048
|
+
isExternal: false,
|
|
6049
|
+
appSpace: {},
|
|
6050
|
+
});
|
|
6051
|
+
}
|
|
6052
|
+
}
|
|
6053
|
+
else {
|
|
6054
|
+
if (!sourceHandler.hasInfo(path)) {
|
|
6055
|
+
sourceHandler.setInfo(path, {
|
|
6056
|
+
code: res.data,
|
|
6057
|
+
appSpace: {}
|
|
6058
|
+
});
|
|
6059
|
+
}
|
|
5116
6060
|
}
|
|
5117
6061
|
}, (err) => {
|
|
5118
6062
|
logError(err);
|
|
@@ -5123,13 +6067,14 @@ function fetchGlobalResources(resources, suffix, cache) {
|
|
|
5123
6067
|
/**
|
|
5124
6068
|
* if app not prefetch & not unmount, then app is active
|
|
5125
6069
|
* @param excludeHiddenApp exclude hidden keep-alive app, default is false
|
|
6070
|
+
* @param excludePreRender exclude pre render app
|
|
5126
6071
|
* @returns active apps
|
|
5127
6072
|
*/
|
|
5128
|
-
function getActiveApps(excludeHiddenApp = false) {
|
|
6073
|
+
function getActiveApps({ excludeHiddenApp = false, excludePreRender = false, } = {}) {
|
|
5129
6074
|
const activeApps = [];
|
|
5130
6075
|
appInstanceMap.forEach((app, appName) => {
|
|
5131
6076
|
if (appStates.UNMOUNT !== app.getAppState() &&
|
|
5132
|
-
!app.isPrefetch &&
|
|
6077
|
+
(!app.isPrefetch || (app.isPrerender && !excludePreRender)) &&
|
|
5133
6078
|
(!excludeHiddenApp ||
|
|
5134
6079
|
keepAliveStates.KEEP_ALIVE_HIDDEN !== app.getKeepAliveState())) {
|
|
5135
6080
|
activeApps.push(appName);
|
|
@@ -5155,33 +6100,43 @@ function unmountApp(appName, options) {
|
|
|
5155
6100
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
5156
6101
|
app.actionsForCompletelyDestroy();
|
|
5157
6102
|
}
|
|
5158
|
-
resolve();
|
|
6103
|
+
resolve(true);
|
|
5159
6104
|
}
|
|
5160
6105
|
else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
5161
6106
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
5162
|
-
app.unmount(
|
|
6107
|
+
app.unmount({
|
|
6108
|
+
destroy: true,
|
|
6109
|
+
clearData: true,
|
|
6110
|
+
keepRouteState: true,
|
|
6111
|
+
unmountcb: resolve.bind(null, true)
|
|
6112
|
+
});
|
|
5163
6113
|
}
|
|
5164
6114
|
else if (options === null || options === void 0 ? void 0 : options.clearAliveState) {
|
|
5165
|
-
app.unmount(
|
|
6115
|
+
app.unmount({
|
|
6116
|
+
destroy: false,
|
|
6117
|
+
clearData: !!options.clearData,
|
|
6118
|
+
keepRouteState: true,
|
|
6119
|
+
unmountcb: resolve.bind(null, true)
|
|
6120
|
+
});
|
|
5166
6121
|
}
|
|
5167
6122
|
else {
|
|
5168
|
-
resolve();
|
|
6123
|
+
resolve(true);
|
|
5169
6124
|
}
|
|
5170
6125
|
}
|
|
5171
6126
|
else {
|
|
5172
6127
|
const container = getRootContainer(app.container);
|
|
5173
6128
|
const unmountHandler = () => {
|
|
5174
|
-
container.removeEventListener(
|
|
5175
|
-
container.removeEventListener(
|
|
5176
|
-
resolve();
|
|
6129
|
+
container.removeEventListener(lifeCycles.UNMOUNT, unmountHandler);
|
|
6130
|
+
container.removeEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
|
|
6131
|
+
resolve(true);
|
|
5177
6132
|
};
|
|
5178
6133
|
const afterhiddenHandler = () => {
|
|
5179
|
-
container.removeEventListener(
|
|
5180
|
-
container.removeEventListener(
|
|
5181
|
-
resolve();
|
|
6134
|
+
container.removeEventListener(lifeCycles.UNMOUNT, unmountHandler);
|
|
6135
|
+
container.removeEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
|
|
6136
|
+
resolve(true);
|
|
5182
6137
|
};
|
|
5183
|
-
container.addEventListener(
|
|
5184
|
-
container.addEventListener(
|
|
6138
|
+
container.addEventListener(lifeCycles.UNMOUNT, unmountHandler);
|
|
6139
|
+
container.addEventListener(lifeCycles.AFTERHIDDEN, afterhiddenHandler);
|
|
5185
6140
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
5186
6141
|
let destroyAttrValue, destoryAttrValue;
|
|
5187
6142
|
container.hasAttribute('destroy') && (destroyAttrValue = container.getAttribute('destroy'));
|
|
@@ -5189,36 +6144,131 @@ function unmountApp(appName, options) {
|
|
|
5189
6144
|
container.setAttribute('destroy', 'true');
|
|
5190
6145
|
container.parentNode.removeChild(container);
|
|
5191
6146
|
container.removeAttribute('destroy');
|
|
5192
|
-
|
|
5193
|
-
|
|
6147
|
+
isString(destroyAttrValue) && container.setAttribute('destroy', destroyAttrValue);
|
|
6148
|
+
isString(destoryAttrValue) && container.setAttribute('destory', destoryAttrValue);
|
|
5194
6149
|
}
|
|
5195
6150
|
else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
|
|
5196
6151
|
const keepAliveAttrValue = container.getAttribute('keep-alive');
|
|
5197
6152
|
container.removeAttribute('keep-alive');
|
|
6153
|
+
let clearDataAttrValue;
|
|
6154
|
+
if (options.clearData) {
|
|
6155
|
+
clearDataAttrValue = container.getAttribute('clear-data');
|
|
6156
|
+
container.setAttribute('clear-data', 'true');
|
|
6157
|
+
}
|
|
5198
6158
|
container.parentNode.removeChild(container);
|
|
5199
6159
|
container.setAttribute('keep-alive', keepAliveAttrValue);
|
|
6160
|
+
isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
|
|
5200
6161
|
}
|
|
5201
6162
|
else {
|
|
6163
|
+
let clearDataAttrValue;
|
|
6164
|
+
if (options === null || options === void 0 ? void 0 : options.clearData) {
|
|
6165
|
+
clearDataAttrValue = container.getAttribute('clear-data');
|
|
6166
|
+
container.setAttribute('clear-data', 'true');
|
|
6167
|
+
}
|
|
5202
6168
|
container.parentNode.removeChild(container);
|
|
6169
|
+
isString(clearDataAttrValue) && container.setAttribute('clear-data', clearDataAttrValue);
|
|
5203
6170
|
}
|
|
5204
6171
|
}
|
|
5205
6172
|
}
|
|
5206
6173
|
else {
|
|
5207
6174
|
logWarn(`app ${appName} does not exist`);
|
|
5208
|
-
resolve();
|
|
6175
|
+
resolve(false);
|
|
5209
6176
|
}
|
|
5210
6177
|
});
|
|
5211
6178
|
}
|
|
5212
6179
|
// unmount all apps in turn
|
|
5213
6180
|
function unmountAllApps(options) {
|
|
5214
|
-
return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve());
|
|
6181
|
+
return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve(true));
|
|
6182
|
+
}
|
|
6183
|
+
/**
|
|
6184
|
+
* Re render app from the command line
|
|
6185
|
+
* microApp.reload(destroy)
|
|
6186
|
+
* @param appName app.name
|
|
6187
|
+
* @param destroy unmount app with destroy mode
|
|
6188
|
+
* @returns Promise<boolean>
|
|
6189
|
+
*/
|
|
6190
|
+
function reload(appName, destroy) {
|
|
6191
|
+
return new Promise((resolve) => {
|
|
6192
|
+
const app = appInstanceMap.get(formatAppName(appName));
|
|
6193
|
+
if (app) {
|
|
6194
|
+
const rootContainer = app.container && getRootContainer(app.container);
|
|
6195
|
+
if (rootContainer) {
|
|
6196
|
+
resolve(rootContainer.reload(destroy));
|
|
6197
|
+
}
|
|
6198
|
+
else {
|
|
6199
|
+
logWarn(`app ${appName} is not rendered, cannot use reload`);
|
|
6200
|
+
resolve(false);
|
|
6201
|
+
}
|
|
6202
|
+
}
|
|
6203
|
+
else {
|
|
6204
|
+
logWarn(`app ${appName} does not exist`);
|
|
6205
|
+
resolve(false);
|
|
6206
|
+
}
|
|
6207
|
+
});
|
|
6208
|
+
}
|
|
6209
|
+
/**
|
|
6210
|
+
* Manually render app
|
|
6211
|
+
* @param options RenderAppOptions
|
|
6212
|
+
* @returns Promise<boolean>
|
|
6213
|
+
*/
|
|
6214
|
+
function renderApp(options) {
|
|
6215
|
+
return new Promise((resolve) => {
|
|
6216
|
+
if (!isPlainObject(options))
|
|
6217
|
+
return logError('renderApp options must be an object');
|
|
6218
|
+
const container = isElement(options.container) ? options.container : isString(options.container) ? document.querySelector(options.container) : null;
|
|
6219
|
+
if (!isElement(container))
|
|
6220
|
+
return logError('Target container is not a DOM element.');
|
|
6221
|
+
const microAppElement = pureCreateElement(microApp.tagName);
|
|
6222
|
+
for (const attr in options) {
|
|
6223
|
+
if (attr === 'onDataChange') {
|
|
6224
|
+
if (isFunction(options[attr])) {
|
|
6225
|
+
microAppElement.addEventListener('datachange', options[attr]);
|
|
6226
|
+
}
|
|
6227
|
+
}
|
|
6228
|
+
else if (attr === 'lifeCycles') {
|
|
6229
|
+
const lifeCycleConfig = options[attr];
|
|
6230
|
+
if (isPlainObject(lifeCycleConfig)) {
|
|
6231
|
+
for (const lifeName in lifeCycleConfig) {
|
|
6232
|
+
if (lifeName.toUpperCase() in lifeCycles && isFunction(lifeCycleConfig[lifeName])) {
|
|
6233
|
+
microAppElement.addEventListener(lifeName.toLowerCase(), lifeCycleConfig[lifeName]);
|
|
6234
|
+
}
|
|
6235
|
+
}
|
|
6236
|
+
}
|
|
6237
|
+
}
|
|
6238
|
+
else if (attr !== 'container') {
|
|
6239
|
+
microAppElement.setAttribute(attr, options[attr]);
|
|
6240
|
+
}
|
|
6241
|
+
}
|
|
6242
|
+
const handleMount = () => {
|
|
6243
|
+
releaseListener();
|
|
6244
|
+
resolve(true);
|
|
6245
|
+
};
|
|
6246
|
+
const handleError = () => {
|
|
6247
|
+
releaseListener();
|
|
6248
|
+
resolve(false);
|
|
6249
|
+
};
|
|
6250
|
+
const releaseListener = () => {
|
|
6251
|
+
microAppElement.removeEventListener(lifeCycles.MOUNTED, handleMount);
|
|
6252
|
+
microAppElement.removeEventListener(lifeCycles.ERROR, handleError);
|
|
6253
|
+
};
|
|
6254
|
+
microAppElement.addEventListener(lifeCycles.MOUNTED, handleMount);
|
|
6255
|
+
microAppElement.addEventListener(lifeCycles.ERROR, handleError);
|
|
6256
|
+
container.appendChild(microAppElement);
|
|
6257
|
+
});
|
|
5215
6258
|
}
|
|
5216
6259
|
class MicroApp extends EventCenterForBaseApp {
|
|
5217
6260
|
constructor() {
|
|
5218
6261
|
super(...arguments);
|
|
5219
6262
|
this.tagName = 'micro-app';
|
|
5220
|
-
this.
|
|
6263
|
+
this.options = {};
|
|
5221
6264
|
this.router = router;
|
|
6265
|
+
this.preFetch = preFetch;
|
|
6266
|
+
this.unmountApp = unmountApp;
|
|
6267
|
+
this.unmountAllApps = unmountAllApps;
|
|
6268
|
+
this.getActiveApps = getActiveApps;
|
|
6269
|
+
this.getAllApps = getAllApps;
|
|
6270
|
+
this.reload = reload;
|
|
6271
|
+
this.renderApp = renderApp;
|
|
5222
6272
|
}
|
|
5223
6273
|
start(options) {
|
|
5224
6274
|
var _a, _b;
|
|
@@ -5237,26 +6287,10 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
5237
6287
|
return logWarn(`element ${this.tagName} is already defined`);
|
|
5238
6288
|
}
|
|
5239
6289
|
initGlobalEnv();
|
|
5240
|
-
if (
|
|
5241
|
-
this.
|
|
5242
|
-
|
|
5243
|
-
|
|
5244
|
-
* compatible with versions below 0.4.2 of destroy
|
|
5245
|
-
* do not merge with the previous line
|
|
5246
|
-
*/
|
|
5247
|
-
// @ts-ignore
|
|
5248
|
-
this.destory = options.destory;
|
|
5249
|
-
this.inline = options.inline;
|
|
5250
|
-
this['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;
|
|
5251
|
-
this['disable-sandbox'] = (_b = options['disable-sandbox']) !== null && _b !== void 0 ? _b : options.disableSandbox;
|
|
5252
|
-
this['disable-memory-router'] = options['disable-memory-router'];
|
|
5253
|
-
this['disable-patch-request'] = options['disable-patch-request'];
|
|
5254
|
-
this['keep-router-state'] = options['keep-router-state'];
|
|
5255
|
-
this['hidden-router'] = options['hidden-router'];
|
|
5256
|
-
this.esmodule = options.esmodule;
|
|
5257
|
-
this.ssr = options.ssr;
|
|
5258
|
-
isFunction(options.fetch) && (this.fetch = options.fetch);
|
|
5259
|
-
isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);
|
|
6290
|
+
if (isPlainObject(options)) {
|
|
6291
|
+
this.options = options;
|
|
6292
|
+
options['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;
|
|
6293
|
+
options['disable-sandbox'] = (_b = options['disable-sandbox']) !== null && _b !== void 0 ? _b : options.disableSandbox;
|
|
5260
6294
|
// load app assets when browser is idle
|
|
5261
6295
|
options.preFetchApps && preFetch(options.preFetchApps);
|
|
5262
6296
|
// load global assets when browser is idle
|
|
@@ -5272,15 +6306,14 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
5272
6306
|
}
|
|
5273
6307
|
}
|
|
5274
6308
|
}
|
|
5275
|
-
this.plugins = options.plugins;
|
|
5276
6309
|
}
|
|
5277
6310
|
}
|
|
5278
6311
|
// define customElement after init
|
|
5279
6312
|
defineElement(this.tagName);
|
|
5280
6313
|
}
|
|
5281
6314
|
}
|
|
5282
|
-
|
|
6315
|
+
const microApp = new MicroApp();
|
|
5283
6316
|
|
|
5284
6317
|
export default microApp;
|
|
5285
|
-
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, unmountAllApps, unmountApp, version };
|
|
6318
|
+
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
|
|
5286
6319
|
//# sourceMappingURL=index.esm.js.map
|