@micro-zoe/micro-app 0.4.2 → 0.5.2
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 +12 -57
- package/README.zh-cn.md +11 -54
- package/lib/index.d.ts +113 -28
- package/lib/index.esm.js +1691 -1621
- 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 +21 -25
- package/typings/global.d.ts +9 -0
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '0.
|
|
1
|
+
const version = '0.5.2';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -37,6 +37,10 @@ function isPromise(target) {
|
|
|
37
37
|
function isBoundFunction(target) {
|
|
38
38
|
return isFunction(target) && target.name.indexOf('bound ') === 0 && !target.hasOwnProperty('prototype');
|
|
39
39
|
}
|
|
40
|
+
// is ShadowRoot
|
|
41
|
+
function isShadowRoot(target) {
|
|
42
|
+
return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
|
|
43
|
+
}
|
|
40
44
|
/**
|
|
41
45
|
* format error log
|
|
42
46
|
* @param msg message
|
|
@@ -81,10 +85,12 @@ function addProtocol(url) {
|
|
|
81
85
|
return url.startsWith('//') ? `${location.protocol}${url}` : url;
|
|
82
86
|
}
|
|
83
87
|
/**
|
|
84
|
-
*
|
|
85
|
-
*
|
|
88
|
+
* format URL address
|
|
89
|
+
* note the scenes:
|
|
90
|
+
* 1. micro-app -> attributeChangedCallback
|
|
91
|
+
* 2. preFetch
|
|
86
92
|
*/
|
|
87
|
-
function
|
|
93
|
+
function formatAppURL(url, appName = null) {
|
|
88
94
|
if (!isString(url) || !url)
|
|
89
95
|
return '';
|
|
90
96
|
try {
|
|
@@ -101,6 +107,20 @@ function formatURL(url, appName = null) {
|
|
|
101
107
|
return '';
|
|
102
108
|
}
|
|
103
109
|
}
|
|
110
|
+
/**
|
|
111
|
+
* format name
|
|
112
|
+
* note the scenes:
|
|
113
|
+
* 1. micro-app -> attributeChangedCallback
|
|
114
|
+
* 2. event_center -> EventCenterForMicroApp -> constructor
|
|
115
|
+
* 3. event_center -> EventCenterForBaseApp -> all methods
|
|
116
|
+
* 4. preFetch
|
|
117
|
+
* 5. plugins
|
|
118
|
+
*/
|
|
119
|
+
function formatAppName(name) {
|
|
120
|
+
if (!isString(name) || !name)
|
|
121
|
+
return '';
|
|
122
|
+
return name.replace(/(^\d+)|([^\w\d-_])/gi, '');
|
|
123
|
+
}
|
|
104
124
|
/**
|
|
105
125
|
* Get valid address, such as https://xxx/xx/xx.html to https://xxx/xx/
|
|
106
126
|
* @param url app.url
|
|
@@ -237,7 +257,7 @@ function pureCreateElement(tagName, options) {
|
|
|
237
257
|
* @param target Accept cloned elements
|
|
238
258
|
* @param deep deep clone or transfer dom
|
|
239
259
|
*/
|
|
240
|
-
function
|
|
260
|
+
function cloneContainer(origin, target, deep) {
|
|
241
261
|
target.innerHTML = '';
|
|
242
262
|
if (deep) {
|
|
243
263
|
const clonedNode = origin.cloneNode(true);
|
|
@@ -253,6 +273,23 @@ function cloneNode(origin, target, deep) {
|
|
|
253
273
|
});
|
|
254
274
|
}
|
|
255
275
|
}
|
|
276
|
+
// is invalid key of querySelector
|
|
277
|
+
function isInvalidQuerySelectorKey(key) {
|
|
278
|
+
return !key || /(^\d)|([^\w\d-_\u4e00-\u9fa5])/gi.test(key);
|
|
279
|
+
}
|
|
280
|
+
// unique element
|
|
281
|
+
function isUniqueElement(key) {
|
|
282
|
+
return (/^body$/i.test(key) ||
|
|
283
|
+
/^head$/i.test(key) ||
|
|
284
|
+
/^html$/i.test(key));
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* get micro-app element
|
|
288
|
+
* @param target app container
|
|
289
|
+
*/
|
|
290
|
+
function getRootContainer(target) {
|
|
291
|
+
return (isShadowRoot(target) ? target.host : target);
|
|
292
|
+
}
|
|
256
293
|
|
|
257
294
|
var ObservedAttrName;
|
|
258
295
|
(function (ObservedAttrName) {
|
|
@@ -280,6 +317,21 @@ var lifeCycles;
|
|
|
280
317
|
lifeCycles["ERROR"] = "error";
|
|
281
318
|
})(lifeCycles || (lifeCycles = {}));
|
|
282
319
|
|
|
320
|
+
/**
|
|
321
|
+
* fetch source of html, js, css
|
|
322
|
+
* @param url source path
|
|
323
|
+
* @param appName app name
|
|
324
|
+
* @param config config of fetch
|
|
325
|
+
*/
|
|
326
|
+
function fetchSource(url, appName = null, options = {}) {
|
|
327
|
+
if (isFunction(microApp.fetch)) {
|
|
328
|
+
return microApp.fetch(url, options, appName);
|
|
329
|
+
}
|
|
330
|
+
return fetch(url, options).then((res) => {
|
|
331
|
+
return res.text();
|
|
332
|
+
});
|
|
333
|
+
}
|
|
334
|
+
|
|
283
335
|
const globalEnv = {};
|
|
284
336
|
function initGlobalEnv() {
|
|
285
337
|
if (isBrowser) {
|
|
@@ -466,33 +518,35 @@ function scopedRule(rules, prefix) {
|
|
|
466
518
|
*/
|
|
467
519
|
function commonAction(templateStyle, styleElement, originContent, prefix, baseURI, linkpath) {
|
|
468
520
|
var _a, _b;
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
521
|
+
if (!styleElement.__MICRO_APP_HAS_SCOPED__) {
|
|
522
|
+
const rules = Array.from((_b = (_a = templateStyle.sheet) === null || _a === void 0 ? void 0 : _a.cssRules) !== null && _b !== void 0 ? _b : []);
|
|
523
|
+
let result = scopedHost(scopedRule(rules, prefix), baseURI, originContent, linkpath);
|
|
524
|
+
/**
|
|
525
|
+
* Solve the problem of missing content quotes in some Safari browsers
|
|
526
|
+
* docs: https://developer.mozilla.org/zh-CN/docs/Web/CSS/content
|
|
527
|
+
* If there are still problems, it is recommended to use the attr()
|
|
528
|
+
*/
|
|
529
|
+
if (isSafari()) {
|
|
530
|
+
result = result.replace(/([;{]\s*content:\s*)([^\s"][^";}]*)/gm, (all, $1, $2) => {
|
|
531
|
+
if ($2 === 'none' ||
|
|
532
|
+
/^(url\()|(counter\()|(attr\()|(open-quote)|(close-quote)/.test($2)) {
|
|
533
|
+
return all;
|
|
534
|
+
}
|
|
535
|
+
return `${$1}"${$2}"`;
|
|
536
|
+
});
|
|
537
|
+
}
|
|
538
|
+
styleElement.textContent = result;
|
|
539
|
+
styleElement.__MICRO_APP_HAS_SCOPED__ = true;
|
|
484
540
|
}
|
|
485
|
-
styleElement.textContent = result;
|
|
486
541
|
}
|
|
487
542
|
/**
|
|
488
543
|
* scopedCSS
|
|
489
544
|
* @param styleElement target style element
|
|
490
545
|
* @param appName app name
|
|
491
546
|
*/
|
|
492
|
-
function scopedCSS(styleElement,
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
const prefix = `${microApp.tagName}[name=${appName}]`;
|
|
547
|
+
function scopedCSS(styleElement, app) {
|
|
548
|
+
if (app.scopecss) {
|
|
549
|
+
const prefix = `${microApp.tagName}[name=${app.name}]`;
|
|
496
550
|
let templateStyle = globalEnv.templateStyle;
|
|
497
551
|
if (!templateStyle) {
|
|
498
552
|
globalEnv.templateStyle = templateStyle = pureCreateElement('style');
|
|
@@ -502,7 +556,7 @@ function scopedCSS(styleElement, appName) {
|
|
|
502
556
|
}
|
|
503
557
|
if (styleElement.textContent) {
|
|
504
558
|
templateStyle.textContent = styleElement.textContent;
|
|
505
|
-
commonAction(templateStyle, styleElement, styleElement.textContent, prefix, app.url, styleElement.
|
|
559
|
+
commonAction(templateStyle, styleElement, styleElement.textContent, prefix, app.url, styleElement.__MICRO_APP_LINK_PATH__);
|
|
506
560
|
templateStyle.textContent = '';
|
|
507
561
|
}
|
|
508
562
|
else {
|
|
@@ -513,7 +567,7 @@ function scopedCSS(styleElement, appName) {
|
|
|
513
567
|
if ((!styleElement.textContent && ((_b = (_a = styleElement.sheet) === null || _a === void 0 ? void 0 : _a.cssRules) === null || _b === void 0 ? void 0 : _b.length)) ||
|
|
514
568
|
styleElement.hasAttribute('data-styled'))
|
|
515
569
|
return;
|
|
516
|
-
commonAction(styleElement, styleElement, styleElement.textContent, prefix, app.url, styleElement.
|
|
570
|
+
commonAction(styleElement, styleElement, styleElement.textContent, prefix, app.url, styleElement.__MICRO_APP_LINK_PATH__);
|
|
517
571
|
});
|
|
518
572
|
observer.observe(styleElement, { childList: true });
|
|
519
573
|
}
|
|
@@ -571,7 +625,7 @@ const globalLinks = new Map();
|
|
|
571
625
|
* @param microAppHead micro-app-head element
|
|
572
626
|
* @param isDynamic dynamic insert
|
|
573
627
|
*/
|
|
574
|
-
function extractLinkFromHtml(link, parent, app,
|
|
628
|
+
function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
575
629
|
const rel = link.getAttribute('rel');
|
|
576
630
|
let href = link.getAttribute('href');
|
|
577
631
|
let replaceComment = null;
|
|
@@ -579,12 +633,9 @@ function extractLinkFromHtml(link, parent, app, microAppHead, isDynamic = false)
|
|
|
579
633
|
href = CompletionPath(href, app.url);
|
|
580
634
|
if (!isDynamic) {
|
|
581
635
|
replaceComment = document.createComment(`link element with href=${href} move to micro-app-head as style element`);
|
|
582
|
-
const placeholderComment = document.createComment(`placeholder for link with href=${href}`);
|
|
583
|
-
// all style elements insert into microAppHead
|
|
584
|
-
microAppHead.appendChild(placeholderComment);
|
|
585
636
|
app.source.links.set(href, {
|
|
586
637
|
code: '',
|
|
587
|
-
placeholder:
|
|
638
|
+
placeholder: replaceComment,
|
|
588
639
|
isGlobal: link.hasAttribute('global'),
|
|
589
640
|
});
|
|
590
641
|
}
|
|
@@ -599,7 +650,7 @@ function extractLinkFromHtml(link, parent, app, microAppHead, isDynamic = false)
|
|
|
599
650
|
}
|
|
600
651
|
}
|
|
601
652
|
else if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
|
|
602
|
-
// preload prefetch
|
|
653
|
+
// preload prefetch icon ....
|
|
603
654
|
if (isDynamic) {
|
|
604
655
|
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
605
656
|
}
|
|
@@ -653,8 +704,9 @@ function fetchLinkSuccess(url, info, data, microAppHead, app) {
|
|
|
653
704
|
}
|
|
654
705
|
const styleLink = pureCreateElement('style');
|
|
655
706
|
styleLink.textContent = data;
|
|
656
|
-
styleLink.
|
|
657
|
-
|
|
707
|
+
styleLink.__MICRO_APP_LINK_PATH__ = url;
|
|
708
|
+
styleLink.setAttribute('data-origin-href', url);
|
|
709
|
+
microAppHead.replaceChild(scopedCSS(styleLink, app), info.placeholder);
|
|
658
710
|
info.placeholder = null;
|
|
659
711
|
info.code = data;
|
|
660
712
|
}
|
|
@@ -669,7 +721,7 @@ function fetchLinkSuccess(url, info, data, microAppHead, app) {
|
|
|
669
721
|
function foramtDynamicLink(url, info, app, originLink, replaceStyle) {
|
|
670
722
|
if (app.source.links.has(url)) {
|
|
671
723
|
replaceStyle.textContent = app.source.links.get(url).code;
|
|
672
|
-
scopedCSS(replaceStyle, app
|
|
724
|
+
scopedCSS(replaceStyle, app);
|
|
673
725
|
defer(() => dispatchOnLoadEvent(originLink));
|
|
674
726
|
return;
|
|
675
727
|
}
|
|
@@ -678,17 +730,16 @@ function foramtDynamicLink(url, info, app, originLink, replaceStyle) {
|
|
|
678
730
|
info.code = code;
|
|
679
731
|
app.source.links.set(url, info);
|
|
680
732
|
replaceStyle.textContent = code;
|
|
681
|
-
scopedCSS(replaceStyle, app
|
|
733
|
+
scopedCSS(replaceStyle, app);
|
|
682
734
|
defer(() => dispatchOnLoadEvent(originLink));
|
|
683
735
|
return;
|
|
684
736
|
}
|
|
685
737
|
fetchSource(url, app.name).then((data) => {
|
|
686
738
|
info.code = data;
|
|
687
739
|
app.source.links.set(url, info);
|
|
688
|
-
|
|
689
|
-
globalLinks.set(url, data);
|
|
740
|
+
info.isGlobal && globalLinks.set(url, data);
|
|
690
741
|
replaceStyle.textContent = data;
|
|
691
|
-
scopedCSS(replaceStyle, app
|
|
742
|
+
scopedCSS(replaceStyle, app);
|
|
692
743
|
dispatchOnLoadEvent(originLink);
|
|
693
744
|
}).catch((err) => {
|
|
694
745
|
logError(err, app.name);
|
|
@@ -828,6 +879,7 @@ function execScripts(scriptList, app, initedHook) {
|
|
|
828
879
|
const deferScriptInfo = [];
|
|
829
880
|
for (const [url, info] of scriptListEntries) {
|
|
830
881
|
if (!info.isDynamic) {
|
|
882
|
+
// Notice the second render
|
|
831
883
|
if (info.defer || info.async) {
|
|
832
884
|
if (info.isExternal && !info.code) {
|
|
833
885
|
deferScriptPromise.push(fetchSource(url, app.name));
|
|
@@ -836,11 +888,10 @@ function execScripts(scriptList, app, initedHook) {
|
|
|
836
888
|
deferScriptPromise.push(info.code);
|
|
837
889
|
}
|
|
838
890
|
deferScriptInfo.push([url, info]);
|
|
839
|
-
|
|
840
|
-
initedHook.moduleCount = initedHook.moduleCount ? ++initedHook.moduleCount : 1;
|
|
891
|
+
info.module && (initedHook.moduleCount = initedHook.moduleCount ? ++initedHook.moduleCount : 1);
|
|
841
892
|
}
|
|
842
893
|
else {
|
|
843
|
-
runScript(url,
|
|
894
|
+
runScript(url, app, info, false);
|
|
844
895
|
initedHook(false);
|
|
845
896
|
}
|
|
846
897
|
}
|
|
@@ -849,9 +900,9 @@ function execScripts(scriptList, app, initedHook) {
|
|
|
849
900
|
Promise.all(deferScriptPromise).then((res) => {
|
|
850
901
|
res.forEach((code, index) => {
|
|
851
902
|
const [url, info] = deferScriptInfo[index];
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
903
|
+
info.code = info.code || code;
|
|
904
|
+
runScript(url, app, info, false, initedHook);
|
|
905
|
+
!info.module && initedHook(false);
|
|
855
906
|
});
|
|
856
907
|
initedHook(isUndefined(initedHook.moduleCount));
|
|
857
908
|
}).catch((err) => {
|
|
@@ -866,26 +917,25 @@ function execScripts(scriptList, app, initedHook) {
|
|
|
866
917
|
/**
|
|
867
918
|
* run code
|
|
868
919
|
* @param url script address
|
|
869
|
-
* @param code js code
|
|
870
920
|
* @param app app
|
|
871
|
-
* @param
|
|
921
|
+
* @param info script info
|
|
872
922
|
* @param isDynamic dynamically created script
|
|
873
923
|
* @param callback callback of module script
|
|
874
924
|
*/
|
|
875
|
-
function runScript(url,
|
|
925
|
+
function runScript(url, app, info, isDynamic, callback) {
|
|
876
926
|
var _a;
|
|
877
927
|
try {
|
|
878
|
-
code = bindScope(url,
|
|
879
|
-
if (app.inline || module) {
|
|
928
|
+
const code = bindScope(url, app, info.code, info.module);
|
|
929
|
+
if (app.inline || info.module) {
|
|
880
930
|
const scriptElement = pureCreateElement('script');
|
|
881
|
-
|
|
931
|
+
runCode2InlineScript(url, code, info.module, scriptElement, callback);
|
|
882
932
|
if (isDynamic)
|
|
883
933
|
return scriptElement;
|
|
884
934
|
// TEST IGNORE
|
|
885
935
|
(_a = app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-body').appendChild(scriptElement);
|
|
886
936
|
}
|
|
887
937
|
else {
|
|
888
|
-
|
|
938
|
+
runCode2Function(code, info);
|
|
889
939
|
if (isDynamic)
|
|
890
940
|
return document.createComment('dynamic script extract by micro-app');
|
|
891
941
|
}
|
|
@@ -903,19 +953,18 @@ function runScript(url, code, app, module, isDynamic, callback) {
|
|
|
903
953
|
*/
|
|
904
954
|
function runDynamicRemoteScript(url, info, app, originScript) {
|
|
905
955
|
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
956
|
+
// url is unique
|
|
906
957
|
if (app.source.scripts.has(url)) {
|
|
907
958
|
const existInfo = app.source.scripts.get(url);
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
return runScript(url, existInfo.code, app, info.module, true, dispatchScriptOnLoadEvent);
|
|
959
|
+
!existInfo.module && defer(dispatchScriptOnLoadEvent);
|
|
960
|
+
return runScript(url, app, existInfo, true, dispatchScriptOnLoadEvent);
|
|
911
961
|
}
|
|
912
962
|
if (globalScripts.has(url)) {
|
|
913
963
|
const code = globalScripts.get(url);
|
|
914
964
|
info.code = code;
|
|
915
965
|
app.source.scripts.set(url, info);
|
|
916
|
-
|
|
917
|
-
|
|
918
|
-
return runScript(url, code, app, info.module, true, dispatchScriptOnLoadEvent);
|
|
966
|
+
!info.module && defer(dispatchScriptOnLoadEvent);
|
|
967
|
+
return runScript(url, app, info, true, dispatchScriptOnLoadEvent);
|
|
919
968
|
}
|
|
920
969
|
let replaceElement;
|
|
921
970
|
if (app.inline || info.module) {
|
|
@@ -927,22 +976,20 @@ function runDynamicRemoteScript(url, info, app, originScript) {
|
|
|
927
976
|
fetchSource(url, app.name).then((code) => {
|
|
928
977
|
info.code = code;
|
|
929
978
|
app.source.scripts.set(url, info);
|
|
930
|
-
|
|
931
|
-
globalScripts.set(url, code);
|
|
979
|
+
info.isGlobal && globalScripts.set(url, code);
|
|
932
980
|
try {
|
|
933
|
-
code = bindScope(url,
|
|
981
|
+
code = bindScope(url, app, code, info.module);
|
|
934
982
|
if (app.inline || info.module) {
|
|
935
|
-
|
|
983
|
+
runCode2InlineScript(url, code, info.module, replaceElement, dispatchScriptOnLoadEvent);
|
|
936
984
|
}
|
|
937
985
|
else {
|
|
938
|
-
|
|
986
|
+
runCode2Function(code, info);
|
|
939
987
|
}
|
|
940
988
|
}
|
|
941
989
|
catch (e) {
|
|
942
990
|
console.error(`[micro-app from runDynamicScript] app ${app.name}: `, e, url);
|
|
943
991
|
}
|
|
944
|
-
|
|
945
|
-
dispatchOnLoadEvent(originScript);
|
|
992
|
+
!info.module && dispatchOnLoadEvent(originScript);
|
|
946
993
|
}).catch((err) => {
|
|
947
994
|
logError(err, app.name);
|
|
948
995
|
dispatchOnErrorEvent(originScript);
|
|
@@ -952,20 +999,17 @@ function runDynamicRemoteScript(url, info, app, originScript) {
|
|
|
952
999
|
/**
|
|
953
1000
|
* common handle for inline script
|
|
954
1001
|
* @param url script address
|
|
955
|
-
* @param code
|
|
1002
|
+
* @param code bound code
|
|
956
1003
|
* @param module type='module' of script
|
|
957
1004
|
* @param scriptElement target script element
|
|
958
1005
|
* @param callback callback of module script
|
|
959
1006
|
*/
|
|
960
|
-
function
|
|
1007
|
+
function runCode2InlineScript(url, code, module, scriptElement, callback) {
|
|
961
1008
|
if (module) {
|
|
962
1009
|
// module script is async, transform it to a blob for subsequent operations
|
|
963
1010
|
const blob = new Blob([code], { type: 'text/javascript' });
|
|
964
1011
|
scriptElement.src = URL.createObjectURL(blob);
|
|
965
1012
|
scriptElement.setAttribute('type', 'module');
|
|
966
|
-
if (!url.startsWith('inline-')) {
|
|
967
|
-
scriptElement.setAttribute('originSrc', url);
|
|
968
|
-
}
|
|
969
1013
|
if (callback) {
|
|
970
1014
|
callback.moduleCount && callback.moduleCount--;
|
|
971
1015
|
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
@@ -974,15 +1018,25 @@ function setInlinScriptContent(url, code, module, scriptElement, callback) {
|
|
|
974
1018
|
else {
|
|
975
1019
|
scriptElement.textContent = code;
|
|
976
1020
|
}
|
|
1021
|
+
if (!url.startsWith('inline-')) {
|
|
1022
|
+
scriptElement.setAttribute('data-origin-src', url);
|
|
1023
|
+
}
|
|
1024
|
+
}
|
|
1025
|
+
// init & run code2Function
|
|
1026
|
+
function runCode2Function(code, info) {
|
|
1027
|
+
if (!info.code2Function) {
|
|
1028
|
+
info.code2Function = new Function(code);
|
|
1029
|
+
}
|
|
1030
|
+
info.code2Function.call(window);
|
|
977
1031
|
}
|
|
978
1032
|
/**
|
|
979
1033
|
* bind js scope
|
|
980
1034
|
* @param url script address
|
|
981
|
-
* @param code code
|
|
982
1035
|
* @param app app
|
|
1036
|
+
* @param code code
|
|
983
1037
|
* @param module type='module' of script
|
|
984
1038
|
*/
|
|
985
|
-
function bindScope(url,
|
|
1039
|
+
function bindScope(url, app, code, module) {
|
|
986
1040
|
if (isPlainObject(microApp.plugins)) {
|
|
987
1041
|
code = usePlugins(url, code, app.name, microApp.plugins);
|
|
988
1042
|
}
|
|
@@ -1018,713 +1072,411 @@ function usePlugins(url, code, appName, plugins) {
|
|
|
1018
1072
|
return code;
|
|
1019
1073
|
}
|
|
1020
1074
|
|
|
1021
|
-
// Record element and map element
|
|
1022
|
-
const dynamicElementInMicroAppMap = new WeakMap();
|
|
1023
1075
|
/**
|
|
1024
|
-
*
|
|
1025
|
-
* @param
|
|
1026
|
-
* @param child new node
|
|
1027
|
-
* @param app app
|
|
1076
|
+
* transform html string to dom
|
|
1077
|
+
* @param str string dom
|
|
1028
1078
|
*/
|
|
1029
|
-
function
|
|
1030
|
-
|
|
1031
|
-
|
|
1032
|
-
|
|
1033
|
-
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
1034
|
-
return replaceComment;
|
|
1035
|
-
}
|
|
1036
|
-
else if (app.scopecss && !child.hasAttribute('ignore')) {
|
|
1037
|
-
return scopedCSS(child, app.name);
|
|
1038
|
-
}
|
|
1039
|
-
return child;
|
|
1040
|
-
}
|
|
1041
|
-
else if (child instanceof HTMLLinkElement) {
|
|
1042
|
-
if (child.hasAttribute('exclude')) {
|
|
1043
|
-
const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
|
|
1044
|
-
dynamicElementInMicroAppMap.set(child, linkReplaceComment);
|
|
1045
|
-
return linkReplaceComment;
|
|
1046
|
-
}
|
|
1047
|
-
else if (!app.scopecss || child.hasAttribute('ignore')) {
|
|
1048
|
-
return child;
|
|
1049
|
-
}
|
|
1050
|
-
const { url, info, replaceComment } = extractLinkFromHtml(child, parent, app, null, true);
|
|
1051
|
-
if (url && info) {
|
|
1052
|
-
const replaceStyle = pureCreateElement('style');
|
|
1053
|
-
replaceStyle.linkpath = url;
|
|
1054
|
-
foramtDynamicLink(url, info, app, child, replaceStyle);
|
|
1055
|
-
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
1056
|
-
return replaceStyle;
|
|
1057
|
-
}
|
|
1058
|
-
else if (replaceComment) {
|
|
1059
|
-
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
1060
|
-
return replaceComment;
|
|
1061
|
-
}
|
|
1062
|
-
return child;
|
|
1063
|
-
}
|
|
1064
|
-
else if (child instanceof HTMLScriptElement) {
|
|
1065
|
-
const { replaceComment, url, info } = extractScriptElement(child, parent, app, true) || {};
|
|
1066
|
-
if (url && info) {
|
|
1067
|
-
if (info.code) { // inline script
|
|
1068
|
-
const replaceElement = runScript(url, info.code, app, info.module, true);
|
|
1069
|
-
dynamicElementInMicroAppMap.set(child, replaceElement);
|
|
1070
|
-
return replaceElement;
|
|
1071
|
-
}
|
|
1072
|
-
else { // remote script
|
|
1073
|
-
const replaceElement = runDynamicRemoteScript(url, info, app, child);
|
|
1074
|
-
dynamicElementInMicroAppMap.set(child, replaceElement);
|
|
1075
|
-
return replaceElement;
|
|
1076
|
-
}
|
|
1077
|
-
}
|
|
1078
|
-
else if (replaceComment) {
|
|
1079
|
-
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
1080
|
-
return replaceComment;
|
|
1081
|
-
}
|
|
1082
|
-
return child;
|
|
1083
|
-
}
|
|
1084
|
-
return child;
|
|
1079
|
+
function getWrapElement(str) {
|
|
1080
|
+
const wrapDiv = pureCreateElement('div');
|
|
1081
|
+
wrapDiv.innerHTML = str;
|
|
1082
|
+
return wrapDiv;
|
|
1085
1083
|
}
|
|
1086
1084
|
/**
|
|
1087
|
-
*
|
|
1085
|
+
* Recursively process each child element
|
|
1086
|
+
* @param parent parent element
|
|
1088
1087
|
* @param app app
|
|
1089
|
-
* @param
|
|
1090
|
-
* @param parent parent node
|
|
1091
|
-
* @param targetChild target node
|
|
1092
|
-
* @param passiveChild second param of insertBefore and replaceChild
|
|
1088
|
+
* @param microAppHead micro-app-head element
|
|
1093
1089
|
*/
|
|
1094
|
-
function
|
|
1095
|
-
|
|
1096
|
-
|
|
1097
|
-
|
|
1098
|
-
|
|
1099
|
-
|
|
1100
|
-
|
|
1101
|
-
|
|
1102
|
-
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
|
|
1106
|
-
|
|
1107
|
-
|
|
1108
|
-
|
|
1109
|
-
if (parent.contains(targetChild)) {
|
|
1110
|
-
return rawMethod.call(parent, targetChild);
|
|
1090
|
+
function flatChildren(parent, app, microAppHead) {
|
|
1091
|
+
const children = Array.from(parent.children);
|
|
1092
|
+
children.length && children.forEach((child) => {
|
|
1093
|
+
flatChildren(child, app);
|
|
1094
|
+
});
|
|
1095
|
+
for (const dom of children) {
|
|
1096
|
+
if (dom instanceof HTMLLinkElement) {
|
|
1097
|
+
if (dom.hasAttribute('exclude')) {
|
|
1098
|
+
parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
|
|
1099
|
+
}
|
|
1100
|
+
else if (!dom.hasAttribute('ignore')) {
|
|
1101
|
+
extractLinkFromHtml(dom, parent, app);
|
|
1102
|
+
}
|
|
1103
|
+
else if (dom.hasAttribute('href')) {
|
|
1104
|
+
dom.setAttribute('href', CompletionPath(dom.getAttribute('href'), app.url));
|
|
1111
1105
|
}
|
|
1112
|
-
return targetChild;
|
|
1113
1106
|
}
|
|
1114
|
-
else if (
|
|
1115
|
-
|
|
1107
|
+
else if (dom instanceof HTMLStyleElement) {
|
|
1108
|
+
if (dom.hasAttribute('exclude')) {
|
|
1109
|
+
parent.replaceChild(document.createComment('style element with exclude attribute ignored by micro-app'), dom);
|
|
1110
|
+
}
|
|
1111
|
+
else if (app.scopecss && !dom.hasAttribute('ignore')) {
|
|
1112
|
+
scopedCSS(dom, app);
|
|
1113
|
+
}
|
|
1116
1114
|
}
|
|
1117
|
-
|
|
1118
|
-
|
|
1119
|
-
else if (parent === document.body) {
|
|
1120
|
-
const microAppBody = app.container.querySelector('micro-app-body');
|
|
1121
|
-
if (passiveChild && !microAppBody.contains(passiveChild)) {
|
|
1122
|
-
return globalEnv.rawAppendChild.call(microAppBody, targetChild);
|
|
1115
|
+
else if (dom instanceof HTMLScriptElement) {
|
|
1116
|
+
extractScriptElement(dom, parent, app);
|
|
1123
1117
|
}
|
|
1124
|
-
else if (
|
|
1125
|
-
|
|
1126
|
-
return rawMethod.call(parent, targetChild);
|
|
1127
|
-
}
|
|
1128
|
-
return targetChild;
|
|
1118
|
+
else if (dom instanceof HTMLMetaElement || dom instanceof HTMLTitleElement) {
|
|
1119
|
+
parent.removeChild(dom);
|
|
1129
1120
|
}
|
|
1130
|
-
else if (
|
|
1131
|
-
|
|
1121
|
+
else if (dom instanceof HTMLImageElement && dom.hasAttribute('src')) {
|
|
1122
|
+
dom.setAttribute('src', CompletionPath(dom.getAttribute('src'), app.url));
|
|
1132
1123
|
}
|
|
1133
|
-
return rawMethod.call(microAppBody, targetChild, passiveChild);
|
|
1134
1124
|
}
|
|
1135
|
-
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1136
|
-
return rawMethod.call(parent, targetChild);
|
|
1137
|
-
}
|
|
1138
|
-
return rawMethod.call(parent, targetChild, passiveChild);
|
|
1139
|
-
}
|
|
1140
|
-
// Get the map element
|
|
1141
|
-
function getMappingNode(node) {
|
|
1142
|
-
var _a;
|
|
1143
|
-
return (_a = dynamicElementInMicroAppMap.get(node)) !== null && _a !== void 0 ? _a : node;
|
|
1144
1125
|
}
|
|
1145
1126
|
/**
|
|
1146
|
-
*
|
|
1147
|
-
* @param
|
|
1148
|
-
* @param
|
|
1149
|
-
* @param passiveChild passive node
|
|
1150
|
-
* @param rawMethodraw method
|
|
1127
|
+
* Extract link and script, bind style scope
|
|
1128
|
+
* @param htmlStr html string
|
|
1129
|
+
* @param app app
|
|
1151
1130
|
*/
|
|
1152
|
-
function
|
|
1153
|
-
|
|
1154
|
-
|
|
1155
|
-
|
|
1156
|
-
|
|
1157
|
-
}
|
|
1158
|
-
|
|
1159
|
-
|
|
1160
|
-
}
|
|
1161
|
-
return rawMethod.call(parent, newChild, passiveChild);
|
|
1131
|
+
function extractSourceDom(htmlStr, app) {
|
|
1132
|
+
const wrapElement = getWrapElement(htmlStr);
|
|
1133
|
+
const microAppHead = wrapElement.querySelector('micro-app-head');
|
|
1134
|
+
const microAppBody = wrapElement.querySelector('micro-app-body');
|
|
1135
|
+
if (!microAppHead || !microAppBody) {
|
|
1136
|
+
const msg = `element ${microAppHead ? 'body' : 'head'} is missing`;
|
|
1137
|
+
app.onerror(new Error(msg));
|
|
1138
|
+
return logError(msg, app.name);
|
|
1162
1139
|
}
|
|
1163
|
-
|
|
1164
|
-
|
|
1165
|
-
|
|
1166
|
-
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
|
|
1170
|
-
|
|
1171
|
-
|
|
1172
|
-
|
|
1173
|
-
|
|
1174
|
-
|
|
1175
|
-
}
|
|
1176
|
-
return rawMethod.call(parent, newChild);
|
|
1140
|
+
flatChildren(wrapElement, app);
|
|
1141
|
+
if (app.source.links.size) {
|
|
1142
|
+
fetchLinksFromHtml(wrapElement, app, microAppHead);
|
|
1143
|
+
}
|
|
1144
|
+
else {
|
|
1145
|
+
app.onLoad(wrapElement);
|
|
1146
|
+
}
|
|
1147
|
+
if (app.source.scripts.size) {
|
|
1148
|
+
fetchScriptsFromHtml(wrapElement, app);
|
|
1149
|
+
}
|
|
1150
|
+
else {
|
|
1151
|
+
app.onLoad(wrapElement);
|
|
1177
1152
|
}
|
|
1178
|
-
return rawMethod.call(parent, newChild, passiveChild);
|
|
1179
1153
|
}
|
|
1180
1154
|
/**
|
|
1181
|
-
*
|
|
1155
|
+
* Get and format html
|
|
1156
|
+
* @param app app
|
|
1182
1157
|
*/
|
|
1183
|
-
function
|
|
1184
|
-
|
|
1185
|
-
|
|
1186
|
-
|
|
1187
|
-
|
|
1188
|
-
|
|
1189
|
-
const cloneValue = {};
|
|
1190
|
-
Object.getOwnPropertyNames(value).forEach((propertyKey) => {
|
|
1191
|
-
if (!(isString(propertyKey) && propertyKey.indexOf('__') === 0)) {
|
|
1192
|
-
// @ts-ignore
|
|
1193
|
-
cloneValue[propertyKey] = value[propertyKey];
|
|
1194
|
-
}
|
|
1195
|
-
});
|
|
1196
|
-
this.data = cloneValue;
|
|
1197
|
-
}
|
|
1198
|
-
else if (value !== '[object Object]') {
|
|
1199
|
-
logWarn('property data must be an object', this.getAttribute('name'));
|
|
1200
|
-
}
|
|
1201
|
-
}
|
|
1202
|
-
else if (((key === 'src' && /^(img|script)$/i.test(this.tagName)) ||
|
|
1203
|
-
(key === 'href' && /^link$/i.test(this.tagName))) &&
|
|
1204
|
-
this.__MICRO_APP_NAME__ &&
|
|
1205
|
-
appInstanceMap.has(this.__MICRO_APP_NAME__)) {
|
|
1206
|
-
const app = appInstanceMap.get(this.__MICRO_APP_NAME__);
|
|
1207
|
-
globalEnv.rawSetAttribute.call(this, key, CompletionPath(value, app.url));
|
|
1208
|
-
}
|
|
1209
|
-
else {
|
|
1210
|
-
globalEnv.rawSetAttribute.call(this, key, value);
|
|
1211
|
-
}
|
|
1212
|
-
};
|
|
1213
|
-
// prototype methods of add element👇
|
|
1214
|
-
Node.prototype.appendChild = function appendChild(newChild) {
|
|
1215
|
-
return commonElementHander(this, newChild, null, globalEnv.rawAppendChild);
|
|
1216
|
-
};
|
|
1217
|
-
Node.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
1218
|
-
return commonElementHander(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
1219
|
-
};
|
|
1220
|
-
Node.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
1221
|
-
return commonElementHander(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
1222
|
-
};
|
|
1223
|
-
Element.prototype.append = function append(...nodes) {
|
|
1224
|
-
let i = 0;
|
|
1225
|
-
const length = nodes.length;
|
|
1226
|
-
while (i < length) {
|
|
1227
|
-
commonElementHander(this, nodes[i], null, globalEnv.rawAppend);
|
|
1228
|
-
i++;
|
|
1229
|
-
}
|
|
1230
|
-
};
|
|
1231
|
-
Element.prototype.prepend = function prepend(...nodes) {
|
|
1232
|
-
let i = nodes.length;
|
|
1233
|
-
while (i > 0) {
|
|
1234
|
-
commonElementHander(this, nodes[i - 1], null, globalEnv.rawPrepend);
|
|
1235
|
-
i--;
|
|
1236
|
-
}
|
|
1237
|
-
};
|
|
1238
|
-
// prototype methods of delete element👇
|
|
1239
|
-
Node.prototype.removeChild = function removeChild(oldChild) {
|
|
1240
|
-
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1241
|
-
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1242
|
-
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1243
|
-
return invokePrototypeMethod(app, globalEnv.rawRemoveChild, this, getMappingNode(oldChild));
|
|
1244
|
-
}
|
|
1245
|
-
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1158
|
+
function extractHtml(app) {
|
|
1159
|
+
fetchSource(app.ssrUrl || app.url, app.name, { cache: 'no-cache' }).then((htmlStr) => {
|
|
1160
|
+
if (!htmlStr) {
|
|
1161
|
+
const msg = 'html is empty, please check in detail';
|
|
1162
|
+
app.onerror(new Error(msg));
|
|
1163
|
+
return logError(msg, app.name);
|
|
1246
1164
|
}
|
|
1247
|
-
|
|
1248
|
-
|
|
1165
|
+
htmlStr = htmlStr
|
|
1166
|
+
.replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
|
|
1167
|
+
return match
|
|
1168
|
+
.replace(/<head/i, '<micro-app-head')
|
|
1169
|
+
.replace(/<\/head>/i, '</micro-app-head>');
|
|
1170
|
+
})
|
|
1171
|
+
.replace(/<body[^>]*>[\s\S]*?<\/body>/i, (match) => {
|
|
1172
|
+
return match
|
|
1173
|
+
.replace(/<body/i, '<micro-app-body')
|
|
1174
|
+
.replace(/<\/body>/i, '</micro-app-body>');
|
|
1175
|
+
});
|
|
1176
|
+
extractSourceDom(htmlStr, app);
|
|
1177
|
+
}).catch((e) => {
|
|
1178
|
+
logError(`Failed to fetch data from ${app.url}, micro-app stop rendering`, app.name, e);
|
|
1179
|
+
app.onLoadError(e);
|
|
1180
|
+
});
|
|
1249
1181
|
}
|
|
1250
|
-
|
|
1251
|
-
|
|
1252
|
-
|
|
1253
|
-
|
|
1254
|
-
|
|
1255
|
-
const appName = getCurrentAppName();
|
|
1256
|
-
if (appName) {
|
|
1257
|
-
element.__MICRO_APP_NAME__ = appName;
|
|
1182
|
+
|
|
1183
|
+
const boundedMap = new WeakMap();
|
|
1184
|
+
function isBoundedFunction(value) {
|
|
1185
|
+
if (boundedMap.has(value)) {
|
|
1186
|
+
return boundedMap.get(value);
|
|
1258
1187
|
}
|
|
1259
|
-
|
|
1188
|
+
// bind function
|
|
1189
|
+
const boundFunction = isBoundFunction(value);
|
|
1190
|
+
boundedMap.set(value, boundFunction);
|
|
1191
|
+
return boundFunction;
|
|
1260
1192
|
}
|
|
1261
|
-
|
|
1262
|
-
function
|
|
1263
|
-
|
|
1264
|
-
|
|
1265
|
-
Document.prototype.createElement = function createElement(tagName, options) {
|
|
1266
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1267
|
-
const element = globalEnv.rawCreateElement.call(_this, tagName, options);
|
|
1268
|
-
return markElement(element);
|
|
1269
|
-
};
|
|
1270
|
-
Document.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
|
|
1271
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1272
|
-
const element = globalEnv.rawCreateElementNS.call(_this, namespaceURI, name, options);
|
|
1273
|
-
return markElement(element);
|
|
1274
|
-
};
|
|
1275
|
-
Document.prototype.createDocumentFragment = function createDocumentFragment() {
|
|
1276
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1277
|
-
const element = globalEnv.rawCreateDocumentFragment.call(_this);
|
|
1278
|
-
return markElement(element);
|
|
1279
|
-
};
|
|
1280
|
-
// query element👇
|
|
1281
|
-
function querySelector(selectors) {
|
|
1282
|
-
var _a, _b, _c;
|
|
1283
|
-
/**
|
|
1284
|
-
* The hijacking of queryselector should only occur on rawDocument, we should ignore document created by new DOMParser().parseFromString()
|
|
1285
|
-
* see https://github.com/micro-zoe/micro-app/issues/56
|
|
1286
|
-
*/
|
|
1287
|
-
if (this && rawDocument !== this)
|
|
1288
|
-
return globalEnv.rawQuerySelector.call(this, selectors);
|
|
1289
|
-
const appName = getCurrentAppName();
|
|
1290
|
-
if (!appName || selectors === 'head' || selectors === 'body' || selectors === 'html') {
|
|
1291
|
-
return globalEnv.rawQuerySelector.call(rawDocument, selectors);
|
|
1292
|
-
}
|
|
1293
|
-
return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) === null || _b === void 0 ? void 0 : _b.querySelector(selectors)) !== null && _c !== void 0 ? _c : null;
|
|
1193
|
+
const constructorMap = new WeakMap();
|
|
1194
|
+
function isConstructor(value) {
|
|
1195
|
+
if (constructorMap.has(value)) {
|
|
1196
|
+
return constructorMap.get(value);
|
|
1294
1197
|
}
|
|
1295
|
-
|
|
1296
|
-
|
|
1297
|
-
|
|
1298
|
-
|
|
1299
|
-
|
|
1300
|
-
|
|
1301
|
-
|
|
1302
|
-
|
|
1303
|
-
|
|
1198
|
+
const valueStr = value.toString();
|
|
1199
|
+
const result = (value.prototype &&
|
|
1200
|
+
value.prototype.constructor === value &&
|
|
1201
|
+
Object.getOwnPropertyNames(value.prototype).length > 1) ||
|
|
1202
|
+
/^function\s+[A-Z]/.test(valueStr) ||
|
|
1203
|
+
/^class\s+/.test(valueStr);
|
|
1204
|
+
constructorMap.set(value, result);
|
|
1205
|
+
return result;
|
|
1206
|
+
}
|
|
1207
|
+
const rawWindowMethodMap = new WeakMap();
|
|
1208
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
1209
|
+
function bindFunctionToRawWidow(rawWindow, value) {
|
|
1210
|
+
if (rawWindowMethodMap.has(value)) {
|
|
1211
|
+
return rawWindowMethodMap.get(value);
|
|
1304
1212
|
}
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
const appName = getCurrentAppName();
|
|
1310
|
-
if (!appName || /^\d/.test(key)) {
|
|
1311
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1312
|
-
return globalEnv.rawGetElementById.call(_this, key);
|
|
1313
|
-
}
|
|
1314
|
-
return querySelector.call(this, `#${key}`);
|
|
1315
|
-
};
|
|
1316
|
-
Document.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
1317
|
-
const appName = getCurrentAppName();
|
|
1318
|
-
if (!appName || /^\d/.test(key)) {
|
|
1319
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1320
|
-
return globalEnv.rawGetElementsByClassName.call(_this, key);
|
|
1321
|
-
}
|
|
1322
|
-
return querySelectorAll.call(this, `.${key}`);
|
|
1323
|
-
};
|
|
1324
|
-
Document.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
1325
|
-
var _a;
|
|
1326
|
-
const appName = getCurrentAppName();
|
|
1327
|
-
if (!appName ||
|
|
1328
|
-
/^body$/i.test(key) ||
|
|
1329
|
-
/^head$/i.test(key) ||
|
|
1330
|
-
/^html$/i.test(key) ||
|
|
1331
|
-
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
1332
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1333
|
-
return globalEnv.rawGetElementsByTagName.call(_this, key);
|
|
1213
|
+
if (isFunction(value) && !isConstructor(value) && !isBoundedFunction(value)) {
|
|
1214
|
+
const bindRawWindowValue = value.bind(rawWindow);
|
|
1215
|
+
for (const key in value) {
|
|
1216
|
+
bindRawWindowValue[key] = value[key];
|
|
1334
1217
|
}
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
Document.prototype.getElementsByName = function getElementsByName(key) {
|
|
1338
|
-
const appName = getCurrentAppName();
|
|
1339
|
-
if (!appName || /^\d/.test(key)) {
|
|
1340
|
-
const _this = this && rawDocument !== this ? this : rawDocument;
|
|
1341
|
-
return globalEnv.rawGetElementsByName.call(_this, key);
|
|
1218
|
+
if (value.hasOwnProperty('prototype') && !bindRawWindowValue.hasOwnProperty('prototype')) {
|
|
1219
|
+
bindRawWindowValue.prototype = value.prototype;
|
|
1342
1220
|
}
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
}
|
|
1346
|
-
function releasePatchDocument() {
|
|
1347
|
-
Document.prototype.createElement = globalEnv.rawCreateElement;
|
|
1348
|
-
Document.prototype.createElementNS = globalEnv.rawCreateElementNS;
|
|
1349
|
-
Document.prototype.createDocumentFragment = globalEnv.rawCreateDocumentFragment;
|
|
1350
|
-
Document.prototype.querySelector = globalEnv.rawQuerySelector;
|
|
1351
|
-
Document.prototype.querySelectorAll = globalEnv.rawQuerySelectorAll;
|
|
1352
|
-
Document.prototype.getElementById = globalEnv.rawGetElementById;
|
|
1353
|
-
Document.prototype.getElementsByClassName = globalEnv.rawGetElementsByClassName;
|
|
1354
|
-
Document.prototype.getElementsByTagName = globalEnv.rawGetElementsByTagName;
|
|
1355
|
-
Document.prototype.getElementsByName = globalEnv.rawGetElementsByName;
|
|
1356
|
-
}
|
|
1357
|
-
// release patch
|
|
1358
|
-
function releasePatches() {
|
|
1359
|
-
setCurrentAppName(null);
|
|
1360
|
-
releasePatchDocument();
|
|
1361
|
-
Element.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
1362
|
-
Node.prototype.appendChild = globalEnv.rawAppendChild;
|
|
1363
|
-
Node.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
1364
|
-
Node.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
1365
|
-
Node.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
1366
|
-
Element.prototype.append = globalEnv.rawAppend;
|
|
1367
|
-
Element.prototype.prepend = globalEnv.rawPrepend;
|
|
1368
|
-
}
|
|
1369
|
-
// Set the style of micro-app-head and micro-app-body
|
|
1370
|
-
let hasRejectMicroAppStyle = false;
|
|
1371
|
-
function rejectMicroAppStyle() {
|
|
1372
|
-
if (!hasRejectMicroAppStyle) {
|
|
1373
|
-
hasRejectMicroAppStyle = true;
|
|
1374
|
-
const style = pureCreateElement('style');
|
|
1375
|
-
style.setAttribute('type', 'text/css');
|
|
1376
|
-
style.textContent = `\n${microApp.tagName}, micro-app-body { display: block; } \nmicro-app-head { display: none; }`;
|
|
1377
|
-
globalEnv.rawDocument.head.appendChild(style);
|
|
1221
|
+
rawWindowMethodMap.set(value, bindRawWindowValue);
|
|
1222
|
+
return bindRawWindowValue;
|
|
1378
1223
|
}
|
|
1224
|
+
return value;
|
|
1379
1225
|
}
|
|
1380
1226
|
|
|
1381
|
-
function
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1386
|
-
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
|
|
1390
|
-
|
|
1391
|
-
}
|
|
1392
|
-
});
|
|
1393
|
-
if (!window.__MICRO_APP_UMD_MODE__)
|
|
1394
|
-
appInstanceMap.clear();
|
|
1395
|
-
if (elementInstanceMap.size) {
|
|
1396
|
-
elementInstanceMap.clear();
|
|
1397
|
-
releasePatches();
|
|
1398
|
-
}
|
|
1399
|
-
}
|
|
1400
|
-
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
1401
|
-
function listenUmountOfNestedApp() {
|
|
1402
|
-
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
1403
|
-
window.addEventListener('unmount', unmountNestedApp, false);
|
|
1227
|
+
// document.onclick binding list, the binding function of each application is unique
|
|
1228
|
+
const documentClickListMap = new Map();
|
|
1229
|
+
let hasRewriteDocumentOnClick = false;
|
|
1230
|
+
/**
|
|
1231
|
+
* Rewrite document.onclick and execute it only once
|
|
1232
|
+
*/
|
|
1233
|
+
function overwriteDocumentOnClick() {
|
|
1234
|
+
hasRewriteDocumentOnClick = true;
|
|
1235
|
+
if (Object.getOwnPropertyDescriptor(document, 'onclick')) {
|
|
1236
|
+
return logWarn('Cannot redefine document property onclick');
|
|
1404
1237
|
}
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
-
|
|
1408
|
-
|
|
1409
|
-
|
|
1238
|
+
const rawOnClick = document.onclick;
|
|
1239
|
+
document.onclick = null;
|
|
1240
|
+
let hasDocumentClickInited = false;
|
|
1241
|
+
function onClickHandler(e) {
|
|
1242
|
+
documentClickListMap.forEach((f) => {
|
|
1243
|
+
isFunction(f) && f.call(document, e);
|
|
1244
|
+
});
|
|
1410
1245
|
}
|
|
1411
|
-
|
|
1412
|
-
|
|
1413
|
-
|
|
1414
|
-
|
|
1415
|
-
|
|
1416
|
-
get()
|
|
1417
|
-
return element;
|
|
1418
|
-
}
|
|
1246
|
+
Object.defineProperty(document, 'onclick', {
|
|
1247
|
+
configurable: true,
|
|
1248
|
+
enumerable: true,
|
|
1249
|
+
get() {
|
|
1250
|
+
const appName = getCurrentAppName();
|
|
1251
|
+
return appName ? documentClickListMap.get(appName) : documentClickListMap.get('base');
|
|
1419
1252
|
},
|
|
1420
|
-
|
|
1421
|
-
|
|
1422
|
-
|
|
1253
|
+
set(f) {
|
|
1254
|
+
const appName = getCurrentAppName();
|
|
1255
|
+
if (appName) {
|
|
1256
|
+
documentClickListMap.set(appName, f);
|
|
1423
1257
|
}
|
|
1424
|
-
|
|
1258
|
+
else {
|
|
1259
|
+
documentClickListMap.set('base', f);
|
|
1260
|
+
}
|
|
1261
|
+
if (!hasDocumentClickInited && isFunction(f)) {
|
|
1262
|
+
hasDocumentClickInited = true;
|
|
1263
|
+
globalEnv.rawDocumentAddEventListener.call(globalEnv.rawDocument, 'click', onClickHandler, false);
|
|
1264
|
+
}
|
|
1265
|
+
}
|
|
1425
1266
|
});
|
|
1267
|
+
rawOnClick && (document.onclick = rawOnClick);
|
|
1426
1268
|
}
|
|
1427
1269
|
/**
|
|
1428
|
-
*
|
|
1429
|
-
* created, beforemount, mounted, unmount, error
|
|
1430
|
-
* @param element container
|
|
1431
|
-
* @param appName app.name
|
|
1432
|
-
* @param lifecycleName lifeCycle name
|
|
1433
|
-
* @param error param from error hook
|
|
1270
|
+
* The document event is globally, we need to clear these event bindings when micro application unmounted
|
|
1434
1271
|
*/
|
|
1435
|
-
|
|
1436
|
-
|
|
1437
|
-
|
|
1438
|
-
|
|
1439
|
-
|
|
1440
|
-
|
|
1441
|
-
|
|
1442
|
-
|
|
1443
|
-
|
|
1444
|
-
|
|
1445
|
-
|
|
1446
|
-
|
|
1447
|
-
|
|
1448
|
-
|
|
1449
|
-
|
|
1450
|
-
|
|
1451
|
-
|
|
1452
|
-
|
|
1453
|
-
|
|
1454
|
-
|
|
1455
|
-
|
|
1456
|
-
|
|
1457
|
-
|
|
1458
|
-
|
|
1459
|
-
|
|
1460
|
-
|
|
1461
|
-
|
|
1272
|
+
const documentEventListenerMap = new Map();
|
|
1273
|
+
function effectDocumentEvent() {
|
|
1274
|
+
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1275
|
+
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
1276
|
+
document.addEventListener = function (type, listener, options) {
|
|
1277
|
+
var _a;
|
|
1278
|
+
const appName = getCurrentAppName();
|
|
1279
|
+
/**
|
|
1280
|
+
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
1281
|
+
*/
|
|
1282
|
+
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1283
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1284
|
+
if (appListenersMap) {
|
|
1285
|
+
const appListenerList = appListenersMap.get(type);
|
|
1286
|
+
if (appListenerList) {
|
|
1287
|
+
appListenerList.add(listener);
|
|
1288
|
+
}
|
|
1289
|
+
else {
|
|
1290
|
+
appListenersMap.set(type, new Set([listener]));
|
|
1291
|
+
}
|
|
1292
|
+
}
|
|
1293
|
+
else {
|
|
1294
|
+
documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
|
|
1295
|
+
}
|
|
1296
|
+
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1297
|
+
}
|
|
1298
|
+
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
1299
|
+
};
|
|
1300
|
+
document.removeEventListener = function (type, listener, options) {
|
|
1301
|
+
var _a;
|
|
1302
|
+
const appName = getCurrentAppName();
|
|
1303
|
+
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1304
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1305
|
+
if (appListenersMap) {
|
|
1306
|
+
const appListenerList = appListenersMap.get(type);
|
|
1307
|
+
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
1308
|
+
appListenerList.delete(listener);
|
|
1309
|
+
}
|
|
1310
|
+
}
|
|
1311
|
+
}
|
|
1312
|
+
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
1313
|
+
};
|
|
1314
|
+
}
|
|
1315
|
+
// Clear the document event agent
|
|
1316
|
+
function releaseEffectDocumentEvent() {
|
|
1317
|
+
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
1318
|
+
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
1462
1319
|
}
|
|
1463
1320
|
/**
|
|
1464
|
-
*
|
|
1465
|
-
* @param
|
|
1321
|
+
* Format event name
|
|
1322
|
+
* @param type event name
|
|
1323
|
+
* @param microWindow micro window
|
|
1466
1324
|
*/
|
|
1467
|
-
function
|
|
1468
|
-
|
|
1469
|
-
|
|
1325
|
+
function formatEventType(type, microWindow) {
|
|
1326
|
+
if (type === 'unmount') {
|
|
1327
|
+
return `unmount-${microWindow.__MICRO_APP_NAME__}`;
|
|
1328
|
+
}
|
|
1329
|
+
return type;
|
|
1470
1330
|
}
|
|
1471
|
-
|
|
1472
|
-
// record all micro-app elements
|
|
1473
|
-
const elementInstanceMap = new Map();
|
|
1474
1331
|
/**
|
|
1475
|
-
*
|
|
1476
|
-
* @param
|
|
1332
|
+
* Rewrite side-effect events
|
|
1333
|
+
* @param microWindow micro window
|
|
1477
1334
|
*/
|
|
1478
|
-
function
|
|
1479
|
-
|
|
1480
|
-
|
|
1481
|
-
|
|
1482
|
-
|
|
1483
|
-
|
|
1484
|
-
|
|
1485
|
-
|
|
1486
|
-
|
|
1487
|
-
|
|
1488
|
-
|
|
1489
|
-
|
|
1490
|
-
*/
|
|
1491
|
-
this.handleAttributeUpdate = () => {
|
|
1492
|
-
var _a;
|
|
1493
|
-
this.isWating = false;
|
|
1494
|
-
const attrName = this.getAttribute('name');
|
|
1495
|
-
const attrUrl = formatURL(this.getAttribute('url'), this.appName);
|
|
1496
|
-
if (this.legalAttribute('name', attrName) && this.legalAttribute('url', attrUrl)) {
|
|
1497
|
-
const existApp = appInstanceMap.get(attrName);
|
|
1498
|
-
if (attrName !== this.appName && existApp) {
|
|
1499
|
-
// handling of cached and non-prefetch apps
|
|
1500
|
-
if (appStatus.UNMOUNT !== existApp.getAppStatus() && !existApp.isPrefetch) {
|
|
1501
|
-
this.setAttribute('name', this.appName);
|
|
1502
|
-
return logError(`an app named ${attrName} already exists`, this.appName);
|
|
1503
|
-
}
|
|
1504
|
-
}
|
|
1505
|
-
if (attrName !== this.appName || attrUrl !== this.appUrl) {
|
|
1506
|
-
this.handleUnmount(attrName === this.appName);
|
|
1507
|
-
this.appName = attrName;
|
|
1508
|
-
this.appUrl = attrUrl;
|
|
1509
|
-
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
1510
|
-
/**
|
|
1511
|
-
* when existApp not undefined
|
|
1512
|
-
* if attrName and this.appName are equal, existApp has been unmounted
|
|
1513
|
-
* if attrName and this.appName are not equal, existApp is prefetch or unmounted
|
|
1514
|
-
*/
|
|
1515
|
-
if (existApp && existApp.url === attrUrl) {
|
|
1516
|
-
// mount app
|
|
1517
|
-
this.handleAppMount(existApp);
|
|
1518
|
-
}
|
|
1519
|
-
else {
|
|
1520
|
-
this.handleCreateApp();
|
|
1521
|
-
}
|
|
1522
|
-
}
|
|
1523
|
-
}
|
|
1524
|
-
else if (attrName !== this.appName) {
|
|
1525
|
-
this.setAttribute('name', this.appName);
|
|
1526
|
-
}
|
|
1527
|
-
};
|
|
1528
|
-
// cloned node of umd container also trigger constructor, we should skip
|
|
1529
|
-
if (!this.querySelector('micro-app-head')) {
|
|
1530
|
-
this.performWhenFirstCreated();
|
|
1531
|
-
}
|
|
1335
|
+
function effect(microWindow) {
|
|
1336
|
+
const appName = microWindow.__MICRO_APP_NAME__;
|
|
1337
|
+
const eventListenerMap = new Map();
|
|
1338
|
+
const intervalIdMap = new Map();
|
|
1339
|
+
const timeoutIdMap = new Map();
|
|
1340
|
+
const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1341
|
+
// listener may be null, e.g test-passive
|
|
1342
|
+
microWindow.addEventListener = function (type, listener, options) {
|
|
1343
|
+
type = formatEventType(type, microWindow);
|
|
1344
|
+
const listenerList = eventListenerMap.get(type);
|
|
1345
|
+
if (listenerList) {
|
|
1346
|
+
listenerList.add(listener);
|
|
1532
1347
|
}
|
|
1533
|
-
|
|
1534
|
-
|
|
1348
|
+
else {
|
|
1349
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
1535
1350
|
}
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1541
|
-
|
|
1542
|
-
|
|
1543
|
-
|
|
1544
|
-
// macro: used to solve the async render problem of vue3, default is false
|
|
1545
|
-
// baseRoute: route prefix, default is ''
|
|
1546
|
-
connectedCallback() {
|
|
1547
|
-
this.hasConnected = true;
|
|
1548
|
-
if (!elementInstanceMap.has(this)) {
|
|
1549
|
-
this.performWhenFirstCreated();
|
|
1550
|
-
}
|
|
1551
|
-
defer(() => dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED));
|
|
1552
|
-
this.initialMount();
|
|
1351
|
+
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1352
|
+
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
1353
|
+
};
|
|
1354
|
+
microWindow.removeEventListener = function (type, listener, options) {
|
|
1355
|
+
type = formatEventType(type, microWindow);
|
|
1356
|
+
const listenerList = eventListenerMap.get(type);
|
|
1357
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
1358
|
+
listenerList.delete(listener);
|
|
1553
1359
|
}
|
|
1554
|
-
|
|
1555
|
-
|
|
1556
|
-
|
|
1557
|
-
|
|
1558
|
-
|
|
1559
|
-
|
|
1360
|
+
rawWindowRemoveEventListener.call(rawWindow, type, listener, options);
|
|
1361
|
+
};
|
|
1362
|
+
microWindow.setInterval = function (handler, timeout, ...args) {
|
|
1363
|
+
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
1364
|
+
intervalIdMap.set(intervalId, { handler, timeout, args });
|
|
1365
|
+
return intervalId;
|
|
1366
|
+
};
|
|
1367
|
+
microWindow.setTimeout = function (handler, timeout, ...args) {
|
|
1368
|
+
const timeoutId = rawSetTimeout.call(rawWindow, handler, timeout, ...args);
|
|
1369
|
+
timeoutIdMap.set(timeoutId, { handler, timeout, args });
|
|
1370
|
+
return timeoutId;
|
|
1371
|
+
};
|
|
1372
|
+
microWindow.clearInterval = function (intervalId) {
|
|
1373
|
+
intervalIdMap.delete(intervalId);
|
|
1374
|
+
rawClearInterval.call(rawWindow, intervalId);
|
|
1375
|
+
};
|
|
1376
|
+
microWindow.clearTimeout = function (timeoutId) {
|
|
1377
|
+
timeoutIdMap.delete(timeoutId);
|
|
1378
|
+
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1379
|
+
};
|
|
1380
|
+
const umdWindowListenerMap = new Map();
|
|
1381
|
+
const umdDocumentListenerMap = new Map();
|
|
1382
|
+
let umdIntervalIdMap = new Map();
|
|
1383
|
+
let umdTimeoutIdMap = new Map();
|
|
1384
|
+
let umdOnClickHandler;
|
|
1385
|
+
// record event and timer before exec umdMountHook
|
|
1386
|
+
const recordUmdEffect = () => {
|
|
1387
|
+
// record window event
|
|
1388
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
1389
|
+
if (listenerList.size) {
|
|
1390
|
+
umdWindowListenerMap.set(type, new Set(listenerList));
|
|
1560
1391
|
}
|
|
1392
|
+
});
|
|
1393
|
+
// record timers
|
|
1394
|
+
if (intervalIdMap.size) {
|
|
1395
|
+
umdIntervalIdMap = new Map(intervalIdMap);
|
|
1561
1396
|
}
|
|
1562
|
-
|
|
1563
|
-
|
|
1564
|
-
this[attr === ObservedAttrName.NAME ? 'appName' : 'appUrl'] !== newVal) {
|
|
1565
|
-
if (attr === ObservedAttrName.URL && !this.appUrl) {
|
|
1566
|
-
newVal = formatURL(newVal, this.appName);
|
|
1567
|
-
if (!newVal) {
|
|
1568
|
-
return logError('Invalid attribute url', this.appName);
|
|
1569
|
-
}
|
|
1570
|
-
this.appUrl = newVal;
|
|
1571
|
-
this.handleInitialNameAndUrl();
|
|
1572
|
-
}
|
|
1573
|
-
else if (attr === ObservedAttrName.NAME && !this.appName) {
|
|
1574
|
-
if (this.cacheData) {
|
|
1575
|
-
microApp.setData(newVal, this.cacheData);
|
|
1576
|
-
this.cacheData = null;
|
|
1577
|
-
}
|
|
1578
|
-
this.appName = newVal;
|
|
1579
|
-
this.handleInitialNameAndUrl();
|
|
1580
|
-
}
|
|
1581
|
-
else if (!this.isWating) {
|
|
1582
|
-
this.isWating = true;
|
|
1583
|
-
defer(this.handleAttributeUpdate);
|
|
1584
|
-
}
|
|
1585
|
-
}
|
|
1397
|
+
if (timeoutIdMap.size) {
|
|
1398
|
+
umdTimeoutIdMap = new Map(timeoutIdMap);
|
|
1586
1399
|
}
|
|
1587
|
-
//
|
|
1588
|
-
|
|
1589
|
-
|
|
1590
|
-
|
|
1591
|
-
|
|
1400
|
+
// record onclick handler
|
|
1401
|
+
umdOnClickHandler = documentClickListMap.get(appName);
|
|
1402
|
+
// record document event
|
|
1403
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1404
|
+
if (documentAppListenersMap) {
|
|
1405
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1406
|
+
if (listenerList.size) {
|
|
1407
|
+
umdDocumentListenerMap.set(type, new Set(listenerList));
|
|
1408
|
+
}
|
|
1409
|
+
});
|
|
1592
1410
|
}
|
|
1593
|
-
|
|
1594
|
-
|
|
1595
|
-
|
|
1596
|
-
|
|
1597
|
-
|
|
1598
|
-
|
|
1599
|
-
|
|
1411
|
+
};
|
|
1412
|
+
// rebuild event and timer before remount umd app
|
|
1413
|
+
const rebuildUmdEffect = () => {
|
|
1414
|
+
// rebuild window event
|
|
1415
|
+
umdWindowListenerMap.forEach((listenerList, type) => {
|
|
1416
|
+
for (const listener of listenerList) {
|
|
1417
|
+
microWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1600
1418
|
}
|
|
1601
|
-
}
|
|
1602
|
-
|
|
1603
|
-
|
|
1604
|
-
|
|
1605
|
-
|
|
1606
|
-
|
|
1607
|
-
|
|
1608
|
-
|
|
1609
|
-
|
|
1419
|
+
});
|
|
1420
|
+
// rebuild timer
|
|
1421
|
+
umdIntervalIdMap.forEach((info) => {
|
|
1422
|
+
microWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
1423
|
+
});
|
|
1424
|
+
umdTimeoutIdMap.forEach((info) => {
|
|
1425
|
+
microWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
1426
|
+
});
|
|
1427
|
+
// rebuild onclick event
|
|
1428
|
+
umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
|
|
1429
|
+
// rebuild document event
|
|
1430
|
+
setCurrentAppName(appName);
|
|
1431
|
+
umdDocumentListenerMap.forEach((listenerList, type) => {
|
|
1432
|
+
for (const listener of listenerList) {
|
|
1433
|
+
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1610
1434
|
}
|
|
1611
|
-
|
|
1612
|
-
|
|
1613
|
-
|
|
1614
|
-
|
|
1615
|
-
|
|
1616
|
-
|
|
1617
|
-
|
|
1618
|
-
|
|
1619
|
-
|
|
1620
|
-
|
|
1621
|
-
/**
|
|
1622
|
-
* add this logic for SSR
|
|
1623
|
-
* if old app has unmounted and url is different, create new app to replace old one
|
|
1624
|
-
*/
|
|
1625
|
-
this.handleCreateApp();
|
|
1626
|
-
}
|
|
1627
|
-
else {
|
|
1628
|
-
logError(`an app named ${this.appName} already exists`, this.appName);
|
|
1435
|
+
});
|
|
1436
|
+
setCurrentAppName(null);
|
|
1437
|
+
};
|
|
1438
|
+
// release all event listener & interval & timeout when unmount app
|
|
1439
|
+
const releaseEffect = () => {
|
|
1440
|
+
// Clear window binding events
|
|
1441
|
+
if (eventListenerMap.size) {
|
|
1442
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
1443
|
+
for (const listener of listenerList) {
|
|
1444
|
+
rawWindowRemoveEventListener.call(rawWindow, type, listener);
|
|
1629
1445
|
}
|
|
1630
|
-
}
|
|
1631
|
-
else {
|
|
1632
|
-
this.handleCreateApp();
|
|
1633
|
-
}
|
|
1634
|
-
}
|
|
1635
|
-
/**
|
|
1636
|
-
* judge the attribute is legal
|
|
1637
|
-
* @param name attribute name
|
|
1638
|
-
* @param val attribute value
|
|
1639
|
-
*/
|
|
1640
|
-
legalAttribute(name, val) {
|
|
1641
|
-
if (!isString(val) || !val) {
|
|
1642
|
-
logError(`unexpected attribute ${name}, please check again`, this.appName);
|
|
1643
|
-
return false;
|
|
1644
|
-
}
|
|
1645
|
-
return true;
|
|
1646
|
-
}
|
|
1647
|
-
/**
|
|
1648
|
-
* mount app
|
|
1649
|
-
* some serious note before mount:
|
|
1650
|
-
* 1. is prefetch ?
|
|
1651
|
-
* 2. is remount in another container ?
|
|
1652
|
-
* 3. is remount with change properties of the container ?
|
|
1653
|
-
*/
|
|
1654
|
-
handleAppMount(app) {
|
|
1655
|
-
app.isPrefetch = false;
|
|
1656
|
-
defer(() => {
|
|
1657
|
-
var _a;
|
|
1658
|
-
return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible());
|
|
1659
1446
|
});
|
|
1447
|
+
eventListenerMap.clear();
|
|
1660
1448
|
}
|
|
1661
|
-
//
|
|
1662
|
-
|
|
1663
|
-
|
|
1664
|
-
|
|
1665
|
-
name: this.appName,
|
|
1666
|
-
url: this.appUrl,
|
|
1667
|
-
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
1668
|
-
inline: this.getDisposeResult('inline'),
|
|
1669
|
-
scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')),
|
|
1670
|
-
useSandbox: !this.getDisposeResult('disableSandbox'),
|
|
1671
|
-
macro: this.getDisposeResult('macro'),
|
|
1672
|
-
baseroute: this.getBaseRouteCompatible(),
|
|
1449
|
+
// Clear timers
|
|
1450
|
+
if (intervalIdMap.size) {
|
|
1451
|
+
intervalIdMap.forEach((_, intervalId) => {
|
|
1452
|
+
rawClearInterval.call(rawWindow, intervalId);
|
|
1673
1453
|
});
|
|
1674
|
-
|
|
1675
|
-
}
|
|
1676
|
-
/**
|
|
1677
|
-
* unmount app
|
|
1678
|
-
* @param destroy delete cache resources when unmount
|
|
1679
|
-
*/
|
|
1680
|
-
handleUnmount(destroy) {
|
|
1681
|
-
const app = appInstanceMap.get(this.appName);
|
|
1682
|
-
if (app && appStatus.UNMOUNT !== app.getAppStatus())
|
|
1683
|
-
app.unmount(destroy);
|
|
1684
|
-
}
|
|
1685
|
-
/**
|
|
1686
|
-
* Get configuration
|
|
1687
|
-
* Global setting is lowest priority
|
|
1688
|
-
* @param name Configuration item name
|
|
1689
|
-
*/
|
|
1690
|
-
getDisposeResult(name) {
|
|
1691
|
-
// @ts-ignore
|
|
1692
|
-
return (this.hasAttribute(name) || microApp[name]) && this.getAttribute(name) !== 'false';
|
|
1693
|
-
}
|
|
1694
|
-
/**
|
|
1695
|
-
* 2021-09-08
|
|
1696
|
-
* get baseRoute
|
|
1697
|
-
* getAttribute('baseurl') is compatible writing of versions below 0.3.1
|
|
1698
|
-
*/
|
|
1699
|
-
getBaseRouteCompatible() {
|
|
1700
|
-
var _a, _b;
|
|
1701
|
-
return (_b = (_a = this.getAttribute('baseroute')) !== null && _a !== void 0 ? _a : this.getAttribute('baseurl')) !== null && _b !== void 0 ? _b : '';
|
|
1454
|
+
intervalIdMap.clear();
|
|
1702
1455
|
}
|
|
1703
|
-
|
|
1704
|
-
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
|
|
1708
|
-
microApp.setData(this.appName, value);
|
|
1709
|
-
}
|
|
1710
|
-
else {
|
|
1711
|
-
this.cacheData = value;
|
|
1712
|
-
}
|
|
1456
|
+
if (timeoutIdMap.size) {
|
|
1457
|
+
timeoutIdMap.forEach((_, timeoutId) => {
|
|
1458
|
+
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1459
|
+
});
|
|
1460
|
+
timeoutIdMap.clear();
|
|
1713
1461
|
}
|
|
1714
|
-
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
get
|
|
1718
|
-
|
|
1719
|
-
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
}
|
|
1724
|
-
|
|
1462
|
+
// Clear the function bound by micro application through document.onclick
|
|
1463
|
+
documentClickListMap.delete(appName);
|
|
1464
|
+
// Clear document binding event
|
|
1465
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1466
|
+
if (documentAppListenersMap) {
|
|
1467
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1468
|
+
for (const listener of listenerList) {
|
|
1469
|
+
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
1470
|
+
}
|
|
1471
|
+
});
|
|
1472
|
+
documentAppListenersMap.clear();
|
|
1725
1473
|
}
|
|
1726
|
-
}
|
|
1727
|
-
|
|
1474
|
+
};
|
|
1475
|
+
return {
|
|
1476
|
+
recordUmdEffect,
|
|
1477
|
+
rebuildUmdEffect,
|
|
1478
|
+
releaseEffect,
|
|
1479
|
+
};
|
|
1728
1480
|
}
|
|
1729
1481
|
|
|
1730
1482
|
class EventCenter {
|
|
@@ -1844,9 +1596,7 @@ class EventCenterForGlobal {
|
|
|
1844
1596
|
* @param cb listener
|
|
1845
1597
|
*/
|
|
1846
1598
|
removeGlobalDataListener(cb) {
|
|
1847
|
-
|
|
1848
|
-
eventCenter.off('global', cb);
|
|
1849
|
-
}
|
|
1599
|
+
isFunction(cb) && eventCenter.off('global', cb);
|
|
1850
1600
|
}
|
|
1851
1601
|
/**
|
|
1852
1602
|
* dispatch global data
|
|
@@ -1890,7 +1640,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
1890
1640
|
* @param autoTrigger If there is cached data when first bind listener, whether it needs to trigger, default is false
|
|
1891
1641
|
*/
|
|
1892
1642
|
addDataListener(appName, cb, autoTrigger) {
|
|
1893
|
-
eventCenter.on(formatEventName(appName, false), cb, autoTrigger);
|
|
1643
|
+
eventCenter.on(formatEventName(formatAppName(appName), false), cb, autoTrigger);
|
|
1894
1644
|
}
|
|
1895
1645
|
/**
|
|
1896
1646
|
* remove listener
|
|
@@ -1898,9 +1648,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
1898
1648
|
* @param cb listener
|
|
1899
1649
|
*/
|
|
1900
1650
|
removeDataListener(appName, cb) {
|
|
1901
|
-
|
|
1902
|
-
eventCenter.off(formatEventName(appName, false), cb);
|
|
1903
|
-
}
|
|
1651
|
+
isFunction(cb) && eventCenter.off(formatEventName(formatAppName(appName), false), cb);
|
|
1904
1652
|
}
|
|
1905
1653
|
/**
|
|
1906
1654
|
* get data from micro app or base app
|
|
@@ -1908,7 +1656,7 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
1908
1656
|
* @param fromBaseApp whether get data from base app, default is false
|
|
1909
1657
|
*/
|
|
1910
1658
|
getData(appName, fromBaseApp = false) {
|
|
1911
|
-
return eventCenter.getData(formatEventName(appName, fromBaseApp));
|
|
1659
|
+
return eventCenter.getData(formatEventName(formatAppName(appName), fromBaseApp));
|
|
1912
1660
|
}
|
|
1913
1661
|
/**
|
|
1914
1662
|
* Dispatch data to the specified micro app
|
|
@@ -1916,21 +1664,22 @@ class EventCenterForBaseApp extends EventCenterForGlobal {
|
|
|
1916
1664
|
* @param data data
|
|
1917
1665
|
*/
|
|
1918
1666
|
setData(appName, data) {
|
|
1919
|
-
eventCenter.dispatch(formatEventName(appName, true), data);
|
|
1667
|
+
eventCenter.dispatch(formatEventName(formatAppName(appName), true), data);
|
|
1920
1668
|
}
|
|
1921
1669
|
/**
|
|
1922
1670
|
* clear all listener for specified micro app
|
|
1923
1671
|
* @param appName app.name
|
|
1924
1672
|
*/
|
|
1925
1673
|
clearDataListener(appName) {
|
|
1926
|
-
eventCenter.off(formatEventName(appName, false));
|
|
1674
|
+
eventCenter.off(formatEventName(formatAppName(appName), false));
|
|
1927
1675
|
}
|
|
1928
1676
|
}
|
|
1929
1677
|
// Event center for sub app
|
|
1930
1678
|
class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
1931
1679
|
constructor(appName) {
|
|
1932
1680
|
super();
|
|
1933
|
-
this.appName = appName;
|
|
1681
|
+
this.appName = formatAppName(appName);
|
|
1682
|
+
!this.appName && logError(`Invalid appName ${appName}`);
|
|
1934
1683
|
}
|
|
1935
1684
|
/**
|
|
1936
1685
|
* add listener, monitor the data sent by the base app
|
|
@@ -1946,9 +1695,7 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
1946
1695
|
* @param cb listener
|
|
1947
1696
|
*/
|
|
1948
1697
|
removeDataListener(cb) {
|
|
1949
|
-
|
|
1950
|
-
eventCenter.off(formatEventName(this.appName, true), cb);
|
|
1951
|
-
}
|
|
1698
|
+
isFunction(cb) && eventCenter.off(formatEventName(this.appName, true), cb);
|
|
1952
1699
|
}
|
|
1953
1700
|
/**
|
|
1954
1701
|
* get data from base app
|
|
@@ -1970,11 +1717,7 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
1970
1717
|
data,
|
|
1971
1718
|
}
|
|
1972
1719
|
});
|
|
1973
|
-
|
|
1974
|
-
if (element instanceof ShadowRoot) {
|
|
1975
|
-
element = element.host;
|
|
1976
|
-
}
|
|
1977
|
-
element.dispatchEvent(event);
|
|
1720
|
+
getRootContainer(app.container).dispatchEvent(event);
|
|
1978
1721
|
}
|
|
1979
1722
|
}
|
|
1980
1723
|
/**
|
|
@@ -2017,1001 +1760,1268 @@ function rebuildDataCenterSnapshot(microAppEventCneter) {
|
|
|
2017
1760
|
}
|
|
2018
1761
|
}
|
|
2019
1762
|
|
|
2020
|
-
|
|
2021
|
-
|
|
2022
|
-
|
|
2023
|
-
|
|
2024
|
-
|
|
2025
|
-
|
|
2026
|
-
|
|
2027
|
-
|
|
2028
|
-
|
|
2029
|
-
|
|
2030
|
-
|
|
2031
|
-
|
|
2032
|
-
|
|
2033
|
-
|
|
2034
|
-
|
|
2035
|
-
|
|
2036
|
-
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
if (options && isPlainObject(options)) {
|
|
2043
|
-
this.shadowDOM = options.shadowDOM;
|
|
2044
|
-
this.destroy = options.destroy;
|
|
2045
|
-
/**
|
|
2046
|
-
* compatible with versions below 0.4.2 of destroy
|
|
2047
|
-
* Do not merge with the previous line of code
|
|
2048
|
-
*/
|
|
2049
|
-
// @ts-ignore
|
|
2050
|
-
this.destory = options.destory;
|
|
2051
|
-
this.inline = options.inline;
|
|
2052
|
-
this.disableScopecss = options.disableScopecss;
|
|
2053
|
-
this.disableSandbox = options.disableSandbox;
|
|
2054
|
-
this.macro = options.macro;
|
|
2055
|
-
if (isFunction(options.fetch))
|
|
2056
|
-
this.fetch = options.fetch;
|
|
2057
|
-
if (isPlainObject(options.lifeCycles)) {
|
|
2058
|
-
this.lifeCycles = options.lifeCycles;
|
|
2059
|
-
}
|
|
2060
|
-
if (isPlainObject(options.plugins)) {
|
|
2061
|
-
this.plugins = options.plugins;
|
|
2062
|
-
}
|
|
2063
|
-
// load app assets when browser is idle
|
|
2064
|
-
if (options.preFetchApps) {
|
|
2065
|
-
preFetch(options.preFetchApps);
|
|
2066
|
-
}
|
|
2067
|
-
// load global assets when browser is idle
|
|
2068
|
-
if (options.globalAssets) {
|
|
2069
|
-
getGlobalAssets(options.globalAssets);
|
|
2070
|
-
}
|
|
2071
|
-
}
|
|
2072
|
-
defineElement(this.tagName);
|
|
2073
|
-
}
|
|
2074
|
-
}
|
|
2075
|
-
var microApp = new MicroApp();
|
|
2076
|
-
|
|
1763
|
+
// Variables that can escape to rawWindow
|
|
1764
|
+
const staticEscapeProperties = [
|
|
1765
|
+
'System',
|
|
1766
|
+
'__cjsWrapper',
|
|
1767
|
+
'__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
|
|
1768
|
+
];
|
|
1769
|
+
// Variables that can only assigned to rawWindow
|
|
1770
|
+
const escapeSetterKeyList = [
|
|
1771
|
+
'location',
|
|
1772
|
+
];
|
|
1773
|
+
const unscopables = {
|
|
1774
|
+
undefined: true,
|
|
1775
|
+
Array: true,
|
|
1776
|
+
Object: true,
|
|
1777
|
+
String: true,
|
|
1778
|
+
Boolean: true,
|
|
1779
|
+
Math: true,
|
|
1780
|
+
Number: true,
|
|
1781
|
+
Symbol: true,
|
|
1782
|
+
parseFloat: true,
|
|
1783
|
+
Float32Array: true,
|
|
1784
|
+
};
|
|
2077
1785
|
/**
|
|
2078
|
-
*
|
|
2079
|
-
* @param url source path
|
|
2080
|
-
* @param appName app name
|
|
2081
|
-
* @param config config of fetch
|
|
1786
|
+
* macro task to solve the rendering problem of vue3
|
|
2082
1787
|
*/
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
|
|
2086
|
-
|
|
2087
|
-
return fetch(url, options).then((res) => {
|
|
2088
|
-
return res.text();
|
|
2089
|
-
});
|
|
2090
|
-
}
|
|
2091
|
-
|
|
2092
|
-
/**
|
|
2093
|
-
* transform html string to dom
|
|
2094
|
-
* @param str string dom
|
|
2095
|
-
*/
|
|
2096
|
-
function getWrapElement(str) {
|
|
2097
|
-
const wrapDiv = pureCreateElement('div');
|
|
2098
|
-
wrapDiv.innerHTML = str;
|
|
2099
|
-
return wrapDiv;
|
|
1788
|
+
let macroTimer;
|
|
1789
|
+
function macroTask(fn) {
|
|
1790
|
+
macroTimer && clearTimeout(macroTimer);
|
|
1791
|
+
macroTimer = setTimeout(fn, 0);
|
|
2100
1792
|
}
|
|
2101
|
-
|
|
2102
|
-
|
|
2103
|
-
|
|
2104
|
-
|
|
2105
|
-
|
|
2106
|
-
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
|
|
2116
|
-
|
|
2117
|
-
|
|
2118
|
-
|
|
2119
|
-
|
|
2120
|
-
|
|
2121
|
-
|
|
1793
|
+
class SandBox {
|
|
1794
|
+
constructor(appName, url, macro) {
|
|
1795
|
+
// Scoped global Properties(Properties that can only get and set in microWindow, will not escape to rawWindow)
|
|
1796
|
+
this.scopeProperties = ['webpackJsonp'];
|
|
1797
|
+
// Properties that can be escape to rawWindow
|
|
1798
|
+
this.escapeProperties = [];
|
|
1799
|
+
// Properties newly added to microWindow
|
|
1800
|
+
this.injectedKeys = new Set();
|
|
1801
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
1802
|
+
this.escapeKeys = new Set();
|
|
1803
|
+
// sandbox state
|
|
1804
|
+
this.active = false;
|
|
1805
|
+
this.microWindow = {}; // Proxy target
|
|
1806
|
+
const rawWindow = globalEnv.rawWindow;
|
|
1807
|
+
const rawDocument = globalEnv.rawDocument;
|
|
1808
|
+
const descriptorTargetMap = new Map();
|
|
1809
|
+
const hasOwnProperty = (key) => this.microWindow.hasOwnProperty(key) || rawWindow.hasOwnProperty(key);
|
|
1810
|
+
// get scopeProperties and escapeProperties from plugins
|
|
1811
|
+
this.getScopeProperties(appName);
|
|
1812
|
+
// inject global properties
|
|
1813
|
+
this.inject(this.microWindow, appName, url);
|
|
1814
|
+
// Rewrite global event listener & timeout
|
|
1815
|
+
Object.assign(this, effect(this.microWindow));
|
|
1816
|
+
this.proxyWindow = new Proxy(this.microWindow, {
|
|
1817
|
+
get: (target, key) => {
|
|
1818
|
+
if (key === Symbol.unscopables)
|
|
1819
|
+
return unscopables;
|
|
1820
|
+
if (['window', 'self', 'globalThis'].includes(key)) {
|
|
1821
|
+
return this.proxyWindow;
|
|
1822
|
+
}
|
|
1823
|
+
if (key === 'top' || key === 'parent') {
|
|
1824
|
+
if (rawWindow === rawWindow.parent) { // not in iframe
|
|
1825
|
+
return this.proxyWindow;
|
|
1826
|
+
}
|
|
1827
|
+
return Reflect.get(rawWindow, key); // iframe
|
|
1828
|
+
}
|
|
1829
|
+
if (key === 'hasOwnProperty')
|
|
1830
|
+
return hasOwnProperty;
|
|
1831
|
+
if (key === 'document' || key === 'eval') {
|
|
1832
|
+
if (this.active) {
|
|
1833
|
+
setCurrentAppName(appName);
|
|
1834
|
+
(macro ? macroTask : defer)(() => setCurrentAppName(null));
|
|
1835
|
+
}
|
|
1836
|
+
switch (key) {
|
|
1837
|
+
case 'document':
|
|
1838
|
+
return rawDocument;
|
|
1839
|
+
case 'eval':
|
|
1840
|
+
return eval;
|
|
1841
|
+
}
|
|
1842
|
+
}
|
|
1843
|
+
if (Reflect.has(target, key)) {
|
|
1844
|
+
return Reflect.get(target, key);
|
|
1845
|
+
}
|
|
1846
|
+
if (this.scopeProperties.includes(key) ||
|
|
1847
|
+
(isString(key) && /^__MICRO_APP_/.test(key))) {
|
|
1848
|
+
return Reflect.get(target, key);
|
|
1849
|
+
}
|
|
1850
|
+
const rawValue = Reflect.get(rawWindow, key);
|
|
1851
|
+
return bindFunctionToRawWidow(rawWindow, rawValue);
|
|
1852
|
+
},
|
|
1853
|
+
set: (target, key, value) => {
|
|
1854
|
+
if (this.active) {
|
|
1855
|
+
if (escapeSetterKeyList.includes(key)) {
|
|
1856
|
+
Reflect.set(rawWindow, key, value);
|
|
1857
|
+
}
|
|
1858
|
+
else if (!target.hasOwnProperty(key) &&
|
|
1859
|
+
rawWindow.hasOwnProperty(key) &&
|
|
1860
|
+
!this.scopeProperties.includes(key)) {
|
|
1861
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1862
|
+
const { writable, configurable, enumerable } = descriptor;
|
|
1863
|
+
if (writable) {
|
|
1864
|
+
Object.defineProperty(target, key, {
|
|
1865
|
+
configurable,
|
|
1866
|
+
enumerable,
|
|
1867
|
+
writable,
|
|
1868
|
+
value,
|
|
1869
|
+
});
|
|
1870
|
+
this.injectedKeys.add(key);
|
|
1871
|
+
}
|
|
1872
|
+
}
|
|
1873
|
+
else {
|
|
1874
|
+
Reflect.set(target, key, value);
|
|
1875
|
+
this.injectedKeys.add(key);
|
|
1876
|
+
}
|
|
1877
|
+
if ((this.escapeProperties.includes(key) ||
|
|
1878
|
+
(staticEscapeProperties.includes(key) && !Reflect.has(rawWindow, key))) &&
|
|
1879
|
+
!this.scopeProperties.includes(key)) {
|
|
1880
|
+
Reflect.set(rawWindow, key, value);
|
|
1881
|
+
this.escapeKeys.add(key);
|
|
1882
|
+
}
|
|
1883
|
+
}
|
|
1884
|
+
return true;
|
|
1885
|
+
},
|
|
1886
|
+
has: (target, key) => {
|
|
1887
|
+
if (this.scopeProperties.includes(key))
|
|
1888
|
+
return key in target;
|
|
1889
|
+
return key in unscopables || key in target || key in rawWindow;
|
|
1890
|
+
},
|
|
1891
|
+
getOwnPropertyDescriptor: (target, key) => {
|
|
1892
|
+
if (target.hasOwnProperty(key)) {
|
|
1893
|
+
descriptorTargetMap.set(key, 'target');
|
|
1894
|
+
return Object.getOwnPropertyDescriptor(target, key);
|
|
1895
|
+
}
|
|
1896
|
+
if (rawWindow.hasOwnProperty(key)) {
|
|
1897
|
+
descriptorTargetMap.set(key, 'rawWindow');
|
|
1898
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1899
|
+
if (descriptor && !descriptor.configurable) {
|
|
1900
|
+
descriptor.configurable = true;
|
|
1901
|
+
}
|
|
1902
|
+
return descriptor;
|
|
1903
|
+
}
|
|
1904
|
+
return undefined;
|
|
1905
|
+
},
|
|
1906
|
+
defineProperty: (target, key, value) => {
|
|
1907
|
+
const from = descriptorTargetMap.get(key);
|
|
1908
|
+
if (from === 'rawWindow') {
|
|
1909
|
+
return Reflect.defineProperty(rawWindow, key, value);
|
|
1910
|
+
}
|
|
1911
|
+
return Reflect.defineProperty(target, key, value);
|
|
1912
|
+
},
|
|
1913
|
+
ownKeys: (target) => {
|
|
1914
|
+
return unique(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)));
|
|
1915
|
+
},
|
|
1916
|
+
deleteProperty: (target, key) => {
|
|
1917
|
+
if (target.hasOwnProperty(key)) {
|
|
1918
|
+
this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
1919
|
+
return Reflect.deleteProperty(target, key);
|
|
1920
|
+
}
|
|
1921
|
+
return true;
|
|
1922
|
+
},
|
|
1923
|
+
});
|
|
1924
|
+
}
|
|
1925
|
+
start(baseroute) {
|
|
1926
|
+
if (!this.active) {
|
|
1927
|
+
this.active = true;
|
|
1928
|
+
this.microWindow.__MICRO_APP_BASE_ROUTE__ = this.microWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
1929
|
+
// BUG FIX: bable-polyfill@6.x
|
|
1930
|
+
globalEnv.rawWindow._babelPolyfill && (globalEnv.rawWindow._babelPolyfill = false);
|
|
1931
|
+
if (++SandBox.activeCount === 1) {
|
|
1932
|
+
effectDocumentEvent();
|
|
2122
1933
|
}
|
|
2123
1934
|
}
|
|
2124
|
-
|
|
2125
|
-
|
|
2126
|
-
|
|
2127
|
-
|
|
2128
|
-
|
|
2129
|
-
|
|
1935
|
+
}
|
|
1936
|
+
stop() {
|
|
1937
|
+
if (this.active) {
|
|
1938
|
+
this.active = false;
|
|
1939
|
+
this.releaseEffect();
|
|
1940
|
+
this.microWindow.microApp.clearDataListener();
|
|
1941
|
+
this.microWindow.microApp.clearGlobalDataListener();
|
|
1942
|
+
this.injectedKeys.forEach((key) => {
|
|
1943
|
+
Reflect.deleteProperty(this.microWindow, key);
|
|
1944
|
+
});
|
|
1945
|
+
this.injectedKeys.clear();
|
|
1946
|
+
this.escapeKeys.forEach((key) => {
|
|
1947
|
+
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
1948
|
+
});
|
|
1949
|
+
this.escapeKeys.clear();
|
|
1950
|
+
if (--SandBox.activeCount === 0) {
|
|
1951
|
+
releaseEffectDocumentEvent();
|
|
2130
1952
|
}
|
|
2131
1953
|
}
|
|
2132
|
-
|
|
2133
|
-
|
|
2134
|
-
|
|
2135
|
-
|
|
2136
|
-
|
|
1954
|
+
}
|
|
1955
|
+
// record umd snapshot before the first execution of umdHookMount
|
|
1956
|
+
recordUmdSnapshot() {
|
|
1957
|
+
this.microWindow.__MICRO_APP_UMD_MODE__ = true;
|
|
1958
|
+
this.recordUmdEffect();
|
|
1959
|
+
recordDataCenterSnapshot(this.microWindow.microApp);
|
|
1960
|
+
this.recordUmdinjectedValues = new Map();
|
|
1961
|
+
this.injectedKeys.forEach((key) => {
|
|
1962
|
+
this.recordUmdinjectedValues.set(key, Reflect.get(this.microWindow, key));
|
|
1963
|
+
});
|
|
1964
|
+
}
|
|
1965
|
+
// rebuild umd snapshot before remount umd app
|
|
1966
|
+
rebuildUmdSnapshot() {
|
|
1967
|
+
this.recordUmdinjectedValues.forEach((value, key) => {
|
|
1968
|
+
Reflect.set(this.proxyWindow, key, value);
|
|
1969
|
+
});
|
|
1970
|
+
this.rebuildUmdEffect();
|
|
1971
|
+
rebuildDataCenterSnapshot(this.microWindow.microApp);
|
|
1972
|
+
}
|
|
1973
|
+
/**
|
|
1974
|
+
* get scopeProperties and escapeProperties from plugins
|
|
1975
|
+
* @param appName app name
|
|
1976
|
+
*/
|
|
1977
|
+
getScopeProperties(appName) {
|
|
1978
|
+
var _a;
|
|
1979
|
+
if (!isPlainObject(microApp.plugins))
|
|
1980
|
+
return;
|
|
1981
|
+
if (isArray(microApp.plugins.global)) {
|
|
1982
|
+
for (const plugin of microApp.plugins.global) {
|
|
1983
|
+
if (isPlainObject(plugin)) {
|
|
1984
|
+
if (isArray(plugin.scopeProperties)) {
|
|
1985
|
+
this.scopeProperties = this.scopeProperties.concat(plugin.scopeProperties);
|
|
1986
|
+
}
|
|
1987
|
+
if (isArray(plugin.escapeProperties)) {
|
|
1988
|
+
this.escapeProperties = this.escapeProperties.concat(plugin.escapeProperties);
|
|
1989
|
+
}
|
|
1990
|
+
}
|
|
1991
|
+
}
|
|
2137
1992
|
}
|
|
2138
|
-
|
|
2139
|
-
|
|
1993
|
+
if (isArray((_a = microApp.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName])) {
|
|
1994
|
+
for (const plugin of microApp.plugins.modules[appName]) {
|
|
1995
|
+
if (isPlainObject(plugin)) {
|
|
1996
|
+
if (isArray(plugin.scopeProperties)) {
|
|
1997
|
+
this.scopeProperties = this.scopeProperties.concat(plugin.scopeProperties);
|
|
1998
|
+
}
|
|
1999
|
+
if (isArray(plugin.escapeProperties)) {
|
|
2000
|
+
this.escapeProperties = this.escapeProperties.concat(plugin.escapeProperties);
|
|
2001
|
+
}
|
|
2002
|
+
}
|
|
2003
|
+
}
|
|
2140
2004
|
}
|
|
2141
2005
|
}
|
|
2006
|
+
/**
|
|
2007
|
+
* inject global properties to microWindow
|
|
2008
|
+
* @param microWindow micro window
|
|
2009
|
+
* @param appName app name
|
|
2010
|
+
* @param url app url
|
|
2011
|
+
*/
|
|
2012
|
+
inject(microWindow, appName, url) {
|
|
2013
|
+
microWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
2014
|
+
microWindow.__MICRO_APP_NAME__ = appName;
|
|
2015
|
+
microWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
2016
|
+
microWindow.microApp = new EventCenterForMicroApp(appName);
|
|
2017
|
+
microWindow.rawWindow = globalEnv.rawWindow;
|
|
2018
|
+
microWindow.rawDocument = globalEnv.rawDocument;
|
|
2019
|
+
microWindow.removeDomScope = removeDomScope;
|
|
2020
|
+
}
|
|
2021
|
+
}
|
|
2022
|
+
SandBox.activeCount = 0; // number of active sandbox
|
|
2023
|
+
|
|
2024
|
+
function eventHandler$1(event, element) {
|
|
2025
|
+
Object.defineProperties(event, {
|
|
2026
|
+
currentTarget: {
|
|
2027
|
+
get() {
|
|
2028
|
+
return element;
|
|
2029
|
+
}
|
|
2030
|
+
},
|
|
2031
|
+
target: {
|
|
2032
|
+
get() {
|
|
2033
|
+
return element;
|
|
2034
|
+
}
|
|
2035
|
+
},
|
|
2036
|
+
});
|
|
2037
|
+
}
|
|
2038
|
+
/**
|
|
2039
|
+
* dispatch lifeCycles event to base app
|
|
2040
|
+
* created, beforemount, mounted, unmount, error
|
|
2041
|
+
* @param element container
|
|
2042
|
+
* @param appName app.name
|
|
2043
|
+
* @param lifecycleName lifeCycle name
|
|
2044
|
+
* @param error param from error hook
|
|
2045
|
+
*/
|
|
2046
|
+
function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
2047
|
+
var _a;
|
|
2048
|
+
if (!element) {
|
|
2049
|
+
return logError(`element does not exist in lifecycle ${lifecycleName}`, appName);
|
|
2050
|
+
}
|
|
2051
|
+
element = getRootContainer(element);
|
|
2052
|
+
// clear dom scope before dispatch lifeCycles event to base app, especially mounted & unmount
|
|
2053
|
+
removeDomScope();
|
|
2054
|
+
const detail = Object.assign({
|
|
2055
|
+
name: appName,
|
|
2056
|
+
container: element,
|
|
2057
|
+
}, error && {
|
|
2058
|
+
error
|
|
2059
|
+
});
|
|
2060
|
+
const event = new CustomEvent(lifecycleName, {
|
|
2061
|
+
detail,
|
|
2062
|
+
});
|
|
2063
|
+
eventHandler$1(event, element);
|
|
2064
|
+
// global hooks
|
|
2065
|
+
// @ts-ignore
|
|
2066
|
+
if (isFunction((_a = microApp.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
2067
|
+
// @ts-ignore
|
|
2068
|
+
microApp.lifeCycles[lifecycleName](event);
|
|
2069
|
+
}
|
|
2070
|
+
element.dispatchEvent(event);
|
|
2142
2071
|
}
|
|
2143
2072
|
/**
|
|
2144
|
-
*
|
|
2145
|
-
* @param
|
|
2146
|
-
* @param app app
|
|
2073
|
+
* Dispatch unmount event to micro app
|
|
2074
|
+
* @param appName app.name
|
|
2147
2075
|
*/
|
|
2148
|
-
function
|
|
2149
|
-
const
|
|
2150
|
-
|
|
2151
|
-
|
|
2152
|
-
|
|
2153
|
-
|
|
2154
|
-
|
|
2155
|
-
|
|
2076
|
+
function dispatchUnmountToMicroApp(appName) {
|
|
2077
|
+
const event = new CustomEvent(`unmount-${appName}`);
|
|
2078
|
+
window.dispatchEvent(event);
|
|
2079
|
+
}
|
|
2080
|
+
|
|
2081
|
+
// micro app instances
|
|
2082
|
+
const appInstanceMap = new Map();
|
|
2083
|
+
class CreateApp {
|
|
2084
|
+
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, macro, baseroute, }) {
|
|
2085
|
+
this.status = appStatus.NOT_LOADED;
|
|
2086
|
+
this.loadSourceLevel = 0;
|
|
2087
|
+
this.umdHookMount = null;
|
|
2088
|
+
this.umdHookUnmount = null;
|
|
2089
|
+
this.libraryName = null;
|
|
2090
|
+
this.umdMode = false;
|
|
2091
|
+
this.isPrefetch = false;
|
|
2092
|
+
this.container = null;
|
|
2093
|
+
this.macro = false;
|
|
2094
|
+
this.baseroute = '';
|
|
2095
|
+
this.sandBox = null;
|
|
2096
|
+
this.container = container !== null && container !== void 0 ? container : null;
|
|
2097
|
+
this.inline = inline !== null && inline !== void 0 ? inline : false;
|
|
2098
|
+
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : '';
|
|
2099
|
+
this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
|
|
2100
|
+
// optional during init👆
|
|
2101
|
+
this.name = name;
|
|
2102
|
+
this.url = url;
|
|
2103
|
+
this.useSandbox = useSandbox;
|
|
2104
|
+
this.scopecss = this.useSandbox && scopecss;
|
|
2105
|
+
this.macro = macro !== null && macro !== void 0 ? macro : false;
|
|
2106
|
+
this.source = {
|
|
2107
|
+
links: new Map(),
|
|
2108
|
+
scripts: new Map(),
|
|
2109
|
+
};
|
|
2110
|
+
this.loadSourceCode();
|
|
2111
|
+
this.useSandbox && (this.sandBox = new SandBox(name, url, this.macro));
|
|
2156
2112
|
}
|
|
2157
|
-
|
|
2158
|
-
|
|
2159
|
-
|
|
2113
|
+
// Load resources
|
|
2114
|
+
loadSourceCode() {
|
|
2115
|
+
this.status = appStatus.LOADING_SOURCE_CODE;
|
|
2116
|
+
extractHtml(this);
|
|
2160
2117
|
}
|
|
2161
|
-
|
|
2162
|
-
|
|
2118
|
+
/**
|
|
2119
|
+
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
2120
|
+
*/
|
|
2121
|
+
onLoad(html) {
|
|
2122
|
+
if (++this.loadSourceLevel === 2) {
|
|
2123
|
+
this.source.html = html;
|
|
2124
|
+
if (this.isPrefetch || appStatus.UNMOUNT === this.status)
|
|
2125
|
+
return;
|
|
2126
|
+
this.status = appStatus.LOAD_SOURCE_FINISHED;
|
|
2127
|
+
this.mount();
|
|
2128
|
+
}
|
|
2163
2129
|
}
|
|
2164
|
-
|
|
2165
|
-
|
|
2130
|
+
/**
|
|
2131
|
+
* Error loading HTML
|
|
2132
|
+
* @param e Error
|
|
2133
|
+
*/
|
|
2134
|
+
onLoadError(e) {
|
|
2135
|
+
this.loadSourceLevel = -1;
|
|
2136
|
+
if (appStatus.UNMOUNT !== this.status) {
|
|
2137
|
+
this.onerror(e);
|
|
2138
|
+
this.status = appStatus.LOAD_SOURCE_ERROR;
|
|
2139
|
+
}
|
|
2166
2140
|
}
|
|
2167
|
-
|
|
2168
|
-
|
|
2141
|
+
/**
|
|
2142
|
+
* mount app
|
|
2143
|
+
* @param container app container
|
|
2144
|
+
* @param inline js runs in inline mode
|
|
2145
|
+
* @param baseroute route prefix, default is ''
|
|
2146
|
+
*/
|
|
2147
|
+
mount(container, inline, baseroute) {
|
|
2148
|
+
var _a, _b, _c;
|
|
2149
|
+
if (isBoolean(inline) && inline !== this.inline) {
|
|
2150
|
+
this.inline = inline;
|
|
2151
|
+
}
|
|
2152
|
+
this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
|
|
2153
|
+
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
|
|
2154
|
+
if (this.loadSourceLevel !== 2) {
|
|
2155
|
+
this.status = appStatus.LOADING_SOURCE_CODE;
|
|
2156
|
+
return;
|
|
2157
|
+
}
|
|
2158
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
2159
|
+
this.status = appStatus.MOUNTING;
|
|
2160
|
+
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
2161
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute);
|
|
2162
|
+
let umdHookMountResult; // result of mount function
|
|
2163
|
+
if (!this.umdMode) {
|
|
2164
|
+
let hasDispatchMountedEvent = false;
|
|
2165
|
+
// if all js are executed, param isFinished will be true
|
|
2166
|
+
execScripts(this.source.scripts, this, (isFinished) => {
|
|
2167
|
+
var _a;
|
|
2168
|
+
if (!this.umdMode) {
|
|
2169
|
+
const { mount, unmount } = this.getUmdLibraryHooks();
|
|
2170
|
+
// if mount & unmount is function, the sub app is umd mode
|
|
2171
|
+
if (isFunction(mount) && isFunction(unmount)) {
|
|
2172
|
+
this.umdHookMount = mount;
|
|
2173
|
+
this.umdHookUnmount = unmount;
|
|
2174
|
+
this.umdMode = true;
|
|
2175
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordUmdSnapshot();
|
|
2176
|
+
try {
|
|
2177
|
+
umdHookMountResult = this.umdHookMount();
|
|
2178
|
+
}
|
|
2179
|
+
catch (e) {
|
|
2180
|
+
logError('an error occurred in the mount function \n', this.name, e);
|
|
2181
|
+
}
|
|
2182
|
+
}
|
|
2183
|
+
}
|
|
2184
|
+
if (!hasDispatchMountedEvent && (isFinished === true || this.umdMode)) {
|
|
2185
|
+
hasDispatchMountedEvent = true;
|
|
2186
|
+
this.handleMounted(umdHookMountResult);
|
|
2187
|
+
}
|
|
2188
|
+
});
|
|
2189
|
+
}
|
|
2190
|
+
else {
|
|
2191
|
+
(_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.rebuildUmdSnapshot();
|
|
2192
|
+
try {
|
|
2193
|
+
umdHookMountResult = this.umdHookMount();
|
|
2194
|
+
}
|
|
2195
|
+
catch (e) {
|
|
2196
|
+
logError('an error occurred in the mount function \n', this.name, e);
|
|
2197
|
+
}
|
|
2198
|
+
this.handleMounted(umdHookMountResult);
|
|
2199
|
+
}
|
|
2169
2200
|
}
|
|
2170
|
-
|
|
2171
|
-
|
|
2172
|
-
|
|
2173
|
-
|
|
2174
|
-
|
|
2175
|
-
|
|
2176
|
-
|
|
2177
|
-
|
|
2178
|
-
|
|
2179
|
-
|
|
2180
|
-
|
|
2201
|
+
/**
|
|
2202
|
+
* handle for promise umdHookMount
|
|
2203
|
+
* @param umdHookMountResult result of umdHookMount
|
|
2204
|
+
*/
|
|
2205
|
+
handleMounted(umdHookMountResult) {
|
|
2206
|
+
if (isPromise(umdHookMountResult)) {
|
|
2207
|
+
umdHookMountResult
|
|
2208
|
+
.then(() => this.dispatchMountedEvent())
|
|
2209
|
+
.catch((e) => this.onerror(e));
|
|
2210
|
+
}
|
|
2211
|
+
else {
|
|
2212
|
+
this.dispatchMountedEvent();
|
|
2181
2213
|
}
|
|
2182
|
-
htmlStr = htmlStr
|
|
2183
|
-
.replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
|
|
2184
|
-
return match
|
|
2185
|
-
.replace(/<head/i, '<micro-app-head')
|
|
2186
|
-
.replace(/<\/head>/i, '</micro-app-head>');
|
|
2187
|
-
})
|
|
2188
|
-
.replace(/<body[^>]*>[\s\S]*?<\/body>/i, (match) => {
|
|
2189
|
-
return match
|
|
2190
|
-
.replace(/<body/i, '<micro-app-body')
|
|
2191
|
-
.replace(/<\/body>/i, '</micro-app-body>');
|
|
2192
|
-
});
|
|
2193
|
-
extractSourceDom(htmlStr, app);
|
|
2194
|
-
}).catch((e) => {
|
|
2195
|
-
logError(`Failed to fetch data from ${app.url}, micro-app stop rendering`, app.name, e);
|
|
2196
|
-
app.onLoadError(e);
|
|
2197
|
-
});
|
|
2198
|
-
}
|
|
2199
|
-
|
|
2200
|
-
const boundedMap = new WeakMap();
|
|
2201
|
-
function isBoundedFunction(value) {
|
|
2202
|
-
if (boundedMap.has(value)) {
|
|
2203
|
-
return boundedMap.get(value);
|
|
2204
2214
|
}
|
|
2205
|
-
|
|
2206
|
-
|
|
2207
|
-
|
|
2208
|
-
|
|
2209
|
-
|
|
2210
|
-
|
|
2211
|
-
|
|
2212
|
-
|
|
2213
|
-
|
|
2215
|
+
/**
|
|
2216
|
+
* dispatch mounted event when app run finished
|
|
2217
|
+
*/
|
|
2218
|
+
dispatchMountedEvent() {
|
|
2219
|
+
if (appStatus.UNMOUNT !== this.status) {
|
|
2220
|
+
this.status = appStatus.MOUNTED;
|
|
2221
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
2222
|
+
}
|
|
2223
|
+
}
|
|
2224
|
+
/**
|
|
2225
|
+
* unmount app
|
|
2226
|
+
* @param destroy completely destroy, delete cache resources
|
|
2227
|
+
*/
|
|
2228
|
+
unmount(destroy) {
|
|
2229
|
+
if (this.status === appStatus.LOAD_SOURCE_ERROR) {
|
|
2230
|
+
destroy = true;
|
|
2231
|
+
}
|
|
2232
|
+
this.status = appStatus.UNMOUNT;
|
|
2233
|
+
// result of unmount function
|
|
2234
|
+
let umdHookUnmountResult;
|
|
2235
|
+
/**
|
|
2236
|
+
* send an unmount event to the micro app or call umd unmount hook
|
|
2237
|
+
* before the sandbox is cleared
|
|
2238
|
+
*/
|
|
2239
|
+
if (this.umdHookUnmount) {
|
|
2240
|
+
try {
|
|
2241
|
+
umdHookUnmountResult = this.umdHookUnmount();
|
|
2242
|
+
}
|
|
2243
|
+
catch (e) {
|
|
2244
|
+
logError('an error occurred in the unmount function \n', this.name, e);
|
|
2245
|
+
}
|
|
2246
|
+
}
|
|
2247
|
+
// dispatch unmount event to micro app
|
|
2248
|
+
dispatchUnmountToMicroApp(this.name);
|
|
2249
|
+
this.handleUnmounted(destroy, umdHookUnmountResult);
|
|
2250
|
+
}
|
|
2251
|
+
/**
|
|
2252
|
+
* handle for promise umdHookUnmount
|
|
2253
|
+
* @param umdHookUnmountResult result of umdHookUnmount
|
|
2254
|
+
*/
|
|
2255
|
+
handleUnmounted(destroy, umdHookUnmountResult) {
|
|
2256
|
+
if (isPromise(umdHookUnmountResult)) {
|
|
2257
|
+
umdHookUnmountResult
|
|
2258
|
+
.then(() => this.actionsForUnmount(destroy))
|
|
2259
|
+
.catch(() => this.actionsForUnmount(destroy));
|
|
2260
|
+
}
|
|
2261
|
+
else {
|
|
2262
|
+
this.actionsForUnmount(destroy);
|
|
2263
|
+
}
|
|
2214
2264
|
}
|
|
2215
|
-
|
|
2216
|
-
|
|
2217
|
-
|
|
2218
|
-
|
|
2219
|
-
|
|
2220
|
-
|
|
2221
|
-
|
|
2222
|
-
|
|
2223
|
-
|
|
2224
|
-
|
|
2225
|
-
|
|
2226
|
-
|
|
2227
|
-
|
|
2228
|
-
|
|
2265
|
+
/**
|
|
2266
|
+
* actions for unmount app
|
|
2267
|
+
* @param destroy completely destroy, delete cache resources
|
|
2268
|
+
*/
|
|
2269
|
+
actionsForUnmount(destroy) {
|
|
2270
|
+
var _a;
|
|
2271
|
+
// dispatch unmount event to base app
|
|
2272
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
2273
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop();
|
|
2274
|
+
if (destroy) {
|
|
2275
|
+
this.actionsForCompletelyDestory();
|
|
2276
|
+
}
|
|
2277
|
+
else if (this.umdMode && this.container.childElementCount) {
|
|
2278
|
+
/**
|
|
2279
|
+
* In umd mode, ui frameworks will no longer create style elements to head in lazy load page when render again, so we should save container to keep these elements
|
|
2280
|
+
*/
|
|
2281
|
+
cloneContainer(this.container, this.source.html, false);
|
|
2282
|
+
}
|
|
2283
|
+
this.container = null;
|
|
2229
2284
|
}
|
|
2230
|
-
|
|
2231
|
-
|
|
2232
|
-
|
|
2233
|
-
|
|
2285
|
+
// actions for completely destroy
|
|
2286
|
+
actionsForCompletelyDestory() {
|
|
2287
|
+
if (!this.useSandbox && this.umdMode) {
|
|
2288
|
+
delete window[this.libraryName];
|
|
2234
2289
|
}
|
|
2235
|
-
|
|
2236
|
-
|
|
2290
|
+
appInstanceMap.delete(this.name);
|
|
2291
|
+
}
|
|
2292
|
+
/**
|
|
2293
|
+
* app rendering error
|
|
2294
|
+
* @param e Error
|
|
2295
|
+
*/
|
|
2296
|
+
onerror(e) {
|
|
2297
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
2298
|
+
}
|
|
2299
|
+
// get app status
|
|
2300
|
+
getAppStatus() {
|
|
2301
|
+
return this.status;
|
|
2302
|
+
}
|
|
2303
|
+
// get umd library, if it not exist, return empty object
|
|
2304
|
+
getUmdLibraryHooks() {
|
|
2305
|
+
var _a, _b;
|
|
2306
|
+
// after execScripts, the app maybe unmounted
|
|
2307
|
+
if (appStatus.UNMOUNT !== this.status) {
|
|
2308
|
+
const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
|
|
2309
|
+
this.libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
2310
|
+
// do not use isObject
|
|
2311
|
+
return typeof global[this.libraryName] === 'object' ? global[this.libraryName] : {};
|
|
2237
2312
|
}
|
|
2238
|
-
|
|
2239
|
-
return bindRawWindowValue;
|
|
2313
|
+
return {};
|
|
2240
2314
|
}
|
|
2241
|
-
|
|
2315
|
+
}
|
|
2316
|
+
// if app not prefetch & not unmount, then app is active
|
|
2317
|
+
function getActiveApps() {
|
|
2318
|
+
const activeApps = [];
|
|
2319
|
+
appInstanceMap.forEach((app, appName) => {
|
|
2320
|
+
if (appStatus.UNMOUNT !== app.getAppStatus() && !app.isPrefetch) {
|
|
2321
|
+
activeApps.push(appName);
|
|
2322
|
+
}
|
|
2323
|
+
});
|
|
2324
|
+
return activeApps;
|
|
2325
|
+
}
|
|
2326
|
+
// get all registered apps
|
|
2327
|
+
function getAllApps() {
|
|
2328
|
+
return Array.from(appInstanceMap.keys());
|
|
2242
2329
|
}
|
|
2243
2330
|
|
|
2244
|
-
//
|
|
2245
|
-
const
|
|
2246
|
-
let hasRewriteDocumentOnClick = false;
|
|
2331
|
+
// Record element and map element
|
|
2332
|
+
const dynamicElementInMicroAppMap = new WeakMap();
|
|
2247
2333
|
/**
|
|
2248
|
-
*
|
|
2334
|
+
* Process the new node and format the style, link and script element
|
|
2335
|
+
* @param parent parent node
|
|
2336
|
+
* @param child new node
|
|
2337
|
+
* @param app app
|
|
2249
2338
|
*/
|
|
2250
|
-
function
|
|
2251
|
-
|
|
2252
|
-
|
|
2253
|
-
|
|
2339
|
+
function handleNewNode(parent, child, app) {
|
|
2340
|
+
if (child instanceof HTMLStyleElement) {
|
|
2341
|
+
if (child.hasAttribute('exclude')) {
|
|
2342
|
+
const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
|
|
2343
|
+
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
2344
|
+
return replaceComment;
|
|
2345
|
+
}
|
|
2346
|
+
else if (app.scopecss && !child.hasAttribute('ignore')) {
|
|
2347
|
+
return scopedCSS(child, app);
|
|
2348
|
+
}
|
|
2349
|
+
return child;
|
|
2254
2350
|
}
|
|
2255
|
-
|
|
2256
|
-
|
|
2257
|
-
|
|
2258
|
-
|
|
2259
|
-
|
|
2260
|
-
|
|
2261
|
-
|
|
2351
|
+
else if (child instanceof HTMLLinkElement) {
|
|
2352
|
+
if (child.hasAttribute('exclude')) {
|
|
2353
|
+
const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
|
|
2354
|
+
dynamicElementInMicroAppMap.set(child, linkReplaceComment);
|
|
2355
|
+
return linkReplaceComment;
|
|
2356
|
+
}
|
|
2357
|
+
else if (child.hasAttribute('ignore')) {
|
|
2358
|
+
return child;
|
|
2359
|
+
}
|
|
2360
|
+
const { url, info, replaceComment } = extractLinkFromHtml(child, parent, app, true);
|
|
2361
|
+
if (url && info) {
|
|
2362
|
+
const replaceStyle = pureCreateElement('style');
|
|
2363
|
+
replaceStyle.__MICRO_APP_LINK_PATH__ = url;
|
|
2364
|
+
foramtDynamicLink(url, info, app, child, replaceStyle);
|
|
2365
|
+
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
2366
|
+
return replaceStyle;
|
|
2367
|
+
}
|
|
2368
|
+
else if (replaceComment) {
|
|
2369
|
+
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
2370
|
+
return replaceComment;
|
|
2371
|
+
}
|
|
2372
|
+
return child;
|
|
2262
2373
|
}
|
|
2263
|
-
|
|
2264
|
-
|
|
2265
|
-
|
|
2266
|
-
|
|
2267
|
-
|
|
2268
|
-
|
|
2269
|
-
|
|
2270
|
-
set(f) {
|
|
2271
|
-
const appName = getCurrentAppName();
|
|
2272
|
-
if (appName) {
|
|
2273
|
-
documentClickListMap.set(appName, f);
|
|
2274
|
-
}
|
|
2275
|
-
else {
|
|
2276
|
-
documentClickListMap.set('base', f);
|
|
2374
|
+
else if (child instanceof HTMLScriptElement) {
|
|
2375
|
+
const { replaceComment, url, info } = extractScriptElement(child, parent, app, true) || {};
|
|
2376
|
+
if (url && info) {
|
|
2377
|
+
if (!info.isExternal) { // inline script
|
|
2378
|
+
const replaceElement = runScript(url, app, info, true);
|
|
2379
|
+
dynamicElementInMicroAppMap.set(child, replaceElement);
|
|
2380
|
+
return replaceElement;
|
|
2277
2381
|
}
|
|
2278
|
-
|
|
2279
|
-
|
|
2280
|
-
|
|
2382
|
+
else { // remote script
|
|
2383
|
+
const replaceElement = runDynamicRemoteScript(url, info, app, child);
|
|
2384
|
+
dynamicElementInMicroAppMap.set(child, replaceElement);
|
|
2385
|
+
return replaceElement;
|
|
2281
2386
|
}
|
|
2282
2387
|
}
|
|
2283
|
-
|
|
2284
|
-
|
|
2285
|
-
|
|
2388
|
+
else if (replaceComment) {
|
|
2389
|
+
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
2390
|
+
return replaceComment;
|
|
2391
|
+
}
|
|
2392
|
+
return child;
|
|
2286
2393
|
}
|
|
2394
|
+
return child;
|
|
2287
2395
|
}
|
|
2288
2396
|
/**
|
|
2289
|
-
*
|
|
2397
|
+
* Handle the elements inserted into head and body, and execute normally in other cases
|
|
2398
|
+
* @param app app
|
|
2399
|
+
* @param method raw method
|
|
2400
|
+
* @param parent parent node
|
|
2401
|
+
* @param targetChild target node
|
|
2402
|
+
* @param passiveChild second param of insertBefore and replaceChild
|
|
2290
2403
|
*/
|
|
2291
|
-
|
|
2292
|
-
|
|
2293
|
-
|
|
2294
|
-
|
|
2295
|
-
|
|
2296
|
-
|
|
2297
|
-
|
|
2298
|
-
var _a;
|
|
2299
|
-
const appName = getCurrentAppName();
|
|
2404
|
+
function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
|
|
2405
|
+
/**
|
|
2406
|
+
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
2407
|
+
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
2408
|
+
*/
|
|
2409
|
+
if (parent === document.head) {
|
|
2410
|
+
const microAppHead = app.container.querySelector('micro-app-head');
|
|
2300
2411
|
/**
|
|
2301
|
-
*
|
|
2412
|
+
* 1. If passivechild exists, it must be insertBefore or replacechild
|
|
2413
|
+
* 2. When removeChild, targetChild may not be in microAppHead or head
|
|
2302
2414
|
*/
|
|
2303
|
-
if (
|
|
2304
|
-
|
|
2305
|
-
|
|
2306
|
-
|
|
2307
|
-
|
|
2308
|
-
|
|
2309
|
-
}
|
|
2310
|
-
else {
|
|
2311
|
-
appListenersMap.set(type, new Set([listener]));
|
|
2312
|
-
}
|
|
2415
|
+
if (passiveChild && !microAppHead.contains(passiveChild)) {
|
|
2416
|
+
return globalEnv.rawAppendChild.call(microAppHead, targetChild);
|
|
2417
|
+
}
|
|
2418
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !microAppHead.contains(targetChild)) {
|
|
2419
|
+
if (parent.contains(targetChild)) {
|
|
2420
|
+
return rawMethod.call(parent, targetChild);
|
|
2313
2421
|
}
|
|
2314
|
-
|
|
2315
|
-
|
|
2422
|
+
return targetChild;
|
|
2423
|
+
}
|
|
2424
|
+
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
2425
|
+
return rawMethod.call(microAppHead, targetChild);
|
|
2426
|
+
}
|
|
2427
|
+
return rawMethod.call(microAppHead, targetChild, passiveChild);
|
|
2428
|
+
}
|
|
2429
|
+
else if (parent === document.body) {
|
|
2430
|
+
const microAppBody = app.container.querySelector('micro-app-body');
|
|
2431
|
+
if (passiveChild && !microAppBody.contains(passiveChild)) {
|
|
2432
|
+
return globalEnv.rawAppendChild.call(microAppBody, targetChild);
|
|
2433
|
+
}
|
|
2434
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !microAppBody.contains(targetChild)) {
|
|
2435
|
+
if (parent.contains(targetChild)) {
|
|
2436
|
+
return rawMethod.call(parent, targetChild);
|
|
2316
2437
|
}
|
|
2317
|
-
|
|
2438
|
+
return targetChild;
|
|
2318
2439
|
}
|
|
2319
|
-
|
|
2320
|
-
|
|
2321
|
-
|
|
2322
|
-
|
|
2323
|
-
|
|
2324
|
-
|
|
2325
|
-
|
|
2326
|
-
|
|
2327
|
-
|
|
2328
|
-
|
|
2440
|
+
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
2441
|
+
return rawMethod.call(microAppBody, targetChild);
|
|
2442
|
+
}
|
|
2443
|
+
return rawMethod.call(microAppBody, targetChild, passiveChild);
|
|
2444
|
+
}
|
|
2445
|
+
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
2446
|
+
return rawMethod.call(parent, targetChild);
|
|
2447
|
+
}
|
|
2448
|
+
return rawMethod.call(parent, targetChild, passiveChild);
|
|
2449
|
+
}
|
|
2450
|
+
// Get the map element
|
|
2451
|
+
function getMappingNode(node) {
|
|
2452
|
+
var _a;
|
|
2453
|
+
return (_a = dynamicElementInMicroAppMap.get(node)) !== null && _a !== void 0 ? _a : node;
|
|
2454
|
+
}
|
|
2455
|
+
/**
|
|
2456
|
+
* method of handle new node
|
|
2457
|
+
* @param parent parent node
|
|
2458
|
+
* @param newChild new node
|
|
2459
|
+
* @param passiveChild passive node
|
|
2460
|
+
* @param rawMethodraw method
|
|
2461
|
+
*/
|
|
2462
|
+
function commonElementHander(parent, newChild, passiveChild, rawMethod) {
|
|
2463
|
+
if (newChild === null || newChild === void 0 ? void 0 : newChild.__MICRO_APP_NAME__) {
|
|
2464
|
+
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
2465
|
+
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
2466
|
+
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(parent, newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
2467
|
+
}
|
|
2468
|
+
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
2469
|
+
return rawMethod.call(parent, newChild);
|
|
2470
|
+
}
|
|
2471
|
+
return rawMethod.call(parent, newChild, passiveChild);
|
|
2472
|
+
}
|
|
2473
|
+
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
2474
|
+
const appName = getCurrentAppName();
|
|
2475
|
+
if (!(newChild instanceof Node) && appName) {
|
|
2476
|
+
const app = appInstanceMap.get(appName);
|
|
2477
|
+
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
2478
|
+
if (parent === document.head) {
|
|
2479
|
+
return rawMethod.call(app.container.querySelector('micro-app-head'), newChild);
|
|
2480
|
+
}
|
|
2481
|
+
else if (parent === document.body) {
|
|
2482
|
+
return rawMethod.call(app.container.querySelector('micro-app-body'), newChild);
|
|
2329
2483
|
}
|
|
2330
2484
|
}
|
|
2331
2485
|
}
|
|
2332
|
-
|
|
2333
|
-
};
|
|
2334
|
-
}
|
|
2335
|
-
// Clear the document event agent
|
|
2336
|
-
function releaseEffectDocumentEvent() {
|
|
2337
|
-
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
2338
|
-
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
2339
|
-
}
|
|
2340
|
-
/**
|
|
2341
|
-
* Format event name
|
|
2342
|
-
* @param type event name
|
|
2343
|
-
* @param microWindow micro window
|
|
2344
|
-
*/
|
|
2345
|
-
function formatEventType(type, microWindow) {
|
|
2346
|
-
if (type === 'unmount') {
|
|
2347
|
-
return `unmount-${microWindow.__MICRO_APP_NAME__}`;
|
|
2486
|
+
return rawMethod.call(parent, newChild);
|
|
2348
2487
|
}
|
|
2349
|
-
return
|
|
2488
|
+
return rawMethod.call(parent, newChild, passiveChild);
|
|
2350
2489
|
}
|
|
2351
2490
|
/**
|
|
2352
|
-
* Rewrite
|
|
2353
|
-
* @param microWindow micro window
|
|
2491
|
+
* Rewrite element prototype method
|
|
2354
2492
|
*/
|
|
2355
|
-
function
|
|
2356
|
-
|
|
2357
|
-
|
|
2358
|
-
|
|
2359
|
-
|
|
2360
|
-
|
|
2361
|
-
|
|
2362
|
-
|
|
2363
|
-
|
|
2364
|
-
|
|
2365
|
-
|
|
2366
|
-
|
|
2493
|
+
function patchElementPrototypeMethods() {
|
|
2494
|
+
patchDocument();
|
|
2495
|
+
// Rewrite setAttribute
|
|
2496
|
+
Element.prototype.setAttribute = function setAttribute(key, value) {
|
|
2497
|
+
if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
|
|
2498
|
+
if (isPlainObject(value)) {
|
|
2499
|
+
const cloneValue = {};
|
|
2500
|
+
Object.getOwnPropertyNames(value).forEach((propertyKey) => {
|
|
2501
|
+
if (!(isString(propertyKey) && propertyKey.indexOf('__') === 0)) {
|
|
2502
|
+
// @ts-ignore
|
|
2503
|
+
cloneValue[propertyKey] = value[propertyKey];
|
|
2504
|
+
}
|
|
2505
|
+
});
|
|
2506
|
+
this.data = cloneValue;
|
|
2507
|
+
}
|
|
2508
|
+
else if (value !== '[object Object]') {
|
|
2509
|
+
logWarn('property data must be an object', this.getAttribute('name'));
|
|
2510
|
+
}
|
|
2511
|
+
}
|
|
2512
|
+
else if ((((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
|
|
2513
|
+
(key === 'href' && /^link$/i.test(this.tagName))) &&
|
|
2514
|
+
this.__MICRO_APP_NAME__ &&
|
|
2515
|
+
appInstanceMap.has(this.__MICRO_APP_NAME__)) {
|
|
2516
|
+
const app = appInstanceMap.get(this.__MICRO_APP_NAME__);
|
|
2517
|
+
globalEnv.rawSetAttribute.call(this, key, CompletionPath(value, app.url));
|
|
2367
2518
|
}
|
|
2368
2519
|
else {
|
|
2369
|
-
|
|
2520
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
2370
2521
|
}
|
|
2371
|
-
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
2372
|
-
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
2373
2522
|
};
|
|
2374
|
-
|
|
2375
|
-
|
|
2376
|
-
|
|
2377
|
-
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
2378
|
-
listenerList.delete(listener);
|
|
2379
|
-
}
|
|
2380
|
-
rawWindowRemoveEventListener.call(rawWindow, type, listener, options);
|
|
2523
|
+
// prototype methods of add element👇
|
|
2524
|
+
Node.prototype.appendChild = function appendChild(newChild) {
|
|
2525
|
+
return commonElementHander(this, newChild, null, globalEnv.rawAppendChild);
|
|
2381
2526
|
};
|
|
2382
|
-
|
|
2383
|
-
|
|
2384
|
-
intervalIdMap.set(intervalId, { handler, timeout, args });
|
|
2385
|
-
return intervalId;
|
|
2527
|
+
Node.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
2528
|
+
return commonElementHander(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
2386
2529
|
};
|
|
2387
|
-
|
|
2388
|
-
|
|
2389
|
-
timeoutIdMap.set(timeoutId, { handler, timeout, args });
|
|
2390
|
-
return timeoutId;
|
|
2530
|
+
Node.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
2531
|
+
return commonElementHander(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
2391
2532
|
};
|
|
2392
|
-
|
|
2393
|
-
|
|
2394
|
-
|
|
2533
|
+
Element.prototype.append = function append(...nodes) {
|
|
2534
|
+
let i = 0;
|
|
2535
|
+
const length = nodes.length;
|
|
2536
|
+
while (i < length) {
|
|
2537
|
+
commonElementHander(this, nodes[i], null, globalEnv.rawAppend);
|
|
2538
|
+
i++;
|
|
2539
|
+
}
|
|
2395
2540
|
};
|
|
2396
|
-
|
|
2397
|
-
|
|
2398
|
-
|
|
2541
|
+
Element.prototype.prepend = function prepend(...nodes) {
|
|
2542
|
+
let i = nodes.length;
|
|
2543
|
+
while (i > 0) {
|
|
2544
|
+
commonElementHander(this, nodes[i - 1], null, globalEnv.rawPrepend);
|
|
2545
|
+
i--;
|
|
2546
|
+
}
|
|
2399
2547
|
};
|
|
2400
|
-
|
|
2401
|
-
|
|
2402
|
-
|
|
2403
|
-
|
|
2404
|
-
|
|
2405
|
-
|
|
2406
|
-
const recordUmdEffect = () => {
|
|
2407
|
-
// record window event
|
|
2408
|
-
eventListenerMap.forEach((listenerList, type) => {
|
|
2409
|
-
if (listenerList.size) {
|
|
2410
|
-
umdWindowListenerMap.set(type, new Set(listenerList));
|
|
2548
|
+
// prototype methods of delete element👇
|
|
2549
|
+
Node.prototype.removeChild = function removeChild(oldChild) {
|
|
2550
|
+
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
2551
|
+
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
2552
|
+
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
2553
|
+
return invokePrototypeMethod(app, globalEnv.rawRemoveChild, this, getMappingNode(oldChild));
|
|
2411
2554
|
}
|
|
2412
|
-
|
|
2413
|
-
// record timers
|
|
2414
|
-
if (intervalIdMap.size) {
|
|
2415
|
-
umdIntervalIdMap = new Map(intervalIdMap);
|
|
2555
|
+
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
2416
2556
|
}
|
|
2417
|
-
|
|
2418
|
-
|
|
2557
|
+
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
2558
|
+
};
|
|
2559
|
+
}
|
|
2560
|
+
/**
|
|
2561
|
+
* Mark the newly created element in the micro application
|
|
2562
|
+
* @param element new element
|
|
2563
|
+
*/
|
|
2564
|
+
function markElement(element) {
|
|
2565
|
+
const appName = getCurrentAppName();
|
|
2566
|
+
appName && (element.__MICRO_APP_NAME__ = appName);
|
|
2567
|
+
return element;
|
|
2568
|
+
}
|
|
2569
|
+
// methods of document
|
|
2570
|
+
function patchDocument() {
|
|
2571
|
+
const rawDocument = globalEnv.rawDocument;
|
|
2572
|
+
// create element 👇
|
|
2573
|
+
Document.prototype.createElement = function createElement(tagName, options) {
|
|
2574
|
+
const element = globalEnv.rawCreateElement.call(this, tagName, options);
|
|
2575
|
+
return markElement(element);
|
|
2576
|
+
};
|
|
2577
|
+
Document.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
|
|
2578
|
+
const element = globalEnv.rawCreateElementNS.call(this, namespaceURI, name, options);
|
|
2579
|
+
return markElement(element);
|
|
2580
|
+
};
|
|
2581
|
+
Document.prototype.createDocumentFragment = function createDocumentFragment() {
|
|
2582
|
+
const element = globalEnv.rawCreateDocumentFragment.call(this);
|
|
2583
|
+
return markElement(element);
|
|
2584
|
+
};
|
|
2585
|
+
// query element👇
|
|
2586
|
+
function querySelector(selectors) {
|
|
2587
|
+
var _a, _b, _c;
|
|
2588
|
+
const appName = getCurrentAppName();
|
|
2589
|
+
if (!appName ||
|
|
2590
|
+
!selectors ||
|
|
2591
|
+
isUniqueElement(selectors) ||
|
|
2592
|
+
// see https://github.com/micro-zoe/micro-app/issues/56
|
|
2593
|
+
rawDocument !== this) {
|
|
2594
|
+
return globalEnv.rawQuerySelector.call(this, selectors);
|
|
2419
2595
|
}
|
|
2420
|
-
|
|
2421
|
-
|
|
2422
|
-
|
|
2423
|
-
|
|
2424
|
-
|
|
2425
|
-
|
|
2426
|
-
|
|
2427
|
-
|
|
2428
|
-
|
|
2429
|
-
|
|
2596
|
+
return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) === null || _b === void 0 ? void 0 : _b.querySelector(selectors)) !== null && _c !== void 0 ? _c : null;
|
|
2597
|
+
}
|
|
2598
|
+
function querySelectorAll(selectors) {
|
|
2599
|
+
var _a, _b, _c;
|
|
2600
|
+
const appName = getCurrentAppName();
|
|
2601
|
+
if (!appName ||
|
|
2602
|
+
!selectors ||
|
|
2603
|
+
isUniqueElement(selectors) ||
|
|
2604
|
+
rawDocument !== this) {
|
|
2605
|
+
return globalEnv.rawQuerySelectorAll.call(this, selectors);
|
|
2606
|
+
}
|
|
2607
|
+
return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container) === null || _b === void 0 ? void 0 : _b.querySelectorAll(selectors)) !== null && _c !== void 0 ? _c : [];
|
|
2608
|
+
}
|
|
2609
|
+
Document.prototype.querySelector = querySelector;
|
|
2610
|
+
Document.prototype.querySelectorAll = querySelectorAll;
|
|
2611
|
+
Document.prototype.getElementById = function getElementById(key) {
|
|
2612
|
+
if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) {
|
|
2613
|
+
return globalEnv.rawGetElementById.call(this, key);
|
|
2614
|
+
}
|
|
2615
|
+
try {
|
|
2616
|
+
return querySelector.call(this, `#${key}`);
|
|
2617
|
+
}
|
|
2618
|
+
catch (_a) {
|
|
2619
|
+
return globalEnv.rawGetElementById.call(this, key);
|
|
2430
2620
|
}
|
|
2431
2621
|
};
|
|
2432
|
-
|
|
2433
|
-
|
|
2434
|
-
|
|
2435
|
-
umdWindowListenerMap.forEach((listenerList, type) => {
|
|
2436
|
-
for (const listener of listenerList) {
|
|
2437
|
-
microWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
2438
|
-
}
|
|
2439
|
-
});
|
|
2440
|
-
// rebuild timer
|
|
2441
|
-
umdIntervalIdMap.forEach((info) => {
|
|
2442
|
-
microWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
2443
|
-
});
|
|
2444
|
-
umdTimeoutIdMap.forEach((info) => {
|
|
2445
|
-
microWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
2446
|
-
});
|
|
2447
|
-
// rebuild onclick event
|
|
2448
|
-
umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
|
|
2449
|
-
// rebuild document event
|
|
2450
|
-
setCurrentAppName(appName);
|
|
2451
|
-
umdDocumentListenerMap.forEach((listenerList, type) => {
|
|
2452
|
-
for (const listener of listenerList) {
|
|
2453
|
-
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
2454
|
-
}
|
|
2455
|
-
});
|
|
2456
|
-
setCurrentAppName(null);
|
|
2457
|
-
};
|
|
2458
|
-
// release all event listener & interval & timeout when unmount app
|
|
2459
|
-
const releaseEffect = () => {
|
|
2460
|
-
// Clear window binding events
|
|
2461
|
-
if (eventListenerMap.size) {
|
|
2462
|
-
eventListenerMap.forEach((listenerList, type) => {
|
|
2463
|
-
for (const listener of listenerList) {
|
|
2464
|
-
rawWindowRemoveEventListener.call(rawWindow, type, listener);
|
|
2465
|
-
}
|
|
2466
|
-
});
|
|
2467
|
-
eventListenerMap.clear();
|
|
2622
|
+
Document.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
2623
|
+
if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) {
|
|
2624
|
+
return globalEnv.rawGetElementsByClassName.call(this, key);
|
|
2468
2625
|
}
|
|
2469
|
-
|
|
2470
|
-
|
|
2471
|
-
intervalIdMap.forEach((_, intervalId) => {
|
|
2472
|
-
rawClearInterval.call(rawWindow, intervalId);
|
|
2473
|
-
});
|
|
2474
|
-
intervalIdMap.clear();
|
|
2626
|
+
try {
|
|
2627
|
+
return querySelectorAll.call(this, `.${key}`);
|
|
2475
2628
|
}
|
|
2476
|
-
|
|
2477
|
-
|
|
2478
|
-
rawClearTimeout.call(rawWindow, timeoutId);
|
|
2479
|
-
});
|
|
2480
|
-
timeoutIdMap.clear();
|
|
2629
|
+
catch (_a) {
|
|
2630
|
+
return globalEnv.rawGetElementsByClassName.call(this, key);
|
|
2481
2631
|
}
|
|
2482
|
-
|
|
2483
|
-
|
|
2484
|
-
|
|
2485
|
-
const
|
|
2486
|
-
if (
|
|
2487
|
-
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2632
|
+
};
|
|
2633
|
+
Document.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
2634
|
+
var _a;
|
|
2635
|
+
const appName = getCurrentAppName();
|
|
2636
|
+
if (!appName ||
|
|
2637
|
+
isUniqueElement(key) ||
|
|
2638
|
+
isInvalidQuerySelectorKey(key) ||
|
|
2639
|
+
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
2640
|
+
return globalEnv.rawGetElementsByTagName.call(this, key);
|
|
2641
|
+
}
|
|
2642
|
+
try {
|
|
2643
|
+
return querySelectorAll.call(this, key);
|
|
2644
|
+
}
|
|
2645
|
+
catch (_b) {
|
|
2646
|
+
return globalEnv.rawGetElementsByTagName.call(this, key);
|
|
2493
2647
|
}
|
|
2494
2648
|
};
|
|
2495
|
-
|
|
2496
|
-
|
|
2497
|
-
|
|
2498
|
-
|
|
2649
|
+
Document.prototype.getElementsByName = function getElementsByName(key) {
|
|
2650
|
+
if (!getCurrentAppName() || isInvalidQuerySelectorKey(key)) {
|
|
2651
|
+
return globalEnv.rawGetElementsByName.call(this, key);
|
|
2652
|
+
}
|
|
2653
|
+
try {
|
|
2654
|
+
return querySelectorAll.call(this, `[name=${key}]`);
|
|
2655
|
+
}
|
|
2656
|
+
catch (_a) {
|
|
2657
|
+
return globalEnv.rawGetElementsByName.call(this, key);
|
|
2658
|
+
}
|
|
2499
2659
|
};
|
|
2500
2660
|
}
|
|
2661
|
+
function releasePatchDocument() {
|
|
2662
|
+
Document.prototype.createElement = globalEnv.rawCreateElement;
|
|
2663
|
+
Document.prototype.createElementNS = globalEnv.rawCreateElementNS;
|
|
2664
|
+
Document.prototype.createDocumentFragment = globalEnv.rawCreateDocumentFragment;
|
|
2665
|
+
Document.prototype.querySelector = globalEnv.rawQuerySelector;
|
|
2666
|
+
Document.prototype.querySelectorAll = globalEnv.rawQuerySelectorAll;
|
|
2667
|
+
Document.prototype.getElementById = globalEnv.rawGetElementById;
|
|
2668
|
+
Document.prototype.getElementsByClassName = globalEnv.rawGetElementsByClassName;
|
|
2669
|
+
Document.prototype.getElementsByTagName = globalEnv.rawGetElementsByTagName;
|
|
2670
|
+
Document.prototype.getElementsByName = globalEnv.rawGetElementsByName;
|
|
2671
|
+
}
|
|
2672
|
+
// release patch
|
|
2673
|
+
function releasePatches() {
|
|
2674
|
+
setCurrentAppName(null);
|
|
2675
|
+
releasePatchDocument();
|
|
2676
|
+
Element.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
2677
|
+
Node.prototype.appendChild = globalEnv.rawAppendChild;
|
|
2678
|
+
Node.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
2679
|
+
Node.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
2680
|
+
Node.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
2681
|
+
Element.prototype.append = globalEnv.rawAppend;
|
|
2682
|
+
Element.prototype.prepend = globalEnv.rawPrepend;
|
|
2683
|
+
}
|
|
2684
|
+
// Set the style of micro-app-head and micro-app-body
|
|
2685
|
+
let hasRejectMicroAppStyle = false;
|
|
2686
|
+
function rejectMicroAppStyle() {
|
|
2687
|
+
if (!hasRejectMicroAppStyle) {
|
|
2688
|
+
hasRejectMicroAppStyle = true;
|
|
2689
|
+
const style = pureCreateElement('style');
|
|
2690
|
+
style.setAttribute('type', 'text/css');
|
|
2691
|
+
style.textContent = `\n${microApp.tagName}, micro-app-body { display: block; } \nmicro-app-head { display: none; }`;
|
|
2692
|
+
globalEnv.rawDocument.head.appendChild(style);
|
|
2693
|
+
}
|
|
2694
|
+
}
|
|
2501
2695
|
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
|
|
2516
|
-
|
|
2517
|
-
|
|
2518
|
-
|
|
2519
|
-
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
2696
|
+
function unmountNestedApp() {
|
|
2697
|
+
replaseUnmountOfNestedApp();
|
|
2698
|
+
appInstanceMap.forEach(app => {
|
|
2699
|
+
// @ts-ignore
|
|
2700
|
+
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
2701
|
+
});
|
|
2702
|
+
!window.__MICRO_APP_UMD_MODE__ && appInstanceMap.clear();
|
|
2703
|
+
if (elementInstanceMap.size) {
|
|
2704
|
+
elementInstanceMap.clear();
|
|
2705
|
+
releasePatches();
|
|
2706
|
+
}
|
|
2707
|
+
}
|
|
2708
|
+
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
2709
|
+
function listenUmountOfNestedApp() {
|
|
2710
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2711
|
+
window.addEventListener('unmount', unmountNestedApp, false);
|
|
2712
|
+
}
|
|
2713
|
+
}
|
|
2714
|
+
// release listener
|
|
2715
|
+
function replaseUnmountOfNestedApp() {
|
|
2716
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2717
|
+
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
2718
|
+
}
|
|
2719
|
+
}
|
|
2720
|
+
|
|
2721
|
+
// record all micro-app elements
|
|
2722
|
+
const elementInstanceMap = new Map();
|
|
2524
2723
|
/**
|
|
2525
|
-
*
|
|
2724
|
+
* define element
|
|
2725
|
+
* @param tagName element name
|
|
2526
2726
|
*/
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
this.inject(this.microWindow, appName, url);
|
|
2554
|
-
// Rewrite global event listener & timeout
|
|
2555
|
-
Object.assign(this, effect(this.microWindow));
|
|
2556
|
-
this.proxyWindow = new Proxy(this.microWindow, {
|
|
2557
|
-
get: (target, key) => {
|
|
2558
|
-
if (key === Symbol.unscopables)
|
|
2559
|
-
return unscopables;
|
|
2560
|
-
if (['window', 'self', 'globalThis'].includes(key)) {
|
|
2561
|
-
return this.proxyWindow;
|
|
2562
|
-
}
|
|
2563
|
-
if (key === 'top' || key === 'parent') {
|
|
2564
|
-
if (rawWindow === rawWindow.parent) { // not in iframe
|
|
2565
|
-
return this.proxyWindow;
|
|
2566
|
-
}
|
|
2567
|
-
return Reflect.get(rawWindow, key); // iframe
|
|
2568
|
-
}
|
|
2569
|
-
if (key === 'hasOwnProperty')
|
|
2570
|
-
return hasOwnProperty;
|
|
2571
|
-
if (key === 'document' || key === 'eval') {
|
|
2572
|
-
if (this.active) {
|
|
2573
|
-
setCurrentAppName(appName);
|
|
2574
|
-
(macro ? macroTask : defer)(() => setCurrentAppName(null));
|
|
2575
|
-
}
|
|
2576
|
-
switch (key) {
|
|
2577
|
-
case 'document':
|
|
2578
|
-
return rawDocument;
|
|
2579
|
-
case 'eval':
|
|
2580
|
-
return eval;
|
|
2581
|
-
}
|
|
2582
|
-
}
|
|
2583
|
-
if (Reflect.has(target, key)) {
|
|
2584
|
-
return Reflect.get(target, key);
|
|
2585
|
-
}
|
|
2586
|
-
if (this.scopeProperties.includes(key) ||
|
|
2587
|
-
(isString(key) && /^__MICRO_APP_/.test(key))) {
|
|
2588
|
-
return Reflect.get(target, key);
|
|
2589
|
-
}
|
|
2590
|
-
const rawValue = Reflect.get(rawWindow, key);
|
|
2591
|
-
return bindFunctionToRawWidow(rawWindow, rawValue);
|
|
2592
|
-
},
|
|
2593
|
-
set: (target, key, value) => {
|
|
2594
|
-
if (this.active) {
|
|
2595
|
-
if (escapeSetterKeyList.includes(key)) {
|
|
2596
|
-
Reflect.set(rawWindow, key, value);
|
|
2597
|
-
}
|
|
2598
|
-
else if (!target.hasOwnProperty(key) &&
|
|
2599
|
-
rawWindow.hasOwnProperty(key) &&
|
|
2600
|
-
!this.scopeProperties.includes(key)) {
|
|
2601
|
-
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
2602
|
-
const { writable, configurable, enumerable } = descriptor;
|
|
2603
|
-
if (writable) {
|
|
2604
|
-
Object.defineProperty(target, key, {
|
|
2605
|
-
configurable,
|
|
2606
|
-
enumerable,
|
|
2607
|
-
writable,
|
|
2608
|
-
value,
|
|
2609
|
-
});
|
|
2610
|
-
this.injectedKeys.add(key);
|
|
2727
|
+
function defineElement(tagName) {
|
|
2728
|
+
class MicroAppElement extends HTMLElement {
|
|
2729
|
+
constructor() {
|
|
2730
|
+
super();
|
|
2731
|
+
this.isWating = false;
|
|
2732
|
+
this.cacheData = null;
|
|
2733
|
+
this.hasConnected = false;
|
|
2734
|
+
this.appName = ''; // app name
|
|
2735
|
+
this.appUrl = ''; // app url
|
|
2736
|
+
this.ssrUrl = ''; // html path in ssr mode
|
|
2737
|
+
this.version = version;
|
|
2738
|
+
/**
|
|
2739
|
+
* handle for change of name an url after element inited
|
|
2740
|
+
*/
|
|
2741
|
+
this.handleAttributeUpdate = () => {
|
|
2742
|
+
var _a;
|
|
2743
|
+
this.isWating = false;
|
|
2744
|
+
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
2745
|
+
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
2746
|
+
if (this.legalAttribute('name', formatAttrName) && this.legalAttribute('url', formatAttrUrl)) {
|
|
2747
|
+
const existApp = appInstanceMap.get(formatAttrName);
|
|
2748
|
+
if (formatAttrName !== this.appName && existApp) {
|
|
2749
|
+
// handling of cached and non-prefetch apps
|
|
2750
|
+
if (appStatus.UNMOUNT !== existApp.getAppStatus() && !existApp.isPrefetch) {
|
|
2751
|
+
this.setAttribute('name', this.appName);
|
|
2752
|
+
return logError(`an app named ${formatAttrName} already exists`, this.appName);
|
|
2611
2753
|
}
|
|
2612
2754
|
}
|
|
2613
|
-
|
|
2614
|
-
|
|
2615
|
-
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
|
|
2635
|
-
|
|
2636
|
-
|
|
2637
|
-
|
|
2638
|
-
|
|
2639
|
-
|
|
2640
|
-
|
|
2641
|
-
|
|
2642
|
-
|
|
2643
|
-
|
|
2644
|
-
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
const from = descriptorTargetMap.get(key);
|
|
2648
|
-
if (from === 'rawWindow') {
|
|
2649
|
-
return Reflect.defineProperty(rawWindow, key, value);
|
|
2650
|
-
}
|
|
2651
|
-
return Reflect.defineProperty(target, key, value);
|
|
2652
|
-
},
|
|
2653
|
-
ownKeys: (target) => {
|
|
2654
|
-
return unique(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)));
|
|
2655
|
-
},
|
|
2656
|
-
deleteProperty: (target, key) => {
|
|
2657
|
-
if (target.hasOwnProperty(key)) {
|
|
2658
|
-
if (this.escapeKeys.has(key)) {
|
|
2659
|
-
Reflect.deleteProperty(rawWindow, key);
|
|
2755
|
+
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
2756
|
+
this.handleUnmount(formatAttrName === this.appName);
|
|
2757
|
+
/**
|
|
2758
|
+
* change ssrUrl in ssr mode
|
|
2759
|
+
* do not add judgment of formatAttrUrl === this.appUrl
|
|
2760
|
+
*/
|
|
2761
|
+
if (this.getDisposeResult('ssr')) {
|
|
2762
|
+
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
2763
|
+
}
|
|
2764
|
+
else if (this.ssrUrl) {
|
|
2765
|
+
this.ssrUrl = '';
|
|
2766
|
+
}
|
|
2767
|
+
this.appName = formatAttrName;
|
|
2768
|
+
this.appUrl = formatAttrUrl;
|
|
2769
|
+
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
2770
|
+
if (formatAttrName !== this.getAttribute('name')) {
|
|
2771
|
+
this.setAttribute('name', this.appName);
|
|
2772
|
+
}
|
|
2773
|
+
/**
|
|
2774
|
+
* when existApp not null:
|
|
2775
|
+
* scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, existApp has been unmounted
|
|
2776
|
+
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
2777
|
+
* scene3: url is different but ssrUrl is equal
|
|
2778
|
+
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
2779
|
+
*/
|
|
2780
|
+
if (existApp &&
|
|
2781
|
+
existApp.url === this.appUrl &&
|
|
2782
|
+
existApp.ssrUrl === this.ssrUrl) {
|
|
2783
|
+
// mount app
|
|
2784
|
+
this.handleAppMount(existApp);
|
|
2785
|
+
}
|
|
2786
|
+
else {
|
|
2787
|
+
this.handleCreateApp();
|
|
2788
|
+
}
|
|
2660
2789
|
}
|
|
2661
|
-
return Reflect.deleteProperty(target, key);
|
|
2662
2790
|
}
|
|
2663
|
-
|
|
2664
|
-
|
|
2665
|
-
|
|
2666
|
-
|
|
2667
|
-
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
this.microWindow.__MICRO_APP_BASE_ROUTE__ = this.microWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
2671
|
-
if (globalEnv.rawWindow._babelPolyfill)
|
|
2672
|
-
globalEnv.rawWindow._babelPolyfill = false;
|
|
2673
|
-
if (++SandBox.activeCount === 1) {
|
|
2674
|
-
effectDocumentEvent();
|
|
2791
|
+
else if (formatAttrName !== this.appName) {
|
|
2792
|
+
this.setAttribute('name', this.appName);
|
|
2793
|
+
}
|
|
2794
|
+
};
|
|
2795
|
+
// cloned node of umd container also trigger constructor, we should skip
|
|
2796
|
+
if (!this.querySelector('micro-app-head')) {
|
|
2797
|
+
this.performWhenFirstCreated();
|
|
2675
2798
|
}
|
|
2676
2799
|
}
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2681
|
-
|
|
2682
|
-
|
|
2683
|
-
|
|
2684
|
-
|
|
2685
|
-
|
|
2686
|
-
|
|
2687
|
-
|
|
2688
|
-
|
|
2689
|
-
|
|
2690
|
-
|
|
2691
|
-
this.
|
|
2692
|
-
if (
|
|
2693
|
-
|
|
2800
|
+
static get observedAttributes() {
|
|
2801
|
+
return ['name', 'url'];
|
|
2802
|
+
}
|
|
2803
|
+
// 👇 Configuration
|
|
2804
|
+
// name: app name
|
|
2805
|
+
// url: html address
|
|
2806
|
+
// shadowDom: use shadowDOM, default is false
|
|
2807
|
+
// destroy: whether delete cache resources when unmount, default is false
|
|
2808
|
+
// inline: whether js runs in inline script mode, default is false
|
|
2809
|
+
// disableScopecss: whether disable css scoped, default is false
|
|
2810
|
+
// disableSandbox: whether disable sandbox, default is false
|
|
2811
|
+
// macro: used to solve the async render problem of vue3, default is false
|
|
2812
|
+
// baseRoute: route prefix, default is ''
|
|
2813
|
+
connectedCallback() {
|
|
2814
|
+
this.hasConnected = true;
|
|
2815
|
+
if (!elementInstanceMap.has(this)) {
|
|
2816
|
+
this.performWhenFirstCreated();
|
|
2694
2817
|
}
|
|
2818
|
+
defer(() => dispatchLifecyclesEvent(this, this.appName, lifeCycles.CREATED));
|
|
2819
|
+
this.initialMount();
|
|
2695
2820
|
}
|
|
2696
|
-
|
|
2697
|
-
|
|
2698
|
-
|
|
2699
|
-
|
|
2700
|
-
|
|
2701
|
-
|
|
2702
|
-
this.recordUmdinjectedValues = new Map();
|
|
2703
|
-
this.injectedKeys.forEach((key) => {
|
|
2704
|
-
this.recordUmdinjectedValues.set(key, Reflect.get(this.microWindow, key));
|
|
2705
|
-
});
|
|
2706
|
-
}
|
|
2707
|
-
// rebuild umd snapshot before remount umd app
|
|
2708
|
-
rebuildUmdSnapshot() {
|
|
2709
|
-
this.recordUmdinjectedValues.forEach((value, key) => {
|
|
2710
|
-
Reflect.set(this.proxyWindow, key, value);
|
|
2711
|
-
});
|
|
2712
|
-
this.rebuildUmdEffect();
|
|
2713
|
-
rebuildDataCenterSnapshot(this.microWindow.microApp);
|
|
2714
|
-
}
|
|
2715
|
-
/**
|
|
2716
|
-
* get scopeProperties and escapeProperties from plugins
|
|
2717
|
-
* @param appName app name
|
|
2718
|
-
*/
|
|
2719
|
-
getScopeProperties(appName) {
|
|
2720
|
-
var _a;
|
|
2721
|
-
if (!isPlainObject(microApp.plugins))
|
|
2722
|
-
return;
|
|
2723
|
-
if (isArray(microApp.plugins.global)) {
|
|
2724
|
-
for (const plugin of microApp.plugins.global) {
|
|
2725
|
-
if (isPlainObject(plugin)) {
|
|
2726
|
-
if (isArray(plugin.scopeProperties)) {
|
|
2727
|
-
this.scopeProperties = this.scopeProperties.concat(plugin.scopeProperties);
|
|
2728
|
-
}
|
|
2729
|
-
if (isArray(plugin.escapeProperties)) {
|
|
2730
|
-
this.escapeProperties = this.escapeProperties.concat(plugin.escapeProperties);
|
|
2731
|
-
}
|
|
2732
|
-
}
|
|
2821
|
+
disconnectedCallback() {
|
|
2822
|
+
this.hasConnected = false;
|
|
2823
|
+
elementInstanceMap.delete(this);
|
|
2824
|
+
this.handleUnmount(this.getDisposeResult('destroy') || this.getDisposeResult('destory'));
|
|
2825
|
+
if (elementInstanceMap.size === 0) {
|
|
2826
|
+
releasePatches();
|
|
2733
2827
|
}
|
|
2734
2828
|
}
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2739
|
-
|
|
2829
|
+
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
2830
|
+
if (this.legalAttribute(attr, newVal) &&
|
|
2831
|
+
this[attr === ObservedAttrName.NAME ? 'appName' : 'appUrl'] !== newVal) {
|
|
2832
|
+
if (attr === ObservedAttrName.URL && !this.appUrl) {
|
|
2833
|
+
newVal = formatAppURL(newVal, this.appName);
|
|
2834
|
+
if (!newVal) {
|
|
2835
|
+
return logError(`Invalid attribute url ${newVal}`, this.appName);
|
|
2740
2836
|
}
|
|
2741
|
-
|
|
2742
|
-
|
|
2837
|
+
this.appUrl = newVal;
|
|
2838
|
+
this.handleInitialNameAndUrl();
|
|
2839
|
+
}
|
|
2840
|
+
else if (attr === ObservedAttrName.NAME && !this.appName) {
|
|
2841
|
+
const formatNewName = formatAppName(newVal);
|
|
2842
|
+
if (!formatNewName) {
|
|
2843
|
+
return logError(`Invalid attribute name ${newVal}`, this.appName);
|
|
2844
|
+
}
|
|
2845
|
+
if (this.cacheData) {
|
|
2846
|
+
microApp.setData(formatNewName, this.cacheData);
|
|
2847
|
+
this.cacheData = null;
|
|
2848
|
+
}
|
|
2849
|
+
this.appName = formatNewName;
|
|
2850
|
+
if (formatNewName !== newVal) {
|
|
2851
|
+
this.setAttribute('name', this.appName);
|
|
2743
2852
|
}
|
|
2853
|
+
this.handleInitialNameAndUrl();
|
|
2854
|
+
}
|
|
2855
|
+
else if (!this.isWating) {
|
|
2856
|
+
this.isWating = true;
|
|
2857
|
+
defer(this.handleAttributeUpdate);
|
|
2744
2858
|
}
|
|
2745
2859
|
}
|
|
2746
2860
|
}
|
|
2747
|
-
|
|
2748
|
-
|
|
2749
|
-
|
|
2750
|
-
* @param microWindow micro window
|
|
2751
|
-
* @param appName app name
|
|
2752
|
-
* @param url app url
|
|
2753
|
-
*/
|
|
2754
|
-
inject(microWindow, appName, url) {
|
|
2755
|
-
microWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
2756
|
-
microWindow.__MICRO_APP_NAME__ = appName;
|
|
2757
|
-
microWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
2758
|
-
microWindow.microApp = new EventCenterForMicroApp(appName);
|
|
2759
|
-
microWindow.rawWindow = globalEnv.rawWindow;
|
|
2760
|
-
microWindow.rawDocument = globalEnv.rawDocument;
|
|
2761
|
-
microWindow.removeDomScope = removeDomScope;
|
|
2762
|
-
}
|
|
2763
|
-
}
|
|
2764
|
-
SandBox.activeCount = 0; // number of active sandbox
|
|
2765
|
-
|
|
2766
|
-
// micro app instances
|
|
2767
|
-
const appInstanceMap = new Map();
|
|
2768
|
-
class CreateApp {
|
|
2769
|
-
constructor({ name, url, container, inline, scopecss, useSandbox, macro, baseroute }) {
|
|
2770
|
-
this.status = appStatus.NOT_LOADED;
|
|
2771
|
-
this.loadSourceLevel = 0;
|
|
2772
|
-
this.umdHookMount = null;
|
|
2773
|
-
this.umdHookUnmount = null;
|
|
2774
|
-
this.libraryName = null;
|
|
2775
|
-
this.umdMode = false;
|
|
2776
|
-
this.isPrefetch = false;
|
|
2777
|
-
this.container = null;
|
|
2778
|
-
this.macro = false;
|
|
2779
|
-
this.baseroute = '';
|
|
2780
|
-
this.sandBox = null;
|
|
2781
|
-
this.container = container !== null && container !== void 0 ? container : null;
|
|
2782
|
-
this.inline = inline !== null && inline !== void 0 ? inline : false;
|
|
2783
|
-
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : '';
|
|
2784
|
-
// optional during init👆
|
|
2785
|
-
this.name = name;
|
|
2786
|
-
this.url = url;
|
|
2787
|
-
this.useSandbox = useSandbox;
|
|
2788
|
-
this.scopecss = this.useSandbox && scopecss;
|
|
2789
|
-
this.macro = macro !== null && macro !== void 0 ? macro : false;
|
|
2790
|
-
this.source = {
|
|
2791
|
-
links: new Map(),
|
|
2792
|
-
scripts: new Map(),
|
|
2793
|
-
};
|
|
2794
|
-
this.loadSourceCode();
|
|
2795
|
-
if (this.useSandbox) {
|
|
2796
|
-
this.sandBox = new SandBox(name, url, this.macro);
|
|
2797
|
-
}
|
|
2798
|
-
}
|
|
2799
|
-
// Load resources
|
|
2800
|
-
loadSourceCode() {
|
|
2801
|
-
this.status = appStatus.LOADING_SOURCE_CODE;
|
|
2802
|
-
extractHtml(this);
|
|
2803
|
-
}
|
|
2804
|
-
/**
|
|
2805
|
-
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
2806
|
-
*/
|
|
2807
|
-
onLoad(html) {
|
|
2808
|
-
if (++this.loadSourceLevel === 2) {
|
|
2809
|
-
this.source.html = html;
|
|
2810
|
-
if (this.isPrefetch || appStatus.UNMOUNT === this.status)
|
|
2811
|
-
return;
|
|
2812
|
-
this.status = appStatus.LOAD_SOURCE_FINISHED;
|
|
2813
|
-
this.mount();
|
|
2814
|
-
}
|
|
2815
|
-
}
|
|
2816
|
-
/**
|
|
2817
|
-
* Error loading HTML
|
|
2818
|
-
* @param e Error
|
|
2819
|
-
*/
|
|
2820
|
-
onLoadError(e) {
|
|
2821
|
-
this.loadSourceLevel = -1;
|
|
2822
|
-
if (appStatus.UNMOUNT !== this.status) {
|
|
2823
|
-
this.onerror(e);
|
|
2824
|
-
this.status = appStatus.LOAD_SOURCE_ERROR;
|
|
2825
|
-
}
|
|
2826
|
-
}
|
|
2827
|
-
/**
|
|
2828
|
-
* mount app
|
|
2829
|
-
* @param container app container
|
|
2830
|
-
* @param inline js runs in inline mode
|
|
2831
|
-
* @param baseroute route prefix, default is ''
|
|
2832
|
-
*/
|
|
2833
|
-
mount(container, inline, baseroute) {
|
|
2834
|
-
var _a, _b, _c;
|
|
2835
|
-
if (isBoolean(inline) && inline !== this.inline) {
|
|
2836
|
-
this.inline = inline;
|
|
2861
|
+
// handle for connectedCallback run before attributeChangedCallback
|
|
2862
|
+
handleInitialNameAndUrl() {
|
|
2863
|
+
this.hasConnected && this.initialMount();
|
|
2837
2864
|
}
|
|
2838
|
-
|
|
2839
|
-
|
|
2840
|
-
|
|
2841
|
-
|
|
2842
|
-
|
|
2865
|
+
// Perform global initialization when the element count is 1
|
|
2866
|
+
performWhenFirstCreated() {
|
|
2867
|
+
if (elementInstanceMap.set(this, true).size === 1) {
|
|
2868
|
+
patchElementPrototypeMethods();
|
|
2869
|
+
rejectMicroAppStyle();
|
|
2870
|
+
replaseUnmountOfNestedApp();
|
|
2871
|
+
listenUmountOfNestedApp();
|
|
2872
|
+
}
|
|
2843
2873
|
}
|
|
2844
|
-
|
|
2845
|
-
|
|
2846
|
-
|
|
2847
|
-
(
|
|
2848
|
-
|
|
2849
|
-
|
|
2850
|
-
|
|
2851
|
-
|
|
2852
|
-
|
|
2853
|
-
|
|
2854
|
-
|
|
2855
|
-
|
|
2856
|
-
|
|
2857
|
-
|
|
2858
|
-
|
|
2859
|
-
|
|
2860
|
-
|
|
2861
|
-
|
|
2862
|
-
|
|
2863
|
-
|
|
2864
|
-
|
|
2865
|
-
|
|
2866
|
-
logError('an error occurred in the mount function \n', this.name, e);
|
|
2867
|
-
}
|
|
2868
|
-
}
|
|
2874
|
+
/**
|
|
2875
|
+
* first mount of this app
|
|
2876
|
+
*/
|
|
2877
|
+
initialMount() {
|
|
2878
|
+
if (!this.appName || !this.appUrl)
|
|
2879
|
+
return;
|
|
2880
|
+
if (this.getDisposeResult('shadowDOM') && !this.shadowRoot && isFunction(this.attachShadow)) {
|
|
2881
|
+
this.attachShadow({ mode: 'open' });
|
|
2882
|
+
}
|
|
2883
|
+
if (this.getDisposeResult('ssr')) {
|
|
2884
|
+
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, this.appUrl);
|
|
2885
|
+
}
|
|
2886
|
+
else if (this.ssrUrl) {
|
|
2887
|
+
this.ssrUrl = '';
|
|
2888
|
+
}
|
|
2889
|
+
const app = appInstanceMap.get(this.appName);
|
|
2890
|
+
if (app) {
|
|
2891
|
+
const existAppUrl = app.ssrUrl || app.url;
|
|
2892
|
+
const activeAppUrl = this.ssrUrl || this.appUrl;
|
|
2893
|
+
if (existAppUrl === activeAppUrl && (app.isPrefetch ||
|
|
2894
|
+
app.getAppStatus() === appStatus.UNMOUNT)) {
|
|
2895
|
+
this.handleAppMount(app);
|
|
2869
2896
|
}
|
|
2870
|
-
if (
|
|
2871
|
-
|
|
2872
|
-
|
|
2897
|
+
else if (app.isPrefetch || app.getAppStatus() === appStatus.UNMOUNT) {
|
|
2898
|
+
/**
|
|
2899
|
+
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
2900
|
+
*/
|
|
2901
|
+
logWarn(`the ${app.isPrefetch ? 'prefetch' : 'unmounted'} app with url: ${existAppUrl} is replaced by a new app`, this.appName);
|
|
2902
|
+
this.handleCreateApp();
|
|
2903
|
+
}
|
|
2904
|
+
else {
|
|
2905
|
+
logError(`an app named ${this.appName} already exists`, this.appName);
|
|
2873
2906
|
}
|
|
2874
|
-
});
|
|
2875
|
-
}
|
|
2876
|
-
else {
|
|
2877
|
-
(_c = this.sandBox) === null || _c === void 0 ? void 0 : _c.rebuildUmdSnapshot();
|
|
2878
|
-
try {
|
|
2879
|
-
umdHookMountResult = this.umdHookMount();
|
|
2880
2907
|
}
|
|
2881
|
-
|
|
2882
|
-
|
|
2908
|
+
else {
|
|
2909
|
+
this.handleCreateApp();
|
|
2883
2910
|
}
|
|
2884
|
-
this.handleMounted(umdHookMountResult);
|
|
2885
|
-
}
|
|
2886
|
-
}
|
|
2887
|
-
/**
|
|
2888
|
-
* handle for promise umdHookMount
|
|
2889
|
-
* @param umdHookMountResult result of umdHookMount
|
|
2890
|
-
*/
|
|
2891
|
-
handleMounted(umdHookMountResult) {
|
|
2892
|
-
if (isPromise(umdHookMountResult)) {
|
|
2893
|
-
umdHookMountResult
|
|
2894
|
-
.then(() => this.dispatchMountedEvent())
|
|
2895
|
-
.catch((e) => this.onerror(e));
|
|
2896
2911
|
}
|
|
2897
|
-
|
|
2898
|
-
|
|
2912
|
+
/**
|
|
2913
|
+
* judge the attribute is legal
|
|
2914
|
+
* @param name attribute name
|
|
2915
|
+
* @param val attribute value
|
|
2916
|
+
*/
|
|
2917
|
+
legalAttribute(name, val) {
|
|
2918
|
+
if (!isString(val) || !val) {
|
|
2919
|
+
logError(`unexpected attribute ${name}, please check again`, this.appName);
|
|
2920
|
+
return false;
|
|
2921
|
+
}
|
|
2922
|
+
return true;
|
|
2899
2923
|
}
|
|
2900
|
-
|
|
2901
|
-
|
|
2902
|
-
|
|
2903
|
-
|
|
2904
|
-
|
|
2905
|
-
|
|
2906
|
-
|
|
2907
|
-
|
|
2908
|
-
|
|
2909
|
-
|
|
2910
|
-
|
|
2911
|
-
|
|
2912
|
-
|
|
2924
|
+
/**
|
|
2925
|
+
* mount app
|
|
2926
|
+
* some serious note before mount:
|
|
2927
|
+
* 1. is prefetch ?
|
|
2928
|
+
* 2. is remount in another container ?
|
|
2929
|
+
* 3. is remount with change properties of the container ?
|
|
2930
|
+
*/
|
|
2931
|
+
handleAppMount(app) {
|
|
2932
|
+
app.isPrefetch = false;
|
|
2933
|
+
defer(() => {
|
|
2934
|
+
var _a;
|
|
2935
|
+
return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible());
|
|
2936
|
+
});
|
|
2913
2937
|
}
|
|
2914
|
-
|
|
2915
|
-
|
|
2916
|
-
|
|
2917
|
-
|
|
2918
|
-
|
|
2919
|
-
|
|
2920
|
-
|
|
2921
|
-
|
|
2938
|
+
// create app instance
|
|
2939
|
+
handleCreateApp() {
|
|
2940
|
+
var _a;
|
|
2941
|
+
/**
|
|
2942
|
+
* actions for destory old app
|
|
2943
|
+
* fix of unmounted umd app with disableSandbox
|
|
2944
|
+
*/
|
|
2945
|
+
if (appInstanceMap.has(this.appName)) {
|
|
2946
|
+
appInstanceMap.get(this.appName).actionsForCompletelyDestory();
|
|
2947
|
+
}
|
|
2948
|
+
const instance = new CreateApp({
|
|
2949
|
+
name: this.appName,
|
|
2950
|
+
url: this.appUrl,
|
|
2951
|
+
ssrUrl: this.ssrUrl,
|
|
2952
|
+
container: (_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this,
|
|
2953
|
+
inline: this.getDisposeResult('inline'),
|
|
2954
|
+
scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')),
|
|
2955
|
+
useSandbox: !this.getDisposeResult('disableSandbox'),
|
|
2956
|
+
macro: this.getDisposeResult('macro'),
|
|
2957
|
+
baseroute: this.getBaseRouteCompatible(),
|
|
2958
|
+
});
|
|
2959
|
+
appInstanceMap.set(this.appName, instance);
|
|
2922
2960
|
}
|
|
2923
|
-
this.status = appStatus.UNMOUNT;
|
|
2924
|
-
// result of unmount function
|
|
2925
|
-
let umdHookUnmountResult;
|
|
2926
2961
|
/**
|
|
2927
|
-
*
|
|
2928
|
-
*
|
|
2962
|
+
* unmount app
|
|
2963
|
+
* @param destroy delete cache resources when unmount
|
|
2929
2964
|
*/
|
|
2930
|
-
|
|
2931
|
-
|
|
2932
|
-
|
|
2933
|
-
|
|
2934
|
-
catch (e) {
|
|
2935
|
-
logError('an error occurred in the unmount function \n', this.name, e);
|
|
2936
|
-
}
|
|
2965
|
+
handleUnmount(destroy) {
|
|
2966
|
+
const app = appInstanceMap.get(this.appName);
|
|
2967
|
+
if (app && appStatus.UNMOUNT !== app.getAppStatus())
|
|
2968
|
+
app.unmount(destroy);
|
|
2937
2969
|
}
|
|
2938
|
-
|
|
2939
|
-
|
|
2940
|
-
|
|
2941
|
-
|
|
2942
|
-
|
|
2943
|
-
|
|
2944
|
-
|
|
2945
|
-
|
|
2946
|
-
handleUnmounted(destroy, umdHookUnmountResult) {
|
|
2947
|
-
if (isPromise(umdHookUnmountResult)) {
|
|
2948
|
-
umdHookUnmountResult
|
|
2949
|
-
.then(() => this.actionsForUnmount(destroy))
|
|
2950
|
-
.catch(() => this.actionsForUnmount(destroy));
|
|
2970
|
+
/**
|
|
2971
|
+
* Get configuration
|
|
2972
|
+
* Global setting is lowest priority
|
|
2973
|
+
* @param name Configuration item name
|
|
2974
|
+
*/
|
|
2975
|
+
getDisposeResult(name) {
|
|
2976
|
+
// @ts-ignore
|
|
2977
|
+
return (this.hasAttribute(name) || microApp[name]) && this.getAttribute(name) !== 'false';
|
|
2951
2978
|
}
|
|
2952
|
-
|
|
2953
|
-
|
|
2979
|
+
/**
|
|
2980
|
+
* 2021-09-08
|
|
2981
|
+
* get baseRoute
|
|
2982
|
+
* getAttribute('baseurl') is compatible writing of versions below 0.3.1
|
|
2983
|
+
*/
|
|
2984
|
+
getBaseRouteCompatible() {
|
|
2985
|
+
var _a, _b;
|
|
2986
|
+
return (_b = (_a = this.getAttribute('baseroute')) !== null && _a !== void 0 ? _a : this.getAttribute('baseurl')) !== null && _b !== void 0 ? _b : '';
|
|
2954
2987
|
}
|
|
2955
|
-
|
|
2956
|
-
|
|
2957
|
-
|
|
2958
|
-
|
|
2959
|
-
|
|
2960
|
-
|
|
2961
|
-
|
|
2962
|
-
|
|
2963
|
-
|
|
2964
|
-
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop();
|
|
2965
|
-
// actions for completely destroy
|
|
2966
|
-
if (destroy) {
|
|
2967
|
-
if (!this.useSandbox && this.umdMode) {
|
|
2968
|
-
delete window[this.libraryName];
|
|
2988
|
+
/**
|
|
2989
|
+
* Data from the base application
|
|
2990
|
+
*/
|
|
2991
|
+
set data(value) {
|
|
2992
|
+
if (this.appName) {
|
|
2993
|
+
microApp.setData(this.appName, value);
|
|
2994
|
+
}
|
|
2995
|
+
else {
|
|
2996
|
+
this.cacheData = value;
|
|
2969
2997
|
}
|
|
2970
|
-
appInstanceMap.delete(this.name);
|
|
2971
|
-
}
|
|
2972
|
-
else if (this.umdMode && this.container.childElementCount) {
|
|
2973
|
-
/**
|
|
2974
|
-
* In umd mode, ui frameworks will no longer create style elements to head in lazy load page when render again, so we should save container to keep these elements
|
|
2975
|
-
*/
|
|
2976
|
-
cloneNode(this.container, this.source.html, false);
|
|
2977
2998
|
}
|
|
2978
|
-
|
|
2979
|
-
|
|
2980
|
-
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
|
|
2984
|
-
|
|
2985
|
-
|
|
2986
|
-
|
|
2987
|
-
|
|
2988
|
-
|
|
2989
|
-
return this.status;
|
|
2990
|
-
}
|
|
2991
|
-
// get umd library, if it not exist, return empty object
|
|
2992
|
-
getUmdLibraryHooks() {
|
|
2993
|
-
var _a, _b;
|
|
2994
|
-
// after execScripts, the app maybe unmounted
|
|
2995
|
-
if (appStatus.UNMOUNT !== this.status) {
|
|
2996
|
-
const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
|
|
2997
|
-
this.libraryName = (this.container instanceof ShadowRoot ? this.container.host : this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
2998
|
-
// do not use isObject
|
|
2999
|
-
return typeof global[this.libraryName] === 'object' ? global[this.libraryName] : {};
|
|
2999
|
+
/**
|
|
3000
|
+
* get data only used in jsx-custom-event once
|
|
3001
|
+
*/
|
|
3002
|
+
get data() {
|
|
3003
|
+
if (this.appName) {
|
|
3004
|
+
return microApp.getData(this.appName, true);
|
|
3005
|
+
}
|
|
3006
|
+
else if (this.cacheData) {
|
|
3007
|
+
return this.cacheData;
|
|
3008
|
+
}
|
|
3009
|
+
return null;
|
|
3000
3010
|
}
|
|
3001
|
-
return {};
|
|
3002
3011
|
}
|
|
3012
|
+
window.customElements.define(tagName, MicroAppElement);
|
|
3003
3013
|
}
|
|
3004
3014
|
|
|
3005
3015
|
function filterPreFetchTarget(apps) {
|
|
3006
3016
|
const validApps = [];
|
|
3007
3017
|
if (isArray(apps)) {
|
|
3008
3018
|
apps.forEach((item) => {
|
|
3009
|
-
|
|
3010
|
-
|
|
3011
|
-
|
|
3012
|
-
item.url &&
|
|
3013
|
-
|
|
3014
|
-
|
|
3019
|
+
if (isPlainObject(item)) {
|
|
3020
|
+
item.name = formatAppName(item.name);
|
|
3021
|
+
item.url = formatAppURL(item.url, item.name);
|
|
3022
|
+
if (item.name && item.url && !appInstanceMap.has(item.name)) {
|
|
3023
|
+
validApps.push(item);
|
|
3024
|
+
}
|
|
3015
3025
|
}
|
|
3016
3026
|
});
|
|
3017
3027
|
}
|
|
@@ -3038,8 +3048,7 @@ function preFetch(apps) {
|
|
|
3038
3048
|
return logError('preFetch is only supported in browser environment');
|
|
3039
3049
|
}
|
|
3040
3050
|
requestIdleCallback(() => {
|
|
3041
|
-
|
|
3042
|
-
apps = apps();
|
|
3051
|
+
isFunction(apps) && (apps = apps());
|
|
3043
3052
|
filterPreFetchTarget(apps).forEach((item) => {
|
|
3044
3053
|
var _a, _b, _c;
|
|
3045
3054
|
const app = new CreateApp({
|
|
@@ -3097,6 +3106,67 @@ function getGlobalAssets(assets) {
|
|
|
3097
3106
|
}
|
|
3098
3107
|
}
|
|
3099
3108
|
|
|
3109
|
+
class MicroApp extends EventCenterForBaseApp {
|
|
3110
|
+
constructor() {
|
|
3111
|
+
super(...arguments);
|
|
3112
|
+
this.tagName = 'micro-app';
|
|
3113
|
+
this.preFetch = preFetch;
|
|
3114
|
+
}
|
|
3115
|
+
start(options) {
|
|
3116
|
+
if (!isBrowser || !window.customElements) {
|
|
3117
|
+
return logError('micro-app is not supported in this environment');
|
|
3118
|
+
}
|
|
3119
|
+
if (options === null || options === void 0 ? void 0 : options.tagName) {
|
|
3120
|
+
if (/^micro-app(-\S+)?/.test(options.tagName)) {
|
|
3121
|
+
this.tagName = options.tagName;
|
|
3122
|
+
}
|
|
3123
|
+
else {
|
|
3124
|
+
return logError(`${options.tagName} is invalid tagName`);
|
|
3125
|
+
}
|
|
3126
|
+
}
|
|
3127
|
+
if (window.customElements.get(this.tagName)) {
|
|
3128
|
+
return logWarn(`element ${this.tagName} is already defined`);
|
|
3129
|
+
}
|
|
3130
|
+
initGlobalEnv();
|
|
3131
|
+
if (options && isPlainObject(options)) {
|
|
3132
|
+
this.shadowDOM = options.shadowDOM;
|
|
3133
|
+
this.destroy = options.destroy;
|
|
3134
|
+
/**
|
|
3135
|
+
* compatible with versions below 0.4.2 of destroy
|
|
3136
|
+
* do not merge with the previous line
|
|
3137
|
+
*/
|
|
3138
|
+
// @ts-ignore
|
|
3139
|
+
this.destory = options.destory;
|
|
3140
|
+
this.inline = options.inline;
|
|
3141
|
+
this.disableScopecss = options.disableScopecss;
|
|
3142
|
+
this.disableSandbox = options.disableSandbox;
|
|
3143
|
+
this.macro = options.macro;
|
|
3144
|
+
isFunction(options.fetch) && (this.fetch = options.fetch);
|
|
3145
|
+
isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);
|
|
3146
|
+
// load app assets when browser is idle
|
|
3147
|
+
options.preFetchApps && preFetch(options.preFetchApps);
|
|
3148
|
+
// load global assets when browser is idle
|
|
3149
|
+
options.globalAssets && getGlobalAssets(options.globalAssets);
|
|
3150
|
+
if (isPlainObject(options.plugins)) {
|
|
3151
|
+
const modules = options.plugins.modules;
|
|
3152
|
+
if (isPlainObject(modules)) {
|
|
3153
|
+
for (const appName in modules) {
|
|
3154
|
+
const formattedAppName = formatAppName(appName);
|
|
3155
|
+
if (formattedAppName && appName !== formattedAppName) {
|
|
3156
|
+
modules[formattedAppName] = modules[appName];
|
|
3157
|
+
delete modules[appName];
|
|
3158
|
+
}
|
|
3159
|
+
}
|
|
3160
|
+
}
|
|
3161
|
+
this.plugins = options.plugins;
|
|
3162
|
+
}
|
|
3163
|
+
}
|
|
3164
|
+
// define customElement after init
|
|
3165
|
+
defineElement(this.tagName);
|
|
3166
|
+
}
|
|
3167
|
+
}
|
|
3168
|
+
var microApp = new MicroApp();
|
|
3169
|
+
|
|
3100
3170
|
export default microApp;
|
|
3101
|
-
export { preFetch, pureCreateElement, removeDomScope,
|
|
3171
|
+
export { EventCenterForMicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, version };
|
|
3102
3172
|
//# sourceMappingURL=index.esm.js.map
|