@micro-zoe/micro-app 1.0.0-alpha.5 → 1.0.0-alpha.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +0 -4
- package/README.zh-cn.md +1 -1
- package/lib/index.d.ts +26 -16
- package/lib/index.esm.js +887 -433
- 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 +97 -73
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-alpha.
|
|
1
|
+
const version = '1.0.0-alpha.6';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -258,8 +258,19 @@ const requestIdleCallback = globalThis.requestIdleCallback ||
|
|
|
258
258
|
return Math.max(0, 50 - (Date.now() - lastTime));
|
|
259
259
|
},
|
|
260
260
|
});
|
|
261
|
-
},
|
|
261
|
+
}, 1);
|
|
262
262
|
};
|
|
263
|
+
/**
|
|
264
|
+
* Wrap requestIdleCallback with promise
|
|
265
|
+
* Exec callback when browser idle
|
|
266
|
+
*/
|
|
267
|
+
function promiseRequestIdle(callback) {
|
|
268
|
+
return new Promise((resolve) => {
|
|
269
|
+
requestIdleCallback(() => {
|
|
270
|
+
callback(resolve);
|
|
271
|
+
});
|
|
272
|
+
});
|
|
273
|
+
}
|
|
263
274
|
/**
|
|
264
275
|
* Record the currently running app.name
|
|
265
276
|
*/
|
|
@@ -433,6 +444,45 @@ function useMapRecord() {
|
|
|
433
444
|
}
|
|
434
445
|
};
|
|
435
446
|
}
|
|
447
|
+
function getAttributes(element) {
|
|
448
|
+
const attr = element.attributes;
|
|
449
|
+
const attrMap = new Map();
|
|
450
|
+
for (let i = 0; i < attr.length; i++) {
|
|
451
|
+
attrMap.set(attr[i].name, attr[i].value);
|
|
452
|
+
}
|
|
453
|
+
return attrMap;
|
|
454
|
+
}
|
|
455
|
+
/**
|
|
456
|
+
* if fiberTasks exist, wrap callback with promiseRequestIdle
|
|
457
|
+
* if not, execute callback
|
|
458
|
+
* @param fiberTasks fiber task list
|
|
459
|
+
* @param callback action callback
|
|
460
|
+
*/
|
|
461
|
+
function injectFiberTask(fiberTasks, callback) {
|
|
462
|
+
if (fiberTasks) {
|
|
463
|
+
fiberTasks.push(() => promiseRequestIdle((resolve) => {
|
|
464
|
+
callback();
|
|
465
|
+
resolve();
|
|
466
|
+
}));
|
|
467
|
+
}
|
|
468
|
+
else {
|
|
469
|
+
callback();
|
|
470
|
+
}
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* serial exec fiber task of link, style, script
|
|
474
|
+
* @param tasks task array or null
|
|
475
|
+
*/
|
|
476
|
+
function serialExecFiberTasks(tasks) {
|
|
477
|
+
return (tasks === null || tasks === void 0 ? void 0 : tasks.reduce((pre, next) => pre.then(next), Promise.resolve())) || null;
|
|
478
|
+
}
|
|
479
|
+
/**
|
|
480
|
+
* inline script start with inline-xxx
|
|
481
|
+
* @param address source address
|
|
482
|
+
*/
|
|
483
|
+
function isInlineScript(address) {
|
|
484
|
+
return address.startsWith('inline-');
|
|
485
|
+
}
|
|
436
486
|
|
|
437
487
|
var ObservedAttrName;
|
|
438
488
|
(function (ObservedAttrName) {
|
|
@@ -493,8 +543,8 @@ function fetchSource(url, appName = null, options = {}) {
|
|
|
493
543
|
* baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
|
|
494
544
|
*/
|
|
495
545
|
removeDomScope();
|
|
496
|
-
if (isFunction(microApp.fetch)) {
|
|
497
|
-
return microApp.fetch(url, options, appName);
|
|
546
|
+
if (isFunction(microApp.options.fetch)) {
|
|
547
|
+
return microApp.options.fetch(url, options, appName);
|
|
498
548
|
}
|
|
499
549
|
// Don’t use globalEnv.rawWindow.fetch, will cause sgm-2.8.0.js throw error in nest app
|
|
500
550
|
return window.fetch(url, options).then((res) => {
|
|
@@ -531,7 +581,7 @@ class HTMLLoader {
|
|
|
531
581
|
});
|
|
532
582
|
}
|
|
533
583
|
formatHTML(htmlUrl, htmlStr, appName) {
|
|
534
|
-
return this.processHtml(htmlUrl, htmlStr, appName, microApp.plugins)
|
|
584
|
+
return this.processHtml(htmlUrl, htmlStr, appName, microApp.options.plugins)
|
|
535
585
|
.replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
|
|
536
586
|
return match
|
|
537
587
|
.replace(/<head/i, '<micro-app-head')
|
|
@@ -553,7 +603,7 @@ class HTMLLoader {
|
|
|
553
603
|
if (mergedPlugins.length > 0) {
|
|
554
604
|
return mergedPlugins.reduce((preCode, plugin) => {
|
|
555
605
|
if (isPlainObject(plugin) && isFunction(plugin.processHtml)) {
|
|
556
|
-
return plugin.processHtml(preCode, url
|
|
606
|
+
return plugin.processHtml(preCode, url);
|
|
557
607
|
}
|
|
558
608
|
return preCode;
|
|
559
609
|
}, code);
|
|
@@ -591,11 +641,13 @@ class CSSParser {
|
|
|
591
641
|
this.scopecssDisableSelectors = []; // disable or enable scopecss for specific selectors
|
|
592
642
|
this.scopecssDisableNextLine = false; // use block comments /* scopecss-disable-next-line */ to disable scopecss on a specific line
|
|
593
643
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSMediaRule
|
|
594
|
-
this.mediaRule = this.
|
|
644
|
+
this.mediaRule = this.createMatcherForRuleWithChildRule(/^@media *([^{]+)/, '@media');
|
|
595
645
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSSupportsRule
|
|
596
|
-
this.supportsRule = this.
|
|
597
|
-
this.documentRule = this.
|
|
598
|
-
this.hostRule = this.
|
|
646
|
+
this.supportsRule = this.createMatcherForRuleWithChildRule(/^@supports *([^{]+)/, '@supports');
|
|
647
|
+
this.documentRule = this.createMatcherForRuleWithChildRule(/^@([-\w]+)?document *([^{]+)/, '@document');
|
|
648
|
+
this.hostRule = this.createMatcherForRuleWithChildRule(/^@host\s*/, '@host');
|
|
649
|
+
// :global is CSS Modules rule, it will be converted to normal syntax
|
|
650
|
+
// private globalRule = this.createMatcherForRuleWithChildRule(/^:global([^{]*)/, ':global')
|
|
599
651
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSImportRule
|
|
600
652
|
this.importRule = this.createMatcherForNoneBraceAtRule('import');
|
|
601
653
|
// Removed in most browsers
|
|
@@ -716,6 +768,13 @@ class CSSParser {
|
|
|
716
768
|
this.hostRule() ||
|
|
717
769
|
this.fontFaceRule();
|
|
718
770
|
}
|
|
771
|
+
// :global is CSS Modules rule, it will be converted to normal syntax
|
|
772
|
+
// private matchGlobalRule (): boolean | void {
|
|
773
|
+
// if (this.cssText[0] !== ':') return false
|
|
774
|
+
// // reset scopecssDisableNextLine
|
|
775
|
+
// this.scopecssDisableNextLine = false
|
|
776
|
+
// return this.globalRule()
|
|
777
|
+
// }
|
|
719
778
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSKeyframesRule
|
|
720
779
|
keyframesRule() {
|
|
721
780
|
if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
|
|
@@ -769,17 +828,17 @@ class CSSParser {
|
|
|
769
828
|
return false;
|
|
770
829
|
return this.commonHandlerForAtRuleWithSelfRule('font-face');
|
|
771
830
|
}
|
|
772
|
-
// common matcher for @media, @supports, @document, @host
|
|
773
|
-
|
|
831
|
+
// common matcher for @media, @supports, @document, @host, :global
|
|
832
|
+
createMatcherForRuleWithChildRule(reg, name) {
|
|
774
833
|
return () => {
|
|
775
834
|
if (!this.commonMatch(reg))
|
|
776
835
|
return false;
|
|
777
836
|
if (!this.matchOpenBrace())
|
|
778
|
-
return parseError(
|
|
837
|
+
return parseError(`${name} missing '{'`, this.linkPath);
|
|
779
838
|
this.matchComments();
|
|
780
839
|
this.matchRules();
|
|
781
840
|
if (!this.matchCloseBrace())
|
|
782
|
-
return parseError(
|
|
841
|
+
return parseError(`${name} missing '}'`, this.linkPath);
|
|
783
842
|
this.matchLeadingSpaces();
|
|
784
843
|
return true;
|
|
785
844
|
};
|
|
@@ -906,20 +965,20 @@ let parser;
|
|
|
906
965
|
* @param styleElement target style element
|
|
907
966
|
* @param appName app name
|
|
908
967
|
*/
|
|
909
|
-
function scopedCSS(styleElement, app) {
|
|
968
|
+
function scopedCSS(styleElement, app, linkPath) {
|
|
910
969
|
if (app.scopecss) {
|
|
911
|
-
const prefix =
|
|
970
|
+
const prefix = createPrefix(app.name);
|
|
912
971
|
if (!parser)
|
|
913
972
|
parser = new CSSParser();
|
|
914
973
|
if (styleElement.textContent) {
|
|
915
|
-
commonAction(styleElement, app.name, prefix, app.url,
|
|
974
|
+
commonAction(styleElement, app.name, prefix, app.url, linkPath);
|
|
916
975
|
}
|
|
917
976
|
else {
|
|
918
977
|
const observer = new MutationObserver(function () {
|
|
919
978
|
observer.disconnect();
|
|
920
979
|
// styled-component will be ignore
|
|
921
980
|
if (styleElement.textContent && !styleElement.hasAttribute('data-styled')) {
|
|
922
|
-
commonAction(styleElement, app.name, prefix, app.url,
|
|
981
|
+
commonAction(styleElement, app.name, prefix, app.url, linkPath);
|
|
923
982
|
}
|
|
924
983
|
});
|
|
925
984
|
observer.observe(styleElement, { childList: true });
|
|
@@ -927,6 +986,10 @@ function scopedCSS(styleElement, app) {
|
|
|
927
986
|
}
|
|
928
987
|
return styleElement;
|
|
929
988
|
}
|
|
989
|
+
function createPrefix(appName, reg = false) {
|
|
990
|
+
const regCharacter = reg ? '\\' : '';
|
|
991
|
+
return `${microApp.tagName}${regCharacter}[name=${appName}${regCharacter}]`;
|
|
992
|
+
}
|
|
930
993
|
|
|
931
994
|
function eventHandler(event, element) {
|
|
932
995
|
Object.defineProperties(event, {
|
|
@@ -968,8 +1031,76 @@ function dispatchOnErrorEvent(element) {
|
|
|
968
1031
|
}
|
|
969
1032
|
}
|
|
970
1033
|
|
|
971
|
-
|
|
972
|
-
|
|
1034
|
+
/**
|
|
1035
|
+
* SourceCenter is a resource management center
|
|
1036
|
+
* All html, js, css will be recorded and processed here
|
|
1037
|
+
* NOTE:
|
|
1038
|
+
* 1. All resources are global and shared between apps
|
|
1039
|
+
* 2. Pay attention to the case of html with parameters
|
|
1040
|
+
* 3. The resource is first processed by the plugin
|
|
1041
|
+
*/
|
|
1042
|
+
function createSourceCenter() {
|
|
1043
|
+
const linkList = new Map();
|
|
1044
|
+
const scriptList = new Map();
|
|
1045
|
+
// setInterval(() => {
|
|
1046
|
+
// console.log(linkList, scriptList)
|
|
1047
|
+
// }, 10000);
|
|
1048
|
+
function createSourceHandler(targetList) {
|
|
1049
|
+
return {
|
|
1050
|
+
setInfo(address, info) {
|
|
1051
|
+
targetList.set(address, info);
|
|
1052
|
+
},
|
|
1053
|
+
getInfo(address) {
|
|
1054
|
+
var _a;
|
|
1055
|
+
return (_a = targetList.get(address)) !== null && _a !== void 0 ? _a : null;
|
|
1056
|
+
},
|
|
1057
|
+
hasInfo(address) {
|
|
1058
|
+
return targetList.has(address);
|
|
1059
|
+
},
|
|
1060
|
+
deleteInfo(address) {
|
|
1061
|
+
return targetList.delete(address);
|
|
1062
|
+
}
|
|
1063
|
+
};
|
|
1064
|
+
}
|
|
1065
|
+
return {
|
|
1066
|
+
link: createSourceHandler(linkList),
|
|
1067
|
+
script: Object.assign(Object.assign({}, createSourceHandler(scriptList)), { deleteInlineInfo(addressList) {
|
|
1068
|
+
addressList.forEach((address) => {
|
|
1069
|
+
if (isInlineScript(address)) {
|
|
1070
|
+
scriptList.delete(address);
|
|
1071
|
+
}
|
|
1072
|
+
});
|
|
1073
|
+
} }),
|
|
1074
|
+
};
|
|
1075
|
+
}
|
|
1076
|
+
var sourceCenter = createSourceCenter();
|
|
1077
|
+
|
|
1078
|
+
/**
|
|
1079
|
+
*
|
|
1080
|
+
* @param appName app.name
|
|
1081
|
+
* @param linkInfo linkInfo of current address
|
|
1082
|
+
*/
|
|
1083
|
+
function getExistParseCode(appName, prefix, linkInfo) {
|
|
1084
|
+
const appSpace = linkInfo.appSpace;
|
|
1085
|
+
for (const item in appSpace) {
|
|
1086
|
+
if (item !== appName) {
|
|
1087
|
+
const appSpaceData = appSpace[item];
|
|
1088
|
+
if (appSpaceData.parsedCode) {
|
|
1089
|
+
return appSpaceData.parsedCode.replaceAll(new RegExp(createPrefix(item, true), 'g'), prefix);
|
|
1090
|
+
}
|
|
1091
|
+
}
|
|
1092
|
+
}
|
|
1093
|
+
}
|
|
1094
|
+
// transfer the attributes on the link to convertStyle
|
|
1095
|
+
function setConvertStyleAttr(convertStyle, attrs) {
|
|
1096
|
+
attrs.forEach((value, key) => {
|
|
1097
|
+
if (key === 'rel')
|
|
1098
|
+
return;
|
|
1099
|
+
if (key === 'href')
|
|
1100
|
+
key = 'data-origin-href';
|
|
1101
|
+
convertStyle.setAttribute(key, value);
|
|
1102
|
+
});
|
|
1103
|
+
}
|
|
973
1104
|
/**
|
|
974
1105
|
* Extract link elements
|
|
975
1106
|
* @param link link element
|
|
@@ -984,22 +1115,29 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
984
1115
|
let replaceComment = null;
|
|
985
1116
|
if (rel === 'stylesheet' && href) {
|
|
986
1117
|
href = CompletionPath(href, app.url);
|
|
1118
|
+
let linkInfo = sourceCenter.link.getInfo(href);
|
|
1119
|
+
const appSpaceData = {
|
|
1120
|
+
attrs: getAttributes(link),
|
|
1121
|
+
};
|
|
1122
|
+
if (!linkInfo) {
|
|
1123
|
+
linkInfo = {
|
|
1124
|
+
code: '',
|
|
1125
|
+
appSpace: {
|
|
1126
|
+
[app.name]: appSpaceData,
|
|
1127
|
+
}
|
|
1128
|
+
};
|
|
1129
|
+
}
|
|
1130
|
+
else {
|
|
1131
|
+
linkInfo.appSpace[app.name] = linkInfo.appSpace[app.name] || appSpaceData;
|
|
1132
|
+
}
|
|
1133
|
+
sourceCenter.link.setInfo(href, linkInfo);
|
|
987
1134
|
if (!isDynamic) {
|
|
1135
|
+
app.source.links.add(href);
|
|
988
1136
|
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
|
-
});
|
|
1137
|
+
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
994
1138
|
}
|
|
995
1139
|
else {
|
|
996
|
-
return {
|
|
997
|
-
url: href,
|
|
998
|
-
info: {
|
|
999
|
-
code: '',
|
|
1000
|
-
isGlobal: link.hasAttribute('global'),
|
|
1001
|
-
}
|
|
1002
|
-
};
|
|
1140
|
+
return { address: href, linkInfo };
|
|
1003
1141
|
}
|
|
1004
1142
|
}
|
|
1005
1143
|
else if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
|
|
@@ -1028,79 +1166,138 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
1028
1166
|
* @param app app
|
|
1029
1167
|
* @param microAppHead micro-app-head
|
|
1030
1168
|
*/
|
|
1031
|
-
function fetchLinksFromHtml(wrapElement, app, microAppHead) {
|
|
1032
|
-
const
|
|
1033
|
-
const fetchLinkPromise =
|
|
1034
|
-
|
|
1169
|
+
function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
1170
|
+
const styleList = Array.from(app.source.links);
|
|
1171
|
+
const fetchLinkPromise = styleList.map((address) => {
|
|
1172
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
1173
|
+
return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
|
|
1035
1174
|
});
|
|
1175
|
+
const fiberLinkTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
1036
1176
|
promiseStream(fetchLinkPromise, (res) => {
|
|
1037
|
-
|
|
1177
|
+
injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
|
|
1038
1178
|
}, (err) => {
|
|
1039
1179
|
logError(err, app.name);
|
|
1040
1180
|
}, () => {
|
|
1041
|
-
|
|
1181
|
+
if (fiberLinkTasks) {
|
|
1182
|
+
/**
|
|
1183
|
+
* 1. If fiberLinkTasks is not null, fiberStyleResult is not null
|
|
1184
|
+
* 2. Download link source while processing style
|
|
1185
|
+
* 3. Process style first, and then process link
|
|
1186
|
+
*/
|
|
1187
|
+
fiberStyleResult.then(() => {
|
|
1188
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1189
|
+
serialExecFiberTasks(fiberLinkTasks);
|
|
1190
|
+
});
|
|
1191
|
+
}
|
|
1192
|
+
else {
|
|
1193
|
+
app.onLoad(wrapElement);
|
|
1194
|
+
}
|
|
1042
1195
|
});
|
|
1043
1196
|
}
|
|
1044
1197
|
/**
|
|
1045
|
-
*
|
|
1046
|
-
*
|
|
1047
|
-
*
|
|
1048
|
-
*
|
|
1198
|
+
* Fetch link succeeded, replace placeholder with style tag
|
|
1199
|
+
* NOTE:
|
|
1200
|
+
* 1. Only exec when init, no longer exec when remount
|
|
1201
|
+
* 2. Only handler html link element, not dynamic link or style
|
|
1202
|
+
* 3. The same prefix can reuse parsedCode
|
|
1203
|
+
* 4. Async exec with requestIdleCallback in prefetch or fiber
|
|
1204
|
+
* 5. appSpace[app.name].placeholder/attrs must exist
|
|
1205
|
+
* @param address resource address
|
|
1206
|
+
* @param code link source code
|
|
1049
1207
|
* @param microAppHead micro-app-head
|
|
1050
|
-
* @param app app
|
|
1208
|
+
* @param app app instance
|
|
1051
1209
|
*/
|
|
1052
|
-
function fetchLinkSuccess(
|
|
1053
|
-
|
|
1054
|
-
|
|
1210
|
+
function fetchLinkSuccess(address, code, microAppHead, app) {
|
|
1211
|
+
/**
|
|
1212
|
+
* linkInfo must exist, but linkInfo.code not
|
|
1213
|
+
* so we set code to linkInfo.code
|
|
1214
|
+
*/
|
|
1215
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
1216
|
+
linkInfo.code = code;
|
|
1217
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
1218
|
+
const placeholder = appSpaceData.placeholder;
|
|
1219
|
+
/**
|
|
1220
|
+
* 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.
|
|
1221
|
+
* This causes placeholder to be possibly null
|
|
1222
|
+
* e.g.
|
|
1223
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
1224
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
1225
|
+
*/
|
|
1226
|
+
if (placeholder) {
|
|
1227
|
+
const convertStyle = pureCreateElement('style');
|
|
1228
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, appSpaceData.attrs);
|
|
1229
|
+
if (placeholder.parentNode) {
|
|
1230
|
+
placeholder.parentNode.replaceChild(convertStyle, placeholder);
|
|
1231
|
+
}
|
|
1232
|
+
else {
|
|
1233
|
+
microAppHead.appendChild(convertStyle);
|
|
1234
|
+
}
|
|
1235
|
+
// clear placeholder
|
|
1236
|
+
appSpaceData.placeholder = null;
|
|
1055
1237
|
}
|
|
1056
|
-
|
|
1057
|
-
|
|
1058
|
-
|
|
1059
|
-
|
|
1060
|
-
|
|
1061
|
-
|
|
1238
|
+
}
|
|
1239
|
+
/**
|
|
1240
|
+
* Get parsedCode, update convertStyle
|
|
1241
|
+
* Actions:
|
|
1242
|
+
* 1. get scope css (through scopedCSS or oldData)
|
|
1243
|
+
* 2. record parsedCode
|
|
1244
|
+
* 3. set parsedCode to convertStyle if need
|
|
1245
|
+
* @param app app instance
|
|
1246
|
+
* @param address resource address
|
|
1247
|
+
* @param convertStyle converted style
|
|
1248
|
+
* @param linkInfo linkInfo in sourceCenter
|
|
1249
|
+
* @param attrs attrs of link
|
|
1250
|
+
*/
|
|
1251
|
+
function handleConvertStyle(app, address, convertStyle, linkInfo, attrs) {
|
|
1252
|
+
if (app.scopecss) {
|
|
1253
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
1254
|
+
appSpaceData.prefix = appSpaceData.prefix || createPrefix(app.name);
|
|
1255
|
+
if (!appSpaceData.parsedCode) {
|
|
1256
|
+
const existParsedCode = getExistParseCode(app.name, appSpaceData.prefix, linkInfo);
|
|
1257
|
+
if (!existParsedCode) {
|
|
1258
|
+
convertStyle.textContent = linkInfo.code;
|
|
1259
|
+
scopedCSS(convertStyle, app, address);
|
|
1260
|
+
}
|
|
1261
|
+
else {
|
|
1262
|
+
convertStyle.textContent = existParsedCode;
|
|
1263
|
+
}
|
|
1264
|
+
appSpaceData.parsedCode = convertStyle.textContent;
|
|
1265
|
+
}
|
|
1266
|
+
else {
|
|
1267
|
+
convertStyle.textContent = appSpaceData.parsedCode;
|
|
1268
|
+
}
|
|
1062
1269
|
}
|
|
1063
1270
|
else {
|
|
1064
|
-
|
|
1271
|
+
convertStyle.textContent = linkInfo.code;
|
|
1065
1272
|
}
|
|
1066
|
-
|
|
1067
|
-
info.code = data;
|
|
1273
|
+
setConvertStyleAttr(convertStyle, attrs);
|
|
1068
1274
|
}
|
|
1069
1275
|
/**
|
|
1070
|
-
*
|
|
1071
|
-
* @param
|
|
1072
|
-
* @param info info
|
|
1276
|
+
* Handle css of dynamic link
|
|
1277
|
+
* @param address link address
|
|
1073
1278
|
* @param app app
|
|
1279
|
+
* @param linkInfo linkInfo
|
|
1074
1280
|
* @param originLink origin link element
|
|
1075
|
-
* @param replaceStyle style element which replaced origin link
|
|
1076
1281
|
*/
|
|
1077
|
-
function formatDynamicLink(
|
|
1078
|
-
|
|
1079
|
-
|
|
1080
|
-
|
|
1081
|
-
|
|
1082
|
-
|
|
1282
|
+
function formatDynamicLink(address, app, linkInfo, originLink) {
|
|
1283
|
+
const convertStyle = pureCreateElement('style');
|
|
1284
|
+
const handleDynamicLink = () => {
|
|
1285
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, linkInfo.appSpace[app.name].attrs);
|
|
1286
|
+
dispatchOnLoadEvent(originLink);
|
|
1287
|
+
};
|
|
1288
|
+
if (linkInfo.code) {
|
|
1289
|
+
defer(handleDynamicLink);
|
|
1083
1290
|
}
|
|
1084
|
-
|
|
1085
|
-
|
|
1086
|
-
|
|
1087
|
-
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1291
|
+
else {
|
|
1292
|
+
fetchSource(address, app.name).then((data) => {
|
|
1293
|
+
linkInfo.code = data;
|
|
1294
|
+
handleDynamicLink();
|
|
1295
|
+
}).catch((err) => {
|
|
1296
|
+
logError(err, app.name);
|
|
1297
|
+
dispatchOnErrorEvent(originLink);
|
|
1298
|
+
});
|
|
1092
1299
|
}
|
|
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
|
-
});
|
|
1300
|
+
return convertStyle;
|
|
1104
1301
|
}
|
|
1105
1302
|
|
|
1106
1303
|
class Adapter {
|
|
@@ -1176,10 +1373,13 @@ function throttleDeferForParentNode(proxyDocument) {
|
|
|
1176
1373
|
}
|
|
1177
1374
|
}
|
|
1178
1375
|
function setRootParentNode(root, value) {
|
|
1179
|
-
Object.
|
|
1180
|
-
|
|
1181
|
-
|
|
1182
|
-
|
|
1376
|
+
const descriptor = Object.getOwnPropertyDescriptor(root, 'parentNode');
|
|
1377
|
+
if (!descriptor || descriptor.configurable) {
|
|
1378
|
+
Object.defineProperty(root, 'parentNode', {
|
|
1379
|
+
value,
|
|
1380
|
+
configurable: true,
|
|
1381
|
+
});
|
|
1382
|
+
}
|
|
1183
1383
|
}
|
|
1184
1384
|
|
|
1185
1385
|
// Record element and map element
|
|
@@ -1208,14 +1408,16 @@ function handleNewNode(parent, child, app) {
|
|
|
1208
1408
|
dynamicElementInMicroAppMap.set(child, linkReplaceComment);
|
|
1209
1409
|
return linkReplaceComment;
|
|
1210
1410
|
}
|
|
1211
|
-
else if (child.hasAttribute('ignore') ||
|
|
1411
|
+
else if (child.hasAttribute('ignore') ||
|
|
1412
|
+
checkIgnoreUrl(child.getAttribute('href'), app.name) ||
|
|
1413
|
+
(child.href &&
|
|
1414
|
+
isFunction(microApp.options.excludeAssetFilter) &&
|
|
1415
|
+
microApp.options.excludeAssetFilter(child.href))) {
|
|
1212
1416
|
return child;
|
|
1213
1417
|
}
|
|
1214
|
-
const {
|
|
1215
|
-
if (
|
|
1216
|
-
const replaceStyle =
|
|
1217
|
-
replaceStyle.__MICRO_APP_LINK_PATH__ = url;
|
|
1218
|
-
formatDynamicLink(url, info, app, child, replaceStyle);
|
|
1418
|
+
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child, parent, app, true);
|
|
1419
|
+
if (address && linkInfo) {
|
|
1420
|
+
const replaceStyle = formatDynamicLink(address, app, linkInfo, child);
|
|
1219
1421
|
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
1220
1422
|
return replaceStyle;
|
|
1221
1423
|
}
|
|
@@ -1226,18 +1428,17 @@ function handleNewNode(parent, child, app) {
|
|
|
1226
1428
|
return child;
|
|
1227
1429
|
}
|
|
1228
1430
|
else if (child instanceof HTMLScriptElement) {
|
|
1229
|
-
|
|
1230
|
-
|
|
1231
|
-
|
|
1232
|
-
|
|
1233
|
-
|
|
1234
|
-
|
|
1235
|
-
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
1239
|
-
|
|
1240
|
-
}
|
|
1431
|
+
if (child.src &&
|
|
1432
|
+
isFunction(microApp.options.excludeAssetFilter) &&
|
|
1433
|
+
microApp.options.excludeAssetFilter(child.src)) {
|
|
1434
|
+
return child;
|
|
1435
|
+
}
|
|
1436
|
+
const { replaceComment, address, scriptInfo } = extractScriptElement(child, parent, app, true) || {};
|
|
1437
|
+
if (address && scriptInfo) {
|
|
1438
|
+
// remote script or inline script
|
|
1439
|
+
const replaceElement = scriptInfo.isExternal ? runDynamicRemoteScript(address, app, scriptInfo, child) : runDynamicInlineScript(address, app, scriptInfo);
|
|
1440
|
+
dynamicElementInMicroAppMap.set(child, replaceElement);
|
|
1441
|
+
return replaceElement;
|
|
1241
1442
|
}
|
|
1242
1443
|
else if (replaceComment) {
|
|
1243
1444
|
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
@@ -1705,8 +1906,80 @@ function initGlobalEnv() {
|
|
|
1705
1906
|
}
|
|
1706
1907
|
}
|
|
1707
1908
|
|
|
1708
|
-
|
|
1709
|
-
|
|
1909
|
+
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1910
|
+
// whether use type='module' script
|
|
1911
|
+
function isTypeModule(app, scriptInfo) {
|
|
1912
|
+
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.esmodule);
|
|
1913
|
+
}
|
|
1914
|
+
// special script element
|
|
1915
|
+
function isSpecialScript(app, scriptInfo) {
|
|
1916
|
+
const attrs = scriptInfo.appSpace[app.name].attrs;
|
|
1917
|
+
return attrs.has('id');
|
|
1918
|
+
}
|
|
1919
|
+
/**
|
|
1920
|
+
* whether to run js in inline mode
|
|
1921
|
+
* scene:
|
|
1922
|
+
* 1. inline config for app
|
|
1923
|
+
* 2. inline attr in script element
|
|
1924
|
+
* 3. module script
|
|
1925
|
+
* 4. script with special attr
|
|
1926
|
+
*/
|
|
1927
|
+
function isInlineMode(app, scriptInfo) {
|
|
1928
|
+
return (app.inline ||
|
|
1929
|
+
scriptInfo.appSpace[app.name].inline ||
|
|
1930
|
+
isTypeModule(app, scriptInfo) ||
|
|
1931
|
+
isSpecialScript(app, scriptInfo));
|
|
1932
|
+
}
|
|
1933
|
+
// Convert string code to function
|
|
1934
|
+
function code2Function(code) {
|
|
1935
|
+
return new Function(code);
|
|
1936
|
+
}
|
|
1937
|
+
/**
|
|
1938
|
+
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
1939
|
+
* @param appName app.name
|
|
1940
|
+
* @param scriptInfo scriptInfo of current address
|
|
1941
|
+
* @param currentCode pure code of current address
|
|
1942
|
+
*/
|
|
1943
|
+
function getExistParseResult(appName, scriptInfo, currentCode) {
|
|
1944
|
+
const appSpace = scriptInfo.appSpace;
|
|
1945
|
+
for (const item in appSpace) {
|
|
1946
|
+
if (item !== appName) {
|
|
1947
|
+
const appSpaceData = appSpace[item];
|
|
1948
|
+
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
1949
|
+
return appSpaceData.parsedFunction;
|
|
1950
|
+
}
|
|
1951
|
+
}
|
|
1952
|
+
}
|
|
1953
|
+
}
|
|
1954
|
+
/**
|
|
1955
|
+
* get parsedFunction from exist data or parsedCode
|
|
1956
|
+
* @returns parsedFunction
|
|
1957
|
+
*/
|
|
1958
|
+
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
1959
|
+
return getExistParseResult(app.name, scriptInfo, parsedCode) || code2Function(parsedCode);
|
|
1960
|
+
}
|
|
1961
|
+
// Prevent randomly created strings from repeating
|
|
1962
|
+
function getUniqueNonceSrc() {
|
|
1963
|
+
const nonceStr = createNonceSrc();
|
|
1964
|
+
if (sourceCenter.script.hasInfo(nonceStr)) {
|
|
1965
|
+
return getUniqueNonceSrc();
|
|
1966
|
+
}
|
|
1967
|
+
return nonceStr;
|
|
1968
|
+
}
|
|
1969
|
+
// transfer the attributes on the script to convertScript
|
|
1970
|
+
function setConvertScriptAttr(convertScript, attrs) {
|
|
1971
|
+
attrs.forEach((value, key) => {
|
|
1972
|
+
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
1973
|
+
return;
|
|
1974
|
+
if (key === 'src')
|
|
1975
|
+
key = 'data-origin-src';
|
|
1976
|
+
convertScript.setAttribute(key, value);
|
|
1977
|
+
});
|
|
1978
|
+
}
|
|
1979
|
+
// wrap code in sandbox
|
|
1980
|
+
function isWrapInSandBox(app, scriptInfo) {
|
|
1981
|
+
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
1982
|
+
}
|
|
1710
1983
|
/**
|
|
1711
1984
|
* Extract script elements
|
|
1712
1985
|
* @param script script element
|
|
@@ -1717,14 +1990,15 @@ const globalScripts = new Map();
|
|
|
1717
1990
|
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
1718
1991
|
let replaceComment = null;
|
|
1719
1992
|
let src = script.getAttribute('src');
|
|
1720
|
-
if (src)
|
|
1993
|
+
if (src)
|
|
1721
1994
|
src = CompletionPath(src, app.url);
|
|
1722
|
-
}
|
|
1723
1995
|
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
1724
1996
|
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
1725
1997
|
}
|
|
1726
|
-
else if ((script.type &&
|
|
1727
|
-
|
|
1998
|
+
else if ((script.type &&
|
|
1999
|
+
!scriptTypes.includes(script.type)) ||
|
|
2000
|
+
script.hasAttribute('ignore') ||
|
|
2001
|
+
checkIgnoreUrl(src, app.name)) {
|
|
1728
2002
|
return null;
|
|
1729
2003
|
}
|
|
1730
2004
|
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
@@ -1732,39 +2006,74 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
1732
2006
|
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
1733
2007
|
}
|
|
1734
2008
|
else if (src) { // remote script
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
isExternal: true,
|
|
1738
|
-
isDynamic: isDynamic,
|
|
2009
|
+
let scriptInfo = sourceCenter.script.getInfo(src);
|
|
2010
|
+
const appSpaceData = {
|
|
1739
2011
|
async: script.hasAttribute('async'),
|
|
1740
2012
|
defer: script.defer || script.type === 'module',
|
|
1741
2013
|
module: script.type === 'module',
|
|
1742
|
-
|
|
2014
|
+
inline: script.hasAttribute('inline'),
|
|
2015
|
+
pure: script.hasAttribute('pure'),
|
|
2016
|
+
attrs: getAttributes(script),
|
|
1743
2017
|
};
|
|
2018
|
+
if (!scriptInfo) {
|
|
2019
|
+
scriptInfo = {
|
|
2020
|
+
code: '',
|
|
2021
|
+
isExternal: true,
|
|
2022
|
+
appSpace: {
|
|
2023
|
+
[app.name]: appSpaceData,
|
|
2024
|
+
}
|
|
2025
|
+
};
|
|
2026
|
+
}
|
|
2027
|
+
else {
|
|
2028
|
+
/**
|
|
2029
|
+
* Reuse when appSpace exists
|
|
2030
|
+
* NOTE:
|
|
2031
|
+
* 1. The same static script, appSpace must be the same (in fact, it may be different when url change)
|
|
2032
|
+
* 2. The same dynamic script, appSpace may be the same, but we still reuse appSpace, which should pay attention
|
|
2033
|
+
*/
|
|
2034
|
+
scriptInfo.appSpace[app.name] = scriptInfo.appSpace[app.name] || appSpaceData;
|
|
2035
|
+
}
|
|
2036
|
+
sourceCenter.script.setInfo(src, scriptInfo);
|
|
1744
2037
|
if (!isDynamic) {
|
|
1745
|
-
app.source.scripts.
|
|
2038
|
+
app.source.scripts.add(src);
|
|
1746
2039
|
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
1747
2040
|
}
|
|
1748
2041
|
else {
|
|
1749
|
-
return {
|
|
2042
|
+
return { address: src, scriptInfo };
|
|
1750
2043
|
}
|
|
1751
2044
|
}
|
|
1752
2045
|
else if (script.textContent) { // inline script
|
|
1753
|
-
|
|
1754
|
-
|
|
2046
|
+
/**
|
|
2047
|
+
* NOTE:
|
|
2048
|
+
* 1. Each inline script is unique
|
|
2049
|
+
* 2. Every dynamic created inline script will be re-executed
|
|
2050
|
+
* ACTION:
|
|
2051
|
+
* 1. Delete dynamic inline script info after exec
|
|
2052
|
+
* 2. Delete static inline script info when destroy
|
|
2053
|
+
*/
|
|
2054
|
+
const nonceStr = getUniqueNonceSrc();
|
|
2055
|
+
const scriptInfo = {
|
|
1755
2056
|
code: script.textContent,
|
|
1756
2057
|
isExternal: false,
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
2058
|
+
appSpace: {
|
|
2059
|
+
[app.name]: {
|
|
2060
|
+
async: false,
|
|
2061
|
+
defer: script.type === 'module',
|
|
2062
|
+
module: script.type === 'module',
|
|
2063
|
+
inline: script.hasAttribute('inline'),
|
|
2064
|
+
pure: script.hasAttribute('pure'),
|
|
2065
|
+
attrs: getAttributes(script),
|
|
2066
|
+
}
|
|
2067
|
+
}
|
|
1761
2068
|
};
|
|
1762
2069
|
if (!isDynamic) {
|
|
1763
|
-
app.source.scripts.
|
|
2070
|
+
app.source.scripts.add(nonceStr);
|
|
2071
|
+
sourceCenter.script.setInfo(nonceStr, scriptInfo);
|
|
1764
2072
|
replaceComment = document.createComment('inline script extract by micro-app');
|
|
1765
2073
|
}
|
|
1766
2074
|
else {
|
|
1767
|
-
|
|
2075
|
+
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
2076
|
+
return { address: nonceStr, scriptInfo };
|
|
1768
2077
|
}
|
|
1769
2078
|
}
|
|
1770
2079
|
else if (!isDynamic) {
|
|
@@ -1787,38 +2096,38 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
1787
2096
|
*/
|
|
1788
2097
|
function getAssetsPlugins(appName) {
|
|
1789
2098
|
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]) || [];
|
|
2099
|
+
const globalPlugins = ((_a = microApp.options.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
2100
|
+
const modulePlugins = ((_c = (_b = microApp.options.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
1792
2101
|
return [...globalPlugins, ...modulePlugins];
|
|
1793
2102
|
}
|
|
1794
2103
|
/**
|
|
1795
|
-
* whether the
|
|
1796
|
-
* @param
|
|
2104
|
+
* whether the address needs to be excluded
|
|
2105
|
+
* @param address css or js link
|
|
1797
2106
|
* @param plugins microApp plugins
|
|
1798
2107
|
*/
|
|
1799
|
-
function checkExcludeUrl(
|
|
1800
|
-
if (!
|
|
2108
|
+
function checkExcludeUrl(address, appName) {
|
|
2109
|
+
if (!address)
|
|
1801
2110
|
return false;
|
|
1802
2111
|
const plugins = getAssetsPlugins(appName) || [];
|
|
1803
2112
|
return plugins.some(plugin => {
|
|
1804
2113
|
if (!plugin.excludeChecker)
|
|
1805
2114
|
return false;
|
|
1806
|
-
return plugin.excludeChecker(
|
|
2115
|
+
return plugin.excludeChecker(address);
|
|
1807
2116
|
});
|
|
1808
2117
|
}
|
|
1809
2118
|
/**
|
|
1810
|
-
* whether the
|
|
1811
|
-
* @param
|
|
2119
|
+
* whether the address needs to be ignore
|
|
2120
|
+
* @param address css or js link
|
|
1812
2121
|
* @param plugins microApp plugins
|
|
1813
2122
|
*/
|
|
1814
|
-
function checkIgnoreUrl(
|
|
1815
|
-
if (!
|
|
2123
|
+
function checkIgnoreUrl(address, appName) {
|
|
2124
|
+
if (!address)
|
|
1816
2125
|
return false;
|
|
1817
2126
|
const plugins = getAssetsPlugins(appName) || [];
|
|
1818
2127
|
return plugins.some(plugin => {
|
|
1819
2128
|
if (!plugin.ignoreChecker)
|
|
1820
2129
|
return false;
|
|
1821
|
-
return plugin.ignoreChecker(
|
|
2130
|
+
return plugin.ignoreChecker(address);
|
|
1822
2131
|
});
|
|
1823
2132
|
}
|
|
1824
2133
|
/**
|
|
@@ -1827,28 +2136,31 @@ function checkIgnoreUrl(url, appName) {
|
|
|
1827
2136
|
* @param app app
|
|
1828
2137
|
*/
|
|
1829
2138
|
function fetchScriptsFromHtml(wrapElement, app) {
|
|
1830
|
-
const
|
|
2139
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1831
2140
|
const fetchScriptPromise = [];
|
|
1832
2141
|
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
|
-
}
|
|
2142
|
+
for (const address of scriptList) {
|
|
2143
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2144
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2145
|
+
if ((!appSpaceData.defer && !appSpaceData.async) || app.isPrefetch) {
|
|
2146
|
+
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
2147
|
+
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
1843
2148
|
}
|
|
1844
2149
|
}
|
|
2150
|
+
const fiberScriptTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
1845
2151
|
if (fetchScriptPromise.length) {
|
|
1846
2152
|
promiseStream(fetchScriptPromise, (res) => {
|
|
1847
|
-
fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data);
|
|
2153
|
+
injectFiberTask(fiberScriptTasks, () => fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data, app));
|
|
1848
2154
|
}, (err) => {
|
|
1849
2155
|
logError(err, app.name);
|
|
1850
2156
|
}, () => {
|
|
1851
|
-
|
|
2157
|
+
if (fiberScriptTasks) {
|
|
2158
|
+
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2159
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
2160
|
+
}
|
|
2161
|
+
else {
|
|
2162
|
+
app.onLoad(wrapElement);
|
|
2163
|
+
}
|
|
1852
2164
|
});
|
|
1853
2165
|
}
|
|
1854
2166
|
else {
|
|
@@ -1857,169 +2169,224 @@ function fetchScriptsFromHtml(wrapElement, app) {
|
|
|
1857
2169
|
}
|
|
1858
2170
|
/**
|
|
1859
2171
|
* fetch js succeeded, record the code value
|
|
1860
|
-
* @param
|
|
1861
|
-
* @param
|
|
2172
|
+
* @param address script address
|
|
2173
|
+
* @param scriptInfo resource script info
|
|
1862
2174
|
* @param data code
|
|
1863
2175
|
*/
|
|
1864
|
-
function fetchScriptSuccess(
|
|
1865
|
-
|
|
1866
|
-
|
|
2176
|
+
function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
2177
|
+
// reset scriptInfo.code
|
|
2178
|
+
scriptInfo.code = code;
|
|
2179
|
+
/**
|
|
2180
|
+
* Pre parse script for prefetch, improve rendering performance
|
|
2181
|
+
* NOTE:
|
|
2182
|
+
* 1. if global parseResult exist, skip this step
|
|
2183
|
+
* 2. if app is inline or script is esmodule, skip this step
|
|
2184
|
+
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
2185
|
+
*/
|
|
2186
|
+
if (app.isPrefetch) {
|
|
2187
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2188
|
+
/**
|
|
2189
|
+
* 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.
|
|
2190
|
+
* This causes parsedCode to already exist when preloading ends
|
|
2191
|
+
* e.g.
|
|
2192
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
2193
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
2194
|
+
*/
|
|
2195
|
+
if (!appSpaceData.parsedCode) {
|
|
2196
|
+
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
2197
|
+
appSpaceData.wrapInSandBox = isWrapInSandBox(app, scriptInfo);
|
|
2198
|
+
if (!isInlineMode(app, scriptInfo)) {
|
|
2199
|
+
try {
|
|
2200
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2201
|
+
}
|
|
2202
|
+
catch (err) {
|
|
2203
|
+
logWarn('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
2204
|
+
}
|
|
2205
|
+
}
|
|
2206
|
+
}
|
|
1867
2207
|
}
|
|
1868
|
-
info.code = data;
|
|
1869
2208
|
}
|
|
1870
2209
|
/**
|
|
1871
2210
|
* Execute js in the mount lifecycle
|
|
1872
|
-
* @param scriptList script list
|
|
1873
2211
|
* @param app app
|
|
1874
2212
|
* @param initHook callback for umd mode
|
|
1875
2213
|
*/
|
|
1876
|
-
function execScripts(
|
|
1877
|
-
const
|
|
2214
|
+
function execScripts(app, initHook) {
|
|
2215
|
+
const fiberScriptTasks = app.fiber ? [] : null;
|
|
2216
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1878
2217
|
const deferScriptPromise = [];
|
|
1879
2218
|
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);
|
|
2219
|
+
for (const address of scriptList) {
|
|
2220
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2221
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2222
|
+
// Notice the second render
|
|
2223
|
+
if (appSpaceData.defer || appSpaceData.async) {
|
|
2224
|
+
if (scriptInfo.isExternal && !scriptInfo.code) {
|
|
2225
|
+
deferScriptPromise.push(fetchSource(address, app.name));
|
|
1892
2226
|
}
|
|
1893
2227
|
else {
|
|
1894
|
-
|
|
1895
|
-
initHook(false);
|
|
2228
|
+
deferScriptPromise.push(scriptInfo.code);
|
|
1896
2229
|
}
|
|
2230
|
+
deferScriptInfo.push([address, scriptInfo]);
|
|
2231
|
+
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
2232
|
+
}
|
|
2233
|
+
else {
|
|
2234
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
2235
|
+
runScript(address, app, scriptInfo);
|
|
2236
|
+
initHook(false);
|
|
2237
|
+
});
|
|
1897
2238
|
}
|
|
1898
2239
|
}
|
|
1899
2240
|
if (deferScriptPromise.length) {
|
|
1900
2241
|
promiseStream(deferScriptPromise, (res) => {
|
|
1901
|
-
const
|
|
1902
|
-
|
|
2242
|
+
const scriptInfo = deferScriptInfo[res.index][1];
|
|
2243
|
+
scriptInfo.code = scriptInfo.code || res.data;
|
|
1903
2244
|
}, (err) => {
|
|
1904
2245
|
initHook.errorCount = initHook.errorCount ? ++initHook.errorCount : 1;
|
|
1905
2246
|
logError(err, app.name);
|
|
1906
2247
|
}, () => {
|
|
1907
|
-
deferScriptInfo.forEach(([
|
|
1908
|
-
if (
|
|
1909
|
-
|
|
1910
|
-
|
|
2248
|
+
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
2249
|
+
if (scriptInfo.code) {
|
|
2250
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
2251
|
+
runScript(address, app, scriptInfo, initHook);
|
|
2252
|
+
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
2253
|
+
});
|
|
1911
2254
|
}
|
|
1912
2255
|
});
|
|
1913
|
-
|
|
1914
|
-
|
|
2256
|
+
/**
|
|
2257
|
+
* Fiber wraps js in requestIdleCallback and executes it in sequence
|
|
2258
|
+
* NOTE:
|
|
2259
|
+
* 1. In order to ensure the execution order, wait for all js loaded and then execute
|
|
2260
|
+
* 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
|
|
2261
|
+
*
|
|
2262
|
+
* BUG: NOTE.2 - execution order problem
|
|
2263
|
+
*/
|
|
2264
|
+
if (fiberScriptTasks) {
|
|
2265
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(isUndefined(initHook.moduleCount) ||
|
|
2266
|
+
initHook.errorCount === deferScriptPromise.length)));
|
|
2267
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
2268
|
+
}
|
|
2269
|
+
else {
|
|
2270
|
+
initHook(isUndefined(initHook.moduleCount) ||
|
|
2271
|
+
initHook.errorCount === deferScriptPromise.length);
|
|
2272
|
+
}
|
|
1915
2273
|
});
|
|
1916
2274
|
}
|
|
1917
2275
|
else {
|
|
1918
|
-
|
|
2276
|
+
if (fiberScriptTasks) {
|
|
2277
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
2278
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
2279
|
+
}
|
|
2280
|
+
else {
|
|
2281
|
+
initHook(true);
|
|
2282
|
+
}
|
|
1919
2283
|
}
|
|
1920
2284
|
}
|
|
1921
2285
|
/**
|
|
1922
2286
|
* run code
|
|
1923
|
-
* @param
|
|
2287
|
+
* @param address script address
|
|
1924
2288
|
* @param app app
|
|
1925
|
-
* @param
|
|
1926
|
-
* @param isDynamic dynamically created script
|
|
2289
|
+
* @param scriptInfo script info
|
|
1927
2290
|
* @param callback callback of module script
|
|
1928
2291
|
*/
|
|
1929
|
-
function runScript(
|
|
2292
|
+
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
1930
2293
|
var _a;
|
|
1931
2294
|
try {
|
|
1932
|
-
|
|
1933
|
-
|
|
1934
|
-
|
|
1935
|
-
|
|
1936
|
-
|
|
1937
|
-
|
|
1938
|
-
|
|
1939
|
-
|
|
2295
|
+
actionsBeforeRunScript(app);
|
|
2296
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2297
|
+
const wrapInSandBox = isWrapInSandBox(app, scriptInfo);
|
|
2298
|
+
/**
|
|
2299
|
+
* NOTE:
|
|
2300
|
+
* 1. plugins and wrapCode will only be executed once
|
|
2301
|
+
* 2. if parsedCode not exist, parsedFunction is not exist
|
|
2302
|
+
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
2303
|
+
*/
|
|
2304
|
+
if (!appSpaceData.parsedCode || appSpaceData.wrapInSandBox !== wrapInSandBox) {
|
|
2305
|
+
appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
|
|
2306
|
+
appSpaceData.wrapInSandBox = wrapInSandBox;
|
|
2307
|
+
appSpaceData.parsedFunction = null;
|
|
2308
|
+
}
|
|
2309
|
+
if (isInlineMode(app, scriptInfo)) {
|
|
2310
|
+
const scriptElement = replaceElement || pureCreateElement('script');
|
|
2311
|
+
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
2312
|
+
if (!replaceElement) {
|
|
2313
|
+
// TEST IGNORE
|
|
2314
|
+
(_a = app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-body').appendChild(scriptElement);
|
|
2315
|
+
}
|
|
1940
2316
|
}
|
|
1941
2317
|
else {
|
|
1942
|
-
|
|
1943
|
-
if (isDynamic)
|
|
1944
|
-
return document.createComment('dynamic script extract by micro-app');
|
|
2318
|
+
runParsedFunction(app, scriptInfo);
|
|
1945
2319
|
}
|
|
1946
2320
|
}
|
|
1947
2321
|
catch (e) {
|
|
1948
|
-
console.error(`[micro-app from runScript] app ${app.name}: `, e);
|
|
2322
|
+
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
1949
2323
|
}
|
|
1950
2324
|
}
|
|
1951
2325
|
/**
|
|
1952
2326
|
* Get dynamically created remote script
|
|
1953
|
-
* @param
|
|
1954
|
-
* @param
|
|
1955
|
-
* @param
|
|
2327
|
+
* @param address script address
|
|
2328
|
+
* @param app app instance
|
|
2329
|
+
* @param scriptInfo scriptInfo
|
|
1956
2330
|
* @param originScript origin script element
|
|
1957
2331
|
*/
|
|
1958
|
-
function runDynamicRemoteScript(
|
|
2332
|
+
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
2333
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
1959
2334
|
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');
|
|
2335
|
+
const runDynamicScript = () => {
|
|
2336
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
2337
|
+
if (!descriptor || descriptor.configurable) {
|
|
2338
|
+
Object.defineProperty(globalEnv.rawDocument, 'currentScript', {
|
|
2339
|
+
value: originScript,
|
|
2340
|
+
configurable: true,
|
|
2341
|
+
});
|
|
2342
|
+
}
|
|
2343
|
+
runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
|
|
2344
|
+
!isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
|
|
2345
|
+
};
|
|
2346
|
+
if (scriptInfo.code) {
|
|
2347
|
+
defer(runDynamicScript);
|
|
1983
2348
|
}
|
|
1984
2349
|
else {
|
|
1985
|
-
|
|
2350
|
+
fetchSource(address, app.name).then((code) => {
|
|
2351
|
+
scriptInfo.code = code;
|
|
2352
|
+
runDynamicScript();
|
|
2353
|
+
}).catch((err) => {
|
|
2354
|
+
logError(err, app.name);
|
|
2355
|
+
dispatchOnErrorEvent(originScript);
|
|
2356
|
+
});
|
|
1986
2357
|
}
|
|
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
|
-
});
|
|
2358
|
+
return replaceElement;
|
|
2359
|
+
}
|
|
2360
|
+
/**
|
|
2361
|
+
* Get dynamically created inline script
|
|
2362
|
+
* @param address script address
|
|
2363
|
+
* @param app app instance
|
|
2364
|
+
* @param scriptInfo scriptInfo
|
|
2365
|
+
*/
|
|
2366
|
+
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
2367
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
2368
|
+
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
2008
2369
|
return replaceElement;
|
|
2009
2370
|
}
|
|
2010
2371
|
/**
|
|
2011
2372
|
* common handle for inline script
|
|
2012
|
-
* @param
|
|
2373
|
+
* @param address script address
|
|
2013
2374
|
* @param code bound code
|
|
2014
2375
|
* @param module type='module' of script
|
|
2015
2376
|
* @param scriptElement target script element
|
|
2377
|
+
* @param attrs attributes of script element
|
|
2016
2378
|
* @param callback callback of module script
|
|
2017
2379
|
*/
|
|
2018
|
-
function runCode2InlineScript(
|
|
2380
|
+
function runCode2InlineScript(address, code, module, scriptElement, attrs, callback) {
|
|
2019
2381
|
if (module) {
|
|
2020
2382
|
// module script is async, transform it to a blob for subsequent operations
|
|
2021
|
-
|
|
2022
|
-
|
|
2383
|
+
if (isInlineScript(address)) {
|
|
2384
|
+
const blob = new Blob([code], { type: 'text/javascript' });
|
|
2385
|
+
scriptElement.src = URL.createObjectURL(blob);
|
|
2386
|
+
}
|
|
2387
|
+
else {
|
|
2388
|
+
scriptElement.src = address;
|
|
2389
|
+
}
|
|
2023
2390
|
scriptElement.setAttribute('type', 'module');
|
|
2024
2391
|
if (callback) {
|
|
2025
2392
|
callback.moduleCount && callback.moduleCount--;
|
|
@@ -2029,55 +2396,65 @@ function runCode2InlineScript(url, code, module, scriptElement, callback) {
|
|
|
2029
2396
|
else {
|
|
2030
2397
|
scriptElement.textContent = code;
|
|
2031
2398
|
}
|
|
2032
|
-
|
|
2033
|
-
scriptElement.setAttribute('data-origin-src', url);
|
|
2034
|
-
}
|
|
2399
|
+
setConvertScriptAttr(scriptElement, attrs);
|
|
2035
2400
|
}
|
|
2036
2401
|
// init & run code2Function
|
|
2037
|
-
function
|
|
2038
|
-
|
|
2039
|
-
|
|
2402
|
+
function runParsedFunction(app, scriptInfo) {
|
|
2403
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2404
|
+
if (!appSpaceData.parsedFunction) {
|
|
2405
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2040
2406
|
}
|
|
2041
|
-
|
|
2407
|
+
appSpaceData.parsedFunction.call(window);
|
|
2042
2408
|
}
|
|
2043
2409
|
/**
|
|
2044
2410
|
* bind js scope
|
|
2045
|
-
* @param url script address
|
|
2046
2411
|
* @param app app
|
|
2047
2412
|
* @param code code
|
|
2048
|
-
* @param
|
|
2413
|
+
* @param scriptInfo source script info
|
|
2049
2414
|
*/
|
|
2050
|
-
function bindScope(
|
|
2051
|
-
// TODO:
|
|
2052
|
-
if (isPlainObject(microApp.plugins)) {
|
|
2053
|
-
code = usePlugins(
|
|
2415
|
+
function bindScope(address, app, code, scriptInfo) {
|
|
2416
|
+
// TODO: cache
|
|
2417
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
2418
|
+
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
2054
2419
|
}
|
|
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__);`;
|
|
2420
|
+
if (isWrapInSandBox(app, scriptInfo)) {
|
|
2421
|
+
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
2422
|
}
|
|
2059
2423
|
return code;
|
|
2060
2424
|
}
|
|
2425
|
+
/**
|
|
2426
|
+
* actions before run script
|
|
2427
|
+
*/
|
|
2428
|
+
function actionsBeforeRunScript(app) {
|
|
2429
|
+
setActiveProxyWindow(app);
|
|
2430
|
+
}
|
|
2431
|
+
/**
|
|
2432
|
+
* set active sandBox.proxyWindow to window.__MICRO_APP_PROXY_WINDOW__
|
|
2433
|
+
*/
|
|
2434
|
+
function setActiveProxyWindow(app) {
|
|
2435
|
+
if (app.sandBox) {
|
|
2436
|
+
globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
|
|
2437
|
+
}
|
|
2438
|
+
}
|
|
2061
2439
|
/**
|
|
2062
2440
|
* Call the plugin to process the file
|
|
2063
|
-
* @param
|
|
2441
|
+
* @param address script address
|
|
2064
2442
|
* @param code code
|
|
2065
2443
|
* @param appName app name
|
|
2066
2444
|
* @param plugins plugin list
|
|
2067
|
-
* @param info source script info
|
|
2068
2445
|
*/
|
|
2069
|
-
function usePlugins(
|
|
2446
|
+
function usePlugins(address, code, appName, plugins) {
|
|
2070
2447
|
var _a;
|
|
2071
|
-
const newCode = processCode(plugins.global, code,
|
|
2072
|
-
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode,
|
|
2448
|
+
const newCode = processCode(plugins.global, code, address);
|
|
2449
|
+
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, address);
|
|
2073
2450
|
}
|
|
2074
|
-
function processCode(configs, code,
|
|
2451
|
+
function processCode(configs, code, address) {
|
|
2075
2452
|
if (!isArray(configs)) {
|
|
2076
2453
|
return code;
|
|
2077
2454
|
}
|
|
2078
2455
|
return configs.reduce((preCode, config) => {
|
|
2079
2456
|
if (isPlainObject(config) && isFunction(config.loader)) {
|
|
2080
|
-
return config.loader(preCode,
|
|
2457
|
+
return config.loader(preCode, address);
|
|
2081
2458
|
}
|
|
2082
2459
|
return preCode;
|
|
2083
2460
|
}, code);
|
|
@@ -2098,10 +2475,10 @@ function getWrapElement(str) {
|
|
|
2098
2475
|
* @param app app
|
|
2099
2476
|
* @param microAppHead micro-app-head element
|
|
2100
2477
|
*/
|
|
2101
|
-
function flatChildren(parent, app, microAppHead) {
|
|
2478
|
+
function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
2102
2479
|
const children = Array.from(parent.children);
|
|
2103
2480
|
children.length && children.forEach((child) => {
|
|
2104
|
-
flatChildren(child, app);
|
|
2481
|
+
flatChildren(child, app, microAppHead, fiberStyleTasks);
|
|
2105
2482
|
});
|
|
2106
2483
|
for (const dom of children) {
|
|
2107
2484
|
if (dom instanceof HTMLLinkElement) {
|
|
@@ -2120,7 +2497,7 @@ function flatChildren(parent, app, microAppHead) {
|
|
|
2120
2497
|
parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
|
|
2121
2498
|
}
|
|
2122
2499
|
else if (app.scopecss && !dom.hasAttribute('ignore')) {
|
|
2123
|
-
scopedCSS(dom, app);
|
|
2500
|
+
injectFiberTask(fiberStyleTasks, () => scopedCSS(dom, app));
|
|
2124
2501
|
}
|
|
2125
2502
|
}
|
|
2126
2503
|
else if (dom instanceof HTMLScriptElement) {
|
|
@@ -2148,9 +2525,17 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2148
2525
|
app.onerror(new Error(msg));
|
|
2149
2526
|
return logError(msg, app.name);
|
|
2150
2527
|
}
|
|
2151
|
-
|
|
2528
|
+
const fiberStyleTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
2529
|
+
flatChildren(wrapElement, app, microAppHead, fiberStyleTasks);
|
|
2530
|
+
/**
|
|
2531
|
+
* 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.
|
|
2532
|
+
*/
|
|
2533
|
+
const fiberStyleResult = serialExecFiberTasks(fiberStyleTasks);
|
|
2152
2534
|
if (app.source.links.size) {
|
|
2153
|
-
fetchLinksFromHtml(wrapElement, app, microAppHead);
|
|
2535
|
+
fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult);
|
|
2536
|
+
}
|
|
2537
|
+
else if (fiberStyleResult) {
|
|
2538
|
+
fiberStyleResult.then(() => app.onLoad(wrapElement));
|
|
2154
2539
|
}
|
|
2155
2540
|
else {
|
|
2156
2541
|
app.onLoad(wrapElement);
|
|
@@ -2989,9 +3374,19 @@ function addHistoryListener(appName) {
|
|
|
2989
3374
|
function dispatchPopStateEventToMicroApp(appName, proxyWindow) {
|
|
2990
3375
|
// create PopStateEvent named popstate-appName with sub app state
|
|
2991
3376
|
const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName) });
|
|
3377
|
+
/**
|
|
3378
|
+
* angular14 takes e.type as type judgment
|
|
3379
|
+
* when e.type is popstate-appName popstate event will be invalid
|
|
3380
|
+
*/
|
|
3381
|
+
// Object.defineProperty(newPopStateEvent, 'type', {
|
|
3382
|
+
// value: 'popstate',
|
|
3383
|
+
// writable: true,
|
|
3384
|
+
// configurable: true,
|
|
3385
|
+
// enumerable: true,
|
|
3386
|
+
// })
|
|
2992
3387
|
globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
|
|
2993
3388
|
// call function window.onpopstate if it exists
|
|
2994
|
-
|
|
3389
|
+
isFunction(proxyWindow.onpopstate) && proxyWindow.onpopstate(newPopStateEvent);
|
|
2995
3390
|
}
|
|
2996
3391
|
/**
|
|
2997
3392
|
* dispatch formatted hashchange event to microApp
|
|
@@ -3006,7 +3401,7 @@ function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
|
|
|
3006
3401
|
});
|
|
3007
3402
|
globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
|
|
3008
3403
|
// call function window.onhashchange if it exists
|
|
3009
|
-
|
|
3404
|
+
isFunction(proxyWindow.onhashchange) && proxyWindow.onhashchange(newHashChangeEvent);
|
|
3010
3405
|
}
|
|
3011
3406
|
/**
|
|
3012
3407
|
* dispatch native PopStateEvent, simulate location behavior
|
|
@@ -3163,7 +3558,6 @@ function reWriteHistoryMethod(method) {
|
|
|
3163
3558
|
* 1. Exec after apply pushState/replaceState
|
|
3164
3559
|
* 2. Unable to catch when base app navigate with location
|
|
3165
3560
|
* 3. When in nest app, rawPushState/rawReplaceState has been modified by parent
|
|
3166
|
-
* 4.
|
|
3167
3561
|
*/
|
|
3168
3562
|
getActiveApps(true).forEach(appName => {
|
|
3169
3563
|
const app = appInstanceMap.get(appName);
|
|
@@ -3273,7 +3667,7 @@ function createRouterApi() {
|
|
|
3273
3667
|
removeDomScope();
|
|
3274
3668
|
for (const guard of guards) {
|
|
3275
3669
|
if (isFunction(guard)) {
|
|
3276
|
-
guard(
|
|
3670
|
+
guard(to, from, appName);
|
|
3277
3671
|
}
|
|
3278
3672
|
else if (isPlainObject(guard) && isFunction(guard[appName])) {
|
|
3279
3673
|
guard[appName](to, from);
|
|
@@ -3614,7 +4008,12 @@ function createMicroRouter(appName, url) {
|
|
|
3614
4008
|
microHistory: createMicroHistory(appName, microLocation),
|
|
3615
4009
|
};
|
|
3616
4010
|
}
|
|
3617
|
-
|
|
4011
|
+
/**
|
|
4012
|
+
* 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
|
|
4013
|
+
* @param appName app.name
|
|
4014
|
+
* @param microLocation MicroLocation for sandbox
|
|
4015
|
+
* @param defaultPage default page
|
|
4016
|
+
*/
|
|
3618
4017
|
function initRouteStateWithURL(appName, microLocation, defaultPage) {
|
|
3619
4018
|
const microPath = getMicroPathFromURL(appName);
|
|
3620
4019
|
if (microPath) {
|
|
@@ -3766,7 +4165,7 @@ function useMicroEventSource() {
|
|
|
3766
4165
|
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
3767
4166
|
const globalPropertyList = ['window', 'self', 'globalThis'];
|
|
3768
4167
|
class SandBox {
|
|
3769
|
-
constructor(appName, url
|
|
4168
|
+
constructor(appName, url) {
|
|
3770
4169
|
/**
|
|
3771
4170
|
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
3772
4171
|
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
@@ -3791,26 +4190,36 @@ class SandBox {
|
|
|
3791
4190
|
// Rewrite global event listener & timeout
|
|
3792
4191
|
assign(this, effect(appName, this.microAppWindow));
|
|
3793
4192
|
// inject global properties
|
|
3794
|
-
this.initStaticGlobalKeys(this.microAppWindow, appName, url
|
|
4193
|
+
this.initStaticGlobalKeys(this.microAppWindow, appName, url);
|
|
3795
4194
|
}
|
|
3796
|
-
|
|
3797
|
-
|
|
4195
|
+
/**
|
|
4196
|
+
* open sandbox and perform some initial actions
|
|
4197
|
+
* @param umdMode is umd mode
|
|
4198
|
+
* @param baseroute base route for child
|
|
4199
|
+
* @param useMemoryRouter use virtual router
|
|
4200
|
+
* @param defaultPage default page when mount child base on virtual router
|
|
4201
|
+
* @param disablePatchRequest prevent patchRequestApi
|
|
4202
|
+
*/
|
|
4203
|
+
start({ umdMode, baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
3798
4204
|
if (!this.active) {
|
|
3799
4205
|
this.active = true;
|
|
3800
4206
|
if (useMemoryRouter) {
|
|
4207
|
+
if (isUndefined(this.microAppWindow.location)) {
|
|
4208
|
+
this.setMicroAppRouter(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__);
|
|
4209
|
+
}
|
|
3801
4210
|
this.initRouteState(defaultPage);
|
|
3802
4211
|
// unique listener of popstate event for sub app
|
|
3803
|
-
this.removeHistoryListener = addHistoryListener(this.
|
|
4212
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
3804
4213
|
}
|
|
3805
4214
|
else {
|
|
3806
|
-
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ =
|
|
4215
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
3807
4216
|
}
|
|
3808
4217
|
/**
|
|
3809
4218
|
* 1. prevent the key deleted during sandBox.stop after rewrite
|
|
3810
4219
|
* 2. umd mode will not delete any keys during sandBox.stop
|
|
3811
4220
|
*/
|
|
3812
4221
|
if (!umdMode) {
|
|
3813
|
-
this.initGlobalKeysWhenStart(this.microAppWindow, this.
|
|
4222
|
+
this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
|
|
3814
4223
|
}
|
|
3815
4224
|
if (++SandBox.activeCount === 1) {
|
|
3816
4225
|
effectDocumentEvent();
|
|
@@ -3821,7 +4230,13 @@ class SandBox {
|
|
|
3821
4230
|
fixBabelPolyfill6();
|
|
3822
4231
|
}
|
|
3823
4232
|
}
|
|
3824
|
-
|
|
4233
|
+
/**
|
|
4234
|
+
* close sandbox and perform some clean up actions
|
|
4235
|
+
* @param umdMode is umd mode
|
|
4236
|
+
* @param keepRouteState prevent reset route
|
|
4237
|
+
* @param clearEventSource clear MicroEventSource when destroy
|
|
4238
|
+
*/
|
|
4239
|
+
stop({ umdMode, keepRouteState, clearEventSource, }) {
|
|
3825
4240
|
if (this.active) {
|
|
3826
4241
|
this.releaseEffect();
|
|
3827
4242
|
this.microAppWindow.microApp.clearDataListener();
|
|
@@ -3832,7 +4247,7 @@ class SandBox {
|
|
|
3832
4247
|
this.removeHistoryListener();
|
|
3833
4248
|
}
|
|
3834
4249
|
if (clearEventSource) {
|
|
3835
|
-
clearMicroEventSource(this.
|
|
4250
|
+
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
3836
4251
|
}
|
|
3837
4252
|
/**
|
|
3838
4253
|
* NOTE:
|
|
@@ -3883,9 +4298,9 @@ class SandBox {
|
|
|
3883
4298
|
getSpecialProperties(appName) {
|
|
3884
4299
|
var _a;
|
|
3885
4300
|
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]);
|
|
4301
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
4302
|
+
this.commonActionForSpecialProperties(microApp.options.plugins.global);
|
|
4303
|
+
this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
3889
4304
|
}
|
|
3890
4305
|
}
|
|
3891
4306
|
// common action for global plugins and module plugins
|
|
@@ -4003,7 +4418,7 @@ class SandBox {
|
|
|
4003
4418
|
* @param url app url
|
|
4004
4419
|
* @param useMemoryRouter whether use memory router
|
|
4005
4420
|
*/
|
|
4006
|
-
initStaticGlobalKeys(microAppWindow, appName, url
|
|
4421
|
+
initStaticGlobalKeys(microAppWindow, appName, url) {
|
|
4007
4422
|
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
4008
4423
|
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
4009
4424
|
microAppWindow.__MICRO_APP_URL__ = url;
|
|
@@ -4018,8 +4433,6 @@ class SandBox {
|
|
|
4018
4433
|
});
|
|
4019
4434
|
this.setProxyDocument(microAppWindow, appName);
|
|
4020
4435
|
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
4021
|
-
if (useMemoryRouter)
|
|
4022
|
-
this.setMicroAppRouter(microAppWindow, appName, url);
|
|
4023
4436
|
}
|
|
4024
4437
|
setProxyDocument(microAppWindow, appName) {
|
|
4025
4438
|
const { proxyDocument, MicroDocument } = this.createProxyDocument(appName);
|
|
@@ -4197,17 +4610,19 @@ class SandBox {
|
|
|
4197
4610
|
return element;
|
|
4198
4611
|
};
|
|
4199
4612
|
const proxyDocument = new Proxy(rawDocument, {
|
|
4200
|
-
get(target, key) {
|
|
4613
|
+
get: (target, key) => {
|
|
4201
4614
|
throttleDeferForSetAppName(appName);
|
|
4202
4615
|
throttleDeferForParentNode(proxyDocument);
|
|
4203
4616
|
if (key === 'createElement')
|
|
4204
4617
|
return createElement;
|
|
4205
4618
|
if (key === Symbol.toStringTag)
|
|
4206
4619
|
return 'ProxyDocument';
|
|
4620
|
+
if (key === 'defaultView')
|
|
4621
|
+
return this.proxyWindow;
|
|
4207
4622
|
const rawValue = Reflect.get(target, key);
|
|
4208
4623
|
return isFunction(rawValue) ? bindFunctionToRawObject(rawDocument, rawValue, 'DOCUMENT') : rawValue;
|
|
4209
4624
|
},
|
|
4210
|
-
set(target, key, value) {
|
|
4625
|
+
set: (target, key, value) => {
|
|
4211
4626
|
// Fix TypeError: Illegal invocation when set document.title
|
|
4212
4627
|
Reflect.set(target, key, value);
|
|
4213
4628
|
/**
|
|
@@ -4299,10 +4714,8 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
4299
4714
|
});
|
|
4300
4715
|
formatEventInfo(event, element);
|
|
4301
4716
|
// global hooks
|
|
4302
|
-
|
|
4303
|
-
|
|
4304
|
-
// @ts-ignore
|
|
4305
|
-
microApp.lifeCycles[lifecycleName](event);
|
|
4717
|
+
if (isFunction((_a = microApp.options.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
4718
|
+
microApp.options.lifeCycles[lifecycleName](event);
|
|
4306
4719
|
}
|
|
4307
4720
|
element.dispatchEvent(event);
|
|
4308
4721
|
}
|
|
@@ -4322,7 +4735,7 @@ function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
|
4322
4735
|
// micro app instances
|
|
4323
4736
|
const appInstanceMap = new Map();
|
|
4324
4737
|
class CreateApp {
|
|
4325
|
-
constructor({ name, url,
|
|
4738
|
+
constructor({ name, url, container, scopecss, useSandbox, inline, esmodule, ssrUrl, isPrefetch, }) {
|
|
4326
4739
|
this.state = appStates.CREATED;
|
|
4327
4740
|
this.keepAliveState = null;
|
|
4328
4741
|
this.keepAliveContainer = null;
|
|
@@ -4331,30 +4744,26 @@ class CreateApp {
|
|
|
4331
4744
|
this.umdHookUnmount = null;
|
|
4332
4745
|
this.libraryName = null;
|
|
4333
4746
|
this.umdMode = false;
|
|
4334
|
-
this.isPrefetch = false;
|
|
4335
|
-
this.prefetchResolve = null;
|
|
4336
|
-
this.container = null;
|
|
4337
4747
|
this.sandBox = null;
|
|
4748
|
+
this.keepRouteState = false;
|
|
4749
|
+
this.fiber = false;
|
|
4750
|
+
this.useMemoryRouter = true;
|
|
4338
4751
|
this.name = name;
|
|
4339
4752
|
this.url = url;
|
|
4340
4753
|
this.useSandbox = useSandbox;
|
|
4341
4754
|
this.scopecss = this.useSandbox && scopecss;
|
|
4342
|
-
this.
|
|
4343
|
-
|
|
4755
|
+
this.inline = inline !== null && inline !== void 0 ? inline : false;
|
|
4756
|
+
this.esmodule = esmodule !== null && esmodule !== void 0 ? esmodule : false;
|
|
4757
|
+
// not exist when prefetch 👇
|
|
4344
4758
|
this.container = container !== null && container !== void 0 ? container : null;
|
|
4345
4759
|
this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
|
|
4346
|
-
|
|
4347
|
-
this.
|
|
4348
|
-
|
|
4349
|
-
this.
|
|
4350
|
-
this.
|
|
4351
|
-
this.disablePatchRequest = disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false;
|
|
4352
|
-
this.source = {
|
|
4353
|
-
links: new Map(),
|
|
4354
|
-
scripts: new Map(),
|
|
4355
|
-
};
|
|
4760
|
+
// not exist when normal 👇
|
|
4761
|
+
this.isPrefetch = isPrefetch !== null && isPrefetch !== void 0 ? isPrefetch : false;
|
|
4762
|
+
// init actions
|
|
4763
|
+
appInstanceMap.set(this.name, this);
|
|
4764
|
+
this.source = { html: null, links: new Set(), scripts: new Set() };
|
|
4356
4765
|
this.loadSourceCode();
|
|
4357
|
-
this.useSandbox && (this.sandBox = new SandBox(name, url
|
|
4766
|
+
this.useSandbox && (this.sandBox = new SandBox(name, url));
|
|
4358
4767
|
}
|
|
4359
4768
|
// Load resources
|
|
4360
4769
|
loadSourceCode() {
|
|
@@ -4365,16 +4774,12 @@ class CreateApp {
|
|
|
4365
4774
|
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
4366
4775
|
*/
|
|
4367
4776
|
onLoad(html) {
|
|
4368
|
-
var _a;
|
|
4369
4777
|
if (++this.loadSourceLevel === 2) {
|
|
4370
4778
|
this.source.html = html;
|
|
4371
|
-
|
|
4372
|
-
|
|
4373
|
-
|
|
4374
|
-
|
|
4375
|
-
else if (appStates.UNMOUNT !== this.state) {
|
|
4376
|
-
this.state = appStates.LOADED;
|
|
4377
|
-
this.mount();
|
|
4779
|
+
this.state = appStates.LOADED;
|
|
4780
|
+
if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
|
|
4781
|
+
// @ts-ignore
|
|
4782
|
+
getRootContainer(this.container).mount(this);
|
|
4378
4783
|
}
|
|
4379
4784
|
}
|
|
4380
4785
|
}
|
|
@@ -4384,10 +4789,6 @@ class CreateApp {
|
|
|
4384
4789
|
*/
|
|
4385
4790
|
onLoadError(e) {
|
|
4386
4791
|
this.loadSourceLevel = -1;
|
|
4387
|
-
if (this.prefetchResolve) {
|
|
4388
|
-
this.prefetchResolve();
|
|
4389
|
-
this.prefetchResolve = null;
|
|
4390
|
-
}
|
|
4391
4792
|
if (appStates.UNMOUNT !== this.state) {
|
|
4392
4793
|
this.onerror(e);
|
|
4393
4794
|
this.state = appStates.LOAD_FAILED;
|
|
@@ -4401,15 +4802,16 @@ class CreateApp {
|
|
|
4401
4802
|
* @param keepRouteState keep route state when unmount, default is false
|
|
4402
4803
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
4403
4804
|
*/
|
|
4404
|
-
mount(container, inline, baseroute, keepRouteState, defaultPage,
|
|
4405
|
-
var _a, _b
|
|
4406
|
-
this.
|
|
4407
|
-
this.
|
|
4408
|
-
this.
|
|
4409
|
-
this.
|
|
4410
|
-
this.
|
|
4411
|
-
|
|
4412
|
-
this.
|
|
4805
|
+
mount({ container, inline, esmodule, useMemoryRouter, baseroute, keepRouteState, defaultPage, disablePatchRequest, fiber, }) {
|
|
4806
|
+
var _a, _b;
|
|
4807
|
+
this.container = container;
|
|
4808
|
+
this.inline = inline;
|
|
4809
|
+
this.esmodule = esmodule;
|
|
4810
|
+
this.keepRouteState = keepRouteState;
|
|
4811
|
+
this.fiber = fiber;
|
|
4812
|
+
// use in sandbox/effect
|
|
4813
|
+
this.useMemoryRouter = useMemoryRouter;
|
|
4814
|
+
// this.hiddenRouter = hiddenRouter ?? this.hiddenRouter
|
|
4413
4815
|
if (this.loadSourceLevel !== 2) {
|
|
4414
4816
|
this.state = appStates.LOADING;
|
|
4415
4817
|
return;
|
|
@@ -4417,12 +4819,18 @@ class CreateApp {
|
|
|
4417
4819
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
4418
4820
|
this.state = appStates.MOUNTING;
|
|
4419
4821
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
4420
|
-
(
|
|
4822
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.start({
|
|
4823
|
+
umdMode: this.umdMode,
|
|
4824
|
+
baseroute,
|
|
4825
|
+
useMemoryRouter,
|
|
4826
|
+
defaultPage,
|
|
4827
|
+
disablePatchRequest,
|
|
4828
|
+
});
|
|
4421
4829
|
let umdHookMountResult; // result of mount function
|
|
4422
4830
|
if (!this.umdMode) {
|
|
4423
4831
|
let hasDispatchMountedEvent = false;
|
|
4424
4832
|
// if all js are executed, param isFinished will be true
|
|
4425
|
-
execScripts(this
|
|
4833
|
+
execScripts(this, (isFinished) => {
|
|
4426
4834
|
if (!this.umdMode) {
|
|
4427
4835
|
const { mount, unmount } = this.getUmdLibraryHooks();
|
|
4428
4836
|
/**
|
|
@@ -4452,7 +4860,7 @@ class CreateApp {
|
|
|
4452
4860
|
});
|
|
4453
4861
|
}
|
|
4454
4862
|
else {
|
|
4455
|
-
(
|
|
4863
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.rebuildUmdSnapshot();
|
|
4456
4864
|
try {
|
|
4457
4865
|
umdHookMountResult = this.umdHookMount();
|
|
4458
4866
|
}
|
|
@@ -4554,7 +4962,11 @@ class CreateApp {
|
|
|
4554
4962
|
* 1. if destroy is true, clear route state
|
|
4555
4963
|
* 2. umd mode and keep-alive will not clear EventSource
|
|
4556
4964
|
*/
|
|
4557
|
-
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop(
|
|
4965
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.stop({
|
|
4966
|
+
umdMode: this.umdMode,
|
|
4967
|
+
keepRouteState: this.keepRouteState && !destroy,
|
|
4968
|
+
clearEventSource: !this.umdMode || destroy,
|
|
4969
|
+
});
|
|
4558
4970
|
if (!getActiveApps().length) {
|
|
4559
4971
|
releasePatchSetAttribute();
|
|
4560
4972
|
}
|
|
@@ -4653,7 +5065,8 @@ function defineElement(tagName) {
|
|
|
4653
5065
|
super();
|
|
4654
5066
|
this.isWaiting = false;
|
|
4655
5067
|
this.cacheData = null;
|
|
4656
|
-
this.
|
|
5068
|
+
this.connectedCount = 0;
|
|
5069
|
+
this.connectStateMap = new Map();
|
|
4657
5070
|
this.appName = ''; // app name
|
|
4658
5071
|
this.appUrl = ''; // app url
|
|
4659
5072
|
this.ssrUrl = ''; // html path in ssr mode
|
|
@@ -4663,6 +5076,8 @@ function defineElement(tagName) {
|
|
|
4663
5076
|
*/
|
|
4664
5077
|
this.handleAttributeUpdate = () => {
|
|
4665
5078
|
this.isWaiting = false;
|
|
5079
|
+
if (!this.connectStateMap.get(this.connectedCount))
|
|
5080
|
+
return;
|
|
4666
5081
|
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
4667
5082
|
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
4668
5083
|
if (this.legalAttribute('name', formatAttrName) && this.legalAttribute('url', formatAttrUrl)) {
|
|
@@ -4714,12 +5129,21 @@ function defineElement(tagName) {
|
|
|
4714
5129
|
// baseRoute: route prefix, default is ''
|
|
4715
5130
|
// keep-alive: open keep-alive mode
|
|
4716
5131
|
connectedCallback() {
|
|
4717
|
-
|
|
4718
|
-
|
|
4719
|
-
|
|
5132
|
+
const cacheCount = ++this.connectedCount;
|
|
5133
|
+
this.connectStateMap.set(cacheCount, true);
|
|
5134
|
+
/**
|
|
5135
|
+
* In some special scenes, such as vue's keep-alive, the micro-app will be inserted and deleted twice in an instant
|
|
5136
|
+
* So we execute the mount method async and record connectState to prevent repeated rendering
|
|
5137
|
+
*/
|
|
5138
|
+
defer(() => {
|
|
5139
|
+
if (this.connectStateMap.get(cacheCount)) {
|
|
5140
|
+
dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED);
|
|
5141
|
+
this.initialMount();
|
|
5142
|
+
}
|
|
5143
|
+
});
|
|
4720
5144
|
}
|
|
4721
5145
|
disconnectedCallback() {
|
|
4722
|
-
this.
|
|
5146
|
+
this.connectStateMap.set(this.connectedCount, false);
|
|
4723
5147
|
const app = appInstanceMap.get(this.appName);
|
|
4724
5148
|
if (app &&
|
|
4725
5149
|
app.getAppState() !== appStates.UNMOUNT &&
|
|
@@ -4767,7 +5191,7 @@ function defineElement(tagName) {
|
|
|
4767
5191
|
}
|
|
4768
5192
|
// handle for connectedCallback run before attributeChangedCallback
|
|
4769
5193
|
handleInitialNameAndUrl() {
|
|
4770
|
-
this.
|
|
5194
|
+
this.connectStateMap.get(this.connectedCount) && this.initialMount();
|
|
4771
5195
|
}
|
|
4772
5196
|
/**
|
|
4773
5197
|
* first mount of this app
|
|
@@ -4782,26 +5206,35 @@ function defineElement(tagName) {
|
|
|
4782
5206
|
if (appInstanceMap.has(this.appName)) {
|
|
4783
5207
|
const app = appInstanceMap.get(this.appName);
|
|
4784
5208
|
const existAppUrl = app.ssrUrl || app.url;
|
|
4785
|
-
const
|
|
4786
|
-
|
|
4787
|
-
|
|
5209
|
+
const targetAppUrl = this.ssrUrl || this.appUrl;
|
|
5210
|
+
/**
|
|
5211
|
+
* NOTE:
|
|
5212
|
+
* 1. keep-alive don't care about ssrUrl
|
|
5213
|
+
* 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
|
|
5214
|
+
* 3. When scopecss, useSandbox of prefetch app different from target app, delete prefetch app and create new one
|
|
5215
|
+
*/
|
|
4788
5216
|
if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
4789
5217
|
app.url === this.appUrl) {
|
|
4790
5218
|
this.handleShowKeepAliveApp(app);
|
|
4791
5219
|
}
|
|
4792
|
-
else if (existAppUrl ===
|
|
4793
|
-
app.
|
|
5220
|
+
else if (existAppUrl === targetAppUrl && (app.getAppState() === appStates.UNMOUNT ||
|
|
5221
|
+
(app.isPrefetch && (app.scopecss === this.isScopecss() &&
|
|
5222
|
+
app.useSandbox === this.isSandbox())))) {
|
|
4794
5223
|
this.handleAppMount(app);
|
|
4795
5224
|
}
|
|
4796
5225
|
else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
|
|
4797
|
-
|
|
4798
|
-
|
|
4799
|
-
|
|
4800
|
-
|
|
5226
|
+
if (process.env.NODE_ENV !== 'production' &&
|
|
5227
|
+
app.scopecss === this.isScopecss() &&
|
|
5228
|
+
app.useSandbox === this.isSandbox()) {
|
|
5229
|
+
/**
|
|
5230
|
+
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
5231
|
+
*/
|
|
5232
|
+
logWarn(`the ${app.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${existAppUrl} replaced by a new app with url: ${targetAppUrl}`, this.appName);
|
|
5233
|
+
}
|
|
4801
5234
|
this.handleCreateApp();
|
|
4802
5235
|
}
|
|
4803
5236
|
else {
|
|
4804
|
-
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
5237
|
+
logError(`app name conflict, an app named: ${this.appName} with url: ${existAppUrl} is running`, this.appName);
|
|
4805
5238
|
}
|
|
4806
5239
|
}
|
|
4807
5240
|
else {
|
|
@@ -4872,9 +5305,24 @@ function defineElement(tagName) {
|
|
|
4872
5305
|
*/
|
|
4873
5306
|
handleAppMount(app) {
|
|
4874
5307
|
app.isPrefetch = false;
|
|
4875
|
-
defer(() =>
|
|
4876
|
-
|
|
4877
|
-
|
|
5308
|
+
defer(() => this.mount(app));
|
|
5309
|
+
}
|
|
5310
|
+
/**
|
|
5311
|
+
* public mount action for micro_app_element & create_app
|
|
5312
|
+
*/
|
|
5313
|
+
mount(app) {
|
|
5314
|
+
var _a;
|
|
5315
|
+
app.mount({
|
|
5316
|
+
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
5317
|
+
inline: this.getDisposeResult('inline'),
|
|
5318
|
+
esmodule: this.getDisposeResult('esmodule'),
|
|
5319
|
+
useMemoryRouter: !this.getDisposeResult('disable-memory-router'),
|
|
5320
|
+
baseroute: this.getBaseRouteCompatible(),
|
|
5321
|
+
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
5322
|
+
defaultPage: this.getDefaultPageValue(),
|
|
5323
|
+
hiddenRouter: this.getDisposeResult('hidden-router'),
|
|
5324
|
+
disablePatchRequest: this.getDisposeResult('disable-patch-request'),
|
|
5325
|
+
fiber: this.getDisposeResult('fiber'),
|
|
4878
5326
|
});
|
|
4879
5327
|
}
|
|
4880
5328
|
// create app instance
|
|
@@ -4887,22 +5335,16 @@ function defineElement(tagName) {
|
|
|
4887
5335
|
if (appInstanceMap.has(this.appName)) {
|
|
4888
5336
|
appInstanceMap.get(this.appName).actionsForCompletelyDestroy();
|
|
4889
5337
|
}
|
|
4890
|
-
|
|
5338
|
+
new CreateApp({
|
|
4891
5339
|
name: this.appName,
|
|
4892
5340
|
url: this.appUrl,
|
|
4893
|
-
|
|
4894
|
-
|
|
5341
|
+
scopecss: this.isScopecss(),
|
|
5342
|
+
useSandbox: this.isSandbox(),
|
|
4895
5343
|
inline: this.getDisposeResult('inline'),
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
baseroute: this.getBaseRouteCompatible(),
|
|
4900
|
-
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
4901
|
-
defaultPage: this.getDefaultPageValue(),
|
|
4902
|
-
hiddenRouter: this.getDisposeResult('hidden-router'),
|
|
4903
|
-
disablePatchRequest: this.getDisposeResult('disable-patch-request'),
|
|
5344
|
+
esmodule: this.getDisposeResult('esmodule'),
|
|
5345
|
+
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
5346
|
+
ssrUrl: this.ssrUrl,
|
|
4904
5347
|
});
|
|
4905
|
-
appInstanceMap.set(this.appName, instance);
|
|
4906
5348
|
}
|
|
4907
5349
|
/**
|
|
4908
5350
|
* unmount app
|
|
@@ -4934,8 +5376,7 @@ function defineElement(tagName) {
|
|
|
4934
5376
|
* @param name Configuration item name
|
|
4935
5377
|
*/
|
|
4936
5378
|
getDisposeResult(name) {
|
|
4937
|
-
|
|
4938
|
-
return (this.compatibleSpecialProperties(name) || !!microApp[name]) && this.compatibleDisableSpecialProperties(name);
|
|
5379
|
+
return (this.compatibleSpecialProperties(name) || !!microApp.options[name]) && this.compatibleDisableSpecialProperties(name);
|
|
4939
5380
|
}
|
|
4940
5381
|
// compatible of disableScopecss & disableSandbox
|
|
4941
5382
|
compatibleSpecialProperties(name) {
|
|
@@ -4957,6 +5398,12 @@ function defineElement(tagName) {
|
|
|
4957
5398
|
}
|
|
4958
5399
|
return this.getAttribute(name) !== 'false';
|
|
4959
5400
|
}
|
|
5401
|
+
isScopecss() {
|
|
5402
|
+
return !(this.getDisposeResult('disable-scopecss') || this.getDisposeResult('shadowDOM'));
|
|
5403
|
+
}
|
|
5404
|
+
isSandbox() {
|
|
5405
|
+
return !this.getDisposeResult('disable-sandbox');
|
|
5406
|
+
}
|
|
4960
5407
|
/**
|
|
4961
5408
|
* 2021-09-08
|
|
4962
5409
|
* get baseRoute
|
|
@@ -5004,8 +5451,10 @@ function defineElement(tagName) {
|
|
|
5004
5451
|
* get config of default page
|
|
5005
5452
|
*/
|
|
5006
5453
|
getDefaultPageValue() {
|
|
5007
|
-
|
|
5008
|
-
|
|
5454
|
+
return (router.getDefaultPage(this.appName) ||
|
|
5455
|
+
this.getAttribute('default-page') ||
|
|
5456
|
+
this.getAttribute('defaultPage') ||
|
|
5457
|
+
'');
|
|
5009
5458
|
}
|
|
5010
5459
|
/**
|
|
5011
5460
|
* Data from the base application
|
|
@@ -5062,33 +5511,40 @@ function preFetch(apps) {
|
|
|
5062
5511
|
});
|
|
5063
5512
|
}
|
|
5064
5513
|
// sequential preload app
|
|
5065
|
-
function preFetchInSerial(
|
|
5066
|
-
return
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
|
|
5084
|
-
else {
|
|
5514
|
+
function preFetchInSerial(options) {
|
|
5515
|
+
return promiseRequestIdle((resolve) => {
|
|
5516
|
+
var _a, _b, _c, _d, _e, _f;
|
|
5517
|
+
if (isPlainObject(options) && navigator.onLine) {
|
|
5518
|
+
options.name = formatAppName(options.name);
|
|
5519
|
+
options.url = formatAppURL(options.url, options.name);
|
|
5520
|
+
if (options.name && options.url && !appInstanceMap.has(options.name)) {
|
|
5521
|
+
const app = new CreateApp({
|
|
5522
|
+
name: options.name,
|
|
5523
|
+
url: options.url,
|
|
5524
|
+
scopecss: !((_b = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss) !== null && _b !== void 0 ? _b : microApp.options['disable-scopecss']),
|
|
5525
|
+
useSandbox: !((_d = (_c = options['disable-sandbox']) !== null && _c !== void 0 ? _c : options.disableSandbox) !== null && _d !== void 0 ? _d : microApp.options['disable-sandbox']),
|
|
5526
|
+
inline: (_e = options.inline) !== null && _e !== void 0 ? _e : microApp.options.inline,
|
|
5527
|
+
esmodule: (_f = options.esmodule) !== null && _f !== void 0 ? _f : microApp.options.esmodule,
|
|
5528
|
+
isPrefetch: true,
|
|
5529
|
+
});
|
|
5530
|
+
const oldOnload = app.onLoad;
|
|
5531
|
+
const oldOnLoadError = app.onLoadError;
|
|
5532
|
+
app.onLoad = (html) => {
|
|
5085
5533
|
resolve();
|
|
5086
|
-
|
|
5534
|
+
oldOnload.call(app, html);
|
|
5535
|
+
};
|
|
5536
|
+
app.onLoadError = (e) => {
|
|
5537
|
+
resolve();
|
|
5538
|
+
oldOnLoadError.call(app, e);
|
|
5539
|
+
};
|
|
5087
5540
|
}
|
|
5088
5541
|
else {
|
|
5089
5542
|
resolve();
|
|
5090
5543
|
}
|
|
5091
|
-
}
|
|
5544
|
+
}
|
|
5545
|
+
else {
|
|
5546
|
+
resolve();
|
|
5547
|
+
}
|
|
5092
5548
|
});
|
|
5093
5549
|
}
|
|
5094
5550
|
/**
|
|
@@ -5098,21 +5554,35 @@ function preFetchInSerial(prefetchApp) {
|
|
|
5098
5554
|
function getGlobalAssets(assets) {
|
|
5099
5555
|
if (isPlainObject(assets)) {
|
|
5100
5556
|
requestIdleCallback(() => {
|
|
5101
|
-
fetchGlobalResources(assets.js, 'js',
|
|
5102
|
-
fetchGlobalResources(assets.css, 'css',
|
|
5557
|
+
fetchGlobalResources(assets.js, 'js', sourceCenter.script);
|
|
5558
|
+
fetchGlobalResources(assets.css, 'css', sourceCenter.link);
|
|
5103
5559
|
});
|
|
5104
5560
|
}
|
|
5105
5561
|
}
|
|
5106
5562
|
// TODO: requestIdleCallback for every file
|
|
5107
|
-
function fetchGlobalResources(resources, suffix,
|
|
5563
|
+
function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
5108
5564
|
if (isArray(resources)) {
|
|
5109
|
-
const effectiveResource = resources.filter((path) => isString(path) && path.includes(`.${suffix}`) && !
|
|
5565
|
+
const effectiveResource = resources.filter((path) => isString(path) && path.includes(`.${suffix}`) && !sourceHandler.hasInfo(path));
|
|
5110
5566
|
const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
|
|
5111
5567
|
// fetch resource with stream
|
|
5112
5568
|
promiseStream(fetchResourcePromise, (res) => {
|
|
5113
5569
|
const path = effectiveResource[res.index];
|
|
5114
|
-
if (
|
|
5115
|
-
|
|
5570
|
+
if (suffix === 'js') {
|
|
5571
|
+
if (!sourceHandler.hasInfo(path)) {
|
|
5572
|
+
sourceHandler.setInfo(path, {
|
|
5573
|
+
code: res.data,
|
|
5574
|
+
isExternal: false,
|
|
5575
|
+
appSpace: {},
|
|
5576
|
+
});
|
|
5577
|
+
}
|
|
5578
|
+
}
|
|
5579
|
+
else {
|
|
5580
|
+
if (!sourceHandler.hasInfo(path)) {
|
|
5581
|
+
sourceHandler.setInfo(path, {
|
|
5582
|
+
code: res.data,
|
|
5583
|
+
appSpace: {}
|
|
5584
|
+
});
|
|
5585
|
+
}
|
|
5116
5586
|
}
|
|
5117
5587
|
}, (err) => {
|
|
5118
5588
|
logError(err);
|
|
@@ -5217,6 +5687,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
5217
5687
|
constructor() {
|
|
5218
5688
|
super(...arguments);
|
|
5219
5689
|
this.tagName = 'micro-app';
|
|
5690
|
+
this.options = {};
|
|
5220
5691
|
this.preFetch = preFetch;
|
|
5221
5692
|
this.router = router;
|
|
5222
5693
|
}
|
|
@@ -5237,26 +5708,10 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
5237
5708
|
return logWarn(`element ${this.tagName} is already defined`);
|
|
5238
5709
|
}
|
|
5239
5710
|
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);
|
|
5711
|
+
if (isPlainObject(options)) {
|
|
5712
|
+
this.options = options;
|
|
5713
|
+
options['disable-scopecss'] = (_a = options['disable-scopecss']) !== null && _a !== void 0 ? _a : options.disableScopecss;
|
|
5714
|
+
options['disable-sandbox'] = (_b = options['disable-sandbox']) !== null && _b !== void 0 ? _b : options.disableSandbox;
|
|
5260
5715
|
// load app assets when browser is idle
|
|
5261
5716
|
options.preFetchApps && preFetch(options.preFetchApps);
|
|
5262
5717
|
// load global assets when browser is idle
|
|
@@ -5272,7 +5727,6 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
5272
5727
|
}
|
|
5273
5728
|
}
|
|
5274
5729
|
}
|
|
5275
|
-
this.plugins = options.plugins;
|
|
5276
5730
|
}
|
|
5277
5731
|
}
|
|
5278
5732
|
// define customElement after init
|