@micro-zoe/micro-app 1.0.0-rc.4 → 1.0.0-rc.6
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/lib/index.d.ts +33 -20
- package/lib/index.esm.js +1309 -816
- 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 +2 -1
- package/typings/global.d.ts +29 -24
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-rc.
|
|
1
|
+
const version = '1.0.0-rc.6';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -56,7 +56,8 @@ function isPromise(target) {
|
|
|
56
56
|
}
|
|
57
57
|
// is bind function
|
|
58
58
|
function isBoundFunction(target) {
|
|
59
|
-
|
|
59
|
+
var _a;
|
|
60
|
+
return isFunction(target) && ((_a = target.name) === null || _a === void 0 ? void 0 : _a.indexOf('bound ')) === 0 && !target.hasOwnProperty('prototype');
|
|
60
61
|
}
|
|
61
62
|
// is constructor function
|
|
62
63
|
function isConstructor(target) {
|
|
@@ -109,13 +110,27 @@ function isImageElement(target) {
|
|
|
109
110
|
function isBaseElement(target) {
|
|
110
111
|
return toTypeString(target) === '[object HTMLBaseElement]';
|
|
111
112
|
}
|
|
113
|
+
function isDocumentFragment(target) {
|
|
114
|
+
return toTypeString(target) === '[object DocumentFragment]';
|
|
115
|
+
}
|
|
112
116
|
function isMicroAppBody(target) {
|
|
113
117
|
return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-BODY';
|
|
114
118
|
}
|
|
119
|
+
function isMicroAppHead(target) {
|
|
120
|
+
return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-HEAD';
|
|
121
|
+
}
|
|
115
122
|
// is ProxyDocument
|
|
116
123
|
function isProxyDocument(target) {
|
|
117
124
|
return toTypeString(target) === '[object ProxyDocument]';
|
|
118
125
|
}
|
|
126
|
+
function isTargetExtension(path, suffix) {
|
|
127
|
+
try {
|
|
128
|
+
return createURL(path).pathname.split('.').pop() === suffix;
|
|
129
|
+
}
|
|
130
|
+
catch (_a) {
|
|
131
|
+
return false;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
119
134
|
function includes(target, searchElement, fromIndex) {
|
|
120
135
|
if (target == null) {
|
|
121
136
|
throw new TypeError('includes target is null or undefined');
|
|
@@ -172,6 +187,14 @@ function logWarn(msg, appName = null, ...rest) {
|
|
|
172
187
|
function defer(fn, ...args) {
|
|
173
188
|
Promise.resolve().then(fn.bind(null, ...args));
|
|
174
189
|
}
|
|
190
|
+
/**
|
|
191
|
+
* async execution with macro task
|
|
192
|
+
* @param fn callback
|
|
193
|
+
* @param args params
|
|
194
|
+
*/
|
|
195
|
+
function macro(fn, delay = 0, ...args) {
|
|
196
|
+
setTimeout(fn.bind(null, ...args), delay);
|
|
197
|
+
}
|
|
175
198
|
/**
|
|
176
199
|
* create URL as MicroLocation
|
|
177
200
|
*/
|
|
@@ -200,12 +223,12 @@ function formatAppURL(url, appName = null) {
|
|
|
200
223
|
return '';
|
|
201
224
|
try {
|
|
202
225
|
const { origin, pathname, search } = createURL(addProtocol(url), (window.rawWindow || window).location.href);
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
const fullPath = `${origin}${pathname}
|
|
208
|
-
return /^https?:\/\//.test(fullPath) ?
|
|
226
|
+
/**
|
|
227
|
+
* keep the original url unchanged, such as .html .node .php .net .etc, search, except hash
|
|
228
|
+
* BUG FIX: Never using '/' to complete url, refer to https://github.com/micro-zoe/micro-app/issues/1147
|
|
229
|
+
*/
|
|
230
|
+
const fullPath = `${origin}${pathname}${search}`;
|
|
231
|
+
return /^https?:\/\//.test(fullPath) ? fullPath : '';
|
|
209
232
|
}
|
|
210
233
|
catch (e) {
|
|
211
234
|
logError(e, appName);
|
|
@@ -228,14 +251,15 @@ function formatAppName(name) {
|
|
|
228
251
|
return name.replace(/(^\d+)|([^\w\d-_])/gi, '');
|
|
229
252
|
}
|
|
230
253
|
/**
|
|
231
|
-
* Get valid address, such as
|
|
254
|
+
* Get valid address, such as
|
|
255
|
+
* 1. https://domain/xx/xx.html to https://domain/xx/
|
|
256
|
+
* 2. https://domain/xx to https://domain/xx/
|
|
232
257
|
* @param url app.url
|
|
233
258
|
*/
|
|
234
259
|
function getEffectivePath(url) {
|
|
235
260
|
const { origin, pathname } = createURL(url);
|
|
236
261
|
if (/\.(\w+)$/.test(pathname)) {
|
|
237
|
-
const
|
|
238
|
-
const pathArr = fullPath.split('/');
|
|
262
|
+
const pathArr = `${origin}${pathname}`.split('/');
|
|
239
263
|
pathArr.pop();
|
|
240
264
|
return pathArr.join('/') + '/';
|
|
241
265
|
}
|
|
@@ -334,33 +358,65 @@ function promiseRequestIdle(callback) {
|
|
|
334
358
|
/**
|
|
335
359
|
* Record the currently running app.name
|
|
336
360
|
*/
|
|
337
|
-
let
|
|
361
|
+
let currentAppName = null;
|
|
338
362
|
function setCurrentAppName(appName) {
|
|
339
|
-
|
|
363
|
+
currentAppName = appName;
|
|
340
364
|
}
|
|
341
365
|
// get the currently running app.name
|
|
342
366
|
function getCurrentAppName() {
|
|
343
|
-
return
|
|
367
|
+
return currentAppName;
|
|
344
368
|
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
setCurrentAppName(null);
|
|
349
|
-
if (force && !preventSetAppName) {
|
|
350
|
-
preventSetAppName = true;
|
|
369
|
+
function throttleDeferForSetAppName(appName) {
|
|
370
|
+
if (currentAppName !== appName && !getPreventSetState()) {
|
|
371
|
+
setCurrentAppName(appName);
|
|
351
372
|
defer(() => {
|
|
352
|
-
|
|
373
|
+
setCurrentAppName(null);
|
|
353
374
|
});
|
|
354
375
|
}
|
|
355
376
|
}
|
|
356
|
-
|
|
357
|
-
|
|
358
|
-
|
|
377
|
+
// only for iframe document.body(head).querySelector(querySelectorAll)
|
|
378
|
+
let iframeCurrentAppName = null;
|
|
379
|
+
function setIframeCurrentAppName(appName) {
|
|
380
|
+
iframeCurrentAppName = appName;
|
|
381
|
+
}
|
|
382
|
+
function getIframeCurrentAppName() {
|
|
383
|
+
return iframeCurrentAppName;
|
|
384
|
+
}
|
|
385
|
+
function throttleDeferForIframeAppName(appName) {
|
|
386
|
+
if (iframeCurrentAppName !== appName && !getPreventSetState()) {
|
|
387
|
+
setIframeCurrentAppName(appName);
|
|
359
388
|
defer(() => {
|
|
360
|
-
|
|
389
|
+
setIframeCurrentAppName(null);
|
|
361
390
|
});
|
|
362
391
|
}
|
|
363
392
|
}
|
|
393
|
+
// prevent set app name
|
|
394
|
+
let preventSetState = false;
|
|
395
|
+
function getPreventSetState() {
|
|
396
|
+
return preventSetState;
|
|
397
|
+
}
|
|
398
|
+
/**
|
|
399
|
+
* prevent set appName
|
|
400
|
+
* usage:
|
|
401
|
+
* removeDomScope(true)
|
|
402
|
+
* -----> element scope point to base app <-----
|
|
403
|
+
* removeDomScope(false)
|
|
404
|
+
*/
|
|
405
|
+
function removeDomScope(force) {
|
|
406
|
+
if (force !== false) {
|
|
407
|
+
setCurrentAppName(null);
|
|
408
|
+
setIframeCurrentAppName(null);
|
|
409
|
+
if (force && !preventSetState) {
|
|
410
|
+
preventSetState = true;
|
|
411
|
+
defer(() => {
|
|
412
|
+
preventSetState = false;
|
|
413
|
+
});
|
|
414
|
+
}
|
|
415
|
+
}
|
|
416
|
+
else {
|
|
417
|
+
preventSetState = false;
|
|
418
|
+
}
|
|
419
|
+
}
|
|
364
420
|
/**
|
|
365
421
|
* Create pure elements
|
|
366
422
|
*/
|
|
@@ -553,13 +609,39 @@ function clearDOM($dom) {
|
|
|
553
609
|
$dom.removeChild($dom.firstChild);
|
|
554
610
|
}
|
|
555
611
|
}
|
|
612
|
+
function instanceOf(instance, constructor) {
|
|
613
|
+
if (instance === null || instance === undefined) {
|
|
614
|
+
return false;
|
|
615
|
+
}
|
|
616
|
+
else if (!isFunction(constructor)) {
|
|
617
|
+
throw new TypeError("Right-hand side of 'instanceof' is not callable");
|
|
618
|
+
}
|
|
619
|
+
let proto = Object.getPrototypeOf(instance);
|
|
620
|
+
while (proto) {
|
|
621
|
+
if (proto === constructor.prototype) {
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
proto = Object.getPrototypeOf(proto);
|
|
625
|
+
}
|
|
626
|
+
return false;
|
|
627
|
+
}
|
|
556
628
|
/**
|
|
557
|
-
*
|
|
558
|
-
*
|
|
629
|
+
* Format event name
|
|
630
|
+
* In with sandbox, child event and lifeCycles bind to microAppElement, there are two events with same name - mounted unmount, it should be handled specifically to prevent conflicts
|
|
631
|
+
* Issue: https://github.com/micro-zoe/micro-app/issues/1161
|
|
632
|
+
* @param type event name
|
|
633
|
+
* @param appName app name
|
|
559
634
|
*/
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
return (
|
|
635
|
+
const formatEventList = ['mounted', 'unmount'];
|
|
636
|
+
function formatEventType(type, appName) {
|
|
637
|
+
return formatEventList.includes(type) ? `${type}-${appName}` : type;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
* Is the object empty
|
|
641
|
+
* target maybe number, string, array ...
|
|
642
|
+
*/
|
|
643
|
+
function isEmptyObject(target) {
|
|
644
|
+
return isPlainObject(target) ? !Object.keys(target).length : true;
|
|
563
645
|
}
|
|
564
646
|
|
|
565
647
|
function formatEventInfo(event, element) {
|
|
@@ -587,7 +669,7 @@ function formatEventInfo(event, element) {
|
|
|
587
669
|
function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
588
670
|
var _a;
|
|
589
671
|
if (!element) {
|
|
590
|
-
return
|
|
672
|
+
return logWarn(`element does not exist in lifecycle ${lifecycleName}`, appName);
|
|
591
673
|
}
|
|
592
674
|
element = getRootContainer(element);
|
|
593
675
|
// clear dom scope before dispatch lifeCycles event to base app, especially mounted & unmount
|
|
@@ -604,19 +686,19 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
604
686
|
formatEventInfo(event, element);
|
|
605
687
|
// global hooks
|
|
606
688
|
if (isFunction((_a = microApp.options.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
607
|
-
microApp.options.lifeCycles[lifecycleName](event);
|
|
689
|
+
microApp.options.lifeCycles[lifecycleName](event, appName);
|
|
608
690
|
}
|
|
609
691
|
element.dispatchEvent(event);
|
|
610
692
|
}
|
|
611
693
|
/**
|
|
612
694
|
* Dispatch custom event to micro app
|
|
613
695
|
* @param app app
|
|
614
|
-
* @param eventName event name ['unmount', 'appstate-change']
|
|
696
|
+
* @param eventName event name ['mounted', 'unmount', 'appstate-change', 'statechange']
|
|
615
697
|
* @param detail event detail
|
|
616
698
|
*/
|
|
617
699
|
function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
|
|
618
700
|
var _a;
|
|
619
|
-
const event = new CustomEvent(eventName, {
|
|
701
|
+
const event = new CustomEvent(formatEventType(eventName, app.name), {
|
|
620
702
|
detail,
|
|
621
703
|
});
|
|
622
704
|
(_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microAppWindow.dispatchEvent(event);
|
|
@@ -660,7 +742,8 @@ class HTMLLoader {
|
|
|
660
742
|
run(app, successCb) {
|
|
661
743
|
const appName = app.name;
|
|
662
744
|
const htmlUrl = app.ssrUrl || app.url;
|
|
663
|
-
const
|
|
745
|
+
const isJsResource = isTargetExtension(htmlUrl, 'js');
|
|
746
|
+
const htmlPromise = isJsResource
|
|
664
747
|
? Promise.resolve(`<micro-app-head><script src='${htmlUrl}'></script></micro-app-head><micro-app-body></micro-app-body>`)
|
|
665
748
|
: fetchSource(htmlUrl, appName, { cache: 'no-cache' });
|
|
666
749
|
htmlPromise.then((htmlStr) => {
|
|
@@ -793,9 +876,24 @@ class CSSParser {
|
|
|
793
876
|
const m = this.commonMatch(/^[^{]+/, skip);
|
|
794
877
|
if (!m)
|
|
795
878
|
return false;
|
|
879
|
+
/**
|
|
880
|
+
* NOTE:
|
|
881
|
+
* 1. :is(h1, h2, h3):has(+ h2, + h3, + h4) {}
|
|
882
|
+
* should be ==> micro-app[name=xxx] :is(h1, h2, h3):has(+ h2, + h3, + h4) {}
|
|
883
|
+
* 2. :dir(ltr) {}
|
|
884
|
+
* should be ==> micro-app[name=xxx] :dir(ltr) {}
|
|
885
|
+
* 3. body :not(div, .fancy) {}
|
|
886
|
+
* should be ==> micro-app[name=xxx] micro-app-body :not(div, .fancy) {}
|
|
887
|
+
* 4. .a, .b, li:nth-child(3)
|
|
888
|
+
* should be ==> micro-app[name=xxx] .a, micro-app[name=xxx] .b, micro-app[name=xxx] li:nth-child(3)
|
|
889
|
+
* 5. :is(.a, .b, .c) a {}
|
|
890
|
+
* should be ==> micro-app[name=xxx] :is(.a, .b, .c) a {}
|
|
891
|
+
* 6. :where(.a, .b, .c) a {}
|
|
892
|
+
* should be ==> micro-app[name=xxx] :where(.a, .b, .c) a {}
|
|
893
|
+
*/
|
|
796
894
|
return m[0].replace(/(^|,[\n\s]*)([^,]+)/g, (_, separator, selector) => {
|
|
797
895
|
selector = trim(selector);
|
|
798
|
-
if (!(this.scopecssDisableNextLine ||
|
|
896
|
+
if (selector && !(this.scopecssDisableNextLine ||
|
|
799
897
|
(this.scopecssDisable && (!this.scopecssDisableSelectors.length ||
|
|
800
898
|
this.scopecssDisableSelectors.includes(selector))) ||
|
|
801
899
|
rootSelectorREG.test(selector))) {
|
|
@@ -818,13 +916,13 @@ class CSSParser {
|
|
|
818
916
|
return parseError("Declaration missing '}'", this.linkPath);
|
|
819
917
|
return true;
|
|
820
918
|
}
|
|
821
|
-
matchAllDeclarations(nesting =
|
|
919
|
+
matchAllDeclarations(nesting = 0) {
|
|
822
920
|
let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^{}/])*/, true)[0];
|
|
823
921
|
if (cssValue) {
|
|
824
922
|
if (!this.scopecssDisableNextLine &&
|
|
825
923
|
(!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
|
|
826
924
|
cssValue = cssValue.replace(/url\(["']?([^)"']+)["']?\)/gm, (all, $1) => {
|
|
827
|
-
if (/^((data|blob)
|
|
925
|
+
if (/^((data|blob):|#|%23)/.test($1) || /^(https?:)?\/\//.test($1)) {
|
|
828
926
|
return all;
|
|
829
927
|
}
|
|
830
928
|
// ./a/b.png ../a/b.png a/b.png
|
|
@@ -840,14 +938,6 @@ class CSSParser {
|
|
|
840
938
|
this.scopecssDisableNextLine = false;
|
|
841
939
|
if (!this.cssText)
|
|
842
940
|
return;
|
|
843
|
-
if (this.cssText.charAt(0) === '}') {
|
|
844
|
-
if (!nesting)
|
|
845
|
-
return;
|
|
846
|
-
if (nesting > 1) {
|
|
847
|
-
this.commonMatch(/}+/);
|
|
848
|
-
}
|
|
849
|
-
return this.matchAllDeclarations(nesting - 1);
|
|
850
|
-
}
|
|
851
941
|
// extract comments in declarations
|
|
852
942
|
if (this.cssText.charAt(0) === '/') {
|
|
853
943
|
if (this.cssText.charAt(1) === '*') {
|
|
@@ -857,10 +947,16 @@ class CSSParser {
|
|
|
857
947
|
this.commonMatch(/\/+/);
|
|
858
948
|
}
|
|
859
949
|
}
|
|
860
|
-
if (this.cssText.charAt(0) === '{') {
|
|
861
|
-
this.
|
|
950
|
+
else if (this.cssText.charAt(0) === '{') {
|
|
951
|
+
this.matchOpenBrace();
|
|
862
952
|
nesting++;
|
|
863
953
|
}
|
|
954
|
+
else if (this.cssText.charAt(0) === '}') {
|
|
955
|
+
if (nesting < 1)
|
|
956
|
+
return;
|
|
957
|
+
this.matchCloseBrace();
|
|
958
|
+
nesting--;
|
|
959
|
+
}
|
|
864
960
|
return this.matchAllDeclarations(nesting);
|
|
865
961
|
}
|
|
866
962
|
matchAtRule() {
|
|
@@ -879,7 +975,8 @@ class CSSParser {
|
|
|
879
975
|
this.documentRule() ||
|
|
880
976
|
this.pageRule() ||
|
|
881
977
|
this.hostRule() ||
|
|
882
|
-
this.fontFaceRule()
|
|
978
|
+
this.fontFaceRule() ||
|
|
979
|
+
this.layerRule();
|
|
883
980
|
}
|
|
884
981
|
// :global is CSS Modules rule, it will be converted to normal syntax
|
|
885
982
|
// private matchGlobalRule (): boolean | void {
|
|
@@ -941,6 +1038,19 @@ class CSSParser {
|
|
|
941
1038
|
return false;
|
|
942
1039
|
return this.commonHandlerForAtRuleWithSelfRule('font-face');
|
|
943
1040
|
}
|
|
1041
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/@layer
|
|
1042
|
+
layerRule() {
|
|
1043
|
+
if (!this.commonMatch(/^@layer\s*([^{;]+)/))
|
|
1044
|
+
return false;
|
|
1045
|
+
if (!this.matchOpenBrace())
|
|
1046
|
+
return !!this.commonMatch(/^[;]+/);
|
|
1047
|
+
this.matchComments();
|
|
1048
|
+
this.matchRules();
|
|
1049
|
+
if (!this.matchCloseBrace())
|
|
1050
|
+
return parseError('@layer missing \'}\'', this.linkPath);
|
|
1051
|
+
this.matchLeadingSpaces();
|
|
1052
|
+
return true;
|
|
1053
|
+
}
|
|
944
1054
|
// common matcher for @media, @supports, @document, @host, :global, @container
|
|
945
1055
|
createMatcherForRuleWithChildRule(reg, name) {
|
|
946
1056
|
return () => {
|
|
@@ -1036,7 +1146,7 @@ class CSSParser {
|
|
|
1036
1146
|
return this.commonMatch(/^{\s*/);
|
|
1037
1147
|
}
|
|
1038
1148
|
matchCloseBrace() {
|
|
1039
|
-
return this.commonMatch(/^}
|
|
1149
|
+
return this.commonMatch(/^}\s*/);
|
|
1040
1150
|
}
|
|
1041
1151
|
// match and slice the leading spaces
|
|
1042
1152
|
matchLeadingSpaces() {
|
|
@@ -1250,7 +1360,7 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
1250
1360
|
return { address: href, linkInfo };
|
|
1251
1361
|
}
|
|
1252
1362
|
}
|
|
1253
|
-
else if (rel && ['prefetch', 'preload', 'prerender'].includes(rel)) {
|
|
1363
|
+
else if (rel && ['prefetch', 'preload', 'prerender', 'modulepreload', 'icon'].includes(rel)) {
|
|
1254
1364
|
// preload prefetch prerender ....
|
|
1255
1365
|
if (isDynamic) {
|
|
1256
1366
|
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
@@ -1464,23 +1574,37 @@ var MicroAppConfig;
|
|
|
1464
1574
|
MicroAppConfig["DISABLE_MEMORY_ROUTER"] = "disable-memory-router";
|
|
1465
1575
|
MicroAppConfig["DISABLE_PATCH_REQUEST"] = "disable-patch-request";
|
|
1466
1576
|
MicroAppConfig["KEEP_ROUTER_STATE"] = "keep-router-state";
|
|
1467
|
-
MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
|
|
1468
1577
|
MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
|
|
1469
1578
|
MicroAppConfig["CLEAR_DATA"] = "clear-data";
|
|
1470
1579
|
MicroAppConfig["SSR"] = "ssr";
|
|
1471
1580
|
MicroAppConfig["FIBER"] = "fiber";
|
|
1472
1581
|
})(MicroAppConfig || (MicroAppConfig = {}));
|
|
1582
|
+
/**
|
|
1583
|
+
* global key must be static key, they can not rewrite
|
|
1584
|
+
* e.g.
|
|
1585
|
+
* window.Promise = newValue
|
|
1586
|
+
* new Promise ==> still get old value, not newValue, because they are cached by top function
|
|
1587
|
+
* NOTE:
|
|
1588
|
+
* 1. Do not add fetch, XMLHttpRequest, EventSource
|
|
1589
|
+
*/
|
|
1590
|
+
const GLOBAL_CACHED_KEY = 'window,self,globalThis,document,Document,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
|
|
1473
1591
|
// prefetch level
|
|
1474
1592
|
const PREFETCH_LEVEL = [1, 2, 3];
|
|
1475
|
-
// memory router constants
|
|
1476
|
-
// default mode, child router info will sync to browser url
|
|
1477
|
-
const DEFAULT_ROUTER_MODE = 'search';
|
|
1478
1593
|
/**
|
|
1479
|
-
*
|
|
1480
|
-
* equal to disable-memory-router
|
|
1594
|
+
* memory router modes
|
|
1481
1595
|
* NOTE:
|
|
1482
1596
|
* 1. The only difference between native and native-scope is location.origin, in native-scope mode location.origin point to child app
|
|
1597
|
+
* 2. native mode equal to disable-memory-router
|
|
1483
1598
|
*/
|
|
1599
|
+
// 临时注释,1.0版本放开,默认模式切换为state
|
|
1600
|
+
// // default mode, sync child app router info to history.state
|
|
1601
|
+
// export const DEFAULT_ROUTER_MODE = 'state'
|
|
1602
|
+
// // sync child app router info to browser url as search
|
|
1603
|
+
// export const ROUTER_MODE_SEARCH = 'search'
|
|
1604
|
+
// 临时放开,1.0版本去除
|
|
1605
|
+
const ROUTER_MODE_STATE = 'state';
|
|
1606
|
+
const DEFAULT_ROUTER_MODE = 'search';
|
|
1607
|
+
// render base on browser url, and location.origin location.href point to base app
|
|
1484
1608
|
const ROUTER_MODE_NATIVE = 'native';
|
|
1485
1609
|
// render base on browser url, but location.origin location.href point to child app
|
|
1486
1610
|
const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
|
|
@@ -1488,32 +1612,45 @@ const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
|
|
|
1488
1612
|
const ROUTER_MODE_PURE = 'pure';
|
|
1489
1613
|
const ROUTER_MODE_LIST = [
|
|
1490
1614
|
DEFAULT_ROUTER_MODE,
|
|
1615
|
+
ROUTER_MODE_STATE,
|
|
1491
1616
|
ROUTER_MODE_NATIVE,
|
|
1492
1617
|
ROUTER_MODE_NATIVE_SCOPE,
|
|
1493
1618
|
ROUTER_MODE_PURE,
|
|
1494
1619
|
];
|
|
1495
1620
|
// event bound to child app window
|
|
1496
|
-
const
|
|
1621
|
+
const BASE_SCOPE_WINDOW_EVENT = [
|
|
1497
1622
|
'popstate',
|
|
1498
1623
|
'hashchange',
|
|
1499
1624
|
'load',
|
|
1500
|
-
'beforeunload',
|
|
1501
1625
|
'unload',
|
|
1502
1626
|
'unmount',
|
|
1503
1627
|
'appstate-change',
|
|
1504
1628
|
'statechange',
|
|
1505
1629
|
'mounted',
|
|
1506
1630
|
];
|
|
1631
|
+
// bind event of with sandbox
|
|
1632
|
+
const SCOPE_WINDOW_EVENT_OF_WITH = BASE_SCOPE_WINDOW_EVENT;
|
|
1633
|
+
// bind event of iframe sandbox
|
|
1634
|
+
const SCOPE_WINDOW_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_EVENT.concat([
|
|
1635
|
+
'unhandledrejection',
|
|
1636
|
+
'message'
|
|
1637
|
+
]);
|
|
1507
1638
|
// on event bound to child app window
|
|
1508
1639
|
// TODO: with和iframe处理方式不同,需修改
|
|
1509
|
-
const
|
|
1640
|
+
const BASE_SCOPE_WINDOW_ON_EVENT = [
|
|
1510
1641
|
'onpopstate',
|
|
1511
1642
|
'onhashchange',
|
|
1512
1643
|
'onload',
|
|
1513
|
-
'onbeforeunload',
|
|
1514
1644
|
'onunload',
|
|
1515
1645
|
'onerror'
|
|
1646
|
+
// 'onbeforeunload', // remove at 2024.5.30 by cangdu
|
|
1516
1647
|
];
|
|
1648
|
+
// bind on event of with sandbox
|
|
1649
|
+
const SCOPE_WINDOW_ON_EVENT_OF_WITH = BASE_SCOPE_WINDOW_ON_EVENT;
|
|
1650
|
+
// bind on event of iframe sandbox
|
|
1651
|
+
const SCOPE_WINDOW_ON_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_ON_EVENT.concat([
|
|
1652
|
+
'onunhandledrejection',
|
|
1653
|
+
]);
|
|
1517
1654
|
// event bound to child app document
|
|
1518
1655
|
const SCOPE_DOCUMENT_EVENT = [
|
|
1519
1656
|
'DOMContentLoaded',
|
|
@@ -1530,15 +1667,13 @@ const GLOBAL_KEY_TO_WINDOW = [
|
|
|
1530
1667
|
'globalThis',
|
|
1531
1668
|
];
|
|
1532
1669
|
const RAW_GLOBAL_TARGET = ['rawWindow', 'rawDocument'];
|
|
1533
|
-
|
|
1534
|
-
|
|
1535
|
-
|
|
1536
|
-
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
*/
|
|
1541
|
-
const GLOBAL_CACHED_KEY = 'window,self,globalThis,document,Document,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
|
|
1670
|
+
const HIJACK_LOCATION_KEYS = [
|
|
1671
|
+
'host',
|
|
1672
|
+
'hostname',
|
|
1673
|
+
'port',
|
|
1674
|
+
'protocol',
|
|
1675
|
+
'origin',
|
|
1676
|
+
];
|
|
1542
1677
|
|
|
1543
1678
|
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1544
1679
|
// whether use type='module' script
|
|
@@ -1938,6 +2073,7 @@ function execScripts(app, initHook) {
|
|
|
1938
2073
|
* @param callback callback of module script
|
|
1939
2074
|
*/
|
|
1940
2075
|
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
2076
|
+
var _a;
|
|
1941
2077
|
try {
|
|
1942
2078
|
actionsBeforeRunScript(app);
|
|
1943
2079
|
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
@@ -1968,7 +2104,7 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
|
1968
2104
|
*/
|
|
1969
2105
|
if (!replaceElement) {
|
|
1970
2106
|
// TEST IGNORE
|
|
1971
|
-
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
2107
|
+
const parent = app.iframe ? (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microBody : app.querySelector('micro-app-body');
|
|
1972
2108
|
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
1973
2109
|
}
|
|
1974
2110
|
}
|
|
@@ -1990,7 +2126,7 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
|
1990
2126
|
* @param originScript origin script element
|
|
1991
2127
|
*/
|
|
1992
2128
|
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
1993
|
-
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment(
|
|
2129
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment(`dynamic script with src='${address}' extract by micro-app`);
|
|
1994
2130
|
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
1995
2131
|
const runDynamicScript = () => {
|
|
1996
2132
|
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
@@ -2024,7 +2160,7 @@ function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
|
2024
2160
|
* @param scriptInfo scriptInfo
|
|
2025
2161
|
*/
|
|
2026
2162
|
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
2027
|
-
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
2163
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic inline script extract by micro-app');
|
|
2028
2164
|
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
2029
2165
|
return replaceElement;
|
|
2030
2166
|
}
|
|
@@ -2202,7 +2338,7 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2202
2338
|
const fiberStyleTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
2203
2339
|
flatChildren(wrapElement, app, microAppHead, fiberStyleTasks);
|
|
2204
2340
|
/**
|
|
2205
|
-
* Style and link are parallel,
|
|
2341
|
+
* Style and link are parallel, as it takes a lot of time for link to request resources. During this period, style processing can be performed to improve efficiency.
|
|
2206
2342
|
*/
|
|
2207
2343
|
const fiberStyleResult = serialExecFiberTasks(fiberStyleTasks);
|
|
2208
2344
|
if (app.source.links.size) {
|
|
@@ -2397,7 +2533,7 @@ const eventCenter = new EventCenter();
|
|
|
2397
2533
|
function createEventName(appName, fromBaseApp) {
|
|
2398
2534
|
if (!isString(appName) || !appName)
|
|
2399
2535
|
return '';
|
|
2400
|
-
return fromBaseApp ? `
|
|
2536
|
+
return fromBaseApp ? `__${appName}_from_base_app__` : `__${appName}_from_micro_app__`;
|
|
2401
2537
|
}
|
|
2402
2538
|
// Global data
|
|
2403
2539
|
class EventCenterForGlobal {
|
|
@@ -2696,7 +2832,15 @@ function isConstructorFunction(value) {
|
|
|
2696
2832
|
}
|
|
2697
2833
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
2698
2834
|
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
2699
|
-
|
|
2835
|
+
/**
|
|
2836
|
+
* In safari, nest app like: A -> B -> C
|
|
2837
|
+
* if B is iframe sandbox, and C is with sandbox, same property of document in C is abnormal
|
|
2838
|
+
* e.g:
|
|
2839
|
+
* document.all:
|
|
2840
|
+
* - typeof document.all ==> 'function'
|
|
2841
|
+
* - document.all.bind ==> undefined
|
|
2842
|
+
*/
|
|
2843
|
+
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value) && value.bind) {
|
|
2700
2844
|
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
2701
2845
|
if (value[cacheKey])
|
|
2702
2846
|
return value[cacheKey];
|
|
@@ -2717,6 +2861,198 @@ function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
|
2717
2861
|
return value;
|
|
2718
2862
|
}
|
|
2719
2863
|
|
|
2864
|
+
class BaseSandbox {
|
|
2865
|
+
constructor(appName, url) {
|
|
2866
|
+
// keys that can only assigned to rawWindow
|
|
2867
|
+
this.rawWindowScopeKeyList = [
|
|
2868
|
+
'location',
|
|
2869
|
+
];
|
|
2870
|
+
// keys that can escape to rawWindow
|
|
2871
|
+
this.staticEscapeProperties = [
|
|
2872
|
+
'System',
|
|
2873
|
+
'__cjsWrapper',
|
|
2874
|
+
];
|
|
2875
|
+
// keys that scoped in child app
|
|
2876
|
+
this.staticScopeProperties = [
|
|
2877
|
+
'webpackJsonp',
|
|
2878
|
+
'webpackHotUpdate',
|
|
2879
|
+
'Vue',
|
|
2880
|
+
// TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
|
|
2881
|
+
'onpopstate',
|
|
2882
|
+
'onhashchange',
|
|
2883
|
+
];
|
|
2884
|
+
// Properties that can only get and set in microAppWindow, will not escape to rawWindow
|
|
2885
|
+
this.scopeProperties = Array.from(this.staticScopeProperties);
|
|
2886
|
+
// Properties that can be escape to rawWindow
|
|
2887
|
+
this.escapeProperties = [];
|
|
2888
|
+
// Properties newly added to microAppWindow
|
|
2889
|
+
this.injectedKeys = new Set();
|
|
2890
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
2891
|
+
this.escapeKeys = new Set();
|
|
2892
|
+
this.appName = appName;
|
|
2893
|
+
this.url = url;
|
|
2894
|
+
this.injectReactHMRProperty();
|
|
2895
|
+
}
|
|
2896
|
+
// adapter for react
|
|
2897
|
+
injectReactHMRProperty() {
|
|
2898
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
2899
|
+
// react child in non-react env
|
|
2900
|
+
this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
|
|
2901
|
+
// in react parent
|
|
2902
|
+
if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
|
|
2903
|
+
this.staticScopeProperties = this.staticScopeProperties.concat([
|
|
2904
|
+
'__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
|
|
2905
|
+
'__reactRefreshInjected',
|
|
2906
|
+
]);
|
|
2907
|
+
}
|
|
2908
|
+
}
|
|
2909
|
+
}
|
|
2910
|
+
}
|
|
2911
|
+
/**
|
|
2912
|
+
* TODO:
|
|
2913
|
+
* 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
|
|
2914
|
+
* 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
|
|
2915
|
+
* 修改时机:在iframe沙箱支持插件后再修改
|
|
2916
|
+
*/
|
|
2917
|
+
class CustomWindow {
|
|
2918
|
+
}
|
|
2919
|
+
// Fix conflict of babel-polyfill@6.x
|
|
2920
|
+
function fixBabelPolyfill6() {
|
|
2921
|
+
if (globalEnv.rawWindow._babelPolyfill)
|
|
2922
|
+
globalEnv.rawWindow._babelPolyfill = false;
|
|
2923
|
+
}
|
|
2924
|
+
/**
|
|
2925
|
+
* Fix error of hot reload when parent&child created by create-react-app in development environment
|
|
2926
|
+
* Issue: https://github.com/micro-zoe/micro-app/issues/382
|
|
2927
|
+
*/
|
|
2928
|
+
function fixReactHMRConflict(app) {
|
|
2929
|
+
var _a;
|
|
2930
|
+
if ((process.env.NODE_ENV !== 'production')) {
|
|
2931
|
+
const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
2932
|
+
const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
2933
|
+
if (rawReactErrorHook && childReactErrorHook) {
|
|
2934
|
+
globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
|
|
2935
|
+
defer(() => {
|
|
2936
|
+
globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
|
|
2937
|
+
});
|
|
2938
|
+
}
|
|
2939
|
+
}
|
|
2940
|
+
}
|
|
2941
|
+
/**
|
|
2942
|
+
* update dom tree of target dom
|
|
2943
|
+
* @param container target dom
|
|
2944
|
+
* @param appName app name
|
|
2945
|
+
*/
|
|
2946
|
+
function patchElementTree(container, appName) {
|
|
2947
|
+
const children = Array.from(container.childNodes);
|
|
2948
|
+
children.length && children.forEach((child) => {
|
|
2949
|
+
patchElementTree(child, appName);
|
|
2950
|
+
});
|
|
2951
|
+
updateElementInfo(container, appName);
|
|
2952
|
+
}
|
|
2953
|
+
/**
|
|
2954
|
+
* rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
|
|
2955
|
+
* @param node target node
|
|
2956
|
+
* @param appName app name
|
|
2957
|
+
* @returns target node
|
|
2958
|
+
*/
|
|
2959
|
+
function updateElementInfo(node, appName) {
|
|
2960
|
+
var _a, _b;
|
|
2961
|
+
if (appName &&
|
|
2962
|
+
isNode(node) &&
|
|
2963
|
+
node.__MICRO_APP_NAME__ !== appName &&
|
|
2964
|
+
!node.__PURE_ELEMENT__ &&
|
|
2965
|
+
!getPreventSetState()) {
|
|
2966
|
+
/**
|
|
2967
|
+
* TODO:
|
|
2968
|
+
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
2969
|
+
* 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
|
|
2970
|
+
*/
|
|
2971
|
+
rawDefineProperties(node, {
|
|
2972
|
+
__MICRO_APP_NAME__: {
|
|
2973
|
+
configurable: true,
|
|
2974
|
+
enumerable: true,
|
|
2975
|
+
writable: true,
|
|
2976
|
+
value: appName,
|
|
2977
|
+
},
|
|
2978
|
+
});
|
|
2979
|
+
/**
|
|
2980
|
+
* In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
|
|
2981
|
+
*
|
|
2982
|
+
* Performance:
|
|
2983
|
+
* iframe element.__proto__ === browser HTMLElement.prototype // Chrome: false, FireFox: true
|
|
2984
|
+
* iframe element.__proto__ === iframe HTMLElement.prototype // Chrome: true, FireFox: false
|
|
2985
|
+
*
|
|
2986
|
+
* NOTE:
|
|
2987
|
+
* 1. Node.prototype.baseURI
|
|
2988
|
+
* 2. Node.prototype.ownerDocument
|
|
2989
|
+
* 3. Node.prototype.parentNode
|
|
2990
|
+
* 4. Node.prototype.getRootNode
|
|
2991
|
+
* 5. Node.prototype.cloneNode
|
|
2992
|
+
* 6. Element.prototype.innerHTML
|
|
2993
|
+
* 7. Image
|
|
2994
|
+
*/
|
|
2995
|
+
if (isIframeSandbox(appName)) {
|
|
2996
|
+
const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
|
|
2997
|
+
if (proxyWindow) {
|
|
2998
|
+
rawDefineProperties(node, {
|
|
2999
|
+
baseURI: {
|
|
3000
|
+
configurable: true,
|
|
3001
|
+
enumerable: true,
|
|
3002
|
+
get: () => proxyWindow.location.href,
|
|
3003
|
+
},
|
|
3004
|
+
ownerDocument: {
|
|
3005
|
+
configurable: true,
|
|
3006
|
+
enumerable: true,
|
|
3007
|
+
get: () => node !== proxyWindow.document ? proxyWindow.document : null,
|
|
3008
|
+
},
|
|
3009
|
+
parentNode: getIframeParentNodeDesc(appName, globalEnv.rawParentNodeDesc),
|
|
3010
|
+
getRootNode: {
|
|
3011
|
+
configurable: true,
|
|
3012
|
+
enumerable: true,
|
|
3013
|
+
writable: true,
|
|
3014
|
+
value: function getRootNode() {
|
|
3015
|
+
return proxyWindow.document;
|
|
3016
|
+
}
|
|
3017
|
+
},
|
|
3018
|
+
});
|
|
3019
|
+
}
|
|
3020
|
+
}
|
|
3021
|
+
}
|
|
3022
|
+
return node;
|
|
3023
|
+
}
|
|
3024
|
+
/**
|
|
3025
|
+
* get Descriptor of Node.prototype.parentNode for iframe
|
|
3026
|
+
* @param appName app name
|
|
3027
|
+
* @param parentNode parentNode Descriptor of iframe or browser
|
|
3028
|
+
*/
|
|
3029
|
+
function getIframeParentNodeDesc(appName, parentNodeDesc) {
|
|
3030
|
+
return {
|
|
3031
|
+
configurable: true,
|
|
3032
|
+
enumerable: true,
|
|
3033
|
+
get() {
|
|
3034
|
+
var _a, _b, _c, _d;
|
|
3035
|
+
throttleDeferForIframeAppName(appName);
|
|
3036
|
+
const result = (_a = parentNodeDesc.get) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
3037
|
+
/**
|
|
3038
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
3039
|
+
* Scenes:
|
|
3040
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
3041
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
3042
|
+
* e.g.:
|
|
3043
|
+
* 1. element-ui@2.x el-dropdown
|
|
3044
|
+
* WARNING:
|
|
3045
|
+
* Will it cause other problems ?
|
|
3046
|
+
* e.g. target.parentNode.remove(target)
|
|
3047
|
+
*/
|
|
3048
|
+
if (isMicroAppBody(result) && ((_b = appInstanceMap.get(appName)) === null || _b === void 0 ? void 0 : _b.container)) {
|
|
3049
|
+
return ((_d = (_c = microApp.options).getRootElementParentNode) === null || _d === void 0 ? void 0 : _d.call(_c, this, appName)) || globalEnv.rawDocument.body;
|
|
3050
|
+
}
|
|
3051
|
+
return result;
|
|
3052
|
+
}
|
|
3053
|
+
};
|
|
3054
|
+
}
|
|
3055
|
+
|
|
2720
3056
|
/**
|
|
2721
3057
|
* create proxyDocument and MicroDocument, rewrite document of child app
|
|
2722
3058
|
* @param appName app name
|
|
@@ -2757,13 +3093,11 @@ function createProxyDocument(appName, sandbox) {
|
|
|
2757
3093
|
const { rawDocument, rawCreateElement, rawCreateElementNS, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
2758
3094
|
function createElement(tagName, options) {
|
|
2759
3095
|
const element = rawCreateElement.call(rawDocument, tagName, options);
|
|
2760
|
-
element
|
|
2761
|
-
return element;
|
|
3096
|
+
return updateElementInfo(element, appName);
|
|
2762
3097
|
}
|
|
2763
3098
|
function createElementNS(namespaceURI, name, options) {
|
|
2764
3099
|
const element = rawCreateElementNS.call(rawDocument, namespaceURI, name, options);
|
|
2765
|
-
element
|
|
2766
|
-
return element;
|
|
3100
|
+
return updateElementInfo(element, appName);
|
|
2767
3101
|
}
|
|
2768
3102
|
/**
|
|
2769
3103
|
* TODO:
|
|
@@ -2989,7 +3323,7 @@ function patchWindowProperty(microAppWindow) {
|
|
|
2989
3323
|
const rawWindow = globalEnv.rawWindow;
|
|
2990
3324
|
Object.getOwnPropertyNames(rawWindow)
|
|
2991
3325
|
.filter((key) => {
|
|
2992
|
-
return /^on/.test(key) && !
|
|
3326
|
+
return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_WITH.includes(key);
|
|
2993
3327
|
})
|
|
2994
3328
|
.forEach((eventName) => {
|
|
2995
3329
|
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(rawWindow, eventName) || {
|
|
@@ -3138,7 +3472,7 @@ function patchWindowEffect(microAppWindow, appName) {
|
|
|
3138
3472
|
*/
|
|
3139
3473
|
function getEventTarget(type) {
|
|
3140
3474
|
var _a;
|
|
3141
|
-
if (
|
|
3475
|
+
if (SCOPE_WINDOW_EVENT_OF_WITH.includes(type) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
3142
3476
|
return getRootContainer(appInstanceMap.get(appName).container);
|
|
3143
3477
|
}
|
|
3144
3478
|
return rawWindow;
|
|
@@ -3151,6 +3485,7 @@ function patchWindowEffect(microAppWindow, appName) {
|
|
|
3151
3485
|
* window.addEventListener.call(非window, type, listener, options)
|
|
3152
3486
|
*/
|
|
3153
3487
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3488
|
+
type = formatEventType(type, appName);
|
|
3154
3489
|
const listenerList = eventListenerMap.get(type);
|
|
3155
3490
|
if (listenerList) {
|
|
3156
3491
|
listenerList.add(listener);
|
|
@@ -3162,6 +3497,7 @@ function patchWindowEffect(microAppWindow, appName) {
|
|
|
3162
3497
|
rawAddEventListener.call(getEventTarget(type), type, listener, options);
|
|
3163
3498
|
};
|
|
3164
3499
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3500
|
+
type = formatEventType(type, appName);
|
|
3165
3501
|
const listenerList = eventListenerMap.get(type);
|
|
3166
3502
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3167
3503
|
listenerList.delete(listener);
|
|
@@ -3254,42 +3590,44 @@ function patchWindowEffect(microAppWindow, appName) {
|
|
|
3254
3590
|
}
|
|
3255
3591
|
|
|
3256
3592
|
// set micro app state to origin state
|
|
3257
|
-
function setMicroState(appName, microState) {
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
3261
|
-
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
|
|
3265
|
-
|
|
3266
|
-
|
|
3267
|
-
|
|
3268
|
-
|
|
3593
|
+
function setMicroState(appName, microState, targetLocation) {
|
|
3594
|
+
// TODO: 验证native模式下修改state nextjs路由是否正常
|
|
3595
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3596
|
+
const additionalState = {
|
|
3597
|
+
__MICRO_APP_STATE__: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__, {
|
|
3598
|
+
[appName]: {
|
|
3599
|
+
fullPath: targetLocation ? targetLocation.pathname + targetLocation.search + targetLocation.hash : null,
|
|
3600
|
+
state: microState !== null && microState !== void 0 ? microState : null,
|
|
3601
|
+
mode: getRouterMode(appName),
|
|
3602
|
+
}
|
|
3603
|
+
}),
|
|
3604
|
+
};
|
|
3605
|
+
// create new state object
|
|
3606
|
+
return assign({}, rawState, additionalState);
|
|
3269
3607
|
}
|
|
3270
3608
|
// delete micro app state form origin state
|
|
3271
3609
|
function removeMicroState(appName, rawState) {
|
|
3272
|
-
if (
|
|
3273
|
-
if (
|
|
3274
|
-
|
|
3275
|
-
|
|
3276
|
-
|
|
3277
|
-
|
|
3278
|
-
delete rawState.microAppState;
|
|
3279
|
-
}
|
|
3610
|
+
if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__)) {
|
|
3611
|
+
if (!isUndefined(rawState.__MICRO_APP_STATE__[appName])) {
|
|
3612
|
+
delete rawState.__MICRO_APP_STATE__[appName];
|
|
3613
|
+
}
|
|
3614
|
+
if (!Object.keys(rawState.__MICRO_APP_STATE__).length) {
|
|
3615
|
+
delete rawState.__MICRO_APP_STATE__;
|
|
3280
3616
|
}
|
|
3281
|
-
return assign({}, rawState);
|
|
3282
3617
|
}
|
|
3283
|
-
return rawState;
|
|
3618
|
+
return !isEmptyObject(rawState) ? assign({}, rawState) : null;
|
|
3284
3619
|
}
|
|
3285
3620
|
// get micro app state form origin state
|
|
3286
3621
|
function getMicroState(appName) {
|
|
3622
|
+
var _a, _b;
|
|
3623
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3624
|
+
return ((_b = (_a = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _a === void 0 ? void 0 : _a[appName]) === null || _b === void 0 ? void 0 : _b.state) || null;
|
|
3625
|
+
}
|
|
3626
|
+
// get micro app router info state form origin state
|
|
3627
|
+
function getMicroRouterInfoState(appName) {
|
|
3287
3628
|
var _a;
|
|
3288
3629
|
const rawState = globalEnv.rawWindow.history.state;
|
|
3289
|
-
|
|
3290
|
-
return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
|
|
3291
|
-
}
|
|
3292
|
-
return rawState;
|
|
3630
|
+
return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _a === void 0 ? void 0 : _a[appName]) || null;
|
|
3293
3631
|
}
|
|
3294
3632
|
const ENC_AD_RE = /&/g; // %M1
|
|
3295
3633
|
const ENC_EQ_RE = /=/g; // %M2
|
|
@@ -3325,17 +3663,35 @@ function formatQueryAppName(appName) {
|
|
|
3325
3663
|
* @param appName app.name
|
|
3326
3664
|
*/
|
|
3327
3665
|
function getMicroPathFromURL(appName) {
|
|
3328
|
-
var _a, _b;
|
|
3329
|
-
// TODO: pure模式从state中获取地址
|
|
3330
|
-
if (isRouterModePure(appName))
|
|
3331
|
-
return null;
|
|
3666
|
+
var _a, _b, _c, _d;
|
|
3332
3667
|
const rawLocation = globalEnv.rawWindow.location;
|
|
3668
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3333
3669
|
if (isRouterModeSearch(appName)) {
|
|
3334
3670
|
const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
|
|
3335
3671
|
const microPath = ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) || ((_b = queryObject.searchQuery) === null || _b === void 0 ? void 0 : _b[formatQueryAppName(appName)]);
|
|
3336
3672
|
return isString(microPath) ? decodeMicroPath(microPath) : null;
|
|
3337
3673
|
}
|
|
3338
|
-
|
|
3674
|
+
/**
|
|
3675
|
+
* Get fullPath from __MICRO_APP_STATE__
|
|
3676
|
+
* NOTE:
|
|
3677
|
+
* 1. state mode: all base on __MICRO_APP_STATE__
|
|
3678
|
+
* 2. pure mode: navigate by location.xxx may contain one-time information in __MICRO_APP_STATE__
|
|
3679
|
+
* 3. native mode: vue-router@4 will exec replaceState with history.state before pushState, like:
|
|
3680
|
+
* history.replaceState(
|
|
3681
|
+
* assign({}, history.state, {...}),
|
|
3682
|
+
* title,
|
|
3683
|
+
* history.state.current, <---
|
|
3684
|
+
* )
|
|
3685
|
+
* when base app jump to another page from child page, it will replace child path with base app path
|
|
3686
|
+
* e.g: base-home --> child-home --> child-about(will replace with child-home before jump to base-home) --> base-home, when go back, it will back to child-home not child-about
|
|
3687
|
+
* So we take the fullPath as standard
|
|
3688
|
+
*/
|
|
3689
|
+
// 问题:1、同一个页面多个子应用,一个修改后... --- native模式不支持多个子应用同时渲染,多个子应用推荐使用其它模式
|
|
3690
|
+
// if (isRouterModeCustom(appName)) {
|
|
3691
|
+
// return rawLocation.pathname + rawLocation.search + rawLocation.hash
|
|
3692
|
+
// }
|
|
3693
|
+
// return rawState?.__MICRO_APP_STATE__?.[appName]?.fullPath || null
|
|
3694
|
+
return ((_d = (_c = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _c === void 0 ? void 0 : _c[appName]) === null || _d === void 0 ? void 0 : _d.fullPath) || (isRouterModeCustom(appName) ? rawLocation.pathname + rawLocation.search + rawLocation.hash : null);
|
|
3339
3695
|
}
|
|
3340
3696
|
/**
|
|
3341
3697
|
* Attach child app fullPath to browser url
|
|
@@ -3343,10 +3699,11 @@ function getMicroPathFromURL(appName) {
|
|
|
3343
3699
|
* @param targetLocation location of child app or rawLocation of window
|
|
3344
3700
|
*/
|
|
3345
3701
|
function setMicroPathToURL(appName, targetLocation) {
|
|
3346
|
-
const
|
|
3702
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
3703
|
+
let targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3347
3704
|
let isAttach2Hash = false;
|
|
3348
3705
|
if (isRouterModeSearch(appName)) {
|
|
3349
|
-
let { pathname, search, hash } =
|
|
3706
|
+
let { pathname, search, hash } = rawLocation;
|
|
3350
3707
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
3351
3708
|
const encodedMicroPath = encodeMicroPath(targetFullPath);
|
|
3352
3709
|
/**
|
|
@@ -3356,6 +3713,7 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3356
3713
|
// If hash exists and search does not exist, it is considered as a hash route
|
|
3357
3714
|
if (hash && !search) {
|
|
3358
3715
|
isAttach2Hash = true;
|
|
3716
|
+
// TODO: 这里和下面的if判断可以简化一下
|
|
3359
3717
|
if (queryObject.hashQuery) {
|
|
3360
3718
|
queryObject.hashQuery[formatQueryAppName(appName)] = encodedMicroPath;
|
|
3361
3719
|
}
|
|
@@ -3383,6 +3741,9 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3383
3741
|
isAttach2Hash,
|
|
3384
3742
|
};
|
|
3385
3743
|
}
|
|
3744
|
+
if (isRouterModeState(appName) || isRouterModePure(appName)) {
|
|
3745
|
+
targetFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
3746
|
+
}
|
|
3386
3747
|
return {
|
|
3387
3748
|
fullPath: targetFullPath,
|
|
3388
3749
|
isAttach2Hash,
|
|
@@ -3391,11 +3752,10 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3391
3752
|
/**
|
|
3392
3753
|
* Delete child app fullPath from browser url
|
|
3393
3754
|
* @param appName app.name
|
|
3394
|
-
* @param targetLocation target Location, default is rawLocation
|
|
3395
3755
|
*/
|
|
3396
|
-
function removeMicroPathFromURL(appName
|
|
3756
|
+
function removeMicroPathFromURL(appName) {
|
|
3397
3757
|
var _a, _b, _c, _d;
|
|
3398
|
-
let { pathname, search, hash } =
|
|
3758
|
+
let { pathname, search, hash } = globalEnv.rawWindow.location;
|
|
3399
3759
|
let isAttach2Hash = false;
|
|
3400
3760
|
if (isRouterModeSearch(appName)) {
|
|
3401
3761
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
@@ -3457,25 +3817,33 @@ function isEffectiveApp(appName) {
|
|
|
3457
3817
|
*/
|
|
3458
3818
|
return !!(app && !app.isPrefetch);
|
|
3459
3819
|
}
|
|
3820
|
+
/**
|
|
3821
|
+
* get router mode of app
|
|
3822
|
+
* NOTE: app maybe undefined
|
|
3823
|
+
*/
|
|
3824
|
+
function getRouterMode(appName) {
|
|
3825
|
+
var _a;
|
|
3826
|
+
return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.routerMode;
|
|
3827
|
+
}
|
|
3460
3828
|
// router mode is search
|
|
3461
3829
|
function isRouterModeSearch(appName) {
|
|
3462
|
-
|
|
3463
|
-
|
|
3830
|
+
return getRouterMode(appName) === DEFAULT_ROUTER_MODE;
|
|
3831
|
+
}
|
|
3832
|
+
// router mode is state
|
|
3833
|
+
function isRouterModeState(appName) {
|
|
3834
|
+
return getRouterMode(appName) === ROUTER_MODE_STATE;
|
|
3464
3835
|
}
|
|
3465
3836
|
// router mode is history
|
|
3466
3837
|
function isRouterModeNative(appName) {
|
|
3467
|
-
|
|
3468
|
-
return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_NATIVE);
|
|
3838
|
+
return getRouterMode(appName) === ROUTER_MODE_NATIVE;
|
|
3469
3839
|
}
|
|
3470
3840
|
// router mode is disable
|
|
3471
3841
|
function isRouterModeNativeScope(appName) {
|
|
3472
|
-
|
|
3473
|
-
return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_NATIVE_SCOPE);
|
|
3842
|
+
return getRouterMode(appName) === ROUTER_MODE_NATIVE_SCOPE;
|
|
3474
3843
|
}
|
|
3475
3844
|
// router mode is pure
|
|
3476
3845
|
function isRouterModePure(appName) {
|
|
3477
|
-
|
|
3478
|
-
return !!(app && app.sandBox && app.routerMode === ROUTER_MODE_PURE);
|
|
3846
|
+
return getRouterMode(appName) === ROUTER_MODE_PURE;
|
|
3479
3847
|
}
|
|
3480
3848
|
/**
|
|
3481
3849
|
* router mode is history or disable
|
|
@@ -3492,7 +3860,7 @@ function isRouterModeCustom(appName) {
|
|
|
3492
3860
|
* @param inlineDisableMemoryRouter disable-memory-router set by micro-app element or prerender
|
|
3493
3861
|
* @returns router mode
|
|
3494
3862
|
*/
|
|
3495
|
-
function
|
|
3863
|
+
function initRouterMode(mode, inlineDisableMemoryRouter) {
|
|
3496
3864
|
/**
|
|
3497
3865
|
* compatible with disable-memory-router in older versions
|
|
3498
3866
|
* if disable-memory-router is true, router-mode will be disable
|
|
@@ -3518,6 +3886,7 @@ function addHistoryListener(appName) {
|
|
|
3518
3886
|
const rawWindow = globalEnv.rawWindow;
|
|
3519
3887
|
// handle popstate event and distribute to child app
|
|
3520
3888
|
const popStateHandler = (e) => {
|
|
3889
|
+
var _a, _b, _c;
|
|
3521
3890
|
/**
|
|
3522
3891
|
* 1. unmount app & hidden keep-alive app will not receive popstate event
|
|
3523
3892
|
* 2. filter out onlyForBrowser
|
|
@@ -3527,7 +3896,28 @@ function addHistoryListener(appName) {
|
|
|
3527
3896
|
excludePreRender: true,
|
|
3528
3897
|
}).includes(appName) &&
|
|
3529
3898
|
!e.onlyForBrowser) {
|
|
3530
|
-
|
|
3899
|
+
/**
|
|
3900
|
+
* base app may respond to popstateEvent async(lazy load page & browser back/forward), but child app will respond to popstateEvent immediately(vue2, react), this will cause some problems
|
|
3901
|
+
* 2 solutions:
|
|
3902
|
+
* 1. child app respond to popstateEvent async -- router-event-delay
|
|
3903
|
+
* 2. child app will not respond to popstateEvent in some scenarios (history.state===null || history.state?__MICRO_APP_STATE__[appName])
|
|
3904
|
+
* NOTE 1:
|
|
3905
|
+
* 1. browser back/forward
|
|
3906
|
+
* 2. location.hash/search/pathname = xxx
|
|
3907
|
+
* 3. <a href="/#/xxx">, <a href="/xxx">
|
|
3908
|
+
* 4. history.back/go/forward
|
|
3909
|
+
* 5. history.pushState/replaceState
|
|
3910
|
+
*
|
|
3911
|
+
* NOTE2:
|
|
3912
|
+
* 1、react16 hash mode navigate by location.hash = xxx, history.state is always null, but react16 respond to popstateEvent sync
|
|
3913
|
+
* 2、multiple child apps may has problems
|
|
3914
|
+
*/
|
|
3915
|
+
if (!isRouterModeCustom(appName) ||
|
|
3916
|
+
!globalEnv.rawWindow.history.state ||
|
|
3917
|
+
getMicroRouterInfoState(appName)) {
|
|
3918
|
+
const container = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container;
|
|
3919
|
+
macro(() => updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName)), (_c = (_b = (container && getRootContainer(container))) === null || _b === void 0 ? void 0 : _b.getRouterEventDelay()) !== null && _c !== void 0 ? _c : 0);
|
|
3920
|
+
}
|
|
3531
3921
|
}
|
|
3532
3922
|
};
|
|
3533
3923
|
rawWindow.addEventListener('popstate', popStateHandler);
|
|
@@ -3545,24 +3935,26 @@ function addHistoryListener(appName) {
|
|
|
3545
3935
|
*/
|
|
3546
3936
|
function updateMicroLocationWithEvent(appName, targetFullPath) {
|
|
3547
3937
|
const app = appInstanceMap.get(appName);
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
|
|
3554
|
-
|
|
3555
|
-
|
|
3556
|
-
|
|
3557
|
-
|
|
3558
|
-
|
|
3559
|
-
|
|
3560
|
-
|
|
3561
|
-
|
|
3562
|
-
|
|
3563
|
-
|
|
3564
|
-
|
|
3565
|
-
|
|
3938
|
+
if (app === null || app === void 0 ? void 0 : app.sandBox) {
|
|
3939
|
+
const proxyWindow = app.sandBox.proxyWindow;
|
|
3940
|
+
const microAppWindow = app.sandBox.microAppWindow;
|
|
3941
|
+
let isHashChange = false;
|
|
3942
|
+
// for hashChangeEvent
|
|
3943
|
+
const oldHref = proxyWindow.location.href;
|
|
3944
|
+
// Do not attach micro state to url when targetFullPath is empty
|
|
3945
|
+
if (targetFullPath) {
|
|
3946
|
+
const oldHash = proxyWindow.location.hash;
|
|
3947
|
+
updateMicroLocation(appName, targetFullPath, microAppWindow.location);
|
|
3948
|
+
isHashChange = proxyWindow.location.hash !== oldHash;
|
|
3949
|
+
}
|
|
3950
|
+
// dispatch formatted popStateEvent to child
|
|
3951
|
+
dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
|
|
3952
|
+
// dispatch formatted hashChangeEvent to child when hash change
|
|
3953
|
+
if (isHashChange)
|
|
3954
|
+
dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
|
|
3955
|
+
// clear element scope before trigger event of next app
|
|
3956
|
+
removeDomScope();
|
|
3957
|
+
}
|
|
3566
3958
|
}
|
|
3567
3959
|
/**
|
|
3568
3960
|
* dispatch formatted popstate event to microApp
|
|
@@ -3575,14 +3967,18 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
|
|
|
3575
3967
|
* TODO: test
|
|
3576
3968
|
* angular14 takes e.type as type judgment
|
|
3577
3969
|
* when e.type is popstate-appName popstate event will be invalid
|
|
3970
|
+
* Object.defineProperty(newPopStateEvent, 'type', {
|
|
3971
|
+
* value: 'popstate',
|
|
3972
|
+
* writable: true,
|
|
3973
|
+
* configurable: true,
|
|
3974
|
+
* enumerable: true,
|
|
3975
|
+
* })
|
|
3976
|
+
*/
|
|
3977
|
+
/**
|
|
3978
|
+
* create PopStateEvent named popstate-appName with sub app state
|
|
3979
|
+
* TODO: feeling like there's something wrong, check carefully
|
|
3980
|
+
* In native mode, getMicroState(appName) return rawWindow.history.state when use microApp.router.push/replace or other scenes when state.__MICRO_APP_STATE__[appName] is null
|
|
3578
3981
|
*/
|
|
3579
|
-
// Object.defineProperty(newPopStateEvent, 'type', {
|
|
3580
|
-
// value: 'popstate',
|
|
3581
|
-
// writable: true,
|
|
3582
|
-
// configurable: true,
|
|
3583
|
-
// enumerable: true,
|
|
3584
|
-
// })
|
|
3585
|
-
// create PopStateEvent named popstate-appName with sub app state
|
|
3586
3982
|
const newPopStateEvent = new PopStateEvent('popstate', { state: getMicroState(appName) });
|
|
3587
3983
|
microAppWindow.dispatchEvent(newPopStateEvent);
|
|
3588
3984
|
if (!isIframeSandbox(appName)) {
|
|
@@ -3657,26 +4053,29 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3657
4053
|
return function (...rests) {
|
|
3658
4054
|
var _a, _b, _c;
|
|
3659
4055
|
// TODO: 测试iframe的URL兼容isURL的情况
|
|
3660
|
-
|
|
3661
|
-
|
|
3662
|
-
|
|
3663
|
-
|
|
3664
|
-
|
|
3665
|
-
}
|
|
3666
|
-
if (targetFullPath !== microLocation.fullPath) {
|
|
3667
|
-
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3668
|
-
}
|
|
3669
|
-
(_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
4056
|
+
rests[2] = isUndefined(rests[2]) || isNull(rests[2]) || ('' + rests[2] === '') ? microLocation.href : '' + rests[2];
|
|
4057
|
+
const targetLocation = createURL(rests[2], microLocation.href);
|
|
4058
|
+
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
4059
|
+
if (!isRouterModePure(appName)) {
|
|
4060
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0], targetLocation), rests[1]);
|
|
3670
4061
|
}
|
|
3671
|
-
|
|
3672
|
-
|
|
4062
|
+
if (targetFullPath !== microLocation.fullPath) {
|
|
4063
|
+
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3673
4064
|
}
|
|
4065
|
+
(_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
3674
4066
|
};
|
|
3675
4067
|
}
|
|
3676
4068
|
const pushState = getMicroHistoryMethod('pushState');
|
|
3677
4069
|
const replaceState = getMicroHistoryMethod('replaceState');
|
|
3678
|
-
if (isIframeSandbox(appName))
|
|
3679
|
-
return {
|
|
4070
|
+
if (isIframeSandbox(appName)) {
|
|
4071
|
+
return {
|
|
4072
|
+
pushState,
|
|
4073
|
+
replaceState,
|
|
4074
|
+
go(delta) {
|
|
4075
|
+
return rawHistory.go(delta);
|
|
4076
|
+
}
|
|
4077
|
+
};
|
|
4078
|
+
}
|
|
3680
4079
|
return new Proxy(rawHistory, {
|
|
3681
4080
|
get(target, key) {
|
|
3682
4081
|
if (key === 'state') {
|
|
@@ -3739,11 +4138,7 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
|
|
|
3739
4138
|
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
3740
4139
|
// navigate with native history method
|
|
3741
4140
|
nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
|
|
3742
|
-
|
|
3743
|
-
* TODO:
|
|
3744
|
-
* 1. 如果所有模式统一发送popstate事件,则isRouterModeSearch(appName)要去掉
|
|
3745
|
-
* 2. 如果发送事件,则会导致vue router-view :key='router.path'绑定,无限卸载应用,死循环
|
|
3746
|
-
*/
|
|
4141
|
+
// just search mode will dispatch native event
|
|
3747
4142
|
if (oldFullPath !== result.fullPath && isRouterModeSearch(appName)) {
|
|
3748
4143
|
dispatchNativeEvent(appName, onlyForBrowser, oldHref);
|
|
3749
4144
|
}
|
|
@@ -3760,22 +4155,22 @@ function attachRouteToBrowserURL(appName, result, state) {
|
|
|
3760
4155
|
navigateWithNativeEvent(appName, 'replaceState', result, true, state);
|
|
3761
4156
|
}
|
|
3762
4157
|
/**
|
|
3763
|
-
* When path is same, keep the
|
|
3764
|
-
* Fix bug of missing
|
|
4158
|
+
* When path is same, keep the __MICRO_APP_STATE__ in history.state
|
|
4159
|
+
* Fix bug of missing __MICRO_APP_STATE__ when base app is next.js or angular
|
|
3765
4160
|
* @param method history.pushState/replaceState
|
|
3766
4161
|
*/
|
|
3767
4162
|
function reWriteHistoryMethod(method) {
|
|
3768
4163
|
const rawWindow = globalEnv.rawWindow;
|
|
3769
4164
|
return function (...rests) {
|
|
3770
4165
|
var _a;
|
|
3771
|
-
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.
|
|
3772
|
-
(!isPlainObject(rests[0]) || !rests[0].
|
|
4166
|
+
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.__MICRO_APP_STATE__) &&
|
|
4167
|
+
(!isPlainObject(rests[0]) || !rests[0].__MICRO_APP_STATE__) &&
|
|
3773
4168
|
(isString(rests[2]) || isURL(rests[2]))) {
|
|
3774
4169
|
const currentHref = rawWindow.location.href;
|
|
3775
4170
|
const targetLocation = createURL(rests[2], currentHref);
|
|
3776
4171
|
if (targetLocation.href === currentHref) {
|
|
3777
4172
|
rests[0] = assign({}, rests[0], {
|
|
3778
|
-
|
|
4173
|
+
__MICRO_APP_STATE__: rawWindow.history.state.__MICRO_APP_STATE__,
|
|
3779
4174
|
});
|
|
3780
4175
|
}
|
|
3781
4176
|
}
|
|
@@ -3791,10 +4186,24 @@ function reWriteHistoryMethod(method) {
|
|
|
3791
4186
|
excludeHiddenApp: true,
|
|
3792
4187
|
excludePreRender: true,
|
|
3793
4188
|
}).forEach(appName => {
|
|
3794
|
-
|
|
4189
|
+
// TODO: 大部分情况下,history.pushState 都是先执行,micro-app后卸载,所以会产生一种情况:跳转到新地址后,search模式会在url上添加参数,卸载后再将参数删除,所以会导致浏览器地址闪烁,是否需要去掉这个功能
|
|
4190
|
+
if ((isRouterModeSearch(appName) || isRouterModeState(appName)) && !getMicroPathFromURL(appName)) {
|
|
3795
4191
|
const app = appInstanceMap.get(appName);
|
|
3796
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
4192
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
|
|
3797
4193
|
}
|
|
4194
|
+
if (isRouterModeCustom(appName) && !getMicroRouterInfoState(appName)) {
|
|
4195
|
+
nativeHistoryNavigate(appName, 'replaceState', rawWindow.location.href, setMicroState(appName));
|
|
4196
|
+
}
|
|
4197
|
+
// if (isRouterModeCustom(appName) || isRouterModeSearch(appName)) {
|
|
4198
|
+
/**
|
|
4199
|
+
* history.pushState/replaceState后主动触发子应用响应
|
|
4200
|
+
* 问题:子应用的卸载可能是异步的,而跳转的地址不一定在基础路径中,太快响应pushState可能会导致url地址被子应用改变或者子应用404,Promise太快卸载时出问题、setTimeout太慢keep-alive二次渲染后出问题
|
|
4201
|
+
* 1、history.pushState/replaceState执行后,子应用以异步的形式被主应用卸载,Promise响应时子应用还在,导致子应用跳转404后者浏览器url被子应用修改,产生异常
|
|
4202
|
+
* 2、keep-alive应用二次渲染时,由于setTimeout响应过慢,子应用在渲染后才接受到popstate事件,响应新的url,从而导致状态丢失
|
|
4203
|
+
* 3、同一个页面多个子应用,修改地址响应
|
|
4204
|
+
* 4、vue3跳转前会执行一次replace,有没有影响?
|
|
4205
|
+
*/
|
|
4206
|
+
// }
|
|
3798
4207
|
});
|
|
3799
4208
|
// fix bug for nest app
|
|
3800
4209
|
removeDomScope();
|
|
@@ -3802,7 +4211,7 @@ function reWriteHistoryMethod(method) {
|
|
|
3802
4211
|
}
|
|
3803
4212
|
/**
|
|
3804
4213
|
* rewrite history.pushState/replaceState
|
|
3805
|
-
* used to fix the problem that the
|
|
4214
|
+
* used to fix the problem that the __MICRO_APP_STATE__ maybe missing when mainApp navigate to same path
|
|
3806
4215
|
* e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
|
|
3807
4216
|
*/
|
|
3808
4217
|
function patchHistory() {
|
|
@@ -3825,7 +4234,7 @@ function createRouterApi() {
|
|
|
3825
4234
|
* @param state to.state
|
|
3826
4235
|
*/
|
|
3827
4236
|
function navigateWithRawHistory(appName, methodName, targetLocation, state) {
|
|
3828
|
-
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
4237
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null, targetLocation));
|
|
3829
4238
|
// clear element scope after navigate
|
|
3830
4239
|
removeDomScope();
|
|
3831
4240
|
}
|
|
@@ -3843,23 +4252,13 @@ function createRouterApi() {
|
|
|
3843
4252
|
const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
|
|
3844
4253
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3845
4254
|
if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
|
|
4255
|
+
// pure mode will not call history.pushState/replaceState
|
|
3846
4256
|
if (!isRouterModePure(appName)) {
|
|
3847
4257
|
const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
|
|
3848
4258
|
navigateWithRawHistory(appName, methodName, targetLocation, to.state);
|
|
3849
4259
|
}
|
|
3850
|
-
|
|
3851
|
-
|
|
3852
|
-
* 1. 关闭虚拟路由的跳转地址不同:baseRoute + 子应用地址,文档中要说明
|
|
3853
|
-
* 2. 关闭虚拟路由时跳转方式不同:1、基座跳转但不发送popstate事件 2、控制子应用更新location,内部发送popstate事件。
|
|
3854
|
-
* 核心思路:减小对基座的影响(子应用跳转不向基座发送popstate事件,其他操作一致),但这是必要的吗,只是多了一个触发popstate的操作
|
|
3855
|
-
* 路由优化方案有两种:
|
|
3856
|
-
* 1、减少对基座的影响,主要是解决vue循环刷新的问题
|
|
3857
|
-
* 2、全局发送popstate事件,解决主、子都是vue3的冲突问题
|
|
3858
|
-
* 两者选一个吧,如果选2,则下面这两行代码可以去掉
|
|
3859
|
-
* NOTE1: history和search模式采用2,这样可以解决vue3的问题,custom采用1,避免vue循环刷新的问题,这样在用户出现问题时各有解决方案。但反过来说,每种方案又分别导致另外的问题,不统一,导致复杂度增高
|
|
3860
|
-
* NOTE2: 关闭虚拟路由,同时发送popstate事件还是无法解决vue3的问题(毕竟history.state理论上还是会冲突),那么就没必要发送popstate事件了。
|
|
3861
|
-
*/
|
|
3862
|
-
if (isRouterModeCustom(appName) || isRouterModePure(appName)) {
|
|
4260
|
+
// only search mode will dispatch PopStateEvent to browser
|
|
4261
|
+
if (!isRouterModeSearch(appName)) {
|
|
3863
4262
|
updateMicroLocationWithEvent(appName, targetFullPath);
|
|
3864
4263
|
}
|
|
3865
4264
|
}
|
|
@@ -3884,27 +4283,18 @@ function createRouterApi() {
|
|
|
3884
4283
|
* 2. disable memory-router
|
|
3885
4284
|
*/
|
|
3886
4285
|
/**
|
|
3887
|
-
* TODO:
|
|
3888
|
-
* 1
|
|
4286
|
+
* TODO:
|
|
4287
|
+
* 1、子应用开始渲染但是还没渲染完成,调用跳转改如何处理
|
|
3889
4288
|
* 2、iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
|
|
3890
|
-
* 3、hidden app 是否支持跳转
|
|
4289
|
+
* 3、hidden app、预渲染 app 是否支持跳转 --- 支持(这里还涉及子应用内部跳转的支持)
|
|
3891
4290
|
*/
|
|
3892
4291
|
if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
|
|
3893
4292
|
const app = appInstanceMap.get(appName);
|
|
3894
4293
|
resolve(app.sandBox.sandboxReady.then(() => handleNavigate(appName, app, to, replace)));
|
|
3895
4294
|
}
|
|
3896
4295
|
else {
|
|
3897
|
-
reject(logError('
|
|
4296
|
+
reject(logError('导航失败,请确保子应用渲染后再调用此方法'));
|
|
3898
4297
|
}
|
|
3899
|
-
// /**
|
|
3900
|
-
// * app not exit or unmounted, update browser URL with replaceState
|
|
3901
|
-
// * use base app location.origin as baseURL
|
|
3902
|
-
// * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
|
|
3903
|
-
// */
|
|
3904
|
-
// /**
|
|
3905
|
-
// * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
|
|
3906
|
-
// * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
|
|
3907
|
-
// */
|
|
3908
4298
|
// const rawLocation = globalEnv.rawWindow.location
|
|
3909
4299
|
// const targetLocation = createURL(to.path, rawLocation.origin)
|
|
3910
4300
|
// const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
|
|
@@ -3977,9 +4367,9 @@ function createRouterApi() {
|
|
|
3977
4367
|
* 3. router mode is custom
|
|
3978
4368
|
*/
|
|
3979
4369
|
function commonHandlerForAttachToURL(appName) {
|
|
3980
|
-
if (isRouterModeSearch(appName)) {
|
|
4370
|
+
if (isRouterModeSearch(appName) || isRouterModeState(appName)) {
|
|
3981
4371
|
const app = appInstanceMap.get(appName);
|
|
3982
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
4372
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
|
|
3983
4373
|
}
|
|
3984
4374
|
}
|
|
3985
4375
|
/**
|
|
@@ -4078,94 +4468,6 @@ function createRouterApi() {
|
|
|
4078
4468
|
}
|
|
4079
4469
|
const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
|
|
4080
4470
|
|
|
4081
|
-
const escape2RawWindowKeys = [
|
|
4082
|
-
'getComputedStyle',
|
|
4083
|
-
'visualViewport',
|
|
4084
|
-
'matchMedia',
|
|
4085
|
-
// 'DOMParser',
|
|
4086
|
-
'ResizeObserver',
|
|
4087
|
-
'IntersectionObserver',
|
|
4088
|
-
];
|
|
4089
|
-
const escape2RawWindowRegExpKeys = [
|
|
4090
|
-
/animationFrame$/i,
|
|
4091
|
-
/mutationObserver$/i,
|
|
4092
|
-
/height$|width$/i,
|
|
4093
|
-
/offset$/i,
|
|
4094
|
-
// /event$/i,
|
|
4095
|
-
/selection$/i,
|
|
4096
|
-
/^range/i,
|
|
4097
|
-
/^screen/i,
|
|
4098
|
-
/^scroll/i,
|
|
4099
|
-
/X$|Y$/,
|
|
4100
|
-
];
|
|
4101
|
-
const uniqueDocumentElement = [
|
|
4102
|
-
'body',
|
|
4103
|
-
'head',
|
|
4104
|
-
'html',
|
|
4105
|
-
'title',
|
|
4106
|
-
];
|
|
4107
|
-
const hijackMicroLocationKeys = [
|
|
4108
|
-
'host',
|
|
4109
|
-
'hostname',
|
|
4110
|
-
'port',
|
|
4111
|
-
'protocol',
|
|
4112
|
-
'origin',
|
|
4113
|
-
];
|
|
4114
|
-
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
|
|
4115
|
-
const proxy2RawDocOrShadowKeys = [
|
|
4116
|
-
'childElementCount',
|
|
4117
|
-
'children',
|
|
4118
|
-
'firstElementChild',
|
|
4119
|
-
'firstChild',
|
|
4120
|
-
'lastElementChild',
|
|
4121
|
-
'activeElement',
|
|
4122
|
-
'fullscreenElement',
|
|
4123
|
-
'pictureInPictureElement',
|
|
4124
|
-
'pointerLockElement',
|
|
4125
|
-
'styleSheets',
|
|
4126
|
-
];
|
|
4127
|
-
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
|
|
4128
|
-
const proxy2RawDocOrShadowMethods = [
|
|
4129
|
-
'append',
|
|
4130
|
-
'contains',
|
|
4131
|
-
'replaceChildren',
|
|
4132
|
-
'createRange',
|
|
4133
|
-
'getSelection',
|
|
4134
|
-
'elementFromPoint',
|
|
4135
|
-
'elementsFromPoint',
|
|
4136
|
-
'getAnimations',
|
|
4137
|
-
];
|
|
4138
|
-
// 直接代理到原生document上 (属性)
|
|
4139
|
-
const proxy2RawDocumentKeys = [
|
|
4140
|
-
'characterSet',
|
|
4141
|
-
'compatMode',
|
|
4142
|
-
'contentType',
|
|
4143
|
-
'designMode',
|
|
4144
|
-
'dir',
|
|
4145
|
-
'doctype',
|
|
4146
|
-
'embeds',
|
|
4147
|
-
'fullscreenEnabled',
|
|
4148
|
-
'hidden',
|
|
4149
|
-
'implementation',
|
|
4150
|
-
'lastModified',
|
|
4151
|
-
'pictureInPictureEnabled',
|
|
4152
|
-
'plugins',
|
|
4153
|
-
'readyState',
|
|
4154
|
-
'referrer',
|
|
4155
|
-
'visibilityState',
|
|
4156
|
-
'fonts',
|
|
4157
|
-
];
|
|
4158
|
-
// 直接代理到原生document上 (方法)
|
|
4159
|
-
const proxy2RawDocumentMethods = [
|
|
4160
|
-
'execCommand',
|
|
4161
|
-
'createRange',
|
|
4162
|
-
'exitFullscreen',
|
|
4163
|
-
'exitPictureInPicture',
|
|
4164
|
-
'getElementsByTagNameNS',
|
|
4165
|
-
'hasFocus',
|
|
4166
|
-
'prepend',
|
|
4167
|
-
];
|
|
4168
|
-
|
|
4169
4471
|
// origin is readonly, so we ignore when updateMicroLocation
|
|
4170
4472
|
const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
|
|
4171
4473
|
// origin, fullPath is necessary for guardLocation
|
|
@@ -4209,39 +4511,47 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4209
4511
|
if (targetLocation.origin === proxyLocation.origin) {
|
|
4210
4512
|
const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
|
|
4211
4513
|
// if disable memory-router, navigate directly through rawLocation
|
|
4212
|
-
if (
|
|
4514
|
+
if (!isRouterModeCustom(appName)) {
|
|
4515
|
+
methodName = isRouterModePure(appName) ? 'replaceState' : methodName;
|
|
4213
4516
|
/**
|
|
4214
4517
|
* change hash with location.href will not trigger the browser reload
|
|
4215
4518
|
* so we use pushState & reload to imitate href behavior
|
|
4216
4519
|
* NOTE:
|
|
4217
|
-
* 1. if child app only change hash, it
|
|
4218
|
-
* 2. if address is same and has hash, it
|
|
4520
|
+
* 1. if child app only change hash, it will not reload browser
|
|
4521
|
+
* 2. if address is same and has hash, it will not add route stack
|
|
4219
4522
|
*/
|
|
4220
4523
|
if (targetLocation.pathname === proxyLocation.pathname &&
|
|
4221
4524
|
targetLocation.search === proxyLocation.search) {
|
|
4222
4525
|
let oldHref = null;
|
|
4223
|
-
if
|
|
4224
|
-
|
|
4526
|
+
// NOTE: if pathname & search is same, it should record router info to history.state in pure mode
|
|
4527
|
+
if (targetLocation.hash !== proxyLocation.hash || isRouterModePure(appName)) {
|
|
4528
|
+
// search mode only
|
|
4529
|
+
if (setMicroPathResult.isAttach2Hash) {
|
|
4225
4530
|
oldHref = rawLocation.href;
|
|
4226
|
-
|
|
4531
|
+
}
|
|
4532
|
+
// if router mode is pure and targetLocation.hash exist, it will not call nativeHistoryNavigate
|
|
4533
|
+
if (!isRouterModePure(appName) || !targetLocation.hash) {
|
|
4534
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4535
|
+
}
|
|
4227
4536
|
}
|
|
4228
4537
|
if (targetLocation.hash) {
|
|
4229
|
-
|
|
4538
|
+
if (isRouterModeSearch(appName)) {
|
|
4539
|
+
dispatchNativeEvent(appName, false, oldHref);
|
|
4540
|
+
}
|
|
4541
|
+
else {
|
|
4542
|
+
updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
|
|
4543
|
+
}
|
|
4230
4544
|
}
|
|
4231
4545
|
else {
|
|
4232
4546
|
reload();
|
|
4233
4547
|
}
|
|
4234
4548
|
return void 0;
|
|
4235
|
-
/**
|
|
4236
|
-
* when baseApp is hash router, address change of child can not reload browser
|
|
4237
|
-
* so we imitate behavior of browser (reload) manually
|
|
4238
|
-
*/
|
|
4239
|
-
}
|
|
4240
|
-
else if (setMicroPathResult.isAttach2Hash) {
|
|
4241
|
-
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
4242
|
-
reload();
|
|
4243
|
-
return void 0;
|
|
4244
4549
|
}
|
|
4550
|
+
// when pathname or search change, simulate behavior of browser (reload) manually
|
|
4551
|
+
// TODO: state模式下pushState会带上上一个页面的state,会不会有问题,尤其是vue3,应不应该将主应用的state设置为null
|
|
4552
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4553
|
+
reload();
|
|
4554
|
+
return void 0;
|
|
4245
4555
|
}
|
|
4246
4556
|
return setMicroPathResult.fullPath;
|
|
4247
4557
|
}
|
|
@@ -4266,7 +4576,9 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4266
4576
|
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
4267
4577
|
* search: ?query ==> ?query#hash
|
|
4268
4578
|
*/
|
|
4269
|
-
nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key]
|
|
4579
|
+
nativeHistoryNavigate(appName, (targetLocation[key] === proxyLocation[key] || isRouterModePure(appName))
|
|
4580
|
+
? 'replaceState'
|
|
4581
|
+
: 'pushState', setMicroPathToURL(appName, targetLocation).fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4270
4582
|
reload();
|
|
4271
4583
|
}
|
|
4272
4584
|
}
|
|
@@ -4305,17 +4617,27 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4305
4617
|
return target;
|
|
4306
4618
|
if (key === 'fullPath')
|
|
4307
4619
|
return target.fullPath;
|
|
4308
|
-
|
|
4309
|
-
|
|
4310
|
-
|
|
4311
|
-
|
|
4312
|
-
|
|
4313
|
-
|
|
4314
|
-
|
|
4620
|
+
/**
|
|
4621
|
+
* Special keys: host, hostname, port, protocol, origin, href
|
|
4622
|
+
* NOTE:
|
|
4623
|
+
* 1. In native mode this keys point to browser, in other mode this keys point to child app origin
|
|
4624
|
+
* 2. In iframe sandbox, iframe.src is base app address, so origin points to the browser by default, we need to replace it with child app origin
|
|
4625
|
+
* 3. In other modes, origin points to child app
|
|
4626
|
+
*/
|
|
4627
|
+
if (HIJACK_LOCATION_KEYS.includes(key)) {
|
|
4628
|
+
if (isRouterModeNative(appName)) {
|
|
4629
|
+
return rawLocation[key];
|
|
4630
|
+
}
|
|
4631
|
+
if (isIframe) {
|
|
4315
4632
|
return childStaticLocation[key];
|
|
4316
4633
|
}
|
|
4317
|
-
|
|
4318
|
-
|
|
4634
|
+
}
|
|
4635
|
+
if (key === 'href') {
|
|
4636
|
+
if (isRouterModeNative(appName)) {
|
|
4637
|
+
return target[key].replace(target.origin, rawLocation.origin);
|
|
4638
|
+
}
|
|
4639
|
+
if (isIframe) {
|
|
4640
|
+
// target may be deleted
|
|
4319
4641
|
return target[key].replace(browserHost, childHost);
|
|
4320
4642
|
}
|
|
4321
4643
|
}
|
|
@@ -4365,7 +4687,12 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4365
4687
|
const targetLocation = createURL(targetPath, url);
|
|
4366
4688
|
// The same hash will not trigger popStateEvent
|
|
4367
4689
|
if (targetLocation.hash !== proxyLocation.hash) {
|
|
4368
|
-
|
|
4690
|
+
if (!isRouterModePure(appName)) {
|
|
4691
|
+
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, null, targetLocation));
|
|
4692
|
+
}
|
|
4693
|
+
if (!isRouterModeSearch(appName)) {
|
|
4694
|
+
updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
|
|
4695
|
+
}
|
|
4369
4696
|
}
|
|
4370
4697
|
}
|
|
4371
4698
|
}
|
|
@@ -4407,12 +4734,12 @@ function autoTriggerNavigationGuard(appName, microLocation) {
|
|
|
4407
4734
|
* @param microLocation micro app location
|
|
4408
4735
|
* @param type auto prevent
|
|
4409
4736
|
*/
|
|
4410
|
-
function updateMicroLocation(appName,
|
|
4737
|
+
function updateMicroLocation(appName, targetFullPath, microLocation, type) {
|
|
4411
4738
|
var _a;
|
|
4412
4739
|
// record old values of microLocation to `from`
|
|
4413
4740
|
const from = createGuardLocation(appName, microLocation);
|
|
4414
4741
|
// if is iframeSandbox, microLocation muse be rawLocation of iframe, not proxyLocation
|
|
4415
|
-
const newLocation = createURL(
|
|
4742
|
+
const newLocation = createURL(targetFullPath, microLocation.href);
|
|
4416
4743
|
if (isIframeSandbox(appName)) {
|
|
4417
4744
|
const microAppWindow = appInstanceMap.get(appName).sandBox.microAppWindow;
|
|
4418
4745
|
(_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
|
|
@@ -4424,6 +4751,20 @@ function updateMicroLocation(appName, path, microLocation, type) {
|
|
|
4424
4751
|
}
|
|
4425
4752
|
microLocation.self.href = targetHref;
|
|
4426
4753
|
}
|
|
4754
|
+
/**
|
|
4755
|
+
* native模式从state中取值,而浏览器地址的修改无法控制,很可能出现浏览器地址和__MICRO_APP_STATE__不一致的情况
|
|
4756
|
+
* 尤其是在初始化和前进后退时,由于vue-router4会主动修改url地址,倒是上述情况经常出现
|
|
4757
|
+
* 为了结局这个问题,在子应用初始化和响应popstate事件后,判断__MICRO_APP_STATE__和浏览器地址是否一致,如果不一致,则将浏览器地址更新为__MICRO_APP_STATE__的地址
|
|
4758
|
+
* 说明:
|
|
4759
|
+
* 1、如果__MICRO_APP_STATE__和url不一样,那么更新url的操作是对的,否则会产生url和渲染页面不一致的问题,开发者会更加困惑
|
|
4760
|
+
* 2、当native模式有多个子应用同时存在,其中一个修改url地址,另外一个并不会改变__MICRO_APP_STATE__,刷新就产生问题,不一致,第二是根据谁更新url?
|
|
4761
|
+
*/
|
|
4762
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
4763
|
+
if (isRouterModeCustom(appName) &&
|
|
4764
|
+
(targetFullPath !== rawLocation.pathname + rawLocation.search + rawLocation.hash) &&
|
|
4765
|
+
type !== 'prevent') {
|
|
4766
|
+
nativeHistoryNavigate(appName, 'replaceState', targetFullPath, globalEnv.rawWindow.history.state);
|
|
4767
|
+
}
|
|
4427
4768
|
// update latest values of microLocation to `to`
|
|
4428
4769
|
const to = createGuardLocation(appName, microLocation);
|
|
4429
4770
|
// The hook called only when fullPath changed
|
|
@@ -4432,11 +4773,6 @@ function updateMicroLocation(appName, path, microLocation, type) {
|
|
|
4432
4773
|
}
|
|
4433
4774
|
}
|
|
4434
4775
|
|
|
4435
|
-
/**
|
|
4436
|
-
* TODO: 关于关闭虚拟路由系统的custom、history模式
|
|
4437
|
-
* 1. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
|
|
4438
|
-
* 2. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
|
|
4439
|
-
*/
|
|
4440
4776
|
/**
|
|
4441
4777
|
* The router system has two operations: read and write
|
|
4442
4778
|
* Read through location and write through history & location
|
|
@@ -4461,6 +4797,9 @@ function initRouteStateWithURL(appName, microLocation, defaultPage) {
|
|
|
4461
4797
|
const microPath = getMicroPathFromURL(appName);
|
|
4462
4798
|
if (microPath) {
|
|
4463
4799
|
updateMicroLocation(appName, microPath, microLocation, 'auto');
|
|
4800
|
+
if (isRouterModePure(appName)) {
|
|
4801
|
+
removePathFromBrowser(appName);
|
|
4802
|
+
}
|
|
4464
4803
|
}
|
|
4465
4804
|
else {
|
|
4466
4805
|
updateBrowserURLWithLocation(appName, microLocation, defaultPage);
|
|
@@ -4478,7 +4817,7 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4478
4817
|
updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
|
|
4479
4818
|
if (!isRouterModePure(appName)) {
|
|
4480
4819
|
// attach microApp route info to browser URL
|
|
4481
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null));
|
|
4820
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null, microLocation));
|
|
4482
4821
|
}
|
|
4483
4822
|
// trigger guards after change browser URL
|
|
4484
4823
|
autoTriggerNavigationGuard(appName, microLocation);
|
|
@@ -4491,14 +4830,13 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4491
4830
|
* @param keepRouteState keep-router-state is only used to control whether to clear the location of microApp, default is false
|
|
4492
4831
|
*/
|
|
4493
4832
|
function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
|
|
4494
|
-
|
|
4495
|
-
|
|
4496
|
-
|
|
4497
|
-
|
|
4498
|
-
|
|
4499
|
-
|
|
4500
|
-
|
|
4501
|
-
}
|
|
4833
|
+
// TODO: keep-router-state 功能太弱,是否可以增加优先级,或者去掉
|
|
4834
|
+
if (!keepRouteState && !isRouterModeCustom(appName)) {
|
|
4835
|
+
const { pathname, search, hash } = createURL(url);
|
|
4836
|
+
updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
|
|
4837
|
+
}
|
|
4838
|
+
if (!isRouterModePure(appName)) {
|
|
4839
|
+
removePathFromBrowser(appName);
|
|
4502
4840
|
}
|
|
4503
4841
|
clearRouterWhenUnmount(appName);
|
|
4504
4842
|
}
|
|
@@ -4510,130 +4848,6 @@ function removePathFromBrowser(appName) {
|
|
|
4510
4848
|
attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
4511
4849
|
}
|
|
4512
4850
|
|
|
4513
|
-
class BaseSandbox {
|
|
4514
|
-
constructor() {
|
|
4515
|
-
// keys that can only assigned to rawWindow
|
|
4516
|
-
this.rawWindowScopeKeyList = [
|
|
4517
|
-
'location',
|
|
4518
|
-
];
|
|
4519
|
-
// keys that can escape to rawWindow
|
|
4520
|
-
this.staticEscapeProperties = [
|
|
4521
|
-
'System',
|
|
4522
|
-
'__cjsWrapper',
|
|
4523
|
-
];
|
|
4524
|
-
// keys that scoped in child app
|
|
4525
|
-
this.staticScopeProperties = [
|
|
4526
|
-
'webpackJsonp',
|
|
4527
|
-
'webpackHotUpdate',
|
|
4528
|
-
'Vue',
|
|
4529
|
-
// TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
|
|
4530
|
-
'onpopstate',
|
|
4531
|
-
'onhashchange',
|
|
4532
|
-
];
|
|
4533
|
-
// Properties that can only get and set in microAppWindow, will not escape to rawWindow
|
|
4534
|
-
this.scopeProperties = Array.from(this.staticScopeProperties);
|
|
4535
|
-
// Properties that can be escape to rawWindow
|
|
4536
|
-
this.escapeProperties = [];
|
|
4537
|
-
// Properties newly added to microAppWindow
|
|
4538
|
-
this.injectedKeys = new Set();
|
|
4539
|
-
// Properties escape to rawWindow, cleared when unmount
|
|
4540
|
-
this.escapeKeys = new Set();
|
|
4541
|
-
this.injectReactHMRProperty();
|
|
4542
|
-
}
|
|
4543
|
-
// adapter for react
|
|
4544
|
-
injectReactHMRProperty() {
|
|
4545
|
-
if ((process.env.NODE_ENV !== 'production')) {
|
|
4546
|
-
// react child in non-react env
|
|
4547
|
-
this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
|
|
4548
|
-
// in react parent
|
|
4549
|
-
if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
|
|
4550
|
-
this.staticScopeProperties = this.staticScopeProperties.concat([
|
|
4551
|
-
'__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
|
|
4552
|
-
'__reactRefreshInjected',
|
|
4553
|
-
]);
|
|
4554
|
-
}
|
|
4555
|
-
}
|
|
4556
|
-
}
|
|
4557
|
-
}
|
|
4558
|
-
/**
|
|
4559
|
-
* TODO:
|
|
4560
|
-
* 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
|
|
4561
|
-
* 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
|
|
4562
|
-
* 修改时机:在iframe沙箱支持插件后再修改
|
|
4563
|
-
*/
|
|
4564
|
-
class CustomWindow {
|
|
4565
|
-
}
|
|
4566
|
-
// Fix conflict of babel-polyfill@6.x
|
|
4567
|
-
function fixBabelPolyfill6() {
|
|
4568
|
-
if (globalEnv.rawWindow._babelPolyfill)
|
|
4569
|
-
globalEnv.rawWindow._babelPolyfill = false;
|
|
4570
|
-
}
|
|
4571
|
-
/**
|
|
4572
|
-
* Fix error of hot reload when parent&child created by create-react-app in development environment
|
|
4573
|
-
* Issue: https://github.com/micro-zoe/micro-app/issues/382
|
|
4574
|
-
*/
|
|
4575
|
-
function fixReactHMRConflict(app) {
|
|
4576
|
-
var _a;
|
|
4577
|
-
if ((process.env.NODE_ENV !== 'production')) {
|
|
4578
|
-
const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
4579
|
-
const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
4580
|
-
if (rawReactErrorHook && childReactErrorHook) {
|
|
4581
|
-
globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
|
|
4582
|
-
defer(() => {
|
|
4583
|
-
globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
|
|
4584
|
-
});
|
|
4585
|
-
}
|
|
4586
|
-
}
|
|
4587
|
-
}
|
|
4588
|
-
/**
|
|
4589
|
-
* update dom tree of target dom
|
|
4590
|
-
* @param container target dom
|
|
4591
|
-
* @param appName app name
|
|
4592
|
-
*/
|
|
4593
|
-
function patchElementTree(container, appName) {
|
|
4594
|
-
const children = Array.from(container.children);
|
|
4595
|
-
children.length && children.forEach((child) => {
|
|
4596
|
-
patchElementTree(child, appName);
|
|
4597
|
-
});
|
|
4598
|
-
for (const child of children) {
|
|
4599
|
-
updateElementInfo(child, appName);
|
|
4600
|
-
}
|
|
4601
|
-
}
|
|
4602
|
-
/**
|
|
4603
|
-
* rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
|
|
4604
|
-
* @param node target node
|
|
4605
|
-
* @param appName app name
|
|
4606
|
-
* @returns target node
|
|
4607
|
-
*/
|
|
4608
|
-
function updateElementInfo(node, appName) {
|
|
4609
|
-
var _a, _b;
|
|
4610
|
-
const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
|
|
4611
|
-
if (isNode(node) &&
|
|
4612
|
-
!node.__MICRO_APP_NAME__ &&
|
|
4613
|
-
!node.__PURE_ELEMENT__ &&
|
|
4614
|
-
proxyWindow) {
|
|
4615
|
-
/**
|
|
4616
|
-
* TODO:
|
|
4617
|
-
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
4618
|
-
* 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
|
|
4619
|
-
* 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
|
|
4620
|
-
*/
|
|
4621
|
-
rawDefineProperties(node, {
|
|
4622
|
-
baseURI: {
|
|
4623
|
-
configurable: true,
|
|
4624
|
-
// if disable-memory-router or router-mode='disable', href point to base app
|
|
4625
|
-
get: () => proxyWindow.location.href,
|
|
4626
|
-
},
|
|
4627
|
-
__MICRO_APP_NAME__: {
|
|
4628
|
-
configurable: true,
|
|
4629
|
-
writable: true,
|
|
4630
|
-
value: appName,
|
|
4631
|
-
},
|
|
4632
|
-
});
|
|
4633
|
-
}
|
|
4634
|
-
return node;
|
|
4635
|
-
}
|
|
4636
|
-
|
|
4637
4851
|
/**
|
|
4638
4852
|
* https://developer.mozilla.org/en-US/docs/Web/API/fetch
|
|
4639
4853
|
* Promise<Response> fetch(input[, init])
|
|
@@ -4738,7 +4952,7 @@ function useMicroEventSource() {
|
|
|
4738
4952
|
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
4739
4953
|
class WithSandBox extends BaseSandbox {
|
|
4740
4954
|
constructor(appName, url) {
|
|
4741
|
-
super();
|
|
4955
|
+
super(appName, url);
|
|
4742
4956
|
this.active = false;
|
|
4743
4957
|
this.microAppWindow = new CustomWindow(); // Proxy target
|
|
4744
4958
|
this.patchWith((resolve) => {
|
|
@@ -4819,6 +5033,7 @@ class WithSandBox extends BaseSandbox {
|
|
|
4819
5033
|
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
4820
5034
|
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
4821
5035
|
* 3. umd mode will not delete global keys
|
|
5036
|
+
* 4. mount & unmount hook should delete in default mode when stop
|
|
4822
5037
|
*/
|
|
4823
5038
|
if (!umdMode || destroy) {
|
|
4824
5039
|
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
@@ -4830,6 +5045,7 @@ class WithSandBox extends BaseSandbox {
|
|
|
4830
5045
|
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
4831
5046
|
});
|
|
4832
5047
|
this.escapeKeys.clear();
|
|
5048
|
+
this.clearHijackUmdHooks();
|
|
4833
5049
|
}
|
|
4834
5050
|
if (--globalEnv.activeSandbox === 0) {
|
|
4835
5051
|
releasePatchElementAndDocument();
|
|
@@ -4862,6 +5078,7 @@ class WithSandBox extends BaseSandbox {
|
|
|
4862
5078
|
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
4863
5079
|
removeDomScope,
|
|
4864
5080
|
pureCreateElement,
|
|
5081
|
+
location: microAppWindow.location,
|
|
4865
5082
|
router,
|
|
4866
5083
|
});
|
|
4867
5084
|
}
|
|
@@ -5143,10 +5360,49 @@ class WithSandBox extends BaseSandbox {
|
|
|
5143
5360
|
* action before exec scripts when mount
|
|
5144
5361
|
* Actions:
|
|
5145
5362
|
* 1. patch static elements from html
|
|
5363
|
+
* 2. hijack umd hooks -- mount, unmount, micro-app-appName
|
|
5146
5364
|
* @param container micro app container
|
|
5147
5365
|
*/
|
|
5148
|
-
|
|
5366
|
+
actionsBeforeExecScripts(container, handleUmdHooks) {
|
|
5149
5367
|
this.patchStaticElement(container);
|
|
5368
|
+
this.clearHijackUmdHooks = this.hijackUmdHooks(this.appName, this.microAppWindow, handleUmdHooks);
|
|
5369
|
+
}
|
|
5370
|
+
// hijack mount, unmount, micro-app-appName hook to microAppWindow
|
|
5371
|
+
hijackUmdHooks(appName, microAppWindow, handleUmdHooks) {
|
|
5372
|
+
let mount, unmount, microAppLibrary;
|
|
5373
|
+
rawDefineProperties(microAppWindow, {
|
|
5374
|
+
mount: {
|
|
5375
|
+
configurable: true,
|
|
5376
|
+
get: () => mount,
|
|
5377
|
+
set: (value) => {
|
|
5378
|
+
if (this.active && isFunction(value) && !mount) {
|
|
5379
|
+
handleUmdHooks(mount = value, unmount);
|
|
5380
|
+
}
|
|
5381
|
+
}
|
|
5382
|
+
},
|
|
5383
|
+
unmount: {
|
|
5384
|
+
configurable: true,
|
|
5385
|
+
get: () => unmount,
|
|
5386
|
+
set: (value) => {
|
|
5387
|
+
if (this.active && isFunction(value) && !unmount) {
|
|
5388
|
+
handleUmdHooks(mount, unmount = value);
|
|
5389
|
+
}
|
|
5390
|
+
}
|
|
5391
|
+
},
|
|
5392
|
+
[`micro-app-${appName}`]: {
|
|
5393
|
+
configurable: true,
|
|
5394
|
+
get: () => microAppLibrary,
|
|
5395
|
+
set: (value) => {
|
|
5396
|
+
if (this.active && isPlainObject(value) && !microAppLibrary) {
|
|
5397
|
+
microAppLibrary = value;
|
|
5398
|
+
handleUmdHooks(microAppLibrary.mount, microAppLibrary.unmount);
|
|
5399
|
+
}
|
|
5400
|
+
}
|
|
5401
|
+
}
|
|
5402
|
+
});
|
|
5403
|
+
return () => {
|
|
5404
|
+
mount = unmount = microAppLibrary = null;
|
|
5405
|
+
};
|
|
5150
5406
|
}
|
|
5151
5407
|
setStaticAppState(state) {
|
|
5152
5408
|
this.microAppWindow.__MICRO_APP_STATE__ = state;
|
|
@@ -5155,13 +5411,29 @@ class WithSandBox extends BaseSandbox {
|
|
|
5155
5411
|
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5156
5412
|
|
|
5157
5413
|
function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
5414
|
+
const rawHistory = globalEnv.rawWindow.history;
|
|
5158
5415
|
const childStaticLocation = createURL(url);
|
|
5159
5416
|
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
5160
5417
|
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
5161
5418
|
// rewrite microAppWindow.history
|
|
5162
5419
|
const microHistory = microAppWindow.history;
|
|
5420
|
+
// save history.replaceState, it will be used in updateMicroLocation
|
|
5163
5421
|
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5422
|
+
// rewrite microAppWindow.history
|
|
5164
5423
|
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5424
|
+
// scrollRestoration proxy to rawHistory
|
|
5425
|
+
rawDefineProperties(microHistory, {
|
|
5426
|
+
scrollRestoration: {
|
|
5427
|
+
configurable: true,
|
|
5428
|
+
enumerable: true,
|
|
5429
|
+
get() {
|
|
5430
|
+
return rawHistory.scrollRestoration;
|
|
5431
|
+
},
|
|
5432
|
+
set(value) {
|
|
5433
|
+
rawHistory.scrollRestoration = value;
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
});
|
|
5165
5437
|
/**
|
|
5166
5438
|
* Init microLocation before exec sandbox.start
|
|
5167
5439
|
* NOTE:
|
|
@@ -5173,6 +5445,87 @@ function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
|
5173
5445
|
return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
5174
5446
|
}
|
|
5175
5447
|
|
|
5448
|
+
const escape2RawWindowKeys = [
|
|
5449
|
+
'getComputedStyle',
|
|
5450
|
+
// FIX ISSUE: https://github.com/micro-zoe/micro-app/issues/1292
|
|
5451
|
+
'DOMParser',
|
|
5452
|
+
'visualViewport',
|
|
5453
|
+
'matchMedia',
|
|
5454
|
+
'ResizeObserver',
|
|
5455
|
+
'IntersectionObserver',
|
|
5456
|
+
];
|
|
5457
|
+
const escape2RawWindowRegExpKeys = [
|
|
5458
|
+
/animationFrame$/i,
|
|
5459
|
+
/mutationObserver$/i,
|
|
5460
|
+
/height$|width$/i,
|
|
5461
|
+
/offset$/i,
|
|
5462
|
+
/selection$/i,
|
|
5463
|
+
/^range/i,
|
|
5464
|
+
/^screen/i,
|
|
5465
|
+
/^scroll/i,
|
|
5466
|
+
/X$|Y$/,
|
|
5467
|
+
];
|
|
5468
|
+
const uniqueDocumentElement = [
|
|
5469
|
+
'body',
|
|
5470
|
+
'head',
|
|
5471
|
+
'html',
|
|
5472
|
+
'title',
|
|
5473
|
+
];
|
|
5474
|
+
// proxy to shadowRoot or rawDocument (property)
|
|
5475
|
+
const proxy2RawDocOrShadowKeys = [
|
|
5476
|
+
'childElementCount',
|
|
5477
|
+
'children',
|
|
5478
|
+
'firstElementChild',
|
|
5479
|
+
'firstChild',
|
|
5480
|
+
'lastElementChild',
|
|
5481
|
+
'activeElement',
|
|
5482
|
+
'fullscreenElement',
|
|
5483
|
+
'pictureInPictureElement',
|
|
5484
|
+
'pointerLockElement',
|
|
5485
|
+
'styleSheets',
|
|
5486
|
+
];
|
|
5487
|
+
// proxy to shadowRoot or rawDocument (method)
|
|
5488
|
+
const proxy2RawDocOrShadowMethods = [
|
|
5489
|
+
'append',
|
|
5490
|
+
'contains',
|
|
5491
|
+
'replaceChildren',
|
|
5492
|
+
'createRange',
|
|
5493
|
+
'getSelection',
|
|
5494
|
+
'elementFromPoint',
|
|
5495
|
+
'elementsFromPoint',
|
|
5496
|
+
'getAnimations',
|
|
5497
|
+
];
|
|
5498
|
+
// proxy to rawDocument (property)
|
|
5499
|
+
const proxy2RawDocumentKeys = [
|
|
5500
|
+
'characterSet',
|
|
5501
|
+
'compatMode',
|
|
5502
|
+
'contentType',
|
|
5503
|
+
'designMode',
|
|
5504
|
+
'dir',
|
|
5505
|
+
'doctype',
|
|
5506
|
+
'embeds',
|
|
5507
|
+
'fullscreenEnabled',
|
|
5508
|
+
'hidden',
|
|
5509
|
+
'implementation',
|
|
5510
|
+
'lastModified',
|
|
5511
|
+
'pictureInPictureEnabled',
|
|
5512
|
+
'plugins',
|
|
5513
|
+
'readyState',
|
|
5514
|
+
'referrer',
|
|
5515
|
+
'visibilityState',
|
|
5516
|
+
'fonts',
|
|
5517
|
+
];
|
|
5518
|
+
// proxy to rawDocument (method)
|
|
5519
|
+
const proxy2RawDocumentMethods = [
|
|
5520
|
+
'execCommand',
|
|
5521
|
+
'createRange',
|
|
5522
|
+
'exitFullscreen',
|
|
5523
|
+
'exitPictureInPicture',
|
|
5524
|
+
'getElementsByTagNameNS',
|
|
5525
|
+
'hasFocus',
|
|
5526
|
+
'prepend',
|
|
5527
|
+
];
|
|
5528
|
+
|
|
5176
5529
|
/**
|
|
5177
5530
|
* patch window of child app
|
|
5178
5531
|
* @param appName app name
|
|
@@ -5220,7 +5573,41 @@ function patchWindowProperty$1(appName, microAppWindow) {
|
|
|
5220
5573
|
}
|
|
5221
5574
|
return false;
|
|
5222
5575
|
});
|
|
5223
|
-
|
|
5576
|
+
/**
|
|
5577
|
+
* In FireFox, iframe Element.prototype will point to native Element.prototype after insert to document
|
|
5578
|
+
* Rewrite all constructor's Symbol.hasInstance of iframeWindow
|
|
5579
|
+
* NOTE:
|
|
5580
|
+
* 1. native event instanceof iframe window.Event
|
|
5581
|
+
* 2. native node instanceof iframe window.Node
|
|
5582
|
+
* 3. native element instanceof iframe window.Element
|
|
5583
|
+
* 4. native url instanceof iframe window.URL
|
|
5584
|
+
* ...
|
|
5585
|
+
*/
|
|
5586
|
+
if (isConstructor(microAppWindow[key]) && key in rawWindow) {
|
|
5587
|
+
rawDefineProperty(microAppWindow[key], Symbol.hasInstance, {
|
|
5588
|
+
configurable: true,
|
|
5589
|
+
enumerable: false,
|
|
5590
|
+
value(target) {
|
|
5591
|
+
return target instanceof rawWindow[key] || instanceOf(target, microAppWindow[key]);
|
|
5592
|
+
},
|
|
5593
|
+
});
|
|
5594
|
+
}
|
|
5595
|
+
// hijackInstanceOfWindowRegExpKeys.some((reg: RegExp) => {
|
|
5596
|
+
// if (reg.test(key) && key in rawWindow) {
|
|
5597
|
+
// rawDefineProperty(microAppWindow[key], Symbol.hasInstance, {
|
|
5598
|
+
// configurable: true,
|
|
5599
|
+
// enumerable: false,
|
|
5600
|
+
// value: (target: unknown) => {
|
|
5601
|
+
// return target instanceof rawWindow[key]
|
|
5602
|
+
// ? true
|
|
5603
|
+
// : instanceOf(target, microAppWindow[key])
|
|
5604
|
+
// },
|
|
5605
|
+
// })
|
|
5606
|
+
// return true
|
|
5607
|
+
// }
|
|
5608
|
+
// return false
|
|
5609
|
+
// })
|
|
5610
|
+
return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_IFRAME.includes(key);
|
|
5224
5611
|
})
|
|
5225
5612
|
.forEach((eventName) => {
|
|
5226
5613
|
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microAppWindow, eventName) || {
|
|
@@ -5305,11 +5692,15 @@ function createProxyWindow$1(microAppWindow, sandbox) {
|
|
|
5305
5692
|
sandbox.proxyWindow = proxyWindow;
|
|
5306
5693
|
}
|
|
5307
5694
|
function patchWindowEffect$1(microAppWindow) {
|
|
5308
|
-
const { rawWindow, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5695
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent } = globalEnv;
|
|
5309
5696
|
const eventListenerMap = new Map();
|
|
5310
5697
|
const sstEventListenerMap = new Map();
|
|
5311
5698
|
function getEventTarget(type) {
|
|
5312
|
-
|
|
5699
|
+
/**
|
|
5700
|
+
* TODO: SCOPE_WINDOW_EVENT_OF_IFRAME的事件非常少,有可能导致问题
|
|
5701
|
+
* 1、一些未知的需要绑定到iframe的事件被错误的绑定到原生window上
|
|
5702
|
+
*/
|
|
5703
|
+
return SCOPE_WINDOW_EVENT_OF_IFRAME.includes(type) ? microAppWindow : rawWindow;
|
|
5313
5704
|
}
|
|
5314
5705
|
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
5315
5706
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
@@ -5330,6 +5721,9 @@ function patchWindowEffect$1(microAppWindow) {
|
|
|
5330
5721
|
}
|
|
5331
5722
|
rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
|
|
5332
5723
|
};
|
|
5724
|
+
microAppWindow.dispatchEvent = function (event) {
|
|
5725
|
+
return rawDispatchEvent.call(getEventTarget(event === null || event === void 0 ? void 0 : event.type), event);
|
|
5726
|
+
};
|
|
5333
5727
|
const reset = () => {
|
|
5334
5728
|
sstEventListenerMap.clear();
|
|
5335
5729
|
};
|
|
@@ -5441,34 +5835,43 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5441
5835
|
const element = rawMicroCreateComment.call(this, data);
|
|
5442
5836
|
return updateElementInfo(element, appName);
|
|
5443
5837
|
};
|
|
5444
|
-
function
|
|
5445
|
-
|
|
5838
|
+
function getBindTarget(target) {
|
|
5839
|
+
/**
|
|
5840
|
+
* handler for:
|
|
5841
|
+
* 1. document.getElementsByTagName('head')[0].querySelector('script')
|
|
5842
|
+
* 2. document.querySelector('body').querySelectorAll('script')
|
|
5843
|
+
* ...
|
|
5844
|
+
*/
|
|
5845
|
+
throttleDeferForIframeAppName(appName);
|
|
5846
|
+
// DOMParser.document !== microDocument
|
|
5847
|
+
return microDocument === target ? rawDocument : target;
|
|
5446
5848
|
}
|
|
5447
5849
|
// query element👇
|
|
5448
5850
|
function querySelector(selectors) {
|
|
5449
|
-
var _a, _b;
|
|
5851
|
+
var _a, _b, _c;
|
|
5852
|
+
const _this = getBindTarget(this);
|
|
5450
5853
|
if (!selectors ||
|
|
5451
5854
|
isUniqueElement(selectors) ||
|
|
5452
|
-
|
|
5453
|
-
const _this = getDefaultRawTarget(this);
|
|
5855
|
+
rawDocument !== _this) {
|
|
5454
5856
|
return rawMicroQuerySelector.call(_this, selectors);
|
|
5455
5857
|
}
|
|
5456
|
-
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
5858
|
+
return (_c = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : rawMicroQuerySelector.call(microDocument, selectors)) !== null && _c !== void 0 ? _c : null;
|
|
5457
5859
|
}
|
|
5458
5860
|
function querySelectorAll(selectors) {
|
|
5459
5861
|
var _a, _b;
|
|
5862
|
+
const _this = getBindTarget(this);
|
|
5460
5863
|
if (!selectors ||
|
|
5461
5864
|
isUniqueElement(selectors) ||
|
|
5462
|
-
|
|
5463
|
-
const _this = getDefaultRawTarget(this);
|
|
5865
|
+
rawDocument !== _this) {
|
|
5464
5866
|
return rawMicroQuerySelectorAll.call(_this, selectors);
|
|
5465
5867
|
}
|
|
5466
|
-
|
|
5868
|
+
const result = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
5869
|
+
return result.length ? result : rawMicroQuerySelectorAll.call(microDocument, selectors);
|
|
5467
5870
|
}
|
|
5468
5871
|
microRootDocument.prototype.querySelector = querySelector;
|
|
5469
5872
|
microRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
5470
5873
|
microRootDocument.prototype.getElementById = function getElementById(key) {
|
|
5471
|
-
const _this =
|
|
5874
|
+
const _this = getBindTarget(this);
|
|
5472
5875
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5473
5876
|
return rawMicroGetElementById.call(_this, key);
|
|
5474
5877
|
}
|
|
@@ -5480,7 +5883,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5480
5883
|
}
|
|
5481
5884
|
};
|
|
5482
5885
|
microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
5483
|
-
const _this =
|
|
5886
|
+
const _this = getBindTarget(this);
|
|
5484
5887
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5485
5888
|
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5486
5889
|
}
|
|
@@ -5492,7 +5895,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5492
5895
|
}
|
|
5493
5896
|
};
|
|
5494
5897
|
microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
5495
|
-
const _this =
|
|
5898
|
+
const _this = getBindTarget(this);
|
|
5496
5899
|
if (isUniqueElement(key) ||
|
|
5497
5900
|
isInvalidQuerySelectorKey(key)) {
|
|
5498
5901
|
return rawMicroGetElementsByTagName.call(_this, key);
|
|
@@ -5508,7 +5911,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5508
5911
|
}
|
|
5509
5912
|
};
|
|
5510
5913
|
microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
|
|
5511
|
-
const _this =
|
|
5914
|
+
const _this = getBindTarget(this);
|
|
5512
5915
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5513
5916
|
return rawMicroGetElementsByName.call(_this, key);
|
|
5514
5917
|
}
|
|
@@ -5575,7 +5978,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
|
|
|
5575
5978
|
enumerable: true,
|
|
5576
5979
|
configurable: true,
|
|
5577
5980
|
get: () => {
|
|
5578
|
-
|
|
5981
|
+
throttleDeferForIframeAppName(appName);
|
|
5579
5982
|
return rawDocument[tagName];
|
|
5580
5983
|
},
|
|
5581
5984
|
set: (value) => { rawDocument[tagName] = value; },
|
|
@@ -5583,7 +5986,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
|
|
|
5583
5986
|
});
|
|
5584
5987
|
}
|
|
5585
5988
|
function patchDocumentEffect(appName, microAppWindow) {
|
|
5586
|
-
const { rawDocument, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5989
|
+
const { rawDocument, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent } = globalEnv;
|
|
5587
5990
|
const eventListenerMap = new Map();
|
|
5588
5991
|
const sstEventListenerMap = new Map();
|
|
5589
5992
|
let onClickHandler = null;
|
|
@@ -5613,6 +6016,9 @@ function patchDocumentEffect(appName, microAppWindow) {
|
|
|
5613
6016
|
const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
|
|
5614
6017
|
rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5615
6018
|
};
|
|
6019
|
+
microRootDocument.prototype.dispatchEvent = function (event) {
|
|
6020
|
+
return rawDispatchEvent.call(getEventTarget(event === null || event === void 0 ? void 0 : event.type, this), event);
|
|
6021
|
+
};
|
|
5616
6022
|
// 重新定义microRootDocument.prototype 上的on开头方法
|
|
5617
6023
|
function createSetterHandler(eventName) {
|
|
5618
6024
|
if (eventName === 'onclick') {
|
|
@@ -5733,12 +6139,18 @@ function patchElement(appName, url, microAppWindow, sandbox) {
|
|
|
5733
6139
|
patchIframeNode(appName, microAppWindow, sandbox);
|
|
5734
6140
|
patchIframeAttribute(url, microAppWindow);
|
|
5735
6141
|
}
|
|
6142
|
+
/**
|
|
6143
|
+
* patch iframe Node/Element
|
|
6144
|
+
*
|
|
6145
|
+
*/
|
|
5736
6146
|
function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
5737
6147
|
const rawRootElement = globalEnv.rawRootElement; // native root Element
|
|
6148
|
+
const rawRootNode = globalEnv.rawRootNode;
|
|
5738
6149
|
const rawDocument = globalEnv.rawDocument;
|
|
5739
6150
|
const microDocument = microAppWindow.document;
|
|
5740
6151
|
const microRootNode = microAppWindow.Node;
|
|
5741
6152
|
const microRootElement = microAppWindow.Element;
|
|
6153
|
+
const microDocumentFragment = microAppWindow.DocumentFragment;
|
|
5742
6154
|
// const rawMicroGetRootNode = microRootNode.prototype.getRootNode
|
|
5743
6155
|
const rawMicroAppendChild = microRootNode.prototype.appendChild;
|
|
5744
6156
|
const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
|
|
@@ -5746,6 +6158,8 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5746
6158
|
const rawMicroRemoveChild = microRootNode.prototype.removeChild;
|
|
5747
6159
|
const rawMicroAppend = microRootElement.prototype.append;
|
|
5748
6160
|
const rawMicroPrepend = microRootElement.prototype.prepend;
|
|
6161
|
+
const rawMicroFragmentAppend = microDocumentFragment.prototype.append;
|
|
6162
|
+
const rawMicroFragmentPrepend = microDocumentFragment.prototype.prepend;
|
|
5749
6163
|
const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
|
|
5750
6164
|
const rawMicroCloneNode = microRootNode.prototype.cloneNode;
|
|
5751
6165
|
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
|
|
@@ -5763,42 +6177,34 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5763
6177
|
}
|
|
5764
6178
|
return parent;
|
|
5765
6179
|
};
|
|
5766
|
-
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
5767
|
-
return microDocument;
|
|
5768
|
-
// TODO: 什么情况下返回原生document?
|
|
5769
|
-
// const rootNode = rawMicroGetRootNode.call(this, options)
|
|
5770
|
-
// if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
|
|
5771
|
-
// return rootNode
|
|
5772
|
-
};
|
|
5773
6180
|
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5774
|
-
// TODO: 有必要执行这么多次updateElementInfo?
|
|
5775
6181
|
updateElementInfo(node, appName);
|
|
5776
6182
|
if (isPureNode(node)) {
|
|
5777
6183
|
return rawMicroAppendChild.call(this, node);
|
|
5778
6184
|
}
|
|
5779
|
-
return
|
|
6185
|
+
return rawRootNode.prototype.appendChild.call(getRawTarget(this), node);
|
|
5780
6186
|
};
|
|
5781
6187
|
microRootNode.prototype.insertBefore = function insertBefore(node, child) {
|
|
5782
6188
|
updateElementInfo(node, appName);
|
|
5783
6189
|
if (isPureNode(node)) {
|
|
5784
6190
|
return rawMicroInsertBefore.call(this, node, child);
|
|
5785
6191
|
}
|
|
5786
|
-
return
|
|
6192
|
+
return rawRootNode.prototype.insertBefore.call(getRawTarget(this), node, child);
|
|
5787
6193
|
};
|
|
5788
6194
|
microRootNode.prototype.replaceChild = function replaceChild(node, child) {
|
|
5789
6195
|
updateElementInfo(node, appName);
|
|
5790
6196
|
if (isPureNode(node)) {
|
|
5791
6197
|
return rawMicroReplaceChild.call(this, node, child);
|
|
5792
6198
|
}
|
|
5793
|
-
return
|
|
6199
|
+
return rawRootNode.prototype.replaceChild.call(getRawTarget(this), node, child);
|
|
5794
6200
|
};
|
|
5795
6201
|
microRootNode.prototype.removeChild = function removeChild(oldChild) {
|
|
5796
6202
|
if (isPureNode(oldChild) || this.contains(oldChild)) {
|
|
5797
6203
|
return rawMicroRemoveChild.call(this, oldChild);
|
|
5798
6204
|
}
|
|
5799
|
-
return
|
|
6205
|
+
return rawRootNode.prototype.removeChild.call(getRawTarget(this), oldChild);
|
|
5800
6206
|
};
|
|
5801
|
-
microRootElement.prototype.append = function append(...nodes) {
|
|
6207
|
+
microDocumentFragment.prototype.append = microRootElement.prototype.append = function append(...nodes) {
|
|
5802
6208
|
let i = 0;
|
|
5803
6209
|
let hasPureNode = false;
|
|
5804
6210
|
while (i < nodes.length) {
|
|
@@ -5808,11 +6214,11 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5808
6214
|
i++;
|
|
5809
6215
|
}
|
|
5810
6216
|
if (hasPureNode) {
|
|
5811
|
-
return rawMicroAppend.call(this, ...nodes);
|
|
6217
|
+
return (isDocumentFragment(this) ? rawMicroFragmentAppend : rawMicroAppend).call(this, ...nodes);
|
|
5812
6218
|
}
|
|
5813
6219
|
return rawRootElement.prototype.append.call(getRawTarget(this), ...nodes);
|
|
5814
6220
|
};
|
|
5815
|
-
microRootElement.prototype.prepend = function prepend(...nodes) {
|
|
6221
|
+
microDocumentFragment.prototype.prepend = microRootElement.prototype.prepend = function prepend(...nodes) {
|
|
5816
6222
|
let i = 0;
|
|
5817
6223
|
let hasPureNode = false;
|
|
5818
6224
|
while (i < nodes.length) {
|
|
@@ -5822,7 +6228,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5822
6228
|
i++;
|
|
5823
6229
|
}
|
|
5824
6230
|
if (hasPureNode) {
|
|
5825
|
-
return rawMicroPrepend.call(this, ...nodes);
|
|
6231
|
+
return (isDocumentFragment(this) ? rawMicroFragmentPrepend : rawMicroPrepend).call(this, ...nodes);
|
|
5826
6232
|
}
|
|
5827
6233
|
return rawRootElement.prototype.prepend.call(getRawTarget(this), ...nodes);
|
|
5828
6234
|
};
|
|
@@ -5838,28 +6244,53 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5838
6244
|
}
|
|
5839
6245
|
return rawRootElement.prototype.insertAdjacentElement.call(getRawTarget(this), where, element);
|
|
5840
6246
|
};
|
|
5841
|
-
|
|
5842
|
-
|
|
5843
|
-
|
|
5844
|
-
|
|
5845
|
-
|
|
6247
|
+
/**
|
|
6248
|
+
* Specific prototype properties:
|
|
6249
|
+
* 1. baseURI
|
|
6250
|
+
* 2. ownerDocument
|
|
6251
|
+
* 3. parentNode
|
|
6252
|
+
* 4. innerHTML
|
|
6253
|
+
*/
|
|
6254
|
+
rawDefineProperty(microRootNode.prototype, 'baseURI', {
|
|
6255
|
+
configurable: true,
|
|
6256
|
+
enumerable: true,
|
|
6257
|
+
get() {
|
|
6258
|
+
return sandbox.proxyWindow.location.href;
|
|
6259
|
+
},
|
|
6260
|
+
});
|
|
5846
6261
|
rawDefineProperty(microRootNode.prototype, 'ownerDocument', {
|
|
5847
6262
|
configurable: true,
|
|
5848
6263
|
enumerable: true,
|
|
5849
6264
|
get() {
|
|
5850
|
-
|
|
5851
|
-
|
|
5852
|
-
: microDocument;
|
|
6265
|
+
var _a;
|
|
6266
|
+
return this.__PURE_ELEMENT__ || this === microDocument
|
|
6267
|
+
? (_a = rawOwnerDocumentDesc.get) === null || _a === void 0 ? void 0 : _a.call(this) : microDocument;
|
|
5853
6268
|
},
|
|
5854
6269
|
});
|
|
6270
|
+
// patch parentNode
|
|
6271
|
+
rawDefineProperty(microRootNode.prototype, 'parentNode', getIframeParentNodeDesc(appName, rawParentNodeDesc));
|
|
6272
|
+
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
6273
|
+
return microDocument;
|
|
6274
|
+
// TODO: any case return document?
|
|
6275
|
+
// const rootNode = rawMicroGetRootNode.call(this, options)
|
|
6276
|
+
// if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
|
|
6277
|
+
// return rootNode
|
|
6278
|
+
};
|
|
6279
|
+
// patch cloneNode
|
|
6280
|
+
microRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
6281
|
+
const clonedNode = rawMicroCloneNode.call(this, deep);
|
|
6282
|
+
return updateElementInfo(clonedNode, appName);
|
|
6283
|
+
};
|
|
5855
6284
|
rawDefineProperty(microRootElement.prototype, 'innerHTML', {
|
|
5856
6285
|
configurable: true,
|
|
5857
6286
|
enumerable: true,
|
|
5858
6287
|
get() {
|
|
5859
|
-
|
|
6288
|
+
var _a;
|
|
6289
|
+
return (_a = rawInnerHTMLDesc.get) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
5860
6290
|
},
|
|
5861
6291
|
set(code) {
|
|
5862
|
-
|
|
6292
|
+
var _a;
|
|
6293
|
+
(_a = rawInnerHTMLDesc.set) === null || _a === void 0 ? void 0 : _a.call(this, code);
|
|
5863
6294
|
Array.from(this.children).forEach((child) => {
|
|
5864
6295
|
if (isElement(child)) {
|
|
5865
6296
|
updateElementInfo(child, appName);
|
|
@@ -5867,34 +6298,6 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5867
6298
|
});
|
|
5868
6299
|
}
|
|
5869
6300
|
});
|
|
5870
|
-
// patch parentNode
|
|
5871
|
-
rawDefineProperty(microRootNode.prototype, 'parentNode', {
|
|
5872
|
-
configurable: true,
|
|
5873
|
-
enumerable: true,
|
|
5874
|
-
get() {
|
|
5875
|
-
var _a, _b, _c;
|
|
5876
|
-
/**
|
|
5877
|
-
* set current appName for hijack parentNode of html
|
|
5878
|
-
* NOTE:
|
|
5879
|
-
* 1. Is there a problem with setting the current appName in iframe mode
|
|
5880
|
-
*/
|
|
5881
|
-
throttleDeferForSetAppName(appName);
|
|
5882
|
-
const result = rawParentNodeDesc.get.call(this);
|
|
5883
|
-
/**
|
|
5884
|
-
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
5885
|
-
* Scenes:
|
|
5886
|
-
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
5887
|
-
* if (this.popperElm.parentNode === document.body) ...
|
|
5888
|
-
* WARNING:
|
|
5889
|
-
* Will it cause other problems ?
|
|
5890
|
-
* e.g. target.parentNode.remove(target)
|
|
5891
|
-
*/
|
|
5892
|
-
if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
5893
|
-
return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
|
|
5894
|
-
}
|
|
5895
|
-
return result;
|
|
5896
|
-
}
|
|
5897
|
-
});
|
|
5898
6301
|
// Adapt to new image(...) scene
|
|
5899
6302
|
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
5900
6303
|
construct(Target, args) {
|
|
@@ -5913,16 +6316,24 @@ function patchIframeAttribute(url, microAppWindow) {
|
|
|
5913
6316
|
const microRootElement = microAppWindow.Element;
|
|
5914
6317
|
const rawMicroSetAttribute = microRootElement.prototype.setAttribute;
|
|
5915
6318
|
microRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
5916
|
-
if (
|
|
5917
|
-
|
|
5918
|
-
|
|
6319
|
+
if (/^micro-app(-\S+)?/i.test(this.tagName) &&
|
|
6320
|
+
key === 'data' &&
|
|
6321
|
+
this.setAttribute !== microRootElement.prototype.setAttribute) {
|
|
6322
|
+
this.setAttribute(key, value);
|
|
6323
|
+
}
|
|
6324
|
+
else {
|
|
6325
|
+
if (((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
6326
|
+
(key === 'href' && /^(link|image)$/i.test(this.tagName))) {
|
|
6327
|
+
value = CompletionPath(value, url);
|
|
6328
|
+
}
|
|
6329
|
+
rawMicroSetAttribute.call(this, key, value);
|
|
5919
6330
|
}
|
|
5920
|
-
rawMicroSetAttribute.call(this, key, value);
|
|
5921
6331
|
};
|
|
5922
6332
|
const protoAttrList = [
|
|
5923
6333
|
[microAppWindow.HTMLImageElement.prototype, 'src'],
|
|
5924
6334
|
[microAppWindow.HTMLScriptElement.prototype, 'src'],
|
|
5925
6335
|
[microAppWindow.HTMLLinkElement.prototype, 'href'],
|
|
6336
|
+
[microAppWindow.SVGImageElement.prototype, 'href'],
|
|
5926
6337
|
];
|
|
5927
6338
|
/**
|
|
5928
6339
|
* element.setAttribute does not trigger this actions:
|
|
@@ -5999,9 +6410,10 @@ class IframeSandbox {
|
|
|
5999
6410
|
createIframeElement(appName, browserPath) {
|
|
6000
6411
|
this.iframe = pureCreateElement('iframe');
|
|
6001
6412
|
const iframeAttrs = {
|
|
6413
|
+
id: appName,
|
|
6002
6414
|
src: microApp.options.iframeSrc || browserPath,
|
|
6003
6415
|
style: 'display: none',
|
|
6004
|
-
|
|
6416
|
+
'powered-by': 'micro-app',
|
|
6005
6417
|
};
|
|
6006
6418
|
Object.keys(iframeAttrs).forEach((key) => this.iframe.setAttribute(key, iframeAttrs[key]));
|
|
6007
6419
|
// effect action during construct
|
|
@@ -6035,15 +6447,6 @@ class IframeSandbox {
|
|
|
6035
6447
|
* 1. iframe router and browser router are separated, we should update iframe router manually
|
|
6036
6448
|
* 2. withSandbox location is browser location when disable memory-router, so no need to do anything
|
|
6037
6449
|
*/
|
|
6038
|
-
/**
|
|
6039
|
-
* TODO:
|
|
6040
|
-
* 1. iframe关闭虚拟路由系统后,default-page无法使用,推荐用户直接使用浏览器地址控制首页渲染
|
|
6041
|
-
* 补充:keep-router-state 也无法配置,因为keep-router-state一定为true。
|
|
6042
|
-
* 2. 导航拦截、current.route 可以正常使用
|
|
6043
|
-
* 3. 可以正常控制子应用跳转,方式还是自上而下(也可以是子应用内部跳转,这种方式更好一点,减小对基座的影响,不会导致vue的循环刷新)
|
|
6044
|
-
* 4. 关闭虚拟路由以后会对应 route-mode='custom' 模式,包括with沙箱也会这么做
|
|
6045
|
-
* 5. 关闭虚拟路由是指尽可能模拟没有虚拟路由的情况,子应用直接获取浏览器location和history,控制浏览器跳转
|
|
6046
|
-
*/
|
|
6047
6450
|
this.initRouteState(defaultPage);
|
|
6048
6451
|
// unique listener of popstate event for child app
|
|
6049
6452
|
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
@@ -6066,6 +6469,7 @@ class IframeSandbox {
|
|
|
6066
6469
|
}
|
|
6067
6470
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
6068
6471
|
var _a;
|
|
6472
|
+
// sandbox.stop may exec before sandbox.start, e.g: iframe sandbox + default mode + remount
|
|
6069
6473
|
if (!this.active)
|
|
6070
6474
|
return;
|
|
6071
6475
|
this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
|
|
@@ -6081,6 +6485,7 @@ class IframeSandbox {
|
|
|
6081
6485
|
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
6082
6486
|
});
|
|
6083
6487
|
this.escapeKeys.clear();
|
|
6488
|
+
this.clearHijackUmdHooks();
|
|
6084
6489
|
}
|
|
6085
6490
|
if (--globalEnv.activeSandbox === 0) {
|
|
6086
6491
|
releasePatchElementAndDocument();
|
|
@@ -6299,10 +6704,49 @@ class IframeSandbox {
|
|
|
6299
6704
|
* action before exec scripts when mount
|
|
6300
6705
|
* Actions:
|
|
6301
6706
|
* 1. patch static elements from html
|
|
6707
|
+
* 2. hijack umd hooks -- mount, unmount, micro-app-appName
|
|
6302
6708
|
* @param container micro app container
|
|
6303
6709
|
*/
|
|
6304
|
-
|
|
6710
|
+
actionsBeforeExecScripts(container, handleUmdHooks) {
|
|
6305
6711
|
this.patchStaticElement(container);
|
|
6712
|
+
this.clearHijackUmdHooks = this.hijackUmdHooks(this.appName, this.microAppWindow, handleUmdHooks);
|
|
6713
|
+
}
|
|
6714
|
+
// hijack mount, unmount, micro-app-appName hook to microAppWindow
|
|
6715
|
+
hijackUmdHooks(appName, microAppWindow, handleUmdHooks) {
|
|
6716
|
+
let mount, unmount, microAppLibrary;
|
|
6717
|
+
rawDefineProperties(microAppWindow, {
|
|
6718
|
+
mount: {
|
|
6719
|
+
configurable: true,
|
|
6720
|
+
get: () => mount,
|
|
6721
|
+
set: (value) => {
|
|
6722
|
+
if (this.active && isFunction(value) && !mount) {
|
|
6723
|
+
handleUmdHooks(mount = value, unmount);
|
|
6724
|
+
}
|
|
6725
|
+
}
|
|
6726
|
+
},
|
|
6727
|
+
unmount: {
|
|
6728
|
+
configurable: true,
|
|
6729
|
+
get: () => unmount,
|
|
6730
|
+
set: (value) => {
|
|
6731
|
+
if (this.active && isFunction(value) && !unmount) {
|
|
6732
|
+
handleUmdHooks(mount, unmount = value);
|
|
6733
|
+
}
|
|
6734
|
+
}
|
|
6735
|
+
},
|
|
6736
|
+
[`micro-app-${appName}`]: {
|
|
6737
|
+
configurable: true,
|
|
6738
|
+
get: () => microAppLibrary,
|
|
6739
|
+
set: (value) => {
|
|
6740
|
+
if (this.active && isPlainObject(value) && !microAppLibrary) {
|
|
6741
|
+
microAppLibrary = value;
|
|
6742
|
+
handleUmdHooks(microAppLibrary.mount, microAppLibrary.unmount);
|
|
6743
|
+
}
|
|
6744
|
+
}
|
|
6745
|
+
}
|
|
6746
|
+
});
|
|
6747
|
+
return () => {
|
|
6748
|
+
mount = unmount = microAppLibrary = null;
|
|
6749
|
+
};
|
|
6306
6750
|
}
|
|
6307
6751
|
setStaticAppState(state) {
|
|
6308
6752
|
this.microAppWindow.__MICRO_APP_STATE__ = state;
|
|
@@ -6319,7 +6763,6 @@ class CreateApp {
|
|
|
6319
6763
|
this.loadSourceLevel = 0;
|
|
6320
6764
|
this.umdHookMount = null;
|
|
6321
6765
|
this.umdHookUnmount = null;
|
|
6322
|
-
this.lifeCycleState = null;
|
|
6323
6766
|
this.umdMode = false;
|
|
6324
6767
|
// TODO: 类型优化,加上iframe沙箱
|
|
6325
6768
|
this.sandBox = null;
|
|
@@ -6364,7 +6807,9 @@ class CreateApp {
|
|
|
6364
6807
|
var _a;
|
|
6365
6808
|
if (++this.loadSourceLevel === 2) {
|
|
6366
6809
|
this.source.html = html;
|
|
6367
|
-
if (
|
|
6810
|
+
if (this.isUnmounted())
|
|
6811
|
+
return;
|
|
6812
|
+
if (!this.isPrefetch) {
|
|
6368
6813
|
getRootContainer(this.container).mount(this);
|
|
6369
6814
|
}
|
|
6370
6815
|
else if (this.isPrerender) {
|
|
@@ -6433,6 +6878,7 @@ class CreateApp {
|
|
|
6433
6878
|
// mount before prerender exec mount (loading source), set isPrerender to false
|
|
6434
6879
|
this.isPrerender = false;
|
|
6435
6880
|
// dispatch state event to micro app
|
|
6881
|
+
// TODO: statechange 还是 state-change,保持一致
|
|
6436
6882
|
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
6437
6883
|
appState: appStates.LOADING
|
|
6438
6884
|
});
|
|
@@ -6456,6 +6902,14 @@ class CreateApp {
|
|
|
6456
6902
|
if (this.isPrerender &&
|
|
6457
6903
|
isDivElement(this.container) &&
|
|
6458
6904
|
this.container.hasAttribute('prerender')) {
|
|
6905
|
+
/**
|
|
6906
|
+
* current this.container is <div prerender='true'></div>
|
|
6907
|
+
* set this.container to <micro-app></micro-app>
|
|
6908
|
+
* NOTE:
|
|
6909
|
+
* 1. must exec before this.sandBox.rebuildEffectSnapshot
|
|
6910
|
+
* 2. must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
6911
|
+
*/
|
|
6912
|
+
this.container = this.cloneContainer(container, this.container, false);
|
|
6459
6913
|
/**
|
|
6460
6914
|
* rebuild effect event of window, document, data center
|
|
6461
6915
|
* explain:
|
|
@@ -6464,14 +6918,6 @@ class CreateApp {
|
|
|
6464
6918
|
* 3. rebuild after js exec end, normal recovery effect event
|
|
6465
6919
|
*/
|
|
6466
6920
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6467
|
-
// current this.container is <div prerender='true'></div>
|
|
6468
|
-
this.cloneContainer(container, this.container, false);
|
|
6469
|
-
/**
|
|
6470
|
-
* set this.container to <micro-app></micro-app>
|
|
6471
|
-
* NOTE:
|
|
6472
|
-
* must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
6473
|
-
*/
|
|
6474
|
-
this.container = container;
|
|
6475
6921
|
(_b = this.preRenderEvents) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
|
|
6476
6922
|
// reset isPrerender config
|
|
6477
6923
|
this.isPrerender = false;
|
|
@@ -6486,7 +6932,6 @@ class CreateApp {
|
|
|
6486
6932
|
this.fiber = fiber;
|
|
6487
6933
|
this.routerMode = routerMode;
|
|
6488
6934
|
const dispatchBeforeMount = () => {
|
|
6489
|
-
this.setLifeCycleState(lifeCycles.BEFOREMOUNT);
|
|
6490
6935
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
6491
6936
|
};
|
|
6492
6937
|
if (this.isPrerender) {
|
|
@@ -6500,7 +6945,7 @@ class CreateApp {
|
|
|
6500
6945
|
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
6501
6946
|
appState: appStates.MOUNTING
|
|
6502
6947
|
});
|
|
6503
|
-
// TODO:
|
|
6948
|
+
// TODO: 兼容shadowRoot的场景
|
|
6504
6949
|
this.cloneContainer(this.container, this.source.html, !this.umdMode);
|
|
6505
6950
|
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
6506
6951
|
umdMode: this.umdMode,
|
|
@@ -6509,38 +6954,35 @@ class CreateApp {
|
|
|
6509
6954
|
disablePatchRequest,
|
|
6510
6955
|
});
|
|
6511
6956
|
if (!this.umdMode) {
|
|
6512
|
-
//
|
|
6513
|
-
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.
|
|
6514
|
-
|
|
6515
|
-
|
|
6516
|
-
|
|
6517
|
-
|
|
6518
|
-
|
|
6519
|
-
* umdHookUnmount can works in default mode
|
|
6520
|
-
* register through window.unmount
|
|
6521
|
-
*/
|
|
6522
|
-
// TODO: 不对,这里要改,因为unmount不一定是函数
|
|
6523
|
-
this.umdHookUnmount = unmount;
|
|
6957
|
+
// patch element info of html
|
|
6958
|
+
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.actionsBeforeExecScripts(this.container, (mount, unmount) => {
|
|
6959
|
+
var _a;
|
|
6960
|
+
if (!this.umdMode && !this.isUnmounted()) {
|
|
6961
|
+
this.umdHookMount = isFunction(mount) ? mount : null;
|
|
6962
|
+
// umdHookUnmount can works in default mode, register by window.unmount
|
|
6963
|
+
this.umdHookUnmount = isFunction(unmount) ? unmount : null;
|
|
6524
6964
|
// if mount & unmount is function, the sub app is umd mode
|
|
6525
|
-
if (isFunction(
|
|
6526
|
-
this.
|
|
6527
|
-
// sandbox must exist
|
|
6528
|
-
this.sandBox.markUmdMode(this.umdMode = true);
|
|
6965
|
+
if (isFunction(this.umdHookMount) && isFunction(this.umdHookUnmount)) {
|
|
6966
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.markUmdMode(this.umdMode = true);
|
|
6529
6967
|
try {
|
|
6530
|
-
this.handleMounted
|
|
6968
|
+
// if appState is mounted, it means that isFinished is true and this.handleMounted has already been executed, just exec this.umdHookMount
|
|
6969
|
+
if (this.getAppState() === appStates.MOUNTED) {
|
|
6970
|
+
this.umdHookMount(microApp.getData(this.name, true));
|
|
6971
|
+
}
|
|
6972
|
+
else {
|
|
6973
|
+
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6974
|
+
}
|
|
6531
6975
|
}
|
|
6532
6976
|
catch (e) {
|
|
6533
|
-
|
|
6534
|
-
* TODO:
|
|
6535
|
-
* 1. 是否应该直接抛出错误
|
|
6536
|
-
* 2. 是否应该触发error生命周期
|
|
6537
|
-
*/
|
|
6538
|
-
logError('An error occurred in window.mount \n', this.name, e);
|
|
6977
|
+
logError('An error occurred when mount \n', this.name, e);
|
|
6539
6978
|
}
|
|
6540
6979
|
}
|
|
6541
|
-
|
|
6542
|
-
|
|
6543
|
-
|
|
6980
|
+
}
|
|
6981
|
+
});
|
|
6982
|
+
// if all js are executed, param isFinished will be true
|
|
6983
|
+
execScripts(this, (isFinished) => {
|
|
6984
|
+
if (!this.umdMode && isFinished === true) {
|
|
6985
|
+
this.handleMounted();
|
|
6544
6986
|
}
|
|
6545
6987
|
});
|
|
6546
6988
|
}
|
|
@@ -6550,13 +6992,22 @@ class CreateApp {
|
|
|
6550
6992
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6551
6993
|
}
|
|
6552
6994
|
catch (e) {
|
|
6553
|
-
logError('An error occurred
|
|
6995
|
+
logError('An error occurred when mount \n', this.name, e);
|
|
6554
6996
|
}
|
|
6555
6997
|
}
|
|
6556
6998
|
}
|
|
6557
6999
|
};
|
|
7000
|
+
/**
|
|
7001
|
+
* Initialization of sandbox is async, especially iframe sandbox are macro tasks
|
|
7002
|
+
* when child apps switch quickly, we need to pay attention to the following points:
|
|
7003
|
+
* NOTE:
|
|
7004
|
+
* 1. unmount app before exec nextAction (especially: iframe sandbox + default mode + remount)
|
|
7005
|
+
* this.container is null, this.sandBox will not start
|
|
7006
|
+
* 2. remount app of note 1
|
|
7007
|
+
* 3. unmount app during exec js
|
|
7008
|
+
*/
|
|
6558
7009
|
// TODO: 可优化?
|
|
6559
|
-
this.sandBox ? this.sandBox.sandboxReady.then(nextAction) : nextAction();
|
|
7010
|
+
this.sandBox ? this.sandBox.sandboxReady.then(() => !this.isUnmounted() && nextAction()) : nextAction();
|
|
6560
7011
|
}
|
|
6561
7012
|
/**
|
|
6562
7013
|
* handle for promise umdHookMount
|
|
@@ -6565,16 +7016,17 @@ class CreateApp {
|
|
|
6565
7016
|
handleMounted(umdHookMountResult) {
|
|
6566
7017
|
var _a, _b;
|
|
6567
7018
|
const dispatchAction = () => {
|
|
7019
|
+
const nextAction = () => this.actionsAfterMounted();
|
|
6568
7020
|
if (isPromise(umdHookMountResult)) {
|
|
6569
7021
|
umdHookMountResult
|
|
6570
|
-
.then(
|
|
7022
|
+
.then(nextAction)
|
|
6571
7023
|
.catch((e) => {
|
|
6572
7024
|
logError('An error occurred in window.mount \n', this.name, e);
|
|
6573
|
-
|
|
7025
|
+
nextAction();
|
|
6574
7026
|
});
|
|
6575
7027
|
}
|
|
6576
7028
|
else {
|
|
6577
|
-
|
|
7029
|
+
nextAction();
|
|
6578
7030
|
}
|
|
6579
7031
|
};
|
|
6580
7032
|
if (this.isPrerender) {
|
|
@@ -6588,7 +7040,7 @@ class CreateApp {
|
|
|
6588
7040
|
/**
|
|
6589
7041
|
* dispatch mounted event when app run finished
|
|
6590
7042
|
*/
|
|
6591
|
-
|
|
7043
|
+
actionsAfterMounted() {
|
|
6592
7044
|
var _a;
|
|
6593
7045
|
if (!this.isUnmounted()) {
|
|
6594
7046
|
this.setAppState(appStates.MOUNTED);
|
|
@@ -6600,7 +7052,6 @@ class CreateApp {
|
|
|
6600
7052
|
});
|
|
6601
7053
|
// dispatch mounted event to micro app
|
|
6602
7054
|
dispatchCustomEventToMicroApp(this, 'mounted');
|
|
6603
|
-
this.setLifeCycleState(lifeCycles.MOUNTED);
|
|
6604
7055
|
// dispatch event mounted to parent
|
|
6605
7056
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
6606
7057
|
/**
|
|
@@ -6623,6 +7074,8 @@ class CreateApp {
|
|
|
6623
7074
|
* unmount app
|
|
6624
7075
|
* NOTE:
|
|
6625
7076
|
* 1. do not add any params on account of unmountApp
|
|
7077
|
+
* 2. this.container maybe null: Initialization of sandbox is async, child app may unmount before exec nextAction of mount
|
|
7078
|
+
* 3. unmount app when loading files (this.container is not null)
|
|
6626
7079
|
* @param destroy completely destroy, delete cache resources
|
|
6627
7080
|
* @param clearData clear data of dateCenter
|
|
6628
7081
|
* @param keepRouteState keep route state when unmount, default is false
|
|
@@ -6632,29 +7085,12 @@ class CreateApp {
|
|
|
6632
7085
|
var _a;
|
|
6633
7086
|
destroy = destroy || this.state === appStates.LOAD_FAILED;
|
|
6634
7087
|
this.setAppState(appStates.UNMOUNT);
|
|
6635
|
-
let umdHookUnmountResult = null;
|
|
6636
7088
|
try {
|
|
6637
|
-
|
|
6638
|
-
umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
|
|
7089
|
+
this.handleUnmounted(destroy, clearData, keepRouteState, unmountcb, (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true)));
|
|
6639
7090
|
}
|
|
6640
7091
|
catch (e) {
|
|
6641
|
-
logError('An error occurred
|
|
7092
|
+
logError('An error occurred when unmount \n', this.name, e);
|
|
6642
7093
|
}
|
|
6643
|
-
// dispatch state event to micro app
|
|
6644
|
-
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
6645
|
-
appState: appStates.UNMOUNT
|
|
6646
|
-
});
|
|
6647
|
-
// dispatch unmount event to micro app
|
|
6648
|
-
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
6649
|
-
// call window.onunmount of child app
|
|
6650
|
-
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
6651
|
-
this.handleUnmounted({
|
|
6652
|
-
destroy,
|
|
6653
|
-
clearData,
|
|
6654
|
-
keepRouteState,
|
|
6655
|
-
unmountcb,
|
|
6656
|
-
umdHookUnmountResult,
|
|
6657
|
-
});
|
|
6658
7094
|
}
|
|
6659
7095
|
/**
|
|
6660
7096
|
* handle for promise umdHookUnmount
|
|
@@ -6664,8 +7100,16 @@ class CreateApp {
|
|
|
6664
7100
|
* @param unmountcb callback of unmount
|
|
6665
7101
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6666
7102
|
*/
|
|
6667
|
-
handleUnmounted(
|
|
6668
|
-
|
|
7103
|
+
handleUnmounted(destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult) {
|
|
7104
|
+
// dispatch state event to micro app
|
|
7105
|
+
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
7106
|
+
appState: appStates.UNMOUNT
|
|
7107
|
+
});
|
|
7108
|
+
// dispatch unmount event to micro app
|
|
7109
|
+
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
7110
|
+
// call window.onunmount of child app
|
|
7111
|
+
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
7112
|
+
const nextAction = () => this.actionsAfterUnmounted({
|
|
6669
7113
|
destroy,
|
|
6670
7114
|
clearData,
|
|
6671
7115
|
keepRouteState,
|
|
@@ -6674,7 +7118,12 @@ class CreateApp {
|
|
|
6674
7118
|
if (isPromise(umdHookUnmountResult)) {
|
|
6675
7119
|
// async window.unmount will cause appName bind error in nest app
|
|
6676
7120
|
removeDomScope();
|
|
6677
|
-
umdHookUnmountResult
|
|
7121
|
+
umdHookUnmountResult
|
|
7122
|
+
.then(nextAction)
|
|
7123
|
+
.catch((e) => {
|
|
7124
|
+
logError('An error occurred in window.unmount \n', this.name, e);
|
|
7125
|
+
nextAction();
|
|
7126
|
+
});
|
|
6678
7127
|
}
|
|
6679
7128
|
else {
|
|
6680
7129
|
nextAction();
|
|
@@ -6687,7 +7136,7 @@ class CreateApp {
|
|
|
6687
7136
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6688
7137
|
* @param unmountcb callback of unmount
|
|
6689
7138
|
*/
|
|
6690
|
-
|
|
7139
|
+
actionsAfterUnmounted({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
6691
7140
|
var _a;
|
|
6692
7141
|
if (this.umdMode && this.container && !destroy) {
|
|
6693
7142
|
this.cloneContainer(this.source.html, this.container, false);
|
|
@@ -6704,20 +7153,33 @@ class CreateApp {
|
|
|
6704
7153
|
destroy,
|
|
6705
7154
|
clearData: clearData || destroy,
|
|
6706
7155
|
});
|
|
6707
|
-
this.setLifeCycleState(lifeCycles.UNMOUNT);
|
|
6708
7156
|
// dispatch unmount event to base app
|
|
6709
7157
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
6710
7158
|
this.clearOptions(destroy);
|
|
6711
7159
|
unmountcb === null || unmountcb === void 0 ? void 0 : unmountcb();
|
|
6712
7160
|
}
|
|
6713
7161
|
clearOptions(destroy) {
|
|
6714
|
-
|
|
6715
|
-
this.container = null;
|
|
7162
|
+
var _a, _b;
|
|
6716
7163
|
this.isPrerender = false;
|
|
6717
7164
|
this.preRenderEvents = null;
|
|
6718
7165
|
this.setKeepAliveState(null);
|
|
7166
|
+
if (this.container) {
|
|
7167
|
+
this.container.innerHTML = '';
|
|
7168
|
+
this.container = null;
|
|
7169
|
+
}
|
|
7170
|
+
else if (!this.umdMode) {
|
|
7171
|
+
/**
|
|
7172
|
+
* this.container is null means sandBox.start has not exec, so sandBox.stop won't exec either
|
|
7173
|
+
* we should remove iframeElement in default mode manually
|
|
7174
|
+
*/
|
|
7175
|
+
(_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.deleteIframeElement) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
7176
|
+
}
|
|
6719
7177
|
// in iframe sandbox & default mode, delete the sandbox & iframeElement
|
|
6720
|
-
|
|
7178
|
+
/**
|
|
7179
|
+
* TODO:
|
|
7180
|
+
* 1. with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
|
|
7181
|
+
* 2. 接1.0,this.sandBox置空,还需要注意后续app.sandBox相关操作,比如 scripts.ts --> app.iframe ? app.sandBox!.microBody : app.querySelector('micro-app-body'),如果是fiber或者预加载,会存在卸载后js还在处理的情况
|
|
7182
|
+
*/
|
|
6721
7183
|
if (this.iframe && !this.umdMode)
|
|
6722
7184
|
this.sandBox = null;
|
|
6723
7185
|
if (destroy)
|
|
@@ -6746,7 +7208,6 @@ class CreateApp {
|
|
|
6746
7208
|
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
6747
7209
|
appState: 'afterhidden',
|
|
6748
7210
|
});
|
|
6749
|
-
this.setLifeCycleState(lifeCycles.AFTERHIDDEN);
|
|
6750
7211
|
// dispatch afterHidden event to base app
|
|
6751
7212
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
|
|
6752
7213
|
if (isRouterModeSearch(this.name)) {
|
|
@@ -6768,6 +7229,14 @@ class CreateApp {
|
|
|
6768
7229
|
// show app when connectedCallback called with keep-alive
|
|
6769
7230
|
showKeepAliveApp(container) {
|
|
6770
7231
|
var _a, _b;
|
|
7232
|
+
/**
|
|
7233
|
+
* NOTE:
|
|
7234
|
+
* 1. this.container must set to container(micro-app element) before exec rebuildEffectSnapshot
|
|
7235
|
+
* ISSUE: https://github.com/micro-zoe/micro-app/issues/1115
|
|
7236
|
+
* 2. rebuildEffectSnapshot must exec before dispatch beforeshow event
|
|
7237
|
+
*/
|
|
7238
|
+
const oldContainer = this.container;
|
|
7239
|
+
this.container = container;
|
|
6771
7240
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6772
7241
|
// dispatch beforeShow event to micro-app
|
|
6773
7242
|
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
@@ -6776,11 +7245,11 @@ class CreateApp {
|
|
|
6776
7245
|
// dispatch beforeShow event to base app
|
|
6777
7246
|
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
6778
7247
|
this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
|
|
6779
|
-
this.
|
|
7248
|
+
this.cloneContainer(this.container, oldContainer, false);
|
|
6780
7249
|
/**
|
|
6781
7250
|
* TODO:
|
|
6782
7251
|
* 问题:当路由模式为custom时,keep-alive应用在重新展示,是否需要根据子应用location信息更新浏览器地址?
|
|
6783
|
-
*
|
|
7252
|
+
* 暂时不这么做,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
|
|
6784
7253
|
*/
|
|
6785
7254
|
if (isRouterModeSearch(this.name)) {
|
|
6786
7255
|
// called before lifeCyclesEvent
|
|
@@ -6790,7 +7259,6 @@ class CreateApp {
|
|
|
6790
7259
|
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
6791
7260
|
appState: 'aftershow',
|
|
6792
7261
|
});
|
|
6793
|
-
this.setLifeCycleState(lifeCycles.AFTERSHOW);
|
|
6794
7262
|
// dispatch afterShow event to base app
|
|
6795
7263
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
|
|
6796
7264
|
}
|
|
@@ -6799,7 +7267,6 @@ class CreateApp {
|
|
|
6799
7267
|
* @param e Error
|
|
6800
7268
|
*/
|
|
6801
7269
|
onerror(e) {
|
|
6802
|
-
this.setLifeCycleState(lifeCycles.ERROR);
|
|
6803
7270
|
// dispatch state event to micro app
|
|
6804
7271
|
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
6805
7272
|
appState: appStates.LOAD_FAILED
|
|
@@ -6820,13 +7287,13 @@ class CreateApp {
|
|
|
6820
7287
|
}
|
|
6821
7288
|
/**
|
|
6822
7289
|
* clone origin elements to target
|
|
6823
|
-
* @param origin Cloned element
|
|
6824
7290
|
* @param target Accept cloned elements
|
|
7291
|
+
* @param origin Cloned element
|
|
6825
7292
|
* @param deep deep clone or transfer dom
|
|
6826
7293
|
*/
|
|
6827
7294
|
cloneContainer(target, origin, deep) {
|
|
6828
7295
|
// 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
|
|
6829
|
-
if (origin) {
|
|
7296
|
+
if (origin && target) {
|
|
6830
7297
|
target.innerHTML = '';
|
|
6831
7298
|
Array.from(deep ? this.parseHtmlString(origin.innerHTML).childNodes : origin.childNodes).forEach((node) => {
|
|
6832
7299
|
target.appendChild(node);
|
|
@@ -6856,14 +7323,6 @@ class CreateApp {
|
|
|
6856
7323
|
getAppState() {
|
|
6857
7324
|
return this.state;
|
|
6858
7325
|
}
|
|
6859
|
-
// set app lifeCycleState
|
|
6860
|
-
setLifeCycleState(state) {
|
|
6861
|
-
this.lifeCycleState = state;
|
|
6862
|
-
}
|
|
6863
|
-
// get app lifeCycleState
|
|
6864
|
-
getLifeCycleState() {
|
|
6865
|
-
return this.lifeCycleState || '';
|
|
6866
|
-
}
|
|
6867
7326
|
// set keep-alive state
|
|
6868
7327
|
setKeepAliveState(state) {
|
|
6869
7328
|
this.keepAliveState = state;
|
|
@@ -6880,23 +7339,6 @@ class CreateApp {
|
|
|
6880
7339
|
isHidden() {
|
|
6881
7340
|
return keepAliveStates.KEEP_ALIVE_HIDDEN === this.keepAliveState;
|
|
6882
7341
|
}
|
|
6883
|
-
// get umd library, if it not exist, return empty object
|
|
6884
|
-
getUmdLibraryHooks() {
|
|
6885
|
-
// after execScripts, the app maybe unmounted
|
|
6886
|
-
if (!this.isUnmounted() && this.sandBox) {
|
|
6887
|
-
const libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
6888
|
-
const proxyWindow = this.sandBox.proxyWindow;
|
|
6889
|
-
// compatible with pre versions
|
|
6890
|
-
if (isObject(proxyWindow[libraryName])) {
|
|
6891
|
-
return proxyWindow[libraryName];
|
|
6892
|
-
}
|
|
6893
|
-
return {
|
|
6894
|
-
mount: proxyWindow.mount,
|
|
6895
|
-
unmount: proxyWindow.unmount,
|
|
6896
|
-
};
|
|
6897
|
-
}
|
|
6898
|
-
return {};
|
|
6899
|
-
}
|
|
6900
7342
|
getMicroAppGlobalHook(eventName) {
|
|
6901
7343
|
var _a, _b;
|
|
6902
7344
|
const listener = (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) === null || _b === void 0 ? void 0 : _b[eventName];
|
|
@@ -7002,11 +7444,11 @@ function handleNewNode(child, app) {
|
|
|
7002
7444
|
* @param app app
|
|
7003
7445
|
* @param method raw method
|
|
7004
7446
|
* @param parent parent node
|
|
7005
|
-
* @param
|
|
7006
|
-
* @param
|
|
7447
|
+
* @param targetNode target node
|
|
7448
|
+
* @param passiveNode second param of insertBefore and replaceChild
|
|
7007
7449
|
*/
|
|
7008
|
-
function invokePrototypeMethod(app, rawMethod, parent,
|
|
7009
|
-
const hijackParent = getHijackParent(parent,
|
|
7450
|
+
function invokePrototypeMethod(app, rawMethod, parent, targetNode, passiveNode) {
|
|
7451
|
+
const hijackParent = getHijackParent(parent, targetNode, app);
|
|
7010
7452
|
if (hijackParent) {
|
|
7011
7453
|
/**
|
|
7012
7454
|
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
@@ -7023,9 +7465,9 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
7023
7465
|
if (!isIframeSandbox(app.name) &&
|
|
7024
7466
|
isMicroAppBody(hijackParent) &&
|
|
7025
7467
|
rawMethod !== globalEnv.rawRemoveChild) {
|
|
7026
|
-
const descriptor = Object.getOwnPropertyDescriptor(
|
|
7027
|
-
if ((!descriptor || descriptor.configurable) && !
|
|
7028
|
-
rawDefineProperties(
|
|
7468
|
+
const descriptor = Object.getOwnPropertyDescriptor(targetNode, 'parentNode');
|
|
7469
|
+
if ((!descriptor || descriptor.configurable) && !targetNode.__MICRO_APP_HAS_DPN__) {
|
|
7470
|
+
rawDefineProperties(targetNode, {
|
|
7029
7471
|
parentNode: {
|
|
7030
7472
|
configurable: true,
|
|
7031
7473
|
get() {
|
|
@@ -7046,68 +7488,84 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
7046
7488
|
}
|
|
7047
7489
|
}
|
|
7048
7490
|
if ((process.env.NODE_ENV !== 'production') &&
|
|
7049
|
-
isIFrameElement(
|
|
7491
|
+
isIFrameElement(targetNode) &&
|
|
7050
7492
|
rawMethod === globalEnv.rawAppendChild) {
|
|
7051
7493
|
fixReactHMRConflict(app);
|
|
7052
7494
|
}
|
|
7053
7495
|
/**
|
|
7054
|
-
* 1. If
|
|
7055
|
-
* 2. When removeChild,
|
|
7496
|
+
* 1. If passiveNode exists, it must be insertBefore or replaceChild
|
|
7497
|
+
* 2. When removeChild, targetNode may not be in microAppHead or head
|
|
7056
7498
|
* NOTE:
|
|
7057
|
-
* 1. If
|
|
7058
|
-
* E.g: document.head.replaceChild(
|
|
7059
|
-
* 2. If
|
|
7060
|
-
* E.g: document.head.insertBefore(
|
|
7499
|
+
* 1. If passiveNode not in hijackParent, insertBefore replaceChild will be degraded to appendChild
|
|
7500
|
+
* E.g: document.head.replaceChild(targetNode, document.scripts[0])
|
|
7501
|
+
* 2. If passiveNode not in hijackParent but in parent and method is insertBefore, try insert it into the position corresponding to hijackParent
|
|
7502
|
+
* E.g: document.head.insertBefore(targetNode, document.head.childNodes[0])
|
|
7061
7503
|
* ISSUE: https://github.com/micro-zoe/micro-app/issues/1071
|
|
7062
7504
|
*/
|
|
7063
|
-
if (
|
|
7064
|
-
if (rawMethod === globalEnv.rawInsertBefore && parent.contains(
|
|
7065
|
-
const indexOfParent = Array.from(parent.childNodes).indexOf(
|
|
7505
|
+
if (passiveNode && !hijackParent.contains(passiveNode)) {
|
|
7506
|
+
if (rawMethod === globalEnv.rawInsertBefore && parent.contains(passiveNode)) {
|
|
7507
|
+
const indexOfParent = Array.from(parent.childNodes).indexOf(passiveNode);
|
|
7066
7508
|
if (hijackParent.childNodes[indexOfParent]) {
|
|
7067
|
-
return invokeRawMethod(rawMethod, hijackParent,
|
|
7509
|
+
return invokeRawMethod(rawMethod, hijackParent, targetNode, hijackParent.childNodes[indexOfParent], app);
|
|
7068
7510
|
}
|
|
7069
7511
|
}
|
|
7070
|
-
return globalEnv.rawAppendChild.call(hijackParent,
|
|
7512
|
+
return globalEnv.rawAppendChild.call(hijackParent, targetNode);
|
|
7071
7513
|
}
|
|
7072
|
-
else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(
|
|
7073
|
-
if (parent.contains(
|
|
7074
|
-
return rawMethod.call(parent,
|
|
7514
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetNode)) {
|
|
7515
|
+
if (parent.contains(targetNode)) {
|
|
7516
|
+
return rawMethod.call(parent, targetNode);
|
|
7075
7517
|
}
|
|
7076
|
-
return
|
|
7518
|
+
return targetNode;
|
|
7077
7519
|
}
|
|
7078
|
-
return invokeRawMethod(rawMethod, hijackParent,
|
|
7520
|
+
return invokeRawMethod(rawMethod, hijackParent, targetNode, passiveNode, app);
|
|
7079
7521
|
}
|
|
7080
|
-
return invokeRawMethod(rawMethod, parent,
|
|
7522
|
+
return invokeRawMethod(rawMethod, parent, targetNode, passiveNode, app);
|
|
7081
7523
|
}
|
|
7082
7524
|
// head/body map to micro-app-head/micro-app-body
|
|
7083
|
-
function getHijackParent(parent,
|
|
7525
|
+
function getHijackParent(parent, targetNode, app) {
|
|
7084
7526
|
if (app) {
|
|
7085
7527
|
if (parent === document.head) {
|
|
7086
|
-
if (app.iframe && isScriptElement(
|
|
7528
|
+
if (app.iframe && isScriptElement(targetNode)) {
|
|
7087
7529
|
return app.sandBox.microHead;
|
|
7088
7530
|
}
|
|
7089
7531
|
return app.querySelector('micro-app-head');
|
|
7090
7532
|
}
|
|
7091
7533
|
if (parent === document.body || parent === document.body.parentNode) {
|
|
7092
|
-
if (app.iframe && isScriptElement(
|
|
7534
|
+
if (app.iframe && isScriptElement(targetNode)) {
|
|
7093
7535
|
return app.sandBox.microBody;
|
|
7094
7536
|
}
|
|
7095
7537
|
return app.querySelector('micro-app-body');
|
|
7096
7538
|
}
|
|
7097
|
-
if (app.iframe && isScriptElement(
|
|
7539
|
+
if (app.iframe && isScriptElement(targetNode)) {
|
|
7098
7540
|
return app.sandBox.microBody;
|
|
7099
7541
|
}
|
|
7100
7542
|
}
|
|
7101
7543
|
return null;
|
|
7102
7544
|
}
|
|
7103
|
-
function invokeRawMethod(rawMethod, parent,
|
|
7545
|
+
function invokeRawMethod(rawMethod, parent, targetNode, passiveNode, app) {
|
|
7104
7546
|
if (isPendMethod(rawMethod)) {
|
|
7105
|
-
|
|
7547
|
+
/**
|
|
7548
|
+
* In iframe sandbox, script will pend to iframe.body, so we should reset rawMethod, because:
|
|
7549
|
+
* Element.prototype.append === DocumentFragment.prototype.append ==> false
|
|
7550
|
+
* Element.prototype.prepend === DocumentFragment.prototype.prepend ==> false
|
|
7551
|
+
*/
|
|
7552
|
+
if ((app === null || app === void 0 ? void 0 : app.iframe) && isScriptElement(targetNode)) {
|
|
7553
|
+
if (rawMethod === globalEnv.rawFragmentAppend) {
|
|
7554
|
+
rawMethod = globalEnv.rawAppend;
|
|
7555
|
+
}
|
|
7556
|
+
else if (rawMethod === globalEnv.rawFragmentPrepend) {
|
|
7557
|
+
rawMethod = globalEnv.rawPrepend;
|
|
7558
|
+
}
|
|
7559
|
+
}
|
|
7560
|
+
return rawMethod.call(parent, targetNode);
|
|
7106
7561
|
}
|
|
7107
|
-
return rawMethod.call(parent,
|
|
7562
|
+
return rawMethod.call(parent, targetNode, passiveNode);
|
|
7108
7563
|
}
|
|
7109
7564
|
function isPendMethod(method) {
|
|
7110
|
-
return method === globalEnv.rawAppend ||
|
|
7565
|
+
return (method === globalEnv.rawAppend ||
|
|
7566
|
+
method === globalEnv.rawPrepend ||
|
|
7567
|
+
method === globalEnv.rawFragmentAppend ||
|
|
7568
|
+
method === globalEnv.rawFragmentPrepend);
|
|
7111
7569
|
}
|
|
7112
7570
|
/**
|
|
7113
7571
|
* Attempt to complete the static resource address again before insert the node
|
|
@@ -7124,7 +7582,7 @@ function completePathDynamic(app, newChild) {
|
|
|
7124
7582
|
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
7125
7583
|
}
|
|
7126
7584
|
}
|
|
7127
|
-
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
7585
|
+
else if (/^(link|image)$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
7128
7586
|
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
7129
7587
|
}
|
|
7130
7588
|
}
|
|
@@ -7133,31 +7591,26 @@ function completePathDynamic(app, newChild) {
|
|
|
7133
7591
|
* method of handle new node
|
|
7134
7592
|
* @param parent parent node
|
|
7135
7593
|
* @param newChild new node
|
|
7136
|
-
* @param
|
|
7594
|
+
* @param passiveNode passive node
|
|
7137
7595
|
* @param rawMethod method
|
|
7138
7596
|
*/
|
|
7139
|
-
function commonElementHandler(parent, newChild,
|
|
7597
|
+
function commonElementHandler(parent, newChild, passiveNode, rawMethod) {
|
|
7140
7598
|
const currentAppName = getCurrentAppName();
|
|
7141
7599
|
if (isNode(newChild) &&
|
|
7142
7600
|
!newChild.__PURE_ELEMENT__ &&
|
|
7143
7601
|
(newChild.__MICRO_APP_NAME__ ||
|
|
7144
7602
|
currentAppName)) {
|
|
7145
|
-
newChild
|
|
7603
|
+
updateElementInfo(newChild, newChild.__MICRO_APP_NAME__ || currentAppName);
|
|
7146
7604
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
7147
|
-
if (isStyleElement(newChild)) {
|
|
7148
|
-
const isShadowNode = parent.getRootNode();
|
|
7149
|
-
const isShadowEnvironment = isShadowNode instanceof ShadowRoot;
|
|
7150
|
-
isShadowEnvironment && newChild.setAttribute('ignore', 'true');
|
|
7151
|
-
}
|
|
7152
7605
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
7606
|
+
if (isStyleElement(newChild)) {
|
|
7607
|
+
parent.getRootNode() instanceof ShadowRoot && newChild.setAttribute('ignore', 'true');
|
|
7608
|
+
}
|
|
7153
7609
|
completePathDynamic(app, newChild);
|
|
7154
|
-
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app),
|
|
7610
|
+
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveNode && getMappingNode(passiveNode));
|
|
7155
7611
|
}
|
|
7156
7612
|
}
|
|
7157
|
-
|
|
7158
|
-
return rawMethod.call(parent, newChild);
|
|
7159
|
-
}
|
|
7160
|
-
return rawMethod.call(parent, newChild, passiveChild);
|
|
7613
|
+
return invokeRawMethod(rawMethod, parent, newChild, passiveNode);
|
|
7161
7614
|
}
|
|
7162
7615
|
/**
|
|
7163
7616
|
* Rewrite element prototype method
|
|
@@ -7166,36 +7619,19 @@ function patchElementAndDocument() {
|
|
|
7166
7619
|
patchDocument$2();
|
|
7167
7620
|
const rawRootElement = globalEnv.rawRootElement;
|
|
7168
7621
|
const rawRootNode = globalEnv.rawRootNode;
|
|
7622
|
+
const rawDocumentFragment = globalEnv.rawDocumentFragment;
|
|
7169
7623
|
// prototype methods of add element👇
|
|
7170
|
-
|
|
7624
|
+
rawRootNode.prototype.appendChild = function appendChild(newChild) {
|
|
7171
7625
|
return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
|
|
7172
7626
|
};
|
|
7173
|
-
|
|
7627
|
+
rawRootNode.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
7174
7628
|
return commonElementHandler(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
7175
7629
|
};
|
|
7176
|
-
|
|
7630
|
+
rawRootNode.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
7177
7631
|
return commonElementHandler(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
7178
7632
|
};
|
|
7179
|
-
rawRootElement.prototype.append = function append(...nodes) {
|
|
7180
|
-
let i = 0;
|
|
7181
|
-
while (i < nodes.length) {
|
|
7182
|
-
let node = nodes[i];
|
|
7183
|
-
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
7184
|
-
commonElementHandler(this, markElement(node), null, globalEnv.rawAppend);
|
|
7185
|
-
i++;
|
|
7186
|
-
}
|
|
7187
|
-
};
|
|
7188
|
-
rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
7189
|
-
let i = nodes.length;
|
|
7190
|
-
while (i > 0) {
|
|
7191
|
-
let node = nodes[i - 1];
|
|
7192
|
-
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
7193
|
-
commonElementHandler(this, markElement(node), null, globalEnv.rawPrepend);
|
|
7194
|
-
i--;
|
|
7195
|
-
}
|
|
7196
|
-
};
|
|
7197
7633
|
// prototype methods of delete element👇
|
|
7198
|
-
|
|
7634
|
+
rawRootNode.prototype.removeChild = function removeChild(oldChild) {
|
|
7199
7635
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
7200
7636
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
7201
7637
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -7210,6 +7646,24 @@ function patchElementAndDocument() {
|
|
|
7210
7646
|
}
|
|
7211
7647
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
7212
7648
|
};
|
|
7649
|
+
rawDocumentFragment.prototype.append = rawRootElement.prototype.append = function append(...nodes) {
|
|
7650
|
+
let i = 0;
|
|
7651
|
+
while (i < nodes.length) {
|
|
7652
|
+
let node = nodes[i];
|
|
7653
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
7654
|
+
commonElementHandler(this, markElement(node), null, isDocumentFragment(this) ? globalEnv.rawFragmentAppend : globalEnv.rawAppend);
|
|
7655
|
+
i++;
|
|
7656
|
+
}
|
|
7657
|
+
};
|
|
7658
|
+
rawDocumentFragment.prototype.prepend = rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
7659
|
+
let i = nodes.length;
|
|
7660
|
+
while (i > 0) {
|
|
7661
|
+
let node = nodes[i - 1];
|
|
7662
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
7663
|
+
commonElementHandler(this, markElement(node), null, isDocumentFragment(this) ? globalEnv.rawFragmentPrepend : globalEnv.rawPrepend);
|
|
7664
|
+
i--;
|
|
7665
|
+
}
|
|
7666
|
+
};
|
|
7213
7667
|
/**
|
|
7214
7668
|
* The insertAdjacentElement method of the Element interface inserts a given element node at a given position relative to the element it is invoked upon.
|
|
7215
7669
|
* NOTE:
|
|
@@ -7229,52 +7683,81 @@ function patchElementAndDocument() {
|
|
|
7229
7683
|
}
|
|
7230
7684
|
return globalEnv.rawInsertAdjacentElement.call(this, where, element);
|
|
7231
7685
|
};
|
|
7232
|
-
// patch cloneNode
|
|
7233
|
-
rawRootElement.prototype.cloneNode = function cloneNode(deep) {
|
|
7234
|
-
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
7235
|
-
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
7236
|
-
return clonedNode;
|
|
7237
|
-
};
|
|
7238
7686
|
/**
|
|
7239
7687
|
* document.body(head).querySelector(querySelectorAll) hijack to microAppBody(microAppHead).querySelector(querySelectorAll)
|
|
7240
7688
|
* NOTE:
|
|
7241
7689
|
* 1. May cause some problems!
|
|
7242
7690
|
* 2. Add config options?
|
|
7243
7691
|
*/
|
|
7244
|
-
function
|
|
7245
|
-
const currentAppName = getCurrentAppName();
|
|
7246
|
-
if ((
|
|
7692
|
+
function getElementQueryTarget(targetNode) {
|
|
7693
|
+
const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
|
|
7694
|
+
if ((targetNode === document.body || targetNode === document.head) && currentAppName) {
|
|
7247
7695
|
const app = appInstanceMap.get(currentAppName);
|
|
7248
7696
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
7249
|
-
if (
|
|
7697
|
+
if (targetNode === document.body) {
|
|
7250
7698
|
return app.querySelector('micro-app-body');
|
|
7251
7699
|
}
|
|
7252
|
-
else if (
|
|
7700
|
+
else if (targetNode === document.head) {
|
|
7253
7701
|
return app.querySelector('micro-app-head');
|
|
7254
7702
|
}
|
|
7255
7703
|
}
|
|
7256
7704
|
}
|
|
7257
|
-
return
|
|
7705
|
+
return targetNode;
|
|
7706
|
+
}
|
|
7707
|
+
/**
|
|
7708
|
+
* In iframe sandbox, script will render to iframe instead of micro-app-body
|
|
7709
|
+
* So when query elements, we need to search both micro-app and iframe
|
|
7710
|
+
* @param isEmpty get empty result
|
|
7711
|
+
* @param targetNode targetNode element
|
|
7712
|
+
* @param result origin result
|
|
7713
|
+
* @param selectors selectors
|
|
7714
|
+
* @param methodName querySelector or querySelectorAll
|
|
7715
|
+
*/
|
|
7716
|
+
function getElementQueryResult(isEmpty, targetNode, result, selectors, methodName) {
|
|
7717
|
+
if (isEmpty) {
|
|
7718
|
+
const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
|
|
7719
|
+
if (currentAppName && isIframeSandbox(currentAppName)) {
|
|
7720
|
+
const app = appInstanceMap.get(currentAppName);
|
|
7721
|
+
if (isMicroAppHead(targetNode)) {
|
|
7722
|
+
return app.sandBox.microHead[methodName](selectors);
|
|
7723
|
+
}
|
|
7724
|
+
if (isMicroAppBody(targetNode)) {
|
|
7725
|
+
return app.sandBox.microBody[methodName](selectors);
|
|
7726
|
+
}
|
|
7727
|
+
}
|
|
7728
|
+
}
|
|
7729
|
+
return result;
|
|
7258
7730
|
}
|
|
7259
7731
|
rawRootElement.prototype.querySelector = function querySelector(selectors) {
|
|
7260
7732
|
var _a;
|
|
7261
|
-
|
|
7733
|
+
const _this = (_a = getElementQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
7734
|
+
const result = globalEnv.rawElementQuerySelector.call(_this, selectors);
|
|
7735
|
+
return getElementQueryResult(isNull(result) && _this !== this, _this, result, selectors, 'querySelector');
|
|
7262
7736
|
};
|
|
7263
7737
|
rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
7264
7738
|
var _a;
|
|
7265
|
-
|
|
7739
|
+
const _this = (_a = getElementQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
7740
|
+
const result = globalEnv.rawElementQuerySelectorAll.call(_this, selectors);
|
|
7741
|
+
return getElementQueryResult(!result.length && _this !== this, _this, result, selectors, 'querySelectorAll');
|
|
7266
7742
|
};
|
|
7267
7743
|
// rewrite setAttribute, complete resource address
|
|
7268
7744
|
rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
7269
|
-
|
|
7270
|
-
|
|
7271
|
-
|
|
7272
|
-
(
|
|
7273
|
-
|
|
7274
|
-
|
|
7275
|
-
|
|
7745
|
+
if (/^micro-app(-\S+)?/i.test(this.tagName) &&
|
|
7746
|
+
key === 'data' &&
|
|
7747
|
+
this.setAttribute !== rawRootElement.prototype.setAttribute) {
|
|
7748
|
+
this.setAttribute(key, value);
|
|
7749
|
+
}
|
|
7750
|
+
else {
|
|
7751
|
+
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
7752
|
+
if (appName &&
|
|
7753
|
+
appInstanceMap.has(appName) &&
|
|
7754
|
+
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
7755
|
+
(key === 'href' && /^(link|image)$/i.test(this.tagName)))) {
|
|
7756
|
+
const app = appInstanceMap.get(appName);
|
|
7757
|
+
value = CompletionPath(value, app.url);
|
|
7758
|
+
}
|
|
7759
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7276
7760
|
}
|
|
7277
|
-
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7278
7761
|
};
|
|
7279
7762
|
/**
|
|
7280
7763
|
* TODO: 兼容直接通过img.src等操作设置的资源
|
|
@@ -7301,7 +7784,7 @@ function patchElementAndDocument() {
|
|
|
7301
7784
|
// return get?.call(this)
|
|
7302
7785
|
// },
|
|
7303
7786
|
// set: function (value) {
|
|
7304
|
-
// const currentAppName = getCurrentAppName()
|
|
7787
|
+
// const currentAppName = this.__MICRO_APP_NAME__ || getCurrentAppName()
|
|
7305
7788
|
// if (currentAppName && appInstanceMap.has(currentAppName)) {
|
|
7306
7789
|
// const app = appInstanceMap.get(currentAppName)
|
|
7307
7790
|
// value = CompletionPath(value, app!.url)
|
|
@@ -7310,41 +7793,25 @@ function patchElementAndDocument() {
|
|
|
7310
7793
|
// },
|
|
7311
7794
|
// })
|
|
7312
7795
|
// })
|
|
7313
|
-
rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
|
|
7314
|
-
configurable: true,
|
|
7315
|
-
enumerable: true,
|
|
7316
|
-
get() {
|
|
7317
|
-
return globalEnv.rawInnerHTMLDesc.get.call(this);
|
|
7318
|
-
},
|
|
7319
|
-
set(code) {
|
|
7320
|
-
globalEnv.rawInnerHTMLDesc.set.call(this, code);
|
|
7321
|
-
const currentAppName = getCurrentAppName();
|
|
7322
|
-
Array.from(this.children).forEach((child) => {
|
|
7323
|
-
if (isElement(child) && currentAppName) {
|
|
7324
|
-
// TODO: 使用updateElementInfo进行更新
|
|
7325
|
-
child.__MICRO_APP_NAME__ = currentAppName;
|
|
7326
|
-
}
|
|
7327
|
-
});
|
|
7328
|
-
}
|
|
7329
|
-
});
|
|
7330
7796
|
rawDefineProperty(rawRootNode.prototype, 'parentNode', {
|
|
7331
7797
|
configurable: true,
|
|
7332
7798
|
enumerable: true,
|
|
7333
7799
|
get() {
|
|
7334
7800
|
var _a, _b, _c;
|
|
7335
7801
|
/**
|
|
7336
|
-
* hijack parentNode of html
|
|
7802
|
+
* hijack parentNode of html for with sandbox
|
|
7337
7803
|
* Scenes:
|
|
7338
7804
|
* 1. element-ui@2/lib/utils/popper.js
|
|
7339
7805
|
* // root is child app window, so root.document is proxyDocument or microDocument
|
|
7340
7806
|
* if (element.parentNode === root.document) ...
|
|
7341
7807
|
*/
|
|
7342
|
-
const currentAppName = getCurrentAppName();
|
|
7808
|
+
const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
|
|
7343
7809
|
if (currentAppName && this === globalEnv.rawDocument.firstElementChild) {
|
|
7344
7810
|
const microDocument = (_c = (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow) === null || _c === void 0 ? void 0 : _c.document;
|
|
7345
7811
|
if (microDocument)
|
|
7346
7812
|
return microDocument;
|
|
7347
7813
|
}
|
|
7814
|
+
// NOTE: run after hijack html.parentNode
|
|
7348
7815
|
const result = globalEnv.rawParentNodeDesc.get.call(this);
|
|
7349
7816
|
/**
|
|
7350
7817
|
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
@@ -7363,16 +7830,34 @@ function patchElementAndDocument() {
|
|
|
7363
7830
|
return result;
|
|
7364
7831
|
},
|
|
7365
7832
|
});
|
|
7833
|
+
rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
|
|
7834
|
+
configurable: true,
|
|
7835
|
+
enumerable: true,
|
|
7836
|
+
get() {
|
|
7837
|
+
return globalEnv.rawInnerHTMLDesc.get.call(this);
|
|
7838
|
+
},
|
|
7839
|
+
set(code) {
|
|
7840
|
+
globalEnv.rawInnerHTMLDesc.set.call(this, code);
|
|
7841
|
+
const currentAppName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
7842
|
+
Array.from(this.children).forEach((child) => {
|
|
7843
|
+
if (isElement(child) && currentAppName) {
|
|
7844
|
+
updateElementInfo(child, currentAppName);
|
|
7845
|
+
}
|
|
7846
|
+
});
|
|
7847
|
+
}
|
|
7848
|
+
});
|
|
7849
|
+
// patch cloneNode
|
|
7850
|
+
rawRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
7851
|
+
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
7852
|
+
return updateElementInfo(clonedNode, this.__MICRO_APP_NAME__);
|
|
7853
|
+
};
|
|
7366
7854
|
}
|
|
7367
7855
|
/**
|
|
7368
7856
|
* Mark the newly created element in the micro application
|
|
7369
7857
|
* @param element new element
|
|
7370
7858
|
*/
|
|
7371
7859
|
function markElement(element) {
|
|
7372
|
-
|
|
7373
|
-
if (currentAppName)
|
|
7374
|
-
element.__MICRO_APP_NAME__ = currentAppName;
|
|
7375
|
-
return element;
|
|
7860
|
+
return updateElementInfo(element, getCurrentAppName());
|
|
7376
7861
|
}
|
|
7377
7862
|
// methods of document
|
|
7378
7863
|
function patchDocument$2() {
|
|
@@ -7503,18 +7988,18 @@ function releasePatchElementAndDocument() {
|
|
|
7503
7988
|
releasePatchDocument();
|
|
7504
7989
|
const rawRootElement = globalEnv.rawRootElement;
|
|
7505
7990
|
const rawRootNode = globalEnv.rawRootNode;
|
|
7506
|
-
|
|
7507
|
-
|
|
7508
|
-
|
|
7509
|
-
|
|
7991
|
+
rawRootNode.prototype.appendChild = globalEnv.rawAppendChild;
|
|
7992
|
+
rawRootNode.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
7993
|
+
rawRootNode.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
7994
|
+
rawRootNode.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
7995
|
+
rawRootNode.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
7510
7996
|
rawRootElement.prototype.append = globalEnv.rawAppend;
|
|
7511
7997
|
rawRootElement.prototype.prepend = globalEnv.rawPrepend;
|
|
7512
|
-
rawRootElement.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
7513
7998
|
rawRootElement.prototype.querySelector = globalEnv.rawElementQuerySelector;
|
|
7514
7999
|
rawRootElement.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
|
|
7515
8000
|
rawRootElement.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
7516
|
-
rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
|
|
7517
8001
|
rawDefineProperty(rawRootNode.prototype, 'parentNode', globalEnv.rawParentNodeDesc);
|
|
8002
|
+
rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
|
|
7518
8003
|
}
|
|
7519
8004
|
// Set the style of micro-app-head and micro-app-body
|
|
7520
8005
|
let hasRejectMicroAppStyle = false;
|
|
@@ -7544,15 +8029,18 @@ function initGlobalEnv() {
|
|
|
7544
8029
|
const rawRootElement = rawWindow.Element;
|
|
7545
8030
|
const rawRootNode = rawWindow.Node;
|
|
7546
8031
|
const rawRootEventTarget = rawWindow.EventTarget;
|
|
8032
|
+
const rawDocumentFragment = rawWindow.DocumentFragment;
|
|
7547
8033
|
// save patch raw methods, pay attention to this binding
|
|
8034
|
+
const rawAppendChild = rawRootNode.prototype.appendChild;
|
|
8035
|
+
const rawInsertBefore = rawRootNode.prototype.insertBefore;
|
|
8036
|
+
const rawReplaceChild = rawRootNode.prototype.replaceChild;
|
|
8037
|
+
const rawRemoveChild = rawRootNode.prototype.removeChild;
|
|
7548
8038
|
const rawSetAttribute = rawRootElement.prototype.setAttribute;
|
|
7549
|
-
const rawAppendChild = rawRootElement.prototype.appendChild;
|
|
7550
|
-
const rawInsertBefore = rawRootElement.prototype.insertBefore;
|
|
7551
|
-
const rawReplaceChild = rawRootElement.prototype.replaceChild;
|
|
7552
|
-
const rawRemoveChild = rawRootElement.prototype.removeChild;
|
|
7553
8039
|
const rawAppend = rawRootElement.prototype.append;
|
|
7554
8040
|
const rawPrepend = rawRootElement.prototype.prepend;
|
|
7555
|
-
const
|
|
8041
|
+
const rawFragmentAppend = rawDocumentFragment.prototype.append;
|
|
8042
|
+
const rawFragmentPrepend = rawDocumentFragment.prototype.prepend;
|
|
8043
|
+
const rawCloneNode = rawRootNode.prototype.cloneNode;
|
|
7556
8044
|
const rawElementQuerySelector = rawRootElement.prototype.querySelector;
|
|
7557
8045
|
const rawElementQuerySelectorAll = rawRootElement.prototype.querySelectorAll;
|
|
7558
8046
|
const rawInsertAdjacentElement = rawRootElement.prototype.insertAdjacentElement;
|
|
@@ -7570,13 +8058,10 @@ function initGlobalEnv() {
|
|
|
7570
8058
|
const rawGetElementsByClassName = rawRootDocument.prototype.getElementsByClassName;
|
|
7571
8059
|
const rawGetElementsByTagName = rawRootDocument.prototype.getElementsByTagName;
|
|
7572
8060
|
const rawGetElementsByName = rawRootDocument.prototype.getElementsByName;
|
|
7573
|
-
|
|
8061
|
+
// TODO: 将ImageProxy移出去
|
|
8062
|
+
const ImageProxy = new Proxy(rawWindow.Image, {
|
|
7574
8063
|
construct(Target, args) {
|
|
7575
|
-
|
|
7576
|
-
const currentAppName = getCurrentAppName();
|
|
7577
|
-
if (currentAppName)
|
|
7578
|
-
elementImage.__MICRO_APP_NAME__ = currentAppName;
|
|
7579
|
-
return elementImage;
|
|
8064
|
+
return updateElementInfo(new Target(...args), getCurrentAppName());
|
|
7580
8065
|
},
|
|
7581
8066
|
});
|
|
7582
8067
|
/**
|
|
@@ -7602,6 +8087,7 @@ function initGlobalEnv() {
|
|
|
7602
8087
|
rawRootDocument,
|
|
7603
8088
|
rawRootElement,
|
|
7604
8089
|
rawRootNode,
|
|
8090
|
+
rawDocumentFragment,
|
|
7605
8091
|
// source/patch
|
|
7606
8092
|
rawSetAttribute,
|
|
7607
8093
|
rawAppendChild,
|
|
@@ -7610,6 +8096,8 @@ function initGlobalEnv() {
|
|
|
7610
8096
|
rawRemoveChild,
|
|
7611
8097
|
rawAppend,
|
|
7612
8098
|
rawPrepend,
|
|
8099
|
+
rawFragmentAppend,
|
|
8100
|
+
rawFragmentPrepend,
|
|
7613
8101
|
rawCloneNode,
|
|
7614
8102
|
rawElementQuerySelector,
|
|
7615
8103
|
rawElementQuerySelectorAll,
|
|
@@ -7649,7 +8137,7 @@ function initGlobalEnv() {
|
|
|
7649
8137
|
* @param tagName element name
|
|
7650
8138
|
*/
|
|
7651
8139
|
function defineElement(tagName) {
|
|
7652
|
-
class MicroAppElement extends
|
|
8140
|
+
class MicroAppElement extends HTMLElement {
|
|
7653
8141
|
constructor() {
|
|
7654
8142
|
super(...arguments);
|
|
7655
8143
|
this.isWaiting = false;
|
|
@@ -7714,6 +8202,13 @@ function defineElement(tagName) {
|
|
|
7714
8202
|
// baseRoute: route prefix, default is ''
|
|
7715
8203
|
// keep-alive: open keep-alive mode
|
|
7716
8204
|
connectedCallback() {
|
|
8205
|
+
/**
|
|
8206
|
+
* In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
|
|
8207
|
+
* If <micro-app>.prototype is not MicroAppElement.prototype, we should reset it
|
|
8208
|
+
*/
|
|
8209
|
+
if (Object.getPrototypeOf(this) !== MicroAppElement.prototype) {
|
|
8210
|
+
Object.setPrototypeOf(this, MicroAppElement.prototype);
|
|
8211
|
+
}
|
|
7717
8212
|
const cacheCount = ++this.connectedCount;
|
|
7718
8213
|
this.connectStateMap.set(cacheCount, true);
|
|
7719
8214
|
/**
|
|
@@ -7846,12 +8341,12 @@ function defineElement(tagName) {
|
|
|
7846
8341
|
/**
|
|
7847
8342
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
7848
8343
|
*/
|
|
7849
|
-
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url
|
|
8344
|
+
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url ${oldAppUrl} replaced by a new app with url ${targetUrl}`, this.appName);
|
|
7850
8345
|
}
|
|
7851
8346
|
this.handleCreateApp();
|
|
7852
8347
|
}
|
|
7853
8348
|
else {
|
|
7854
|
-
logError(`app name conflict, an app named
|
|
8349
|
+
logError(`app name conflict, an app named ${this.appName} with url ${oldAppUrl} is running`);
|
|
7855
8350
|
}
|
|
7856
8351
|
}
|
|
7857
8352
|
else {
|
|
@@ -8095,6 +8590,7 @@ function defineElement(tagName) {
|
|
|
8095
8590
|
}
|
|
8096
8591
|
else {
|
|
8097
8592
|
// get path from browser URL
|
|
8593
|
+
// TODO: 新版本路由系统要重新兼容ssr
|
|
8098
8594
|
let targetPath = getNoHashMicroPathFromURL(this.appName, baseUrl);
|
|
8099
8595
|
const defaultPagePath = this.getDefaultPage();
|
|
8100
8596
|
if (!targetPath && defaultPagePath) {
|
|
@@ -8122,8 +8618,9 @@ function defineElement(tagName) {
|
|
|
8122
8618
|
* @returns router-mode
|
|
8123
8619
|
*/
|
|
8124
8620
|
getMemoryRouterMode() {
|
|
8125
|
-
return
|
|
8621
|
+
return initRouterMode(this.getAttribute('router-mode'),
|
|
8126
8622
|
// is micro-app element set disable-memory-router, like <micro-app disable-memory-router></micro-app>
|
|
8623
|
+
// or <micro-app disable-memory-router='false'></micro-app>
|
|
8127
8624
|
this.compatibleProperties('disable-memory-router') && this.compatibleDisableProperties('disable-memory-router'));
|
|
8128
8625
|
}
|
|
8129
8626
|
/**
|
|
@@ -8150,6 +8647,17 @@ function defineElement(tagName) {
|
|
|
8150
8647
|
globalEnv.rawSetAttribute.call(this, key, value);
|
|
8151
8648
|
}
|
|
8152
8649
|
}
|
|
8650
|
+
/**
|
|
8651
|
+
* get delay time of router event
|
|
8652
|
+
* @returns delay time
|
|
8653
|
+
*/
|
|
8654
|
+
getRouterEventDelay() {
|
|
8655
|
+
let delay = parseInt(this.getAttribute('router-event-delay'));
|
|
8656
|
+
if (isNaN(delay)) {
|
|
8657
|
+
delay = parseInt((isFunction(microApp.options['router-event-delay']) ? microApp.options['router-event-delay'](this.appName) : microApp.options['router-event-delay']));
|
|
8658
|
+
}
|
|
8659
|
+
return !isNaN(delay) ? delay : 0;
|
|
8660
|
+
}
|
|
8153
8661
|
/**
|
|
8154
8662
|
* Data from the base application
|
|
8155
8663
|
*/
|
|
@@ -8186,7 +8694,7 @@ function defineElement(tagName) {
|
|
|
8186
8694
|
return this.getBaseRouteCompatible();
|
|
8187
8695
|
}
|
|
8188
8696
|
}
|
|
8189
|
-
|
|
8697
|
+
window.customElements.define(tagName, MicroAppElement);
|
|
8190
8698
|
}
|
|
8191
8699
|
|
|
8192
8700
|
/**
|
|
@@ -8218,7 +8726,7 @@ function preFetch(apps, delay) {
|
|
|
8218
8726
|
const delayTime = isNumber(delay) ? delay : microApp.options.prefetchDelay;
|
|
8219
8727
|
/**
|
|
8220
8728
|
* TODO: remove setTimeout
|
|
8221
|
-
*
|
|
8729
|
+
* 如果要保留setTimeout,则需要考虑清空定时器的情况
|
|
8222
8730
|
*/
|
|
8223
8731
|
setTimeout(() => {
|
|
8224
8732
|
// releasePrefetchEffect()
|
|
@@ -8272,7 +8780,7 @@ function preFetchAction(options) {
|
|
|
8272
8780
|
* 问题:
|
|
8273
8781
|
* 1、如何确保子应用进行跳转时不影响到浏览器地址??pure??
|
|
8274
8782
|
*/
|
|
8275
|
-
routerMode:
|
|
8783
|
+
routerMode: initRouterMode(options['router-mode']),
|
|
8276
8784
|
baseroute: options.baseroute,
|
|
8277
8785
|
disablePatchRequest: options['disable-patch-request'],
|
|
8278
8786
|
});
|
|
@@ -8309,7 +8817,7 @@ function getGlobalAssets(assets) {
|
|
|
8309
8817
|
// TODO: requestIdleCallback for every file
|
|
8310
8818
|
function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
8311
8819
|
if (isArray(resources)) {
|
|
8312
|
-
const effectiveResource = resources.filter((path) => isString(path) && path
|
|
8820
|
+
const effectiveResource = resources.filter((path) => isString(path) && isTargetExtension(path, suffix) && !sourceHandler.hasInfo(path));
|
|
8313
8821
|
const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
|
|
8314
8822
|
// fetch resource with stream
|
|
8315
8823
|
promiseStream(fetchResourcePromise, (res) => {
|
|
@@ -8453,7 +8961,7 @@ function unmountApp(appName, options) {
|
|
|
8453
8961
|
}
|
|
8454
8962
|
}
|
|
8455
8963
|
else {
|
|
8456
|
-
logWarn(`app ${appName} does not exist`);
|
|
8964
|
+
logWarn(`app ${appName} does not exist when unmountApp`);
|
|
8457
8965
|
resolve(false);
|
|
8458
8966
|
}
|
|
8459
8967
|
});
|
|
@@ -8483,7 +8991,7 @@ function reload(appName, destroy) {
|
|
|
8483
8991
|
}
|
|
8484
8992
|
}
|
|
8485
8993
|
else {
|
|
8486
|
-
logWarn(`app ${appName} does not exist`);
|
|
8994
|
+
logWarn(`app ${appName} does not exist when reload app`);
|
|
8487
8995
|
resolve(false);
|
|
8488
8996
|
}
|
|
8489
8997
|
});
|
|
@@ -8538,20 +9046,6 @@ function renderApp(options) {
|
|
|
8538
9046
|
container.appendChild(microAppElement);
|
|
8539
9047
|
});
|
|
8540
9048
|
}
|
|
8541
|
-
/**
|
|
8542
|
-
* get app state
|
|
8543
|
-
* @param appName app.name
|
|
8544
|
-
* @returns app.state
|
|
8545
|
-
*/
|
|
8546
|
-
function getAppStatus(appName) {
|
|
8547
|
-
const app = appInstanceMap.get(formatAppName(appName));
|
|
8548
|
-
if (app) {
|
|
8549
|
-
return app.getLifeCycleState();
|
|
8550
|
-
}
|
|
8551
|
-
else {
|
|
8552
|
-
logWarn(`app ${appName} does not exist`);
|
|
8553
|
-
}
|
|
8554
|
-
}
|
|
8555
9049
|
class MicroApp extends EventCenterForBaseApp {
|
|
8556
9050
|
constructor() {
|
|
8557
9051
|
super(...arguments);
|
|
@@ -8566,7 +9060,6 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
8566
9060
|
this.getAllApps = getAllApps;
|
|
8567
9061
|
this.reload = reload;
|
|
8568
9062
|
this.renderApp = renderApp;
|
|
8569
|
-
this.getAppStatus = getAppStatus;
|
|
8570
9063
|
}
|
|
8571
9064
|
start(options) {
|
|
8572
9065
|
var _a, _b;
|
|
@@ -8591,7 +9084,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
8591
9084
|
}
|
|
8592
9085
|
}
|
|
8593
9086
|
initGlobalEnv();
|
|
8594
|
-
if (
|
|
9087
|
+
if (window.customElements.get(this.tagName)) {
|
|
8595
9088
|
return logWarn(`element ${this.tagName} is already defined`);
|
|
8596
9089
|
}
|
|
8597
9090
|
if (isPlainObject(options)) {
|
|
@@ -8622,5 +9115,5 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
8622
9115
|
const microApp = new MicroApp();
|
|
8623
9116
|
|
|
8624
9117
|
export default microApp;
|
|
8625
|
-
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps,
|
|
9118
|
+
export { EventCenterForMicroApp, MicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, reload, removeDomScope, renderApp, unmountAllApps, unmountApp, version };
|
|
8626
9119
|
//# sourceMappingURL=index.esm.js.map
|