@micro-zoe/micro-app 1.0.0-rc.0 → 1.0.0-rc.10
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 +46 -12
- package/lib/index.esm.js +1860 -952
- 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 +4 -1
- package/typings/global.d.ts +60 -46
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-rc.
|
|
1
|
+
const version = '1.0.0-rc.10';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -15,7 +15,9 @@ const assign = Object.assign;
|
|
|
15
15
|
// Object prototype methods
|
|
16
16
|
const rawDefineProperty = Object.defineProperty;
|
|
17
17
|
const rawDefineProperties = Object.defineProperties;
|
|
18
|
+
const rawToString = Object.prototype.toString;
|
|
18
19
|
const rawHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
20
|
+
const toTypeString = (value) => rawToString.call(value);
|
|
19
21
|
// is Undefined
|
|
20
22
|
function isUndefined(target) {
|
|
21
23
|
return target === undefined;
|
|
@@ -42,19 +44,20 @@ function isFunction(target) {
|
|
|
42
44
|
}
|
|
43
45
|
// is PlainObject
|
|
44
46
|
function isPlainObject(target) {
|
|
45
|
-
return
|
|
47
|
+
return toTypeString(target) === '[object Object]';
|
|
46
48
|
}
|
|
47
49
|
// is Object
|
|
48
50
|
function isObject(target) {
|
|
49
|
-
return typeof target === 'object';
|
|
51
|
+
return !isNull(target) && typeof target === 'object';
|
|
50
52
|
}
|
|
51
53
|
// is Promise
|
|
52
54
|
function isPromise(target) {
|
|
53
|
-
return
|
|
55
|
+
return toTypeString(target) === '[object Promise]';
|
|
54
56
|
}
|
|
55
57
|
// is bind function
|
|
56
58
|
function isBoundFunction(target) {
|
|
57
|
-
|
|
59
|
+
var _a;
|
|
60
|
+
return isFunction(target) && ((_a = target.name) === null || _a === void 0 ? void 0 : _a.indexOf('bound ')) === 0 && !target.hasOwnProperty('prototype');
|
|
58
61
|
}
|
|
59
62
|
// is constructor function
|
|
60
63
|
function isConstructor(target) {
|
|
@@ -86,41 +89,76 @@ function isNode(target) {
|
|
|
86
89
|
var _a;
|
|
87
90
|
return target instanceof Node || isNumber((_a = target) === null || _a === void 0 ? void 0 : _a.nodeType);
|
|
88
91
|
}
|
|
92
|
+
function isAnchorElement(target) {
|
|
93
|
+
return toTypeString(target) === '[object HTMLAnchorElement]';
|
|
94
|
+
}
|
|
95
|
+
function isAudioElement(target) {
|
|
96
|
+
return toTypeString(target) === '[object HTMLAudioElement]';
|
|
97
|
+
}
|
|
98
|
+
function isVideoElement(target) {
|
|
99
|
+
return toTypeString(target) === '[object HTMLVideoElement]';
|
|
100
|
+
}
|
|
89
101
|
function isLinkElement(target) {
|
|
90
|
-
|
|
91
|
-
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'LINK';
|
|
102
|
+
return toTypeString(target) === '[object HTMLLinkElement]';
|
|
92
103
|
}
|
|
93
104
|
function isStyleElement(target) {
|
|
94
|
-
|
|
95
|
-
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'STYLE';
|
|
105
|
+
return toTypeString(target) === '[object HTMLStyleElement]';
|
|
96
106
|
}
|
|
97
107
|
function isScriptElement(target) {
|
|
98
|
-
|
|
99
|
-
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'SCRIPT';
|
|
108
|
+
return toTypeString(target) === '[object HTMLScriptElement]';
|
|
100
109
|
}
|
|
101
110
|
function isIFrameElement(target) {
|
|
102
|
-
|
|
103
|
-
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IFRAME';
|
|
111
|
+
return toTypeString(target) === '[object HTMLIFrameElement]';
|
|
104
112
|
}
|
|
105
113
|
function isDivElement(target) {
|
|
106
|
-
|
|
107
|
-
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'DIV';
|
|
114
|
+
return toTypeString(target) === '[object HTMLDivElement]';
|
|
108
115
|
}
|
|
109
116
|
function isImageElement(target) {
|
|
110
|
-
|
|
111
|
-
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'IMG';
|
|
117
|
+
return toTypeString(target) === '[object HTMLImageElement]';
|
|
112
118
|
}
|
|
113
119
|
function isBaseElement(target) {
|
|
114
|
-
|
|
115
|
-
|
|
120
|
+
return toTypeString(target) === '[object HTMLBaseElement]';
|
|
121
|
+
}
|
|
122
|
+
function isDocumentFragment(target) {
|
|
123
|
+
return toTypeString(target) === '[object DocumentFragment]';
|
|
116
124
|
}
|
|
117
125
|
function isMicroAppBody(target) {
|
|
118
|
-
|
|
119
|
-
|
|
126
|
+
return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-BODY';
|
|
127
|
+
}
|
|
128
|
+
function isMicroAppHead(target) {
|
|
129
|
+
return isElement(target) && target.tagName.toUpperCase() === 'MICRO-APP-HEAD';
|
|
120
130
|
}
|
|
121
131
|
// is ProxyDocument
|
|
122
132
|
function isProxyDocument(target) {
|
|
123
|
-
return
|
|
133
|
+
return toTypeString(target) === '[object ProxyDocument]';
|
|
134
|
+
}
|
|
135
|
+
function isTargetExtension(path, suffix) {
|
|
136
|
+
try {
|
|
137
|
+
return createURL(path).pathname.split('.').pop() === suffix;
|
|
138
|
+
}
|
|
139
|
+
catch (_a) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
142
|
+
}
|
|
143
|
+
function includes(target, searchElement, fromIndex) {
|
|
144
|
+
if (target == null) {
|
|
145
|
+
throw new TypeError('includes target is null or undefined');
|
|
146
|
+
}
|
|
147
|
+
const O = Object(target);
|
|
148
|
+
const len = parseInt(O.length, 10) || 0;
|
|
149
|
+
if (len === 0)
|
|
150
|
+
return false;
|
|
151
|
+
// @ts-ignore
|
|
152
|
+
fromIndex = parseInt(fromIndex, 10) || 0;
|
|
153
|
+
let i = Math.max(fromIndex >= 0 ? fromIndex : len + fromIndex, 0);
|
|
154
|
+
while (i < len) {
|
|
155
|
+
// NaN !== NaN
|
|
156
|
+
if (searchElement === O[i] || (searchElement !== searchElement && O[i] !== O[i])) {
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
159
|
+
i++;
|
|
160
|
+
}
|
|
161
|
+
return false;
|
|
124
162
|
}
|
|
125
163
|
/**
|
|
126
164
|
* format error log
|
|
@@ -158,6 +196,14 @@ function logWarn(msg, appName = null, ...rest) {
|
|
|
158
196
|
function defer(fn, ...args) {
|
|
159
197
|
Promise.resolve().then(fn.bind(null, ...args));
|
|
160
198
|
}
|
|
199
|
+
/**
|
|
200
|
+
* async execution with macro task
|
|
201
|
+
* @param fn callback
|
|
202
|
+
* @param args params
|
|
203
|
+
*/
|
|
204
|
+
function macro(fn, delay = 0, ...args) {
|
|
205
|
+
setTimeout(fn.bind(null, ...args), delay);
|
|
206
|
+
}
|
|
161
207
|
/**
|
|
162
208
|
* create URL as MicroLocation
|
|
163
209
|
*/
|
|
@@ -185,13 +231,13 @@ function formatAppURL(url, appName = null) {
|
|
|
185
231
|
if (!isString(url) || !url)
|
|
186
232
|
return '';
|
|
187
233
|
try {
|
|
188
|
-
const { origin, pathname, search } = createURL(addProtocol(url));
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
const fullPath = `${origin}${pathname}
|
|
194
|
-
return /^https?:\/\//.test(fullPath) ?
|
|
234
|
+
const { origin, pathname, search } = createURL(addProtocol(url), (window.rawWindow || window).location.href);
|
|
235
|
+
/**
|
|
236
|
+
* keep the original url unchanged, such as .html .node .php .net .etc, search, except hash
|
|
237
|
+
* BUG FIX: Never using '/' to complete url, refer to https://github.com/micro-zoe/micro-app/issues/1147
|
|
238
|
+
*/
|
|
239
|
+
const fullPath = `${origin}${pathname}${search}`;
|
|
240
|
+
return /^https?:\/\//.test(fullPath) ? fullPath : '';
|
|
195
241
|
}
|
|
196
242
|
catch (e) {
|
|
197
243
|
logError(e, appName);
|
|
@@ -214,14 +260,15 @@ function formatAppName(name) {
|
|
|
214
260
|
return name.replace(/(^\d+)|([^\w\d-_])/gi, '');
|
|
215
261
|
}
|
|
216
262
|
/**
|
|
217
|
-
* Get valid address, such as
|
|
263
|
+
* Get valid address, such as
|
|
264
|
+
* 1. https://domain/xx/xx.html to https://domain/xx/
|
|
265
|
+
* 2. https://domain/xx to https://domain/xx/
|
|
218
266
|
* @param url app.url
|
|
219
267
|
*/
|
|
220
268
|
function getEffectivePath(url) {
|
|
221
269
|
const { origin, pathname } = createURL(url);
|
|
222
270
|
if (/\.(\w+)$/.test(pathname)) {
|
|
223
|
-
const
|
|
224
|
-
const pathArr = fullPath.split('/');
|
|
271
|
+
const pathArr = `${origin}${pathname}`.split('/');
|
|
225
272
|
pathArr.pop();
|
|
226
273
|
return pathArr.join('/') + '/';
|
|
227
274
|
}
|
|
@@ -320,63 +367,75 @@ function promiseRequestIdle(callback) {
|
|
|
320
367
|
/**
|
|
321
368
|
* Record the currently running app.name
|
|
322
369
|
*/
|
|
323
|
-
let
|
|
370
|
+
let currentAppName = null;
|
|
324
371
|
function setCurrentAppName(appName) {
|
|
325
|
-
|
|
372
|
+
currentAppName = appName;
|
|
373
|
+
}
|
|
374
|
+
// get the currently running app.name
|
|
375
|
+
function getCurrentAppName() {
|
|
376
|
+
return currentAppName;
|
|
326
377
|
}
|
|
327
378
|
function throttleDeferForSetAppName(appName) {
|
|
328
|
-
if (
|
|
379
|
+
if (currentAppName !== appName && !getPreventSetState()) {
|
|
329
380
|
setCurrentAppName(appName);
|
|
330
381
|
defer(() => {
|
|
331
382
|
setCurrentAppName(null);
|
|
332
383
|
});
|
|
333
384
|
}
|
|
334
385
|
}
|
|
335
|
-
//
|
|
336
|
-
|
|
337
|
-
|
|
386
|
+
// only for iframe document.body(head).querySelector(querySelectorAll)
|
|
387
|
+
let iframeCurrentAppName = null;
|
|
388
|
+
function setIframeCurrentAppName(appName) {
|
|
389
|
+
iframeCurrentAppName = appName;
|
|
338
390
|
}
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
391
|
+
function getIframeCurrentAppName() {
|
|
392
|
+
return iframeCurrentAppName;
|
|
393
|
+
}
|
|
394
|
+
function throttleDeferForIframeAppName(appName) {
|
|
395
|
+
if (iframeCurrentAppName !== appName && !getPreventSetState()) {
|
|
396
|
+
setIframeCurrentAppName(appName);
|
|
397
|
+
defer(() => {
|
|
398
|
+
setIframeCurrentAppName(null);
|
|
399
|
+
});
|
|
400
|
+
}
|
|
401
|
+
}
|
|
402
|
+
// prevent set app name
|
|
403
|
+
let preventSetState = false;
|
|
404
|
+
function getPreventSetState() {
|
|
405
|
+
return preventSetState;
|
|
406
|
+
}
|
|
407
|
+
/**
|
|
408
|
+
* prevent set appName
|
|
409
|
+
* usage:
|
|
410
|
+
* removeDomScope(true)
|
|
411
|
+
* -----> element scope point to base app <-----
|
|
412
|
+
* removeDomScope(false)
|
|
413
|
+
*/
|
|
414
|
+
function removeDomScope(force) {
|
|
415
|
+
if (force !== false) {
|
|
416
|
+
setCurrentAppName(null);
|
|
417
|
+
setIframeCurrentAppName(null);
|
|
418
|
+
if (force && !preventSetState) {
|
|
419
|
+
preventSetState = true;
|
|
420
|
+
defer(() => {
|
|
421
|
+
preventSetState = false;
|
|
422
|
+
});
|
|
423
|
+
}
|
|
424
|
+
}
|
|
425
|
+
else {
|
|
426
|
+
preventSetState = false;
|
|
427
|
+
}
|
|
342
428
|
}
|
|
343
429
|
/**
|
|
344
430
|
* Create pure elements
|
|
345
431
|
*/
|
|
346
432
|
function pureCreateElement(tagName, options) {
|
|
347
|
-
const element = document.createElement(tagName, options);
|
|
433
|
+
const element = (window.rawDocument || document).createElement(tagName, options);
|
|
348
434
|
if (element.__MICRO_APP_NAME__)
|
|
349
435
|
delete element.__MICRO_APP_NAME__;
|
|
350
436
|
element.__PURE_ELEMENT__ = true;
|
|
351
437
|
return element;
|
|
352
438
|
}
|
|
353
|
-
/**
|
|
354
|
-
* clone origin elements to target
|
|
355
|
-
* @param origin Cloned element
|
|
356
|
-
* @param target Accept cloned elements
|
|
357
|
-
* @param deep deep clone or transfer dom
|
|
358
|
-
*/
|
|
359
|
-
function cloneContainer(target, origin, deep) {
|
|
360
|
-
// 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
|
|
361
|
-
if (origin) {
|
|
362
|
-
target.innerHTML = '';
|
|
363
|
-
if (deep) {
|
|
364
|
-
// TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
|
|
365
|
-
const clonedNode = origin.cloneNode(true);
|
|
366
|
-
const fragment = document.createDocumentFragment();
|
|
367
|
-
Array.from(clonedNode.childNodes).forEach((node) => {
|
|
368
|
-
fragment.appendChild(node);
|
|
369
|
-
});
|
|
370
|
-
target.appendChild(fragment);
|
|
371
|
-
}
|
|
372
|
-
else {
|
|
373
|
-
Array.from(origin.childNodes).forEach((node) => {
|
|
374
|
-
target.appendChild(node);
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
}
|
|
378
|
-
return target;
|
|
379
|
-
}
|
|
380
439
|
// is invalid key of querySelector
|
|
381
440
|
function isInvalidQuerySelectorKey(key) {
|
|
382
441
|
return !key || /(^\d)|([^\w\d-_\u4e00-\u9fa5])/gi.test(key);
|
|
@@ -550,11 +609,49 @@ function execMicroAppGlobalHook(fn, appName, hookName, ...args) {
|
|
|
550
609
|
logError(`An error occurred in app ${appName} window.${hookName} \n`, null, e);
|
|
551
610
|
}
|
|
552
611
|
}
|
|
612
|
+
/**
|
|
613
|
+
* remove all childNode from target node
|
|
614
|
+
* @param $dom target node
|
|
615
|
+
*/
|
|
553
616
|
function clearDOM($dom) {
|
|
554
617
|
while ($dom === null || $dom === void 0 ? void 0 : $dom.firstChild) {
|
|
555
618
|
$dom.removeChild($dom.firstChild);
|
|
556
619
|
}
|
|
557
620
|
}
|
|
621
|
+
function instanceOf(instance, constructor) {
|
|
622
|
+
if (instance === null || instance === undefined) {
|
|
623
|
+
return false;
|
|
624
|
+
}
|
|
625
|
+
else if (!isFunction(constructor)) {
|
|
626
|
+
throw new TypeError("Right-hand side of 'instanceof' is not callable");
|
|
627
|
+
}
|
|
628
|
+
let proto = Object.getPrototypeOf(instance);
|
|
629
|
+
while (proto) {
|
|
630
|
+
if (proto === constructor.prototype) {
|
|
631
|
+
return true;
|
|
632
|
+
}
|
|
633
|
+
proto = Object.getPrototypeOf(proto);
|
|
634
|
+
}
|
|
635
|
+
return false;
|
|
636
|
+
}
|
|
637
|
+
/**
|
|
638
|
+
* Format event name
|
|
639
|
+
* 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
|
|
640
|
+
* Issue: https://github.com/micro-zoe/micro-app/issues/1161
|
|
641
|
+
* @param type event name
|
|
642
|
+
* @param appName app name
|
|
643
|
+
*/
|
|
644
|
+
const formatEventList = ['mounted', 'unmount'];
|
|
645
|
+
function formatEventType(type, appName) {
|
|
646
|
+
return formatEventList.includes(type) ? `${type}-${appName}` : type;
|
|
647
|
+
}
|
|
648
|
+
/**
|
|
649
|
+
* Is the object empty
|
|
650
|
+
* target maybe number, string, array ...
|
|
651
|
+
*/
|
|
652
|
+
function isEmptyObject(target) {
|
|
653
|
+
return isPlainObject(target) ? !Object.keys(target).length : true;
|
|
654
|
+
}
|
|
558
655
|
|
|
559
656
|
function formatEventInfo(event, element) {
|
|
560
657
|
Object.defineProperties(event, {
|
|
@@ -581,7 +678,7 @@ function formatEventInfo(event, element) {
|
|
|
581
678
|
function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
582
679
|
var _a;
|
|
583
680
|
if (!element) {
|
|
584
|
-
return
|
|
681
|
+
return logWarn(`element does not exist in lifecycle ${lifecycleName}`, appName);
|
|
585
682
|
}
|
|
586
683
|
element = getRootContainer(element);
|
|
587
684
|
// clear dom scope before dispatch lifeCycles event to base app, especially mounted & unmount
|
|
@@ -598,19 +695,19 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
598
695
|
formatEventInfo(event, element);
|
|
599
696
|
// global hooks
|
|
600
697
|
if (isFunction((_a = microApp.options.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
601
|
-
microApp.options.lifeCycles[lifecycleName](event);
|
|
698
|
+
microApp.options.lifeCycles[lifecycleName](event, appName);
|
|
602
699
|
}
|
|
603
700
|
element.dispatchEvent(event);
|
|
604
701
|
}
|
|
605
702
|
/**
|
|
606
703
|
* Dispatch custom event to micro app
|
|
607
704
|
* @param app app
|
|
608
|
-
* @param eventName event name ['unmount', 'appstate-change']
|
|
705
|
+
* @param eventName event name ['mounted', 'unmount', 'appstate-change', 'statechange']
|
|
609
706
|
* @param detail event detail
|
|
610
707
|
*/
|
|
611
708
|
function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
|
|
612
709
|
var _a;
|
|
613
|
-
const event = new CustomEvent(eventName, {
|
|
710
|
+
const event = new CustomEvent(formatEventType(eventName, app.name), {
|
|
614
711
|
detail,
|
|
615
712
|
});
|
|
616
713
|
(_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microAppWindow.dispatchEvent(event);
|
|
@@ -654,7 +751,11 @@ class HTMLLoader {
|
|
|
654
751
|
run(app, successCb) {
|
|
655
752
|
const appName = app.name;
|
|
656
753
|
const htmlUrl = app.ssrUrl || app.url;
|
|
657
|
-
|
|
754
|
+
const isJsResource = isTargetExtension(htmlUrl, 'js');
|
|
755
|
+
const htmlPromise = isJsResource
|
|
756
|
+
? Promise.resolve(`<micro-app-head><script src='${htmlUrl}'></script></micro-app-head><micro-app-body></micro-app-body>`)
|
|
757
|
+
: fetchSource(htmlUrl, appName, { cache: 'no-cache' });
|
|
758
|
+
htmlPromise.then((htmlStr) => {
|
|
658
759
|
if (!htmlStr) {
|
|
659
760
|
const msg = 'html is empty, please check in detail';
|
|
660
761
|
app.onerror(new Error(msg));
|
|
@@ -773,7 +874,7 @@ class CSSParser {
|
|
|
773
874
|
// reset scopecssDisableNextLine
|
|
774
875
|
this.scopecssDisableNextLine = false;
|
|
775
876
|
if (!selectors)
|
|
776
|
-
return
|
|
877
|
+
return this.printError('selector missing', this.linkPath);
|
|
777
878
|
this.recordResult(selectors);
|
|
778
879
|
this.matchComments();
|
|
779
880
|
this.styleDeclarations();
|
|
@@ -784,9 +885,24 @@ class CSSParser {
|
|
|
784
885
|
const m = this.commonMatch(/^[^{]+/, skip);
|
|
785
886
|
if (!m)
|
|
786
887
|
return false;
|
|
888
|
+
/**
|
|
889
|
+
* NOTE:
|
|
890
|
+
* 1. :is(h1, h2, h3):has(+ h2, + h3, + h4) {}
|
|
891
|
+
* should be ==> micro-app[name=xxx] :is(h1, h2, h3):has(+ h2, + h3, + h4) {}
|
|
892
|
+
* 2. :dir(ltr) {}
|
|
893
|
+
* should be ==> micro-app[name=xxx] :dir(ltr) {}
|
|
894
|
+
* 3. body :not(div, .fancy) {}
|
|
895
|
+
* should be ==> micro-app[name=xxx] micro-app-body :not(div, .fancy) {}
|
|
896
|
+
* 4. .a, .b, li:nth-child(3)
|
|
897
|
+
* should be ==> micro-app[name=xxx] .a, micro-app[name=xxx] .b, micro-app[name=xxx] li:nth-child(3)
|
|
898
|
+
* 5. :is(.a, .b, .c) a {}
|
|
899
|
+
* should be ==> micro-app[name=xxx] :is(.a, .b, .c) a {}
|
|
900
|
+
* 6. :where(.a, .b, .c) a {}
|
|
901
|
+
* should be ==> micro-app[name=xxx] :where(.a, .b, .c) a {}
|
|
902
|
+
*/
|
|
787
903
|
return m[0].replace(/(^|,[\n\s]*)([^,]+)/g, (_, separator, selector) => {
|
|
788
904
|
selector = trim(selector);
|
|
789
|
-
if (!(this.scopecssDisableNextLine ||
|
|
905
|
+
if (selector && !(this.scopecssDisableNextLine ||
|
|
790
906
|
(this.scopecssDisable && (!this.scopecssDisableSelectors.length ||
|
|
791
907
|
this.scopecssDisableSelectors.includes(selector))) ||
|
|
792
908
|
rootSelectorREG.test(selector))) {
|
|
@@ -803,19 +919,19 @@ class CSSParser {
|
|
|
803
919
|
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration
|
|
804
920
|
styleDeclarations() {
|
|
805
921
|
if (!this.matchOpenBrace())
|
|
806
|
-
return
|
|
922
|
+
return this.printError("Declaration missing '{'", this.linkPath);
|
|
807
923
|
this.matchAllDeclarations();
|
|
808
924
|
if (!this.matchCloseBrace())
|
|
809
|
-
return
|
|
925
|
+
return this.printError("Declaration missing '}'", this.linkPath);
|
|
810
926
|
return true;
|
|
811
927
|
}
|
|
812
|
-
matchAllDeclarations() {
|
|
813
|
-
let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^}/])*/, true)[0];
|
|
928
|
+
matchAllDeclarations(nesting = 0) {
|
|
929
|
+
let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^{}/])*/, true)[0];
|
|
814
930
|
if (cssValue) {
|
|
815
931
|
if (!this.scopecssDisableNextLine &&
|
|
816
932
|
(!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
|
|
817
933
|
cssValue = cssValue.replace(/url\(["']?([^)"']+)["']?\)/gm, (all, $1) => {
|
|
818
|
-
if (/^((data|blob)
|
|
934
|
+
if (/^((data|blob):|#|%23)/.test($1) || /^(https?:)?\/\//.test($1)) {
|
|
819
935
|
return all;
|
|
820
936
|
}
|
|
821
937
|
// ./a/b.png ../a/b.png a/b.png
|
|
@@ -829,16 +945,28 @@ class CSSParser {
|
|
|
829
945
|
}
|
|
830
946
|
// reset scopecssDisableNextLine
|
|
831
947
|
this.scopecssDisableNextLine = false;
|
|
832
|
-
if (!this.cssText
|
|
948
|
+
if (!this.cssText.length)
|
|
833
949
|
return;
|
|
834
950
|
// extract comments in declarations
|
|
835
|
-
if (this.cssText.charAt(0) === '/'
|
|
836
|
-
this.
|
|
951
|
+
if (this.cssText.charAt(0) === '/') {
|
|
952
|
+
if (this.cssText.charAt(1) === '*') {
|
|
953
|
+
this.matchComments();
|
|
954
|
+
}
|
|
955
|
+
else {
|
|
956
|
+
this.commonMatch(/\/+/);
|
|
957
|
+
}
|
|
837
958
|
}
|
|
838
|
-
else {
|
|
839
|
-
this.
|
|
959
|
+
else if (this.cssText.charAt(0) === '{') {
|
|
960
|
+
this.matchOpenBrace();
|
|
961
|
+
nesting++;
|
|
962
|
+
}
|
|
963
|
+
else if (this.cssText.charAt(0) === '}') {
|
|
964
|
+
if (nesting < 1)
|
|
965
|
+
return;
|
|
966
|
+
this.matchCloseBrace();
|
|
967
|
+
nesting--;
|
|
840
968
|
}
|
|
841
|
-
return this.matchAllDeclarations();
|
|
969
|
+
return this.matchAllDeclarations(nesting);
|
|
842
970
|
}
|
|
843
971
|
matchAtRule() {
|
|
844
972
|
if (this.cssText[0] !== '@')
|
|
@@ -856,7 +984,8 @@ class CSSParser {
|
|
|
856
984
|
this.documentRule() ||
|
|
857
985
|
this.pageRule() ||
|
|
858
986
|
this.hostRule() ||
|
|
859
|
-
this.fontFaceRule()
|
|
987
|
+
this.fontFaceRule() ||
|
|
988
|
+
this.layerRule();
|
|
860
989
|
}
|
|
861
990
|
// :global is CSS Modules rule, it will be converted to normal syntax
|
|
862
991
|
// private matchGlobalRule (): boolean | void {
|
|
@@ -870,16 +999,16 @@ class CSSParser {
|
|
|
870
999
|
if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
|
|
871
1000
|
return false;
|
|
872
1001
|
if (!this.commonMatch(/^[^{]+/))
|
|
873
|
-
return
|
|
1002
|
+
return this.printError('@keyframes missing name', this.linkPath);
|
|
874
1003
|
this.matchComments();
|
|
875
1004
|
if (!this.matchOpenBrace())
|
|
876
|
-
return
|
|
1005
|
+
return this.printError("@keyframes missing '{'", this.linkPath);
|
|
877
1006
|
this.matchComments();
|
|
878
1007
|
while (this.keyframeRule()) {
|
|
879
1008
|
this.matchComments();
|
|
880
1009
|
}
|
|
881
1010
|
if (!this.matchCloseBrace())
|
|
882
|
-
return
|
|
1011
|
+
return this.printError("@keyframes missing '}'", this.linkPath);
|
|
883
1012
|
this.matchLeadingSpaces();
|
|
884
1013
|
return true;
|
|
885
1014
|
}
|
|
@@ -918,17 +1047,30 @@ class CSSParser {
|
|
|
918
1047
|
return false;
|
|
919
1048
|
return this.commonHandlerForAtRuleWithSelfRule('font-face');
|
|
920
1049
|
}
|
|
1050
|
+
// https://developer.mozilla.org/en-US/docs/Web/CSS/@layer
|
|
1051
|
+
layerRule() {
|
|
1052
|
+
if (!this.commonMatch(/^@layer\s*([^{;]+)/))
|
|
1053
|
+
return false;
|
|
1054
|
+
if (!this.matchOpenBrace())
|
|
1055
|
+
return !!this.commonMatch(/^[;]+/);
|
|
1056
|
+
this.matchComments();
|
|
1057
|
+
this.matchRules();
|
|
1058
|
+
if (!this.matchCloseBrace())
|
|
1059
|
+
return this.printError('@layer missing \'}\'', this.linkPath);
|
|
1060
|
+
this.matchLeadingSpaces();
|
|
1061
|
+
return true;
|
|
1062
|
+
}
|
|
921
1063
|
// common matcher for @media, @supports, @document, @host, :global, @container
|
|
922
1064
|
createMatcherForRuleWithChildRule(reg, name) {
|
|
923
1065
|
return () => {
|
|
924
1066
|
if (!this.commonMatch(reg))
|
|
925
1067
|
return false;
|
|
926
1068
|
if (!this.matchOpenBrace())
|
|
927
|
-
return
|
|
1069
|
+
return this.printError(`${name} missing '{'`, this.linkPath);
|
|
928
1070
|
this.matchComments();
|
|
929
1071
|
this.matchRules();
|
|
930
1072
|
if (!this.matchCloseBrace())
|
|
931
|
-
return
|
|
1073
|
+
return this.printError(`${name} missing '}'`, this.linkPath);
|
|
932
1074
|
this.matchLeadingSpaces();
|
|
933
1075
|
return true;
|
|
934
1076
|
};
|
|
@@ -946,10 +1088,10 @@ class CSSParser {
|
|
|
946
1088
|
// common handler for @font-face, @page
|
|
947
1089
|
commonHandlerForAtRuleWithSelfRule(name) {
|
|
948
1090
|
if (!this.matchOpenBrace())
|
|
949
|
-
return
|
|
1091
|
+
return this.printError(`@${name} missing '{'`, this.linkPath);
|
|
950
1092
|
this.matchAllDeclarations();
|
|
951
1093
|
if (!this.matchCloseBrace())
|
|
952
|
-
return
|
|
1094
|
+
return this.printError(`@${name} missing '}'`, this.linkPath);
|
|
953
1095
|
this.matchLeadingSpaces();
|
|
954
1096
|
return true;
|
|
955
1097
|
}
|
|
@@ -969,7 +1111,7 @@ class CSSParser {
|
|
|
969
1111
|
++i;
|
|
970
1112
|
i += 2;
|
|
971
1113
|
if (this.cssText.charAt(i - 1) === '') {
|
|
972
|
-
return
|
|
1114
|
+
return this.printError('End of comment missing', this.linkPath);
|
|
973
1115
|
}
|
|
974
1116
|
// get comment content
|
|
975
1117
|
let commentText = this.cssText.slice(2, i - 2);
|
|
@@ -1013,7 +1155,7 @@ class CSSParser {
|
|
|
1013
1155
|
return this.commonMatch(/^{\s*/);
|
|
1014
1156
|
}
|
|
1015
1157
|
matchCloseBrace() {
|
|
1016
|
-
return this.commonMatch(/^}
|
|
1158
|
+
return this.commonMatch(/^}\s*/);
|
|
1017
1159
|
}
|
|
1018
1160
|
// match and slice the leading spaces
|
|
1019
1161
|
matchLeadingSpaces() {
|
|
@@ -1029,6 +1171,11 @@ class CSSParser {
|
|
|
1029
1171
|
this.result += strFragment;
|
|
1030
1172
|
}
|
|
1031
1173
|
}
|
|
1174
|
+
printError(msg, linkPath) {
|
|
1175
|
+
if (this.cssText.length) {
|
|
1176
|
+
parseError(msg, linkPath);
|
|
1177
|
+
}
|
|
1178
|
+
}
|
|
1032
1179
|
}
|
|
1033
1180
|
/**
|
|
1034
1181
|
* common method of bind CSS
|
|
@@ -1227,7 +1374,7 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
1227
1374
|
return { address: href, linkInfo };
|
|
1228
1375
|
}
|
|
1229
1376
|
}
|
|
1230
|
-
else if (rel && ['prefetch', 'preload', 'prerender'].includes(rel)) {
|
|
1377
|
+
else if (rel && ['prefetch', 'preload', 'prerender', 'modulepreload', 'icon'].includes(rel)) {
|
|
1231
1378
|
// preload prefetch prerender ....
|
|
1232
1379
|
if (isDynamic) {
|
|
1233
1380
|
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
@@ -1272,12 +1419,12 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
|
1272
1419
|
*/
|
|
1273
1420
|
if (fiberStyleResult) {
|
|
1274
1421
|
fiberStyleResult.then(() => {
|
|
1275
|
-
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1422
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
|
|
1276
1423
|
serialExecFiberTasks(fiberLinkTasks);
|
|
1277
1424
|
});
|
|
1278
1425
|
}
|
|
1279
1426
|
else {
|
|
1280
|
-
app.onLoad(wrapElement);
|
|
1427
|
+
app.onLoad({ html: wrapElement });
|
|
1281
1428
|
}
|
|
1282
1429
|
});
|
|
1283
1430
|
}
|
|
@@ -1441,41 +1588,83 @@ var MicroAppConfig;
|
|
|
1441
1588
|
MicroAppConfig["DISABLE_MEMORY_ROUTER"] = "disable-memory-router";
|
|
1442
1589
|
MicroAppConfig["DISABLE_PATCH_REQUEST"] = "disable-patch-request";
|
|
1443
1590
|
MicroAppConfig["KEEP_ROUTER_STATE"] = "keep-router-state";
|
|
1444
|
-
MicroAppConfig["HIDDEN_ROUTER"] = "hidden-router";
|
|
1445
1591
|
MicroAppConfig["KEEP_ALIVE"] = "keep-alive";
|
|
1446
1592
|
MicroAppConfig["CLEAR_DATA"] = "clear-data";
|
|
1447
1593
|
MicroAppConfig["SSR"] = "ssr";
|
|
1448
1594
|
MicroAppConfig["FIBER"] = "fiber";
|
|
1449
1595
|
})(MicroAppConfig || (MicroAppConfig = {}));
|
|
1596
|
+
/**
|
|
1597
|
+
* global key must be static key, they can not rewrite
|
|
1598
|
+
* e.g.
|
|
1599
|
+
* window.Promise = newValue
|
|
1600
|
+
* new Promise ==> still get old value, not newValue, because they are cached by top function
|
|
1601
|
+
* NOTE:
|
|
1602
|
+
* 1. Do not add fetch, XMLHttpRequest, EventSource
|
|
1603
|
+
*/
|
|
1604
|
+
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';
|
|
1450
1605
|
// prefetch level
|
|
1451
1606
|
const PREFETCH_LEVEL = [1, 2, 3];
|
|
1452
|
-
|
|
1607
|
+
/**
|
|
1608
|
+
* memory router modes
|
|
1609
|
+
* NOTE:
|
|
1610
|
+
* 1. The only difference between native and native-scope is location.origin, in native-scope mode location.origin point to child app
|
|
1611
|
+
* 2. native mode equal to disable-memory-router
|
|
1612
|
+
*/
|
|
1613
|
+
// 临时注释,1.0版本放开,默认模式切换为state
|
|
1614
|
+
// // default mode, sync child app router info to history.state
|
|
1615
|
+
// export const DEFAULT_ROUTER_MODE = 'state'
|
|
1616
|
+
// // sync child app router info to browser url as search
|
|
1617
|
+
// export const ROUTER_MODE_SEARCH = 'search'
|
|
1618
|
+
// 临时放开,1.0版本去除
|
|
1619
|
+
const ROUTER_MODE_STATE = 'state';
|
|
1453
1620
|
const DEFAULT_ROUTER_MODE = 'search';
|
|
1454
|
-
|
|
1455
|
-
const
|
|
1621
|
+
// render base on browser url, and location.origin location.href point to base app
|
|
1622
|
+
const ROUTER_MODE_NATIVE = 'native';
|
|
1623
|
+
// render base on browser url, but location.origin location.href point to child app
|
|
1624
|
+
const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
|
|
1625
|
+
// search mode, but child router info will not sync to browser url
|
|
1626
|
+
const ROUTER_MODE_PURE = 'pure';
|
|
1456
1627
|
const ROUTER_MODE_LIST = [
|
|
1457
1628
|
DEFAULT_ROUTER_MODE,
|
|
1458
|
-
|
|
1459
|
-
|
|
1629
|
+
ROUTER_MODE_STATE,
|
|
1630
|
+
ROUTER_MODE_NATIVE,
|
|
1631
|
+
ROUTER_MODE_NATIVE_SCOPE,
|
|
1632
|
+
ROUTER_MODE_PURE,
|
|
1460
1633
|
];
|
|
1461
1634
|
// event bound to child app window
|
|
1462
|
-
const
|
|
1635
|
+
const BASE_SCOPE_WINDOW_EVENT = [
|
|
1463
1636
|
'popstate',
|
|
1464
1637
|
'hashchange',
|
|
1465
1638
|
'load',
|
|
1466
|
-
'beforeunload',
|
|
1467
1639
|
'unload',
|
|
1468
1640
|
'unmount',
|
|
1469
1641
|
'appstate-change',
|
|
1642
|
+
'statechange',
|
|
1643
|
+
'mounted',
|
|
1470
1644
|
];
|
|
1645
|
+
// bind event of with sandbox
|
|
1646
|
+
const SCOPE_WINDOW_EVENT_OF_WITH = BASE_SCOPE_WINDOW_EVENT;
|
|
1647
|
+
// bind event of iframe sandbox
|
|
1648
|
+
const SCOPE_WINDOW_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_EVENT.concat([
|
|
1649
|
+
'unhandledrejection',
|
|
1650
|
+
'message'
|
|
1651
|
+
]);
|
|
1471
1652
|
// on event bound to child app window
|
|
1472
|
-
|
|
1653
|
+
// TODO: with和iframe处理方式不同,需修改
|
|
1654
|
+
const BASE_SCOPE_WINDOW_ON_EVENT = [
|
|
1473
1655
|
'onpopstate',
|
|
1474
1656
|
'onhashchange',
|
|
1475
1657
|
'onload',
|
|
1476
|
-
'onbeforeunload',
|
|
1477
1658
|
'onunload',
|
|
1659
|
+
'onerror'
|
|
1660
|
+
// 'onbeforeunload', // remove at 2024.5.30 by cangdu
|
|
1478
1661
|
];
|
|
1662
|
+
// bind on event of with sandbox
|
|
1663
|
+
const SCOPE_WINDOW_ON_EVENT_OF_WITH = BASE_SCOPE_WINDOW_ON_EVENT;
|
|
1664
|
+
// bind on event of iframe sandbox
|
|
1665
|
+
const SCOPE_WINDOW_ON_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_ON_EVENT.concat([
|
|
1666
|
+
'onunhandledrejection',
|
|
1667
|
+
]);
|
|
1479
1668
|
// event bound to child app document
|
|
1480
1669
|
const SCOPE_DOCUMENT_EVENT = [
|
|
1481
1670
|
'DOMContentLoaded',
|
|
@@ -1492,15 +1681,13 @@ const GLOBAL_KEY_TO_WINDOW = [
|
|
|
1492
1681
|
'globalThis',
|
|
1493
1682
|
];
|
|
1494
1683
|
const RAW_GLOBAL_TARGET = ['rawWindow', 'rawDocument'];
|
|
1495
|
-
|
|
1496
|
-
|
|
1497
|
-
|
|
1498
|
-
|
|
1499
|
-
|
|
1500
|
-
|
|
1501
|
-
|
|
1502
|
-
*/
|
|
1503
|
-
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';
|
|
1684
|
+
const HIJACK_LOCATION_KEYS = [
|
|
1685
|
+
'host',
|
|
1686
|
+
'hostname',
|
|
1687
|
+
'port',
|
|
1688
|
+
'protocol',
|
|
1689
|
+
'origin',
|
|
1690
|
+
];
|
|
1504
1691
|
|
|
1505
1692
|
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1506
1693
|
// whether use type='module' script
|
|
@@ -1524,8 +1711,7 @@ function isInlineMode(app, scriptInfo) {
|
|
|
1524
1711
|
return (app.inline ||
|
|
1525
1712
|
scriptInfo.appSpace[app.name].inline ||
|
|
1526
1713
|
isTypeModule(app, scriptInfo) ||
|
|
1527
|
-
isSpecialScript(app, scriptInfo)
|
|
1528
|
-
app.iframe);
|
|
1714
|
+
isSpecialScript(app, scriptInfo));
|
|
1529
1715
|
}
|
|
1530
1716
|
// TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
|
|
1531
1717
|
function getEffectWindow(app) {
|
|
@@ -1765,16 +1951,16 @@ function fetchScriptsFromHtml(wrapElement, app) {
|
|
|
1765
1951
|
logError(err, app.name);
|
|
1766
1952
|
}, () => {
|
|
1767
1953
|
if (fiberScriptTasks) {
|
|
1768
|
-
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1954
|
+
fiberScriptTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
|
|
1769
1955
|
serialExecFiberTasks(fiberScriptTasks);
|
|
1770
1956
|
}
|
|
1771
1957
|
else {
|
|
1772
|
-
app.onLoad(wrapElement);
|
|
1958
|
+
app.onLoad({ html: wrapElement });
|
|
1773
1959
|
}
|
|
1774
1960
|
});
|
|
1775
1961
|
}
|
|
1776
1962
|
else {
|
|
1777
|
-
app.onLoad(wrapElement);
|
|
1963
|
+
app.onLoad({ html: wrapElement });
|
|
1778
1964
|
}
|
|
1779
1965
|
}
|
|
1780
1966
|
/**
|
|
@@ -1901,6 +2087,7 @@ function execScripts(app, initHook) {
|
|
|
1901
2087
|
* @param callback callback of module script
|
|
1902
2088
|
*/
|
|
1903
2089
|
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
2090
|
+
var _a;
|
|
1904
2091
|
try {
|
|
1905
2092
|
actionsBeforeRunScript(app);
|
|
1906
2093
|
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
@@ -1931,7 +2118,7 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
|
1931
2118
|
*/
|
|
1932
2119
|
if (!replaceElement) {
|
|
1933
2120
|
// TEST IGNORE
|
|
1934
|
-
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
2121
|
+
const parent = app.iframe ? (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microBody : app.querySelector('micro-app-body');
|
|
1935
2122
|
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
1936
2123
|
}
|
|
1937
2124
|
}
|
|
@@ -1941,6 +2128,8 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
|
1941
2128
|
}
|
|
1942
2129
|
catch (e) {
|
|
1943
2130
|
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
2131
|
+
// throw error in with sandbox to parent app
|
|
2132
|
+
throw e;
|
|
1944
2133
|
}
|
|
1945
2134
|
}
|
|
1946
2135
|
/**
|
|
@@ -1951,7 +2140,7 @@ function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
|
1951
2140
|
* @param originScript origin script element
|
|
1952
2141
|
*/
|
|
1953
2142
|
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
1954
|
-
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment(
|
|
2143
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment(`dynamic script with src='${address}' extract by micro-app`);
|
|
1955
2144
|
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
1956
2145
|
const runDynamicScript = () => {
|
|
1957
2146
|
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
@@ -1985,7 +2174,7 @@ function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
|
1985
2174
|
* @param scriptInfo scriptInfo
|
|
1986
2175
|
*/
|
|
1987
2176
|
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
1988
|
-
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
2177
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic inline script extract by micro-app');
|
|
1989
2178
|
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
1990
2179
|
return replaceElement;
|
|
1991
2180
|
}
|
|
@@ -2096,15 +2285,6 @@ function processCode(configs, code, address) {
|
|
|
2096
2285
|
}, code);
|
|
2097
2286
|
}
|
|
2098
2287
|
|
|
2099
|
-
/**
|
|
2100
|
-
* transform html string to dom
|
|
2101
|
-
* @param str string dom
|
|
2102
|
-
*/
|
|
2103
|
-
function getWrapElement(str) {
|
|
2104
|
-
const wrapDiv = pureCreateElement('div');
|
|
2105
|
-
wrapDiv.innerHTML = str;
|
|
2106
|
-
return wrapDiv;
|
|
2107
|
-
}
|
|
2108
2288
|
/**
|
|
2109
2289
|
* Recursively process each child element
|
|
2110
2290
|
* @param parent parent element
|
|
@@ -2161,7 +2341,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2161
2341
|
* @param app app
|
|
2162
2342
|
*/
|
|
2163
2343
|
function extractSourceDom(htmlStr, app) {
|
|
2164
|
-
const wrapElement =
|
|
2344
|
+
const wrapElement = app.parseHtmlString(htmlStr);
|
|
2165
2345
|
const microAppHead = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-head');
|
|
2166
2346
|
const microAppBody = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-body');
|
|
2167
2347
|
if (!microAppHead || !microAppBody) {
|
|
@@ -2172,23 +2352,23 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2172
2352
|
const fiberStyleTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
2173
2353
|
flatChildren(wrapElement, app, microAppHead, fiberStyleTasks);
|
|
2174
2354
|
/**
|
|
2175
|
-
* Style and link are parallel,
|
|
2355
|
+
* 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.
|
|
2176
2356
|
*/
|
|
2177
2357
|
const fiberStyleResult = serialExecFiberTasks(fiberStyleTasks);
|
|
2178
2358
|
if (app.source.links.size) {
|
|
2179
2359
|
fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult);
|
|
2180
2360
|
}
|
|
2181
2361
|
else if (fiberStyleResult) {
|
|
2182
|
-
fiberStyleResult.then(() => app.onLoad(wrapElement));
|
|
2362
|
+
fiberStyleResult.then(() => app.onLoad({ html: wrapElement }));
|
|
2183
2363
|
}
|
|
2184
2364
|
else {
|
|
2185
|
-
app.onLoad(wrapElement);
|
|
2365
|
+
app.onLoad({ html: wrapElement });
|
|
2186
2366
|
}
|
|
2187
2367
|
if (app.source.scripts.size) {
|
|
2188
2368
|
fetchScriptsFromHtml(wrapElement, app);
|
|
2189
2369
|
}
|
|
2190
2370
|
else {
|
|
2191
|
-
app.onLoad(wrapElement);
|
|
2371
|
+
app.onLoad({ html: wrapElement });
|
|
2192
2372
|
}
|
|
2193
2373
|
}
|
|
2194
2374
|
|
|
@@ -2367,7 +2547,7 @@ const eventCenter = new EventCenter();
|
|
|
2367
2547
|
function createEventName(appName, fromBaseApp) {
|
|
2368
2548
|
if (!isString(appName) || !appName)
|
|
2369
2549
|
return '';
|
|
2370
|
-
return fromBaseApp ? `
|
|
2550
|
+
return fromBaseApp ? `__${appName}_from_base_app__` : `__${appName}_from_micro_app__`;
|
|
2371
2551
|
}
|
|
2372
2552
|
// Global data
|
|
2373
2553
|
class EventCenterForGlobal {
|
|
@@ -2666,7 +2846,15 @@ function isConstructorFunction(value) {
|
|
|
2666
2846
|
}
|
|
2667
2847
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
2668
2848
|
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
2669
|
-
|
|
2849
|
+
/**
|
|
2850
|
+
* In safari, nest app like: A -> B -> C
|
|
2851
|
+
* if B is iframe sandbox, and C is with sandbox, same property of document in C is abnormal
|
|
2852
|
+
* e.g:
|
|
2853
|
+
* document.all:
|
|
2854
|
+
* - typeof document.all ==> 'function'
|
|
2855
|
+
* - document.all.bind ==> undefined
|
|
2856
|
+
*/
|
|
2857
|
+
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value) && value.bind) {
|
|
2670
2858
|
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
2671
2859
|
if (value[cacheKey])
|
|
2672
2860
|
return value[cacheKey];
|
|
@@ -2687,10 +2875,10 @@ function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
|
2687
2875
|
return value;
|
|
2688
2876
|
}
|
|
2689
2877
|
|
|
2690
|
-
class
|
|
2691
|
-
constructor() {
|
|
2878
|
+
class BaseSandbox {
|
|
2879
|
+
constructor(appName, url) {
|
|
2692
2880
|
// keys that can only assigned to rawWindow
|
|
2693
|
-
this.
|
|
2881
|
+
this.rawWindowScopeKeyList = [
|
|
2694
2882
|
'location',
|
|
2695
2883
|
];
|
|
2696
2884
|
// keys that can escape to rawWindow
|
|
@@ -2703,7 +2891,20 @@ class Adapter {
|
|
|
2703
2891
|
'webpackJsonp',
|
|
2704
2892
|
'webpackHotUpdate',
|
|
2705
2893
|
'Vue',
|
|
2894
|
+
// TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
|
|
2895
|
+
'onpopstate',
|
|
2896
|
+
'onhashchange',
|
|
2706
2897
|
];
|
|
2898
|
+
// Properties that can only get and set in microAppWindow, will not escape to rawWindow
|
|
2899
|
+
this.scopeProperties = Array.from(this.staticScopeProperties);
|
|
2900
|
+
// Properties that can be escape to rawWindow
|
|
2901
|
+
this.escapeProperties = [];
|
|
2902
|
+
// Properties newly added to microAppWindow
|
|
2903
|
+
this.injectedKeys = new Set();
|
|
2904
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
2905
|
+
this.escapeKeys = new Set();
|
|
2906
|
+
this.appName = appName;
|
|
2907
|
+
this.url = url;
|
|
2707
2908
|
this.injectReactHMRProperty();
|
|
2708
2909
|
}
|
|
2709
2910
|
// adapter for react
|
|
@@ -2721,6 +2922,14 @@ class Adapter {
|
|
|
2721
2922
|
}
|
|
2722
2923
|
}
|
|
2723
2924
|
}
|
|
2925
|
+
/**
|
|
2926
|
+
* TODO:
|
|
2927
|
+
* 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
|
|
2928
|
+
* 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
|
|
2929
|
+
* 修改时机:在iframe沙箱支持插件后再修改
|
|
2930
|
+
*/
|
|
2931
|
+
class CustomWindow {
|
|
2932
|
+
}
|
|
2724
2933
|
// Fix conflict of babel-polyfill@6.x
|
|
2725
2934
|
function fixBabelPolyfill6() {
|
|
2726
2935
|
if (globalEnv.rawWindow._babelPolyfill)
|
|
@@ -2743,50 +2952,17 @@ function fixReactHMRConflict(app) {
|
|
|
2743
2952
|
}
|
|
2744
2953
|
}
|
|
2745
2954
|
}
|
|
2746
|
-
/**
|
|
2747
|
-
* reDefine parentNode of html
|
|
2748
|
-
* Scenes:
|
|
2749
|
-
* 1. element-ui@2/lib/utils/popper.js
|
|
2750
|
-
* var parent = element.parentNode;
|
|
2751
|
-
* // root is child app window
|
|
2752
|
-
* if (parent === root.document) ...
|
|
2753
|
-
*/
|
|
2754
|
-
function throttleDeferForParentNode(microDocument) {
|
|
2755
|
-
const html = globalEnv.rawDocument.firstElementChild;
|
|
2756
|
-
if ((html === null || html === void 0 ? void 0 : html.parentNode) === globalEnv.rawDocument) {
|
|
2757
|
-
setParentNode(html, microDocument);
|
|
2758
|
-
defer(() => {
|
|
2759
|
-
setParentNode(html, globalEnv.rawDocument);
|
|
2760
|
-
});
|
|
2761
|
-
}
|
|
2762
|
-
}
|
|
2763
|
-
/**
|
|
2764
|
-
* Modify the point of parentNode
|
|
2765
|
-
* @param target target Node
|
|
2766
|
-
* @param value parentNode
|
|
2767
|
-
*/
|
|
2768
|
-
function setParentNode(target, value) {
|
|
2769
|
-
const descriptor = Object.getOwnPropertyDescriptor(target, 'parentNode');
|
|
2770
|
-
if (!descriptor || descriptor.configurable) {
|
|
2771
|
-
rawDefineProperty(target, 'parentNode', {
|
|
2772
|
-
value,
|
|
2773
|
-
configurable: true,
|
|
2774
|
-
});
|
|
2775
|
-
}
|
|
2776
|
-
}
|
|
2777
2955
|
/**
|
|
2778
2956
|
* update dom tree of target dom
|
|
2779
2957
|
* @param container target dom
|
|
2780
2958
|
* @param appName app name
|
|
2781
2959
|
*/
|
|
2782
2960
|
function patchElementTree(container, appName) {
|
|
2783
|
-
const children = Array.from(container.
|
|
2961
|
+
const children = Array.from(container.childNodes);
|
|
2784
2962
|
children.length && children.forEach((child) => {
|
|
2785
2963
|
patchElementTree(child, appName);
|
|
2786
2964
|
});
|
|
2787
|
-
|
|
2788
|
-
updateElementInfo(child, appName);
|
|
2789
|
-
}
|
|
2965
|
+
updateElementInfo(container, appName);
|
|
2790
2966
|
}
|
|
2791
2967
|
/**
|
|
2792
2968
|
* rewrite baseURI, ownerDocument, __MICRO_APP_NAME__ of target node
|
|
@@ -2796,38 +2972,119 @@ function patchElementTree(container, appName) {
|
|
|
2796
2972
|
*/
|
|
2797
2973
|
function updateElementInfo(node, appName) {
|
|
2798
2974
|
var _a, _b;
|
|
2799
|
-
|
|
2800
|
-
|
|
2801
|
-
|
|
2975
|
+
if (appName &&
|
|
2976
|
+
isNode(node) &&
|
|
2977
|
+
node.__MICRO_APP_NAME__ !== appName &&
|
|
2802
2978
|
!node.__PURE_ELEMENT__ &&
|
|
2803
|
-
|
|
2979
|
+
!getPreventSetState()) {
|
|
2804
2980
|
/**
|
|
2805
2981
|
* TODO:
|
|
2806
2982
|
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
2807
2983
|
* 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
|
|
2808
|
-
* 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
|
|
2809
|
-
* 3. 性能: defineProperty的性能肯定不如直接设置
|
|
2810
2984
|
*/
|
|
2811
|
-
|
|
2812
|
-
baseURI: {
|
|
2813
|
-
configurable: true,
|
|
2814
|
-
get: () => proxyWindow.location.href,
|
|
2815
|
-
},
|
|
2985
|
+
const props = {
|
|
2816
2986
|
__MICRO_APP_NAME__: {
|
|
2817
2987
|
configurable: true,
|
|
2988
|
+
enumerable: true,
|
|
2818
2989
|
writable: true,
|
|
2819
2990
|
value: appName,
|
|
2820
2991
|
},
|
|
2821
|
-
}
|
|
2992
|
+
};
|
|
2993
|
+
if (isAnchorElement(node)) {
|
|
2994
|
+
// a 标签
|
|
2995
|
+
const microApp = AppManager.getInstance().get(appName);
|
|
2996
|
+
if (microApp) {
|
|
2997
|
+
props.href = {
|
|
2998
|
+
get() {
|
|
2999
|
+
return this.getAttribute('href');
|
|
3000
|
+
},
|
|
3001
|
+
set(value) {
|
|
3002
|
+
this.setAttribute('href', value);
|
|
3003
|
+
},
|
|
3004
|
+
};
|
|
3005
|
+
}
|
|
3006
|
+
}
|
|
3007
|
+
if (isImageElement(node) || isVideoElement(node) || isAudioElement(node)) {
|
|
3008
|
+
// @ts-ignore
|
|
3009
|
+
node.crossOrigin = 'anonymous';
|
|
3010
|
+
}
|
|
3011
|
+
rawDefineProperties(node, props);
|
|
3012
|
+
/**
|
|
3013
|
+
* In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
|
|
3014
|
+
*
|
|
3015
|
+
* Performance:
|
|
3016
|
+
* iframe element.__proto__ === browser HTMLElement.prototype // Chrome: false, FireFox: true
|
|
3017
|
+
* iframe element.__proto__ === iframe HTMLElement.prototype // Chrome: true, FireFox: false
|
|
3018
|
+
*
|
|
3019
|
+
* NOTE:
|
|
3020
|
+
* 1. Node.prototype.baseURI
|
|
3021
|
+
* 2. Node.prototype.ownerDocument
|
|
3022
|
+
* 3. Node.prototype.parentNode
|
|
3023
|
+
* 4. Node.prototype.getRootNode
|
|
3024
|
+
* 5. Node.prototype.cloneNode
|
|
3025
|
+
* 6. Element.prototype.innerHTML
|
|
3026
|
+
* 7. Image
|
|
3027
|
+
*/
|
|
2822
3028
|
if (isIframeSandbox(appName)) {
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
3029
|
+
const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
|
|
3030
|
+
if (proxyWindow) {
|
|
3031
|
+
rawDefineProperties(node, {
|
|
3032
|
+
baseURI: {
|
|
3033
|
+
configurable: true,
|
|
3034
|
+
enumerable: true,
|
|
3035
|
+
get: () => proxyWindow.location.href,
|
|
3036
|
+
},
|
|
3037
|
+
ownerDocument: {
|
|
3038
|
+
configurable: true,
|
|
3039
|
+
enumerable: true,
|
|
3040
|
+
get: () => node !== proxyWindow.document ? proxyWindow.document : null,
|
|
3041
|
+
},
|
|
3042
|
+
parentNode: getIframeParentNodeDesc(appName, globalEnv.rawParentNodeDesc),
|
|
3043
|
+
getRootNode: {
|
|
3044
|
+
configurable: true,
|
|
3045
|
+
enumerable: true,
|
|
3046
|
+
writable: true,
|
|
3047
|
+
value: function getRootNode() {
|
|
3048
|
+
return proxyWindow.document;
|
|
3049
|
+
}
|
|
3050
|
+
},
|
|
3051
|
+
});
|
|
3052
|
+
}
|
|
2827
3053
|
}
|
|
2828
3054
|
}
|
|
2829
3055
|
return node;
|
|
2830
3056
|
}
|
|
3057
|
+
/**
|
|
3058
|
+
* get Descriptor of Node.prototype.parentNode for iframe
|
|
3059
|
+
* @param appName app name
|
|
3060
|
+
* @param parentNode parentNode Descriptor of iframe or browser
|
|
3061
|
+
*/
|
|
3062
|
+
function getIframeParentNodeDesc(appName, parentNodeDesc) {
|
|
3063
|
+
return {
|
|
3064
|
+
configurable: true,
|
|
3065
|
+
enumerable: true,
|
|
3066
|
+
get() {
|
|
3067
|
+
var _a, _b, _c, _d;
|
|
3068
|
+
throttleDeferForIframeAppName(appName);
|
|
3069
|
+
const result = (_a = parentNodeDesc.get) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
3070
|
+
/**
|
|
3071
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
3072
|
+
* Scenes:
|
|
3073
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
3074
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
3075
|
+
* e.g.:
|
|
3076
|
+
* 1. element-ui@2.x el-dropdown
|
|
3077
|
+
* WARNING:
|
|
3078
|
+
* Will it cause other problems ?
|
|
3079
|
+
* e.g. target.parentNode.remove(target)
|
|
3080
|
+
*/
|
|
3081
|
+
if (isMicroAppBody(result) && ((_b = appInstanceMap.get(appName)) === null || _b === void 0 ? void 0 : _b.container)) {
|
|
3082
|
+
return ((_d = (_c = microApp.options).getRootElementParentNode) === null || _d === void 0 ? void 0 : _d.call(_c, this, appName)) || globalEnv.rawDocument.body;
|
|
3083
|
+
}
|
|
3084
|
+
return result;
|
|
3085
|
+
}
|
|
3086
|
+
};
|
|
3087
|
+
}
|
|
2831
3088
|
|
|
2832
3089
|
/**
|
|
2833
3090
|
* create proxyDocument and MicroDocument, rewrite document of child app
|
|
@@ -2866,11 +3123,14 @@ function createProxyDocument(appName, sandbox) {
|
|
|
2866
3123
|
const sstEventListenerMap = new Map();
|
|
2867
3124
|
let onClickHandler = null;
|
|
2868
3125
|
let sstOnClickHandler = null;
|
|
2869
|
-
const { rawDocument, rawCreateElement, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
3126
|
+
const { rawDocument, rawCreateElement, rawCreateElementNS, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
2870
3127
|
function createElement(tagName, options) {
|
|
2871
3128
|
const element = rawCreateElement.call(rawDocument, tagName, options);
|
|
2872
|
-
element
|
|
2873
|
-
|
|
3129
|
+
return updateElementInfo(element, appName);
|
|
3130
|
+
}
|
|
3131
|
+
function createElementNS(namespaceURI, name, options) {
|
|
3132
|
+
const element = rawCreateElementNS.call(rawDocument, namespaceURI, name, options);
|
|
3133
|
+
return updateElementInfo(element, appName);
|
|
2874
3134
|
}
|
|
2875
3135
|
/**
|
|
2876
3136
|
* TODO:
|
|
@@ -2955,13 +3215,40 @@ function createProxyDocument(appName, sandbox) {
|
|
|
2955
3215
|
eventListenerMap.clear();
|
|
2956
3216
|
}
|
|
2957
3217
|
};
|
|
3218
|
+
const genProxyDocumentProps = () => {
|
|
3219
|
+
var _a;
|
|
3220
|
+
// microApp framework built-in Proxy
|
|
3221
|
+
const builtInProxyProps = new Map([
|
|
3222
|
+
['onclick', (value) => {
|
|
3223
|
+
if (isFunction(onClickHandler)) {
|
|
3224
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
|
|
3225
|
+
}
|
|
3226
|
+
// TODO: listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
3227
|
+
if (isFunction(value)) {
|
|
3228
|
+
rawAddEventListener.call(rawDocument, 'click', value, false);
|
|
3229
|
+
}
|
|
3230
|
+
onClickHandler = value;
|
|
3231
|
+
}]
|
|
3232
|
+
]);
|
|
3233
|
+
// external custom proxy
|
|
3234
|
+
const customProxyDocumentProps = ((_a = microApp.options) === null || _a === void 0 ? void 0 : _a.customProxyDocumentProps) || new Map();
|
|
3235
|
+
// External has higher priority than built-in
|
|
3236
|
+
const mergedProxyDocumentProps = new Map([
|
|
3237
|
+
...builtInProxyProps,
|
|
3238
|
+
...customProxyDocumentProps,
|
|
3239
|
+
]);
|
|
3240
|
+
return mergedProxyDocumentProps;
|
|
3241
|
+
};
|
|
3242
|
+
const mergedProxyDocumentProps = genProxyDocumentProps();
|
|
2958
3243
|
const proxyDocument = new Proxy(rawDocument, {
|
|
2959
3244
|
get: (target, key) => {
|
|
2960
3245
|
var _a;
|
|
2961
3246
|
throttleDeferForSetAppName(appName);
|
|
2962
|
-
|
|
3247
|
+
// TODO: 转换成数据形式,类似iframe的方式
|
|
2963
3248
|
if (key === 'createElement')
|
|
2964
3249
|
return createElement;
|
|
3250
|
+
if (key === 'createElementNS')
|
|
3251
|
+
return createElementNS;
|
|
2965
3252
|
if (key === Symbol.toStringTag)
|
|
2966
3253
|
return 'ProxyDocument';
|
|
2967
3254
|
if (key === 'defaultView')
|
|
@@ -2974,18 +3261,14 @@ function createProxyDocument(appName, sandbox) {
|
|
|
2974
3261
|
return removeEventListener;
|
|
2975
3262
|
if (key === 'microAppElement')
|
|
2976
3263
|
return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container;
|
|
3264
|
+
if (key === '__MICRO_APP_NAME__')
|
|
3265
|
+
return appName;
|
|
2977
3266
|
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
2978
3267
|
},
|
|
2979
3268
|
set: (target, key, value) => {
|
|
2980
|
-
if (key
|
|
2981
|
-
|
|
2982
|
-
|
|
2983
|
-
}
|
|
2984
|
-
// TODO: listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
2985
|
-
if (isFunction(value)) {
|
|
2986
|
-
rawAddEventListener.call(rawDocument, 'click', value, false);
|
|
2987
|
-
}
|
|
2988
|
-
onClickHandler = value;
|
|
3269
|
+
if (mergedProxyDocumentProps.has(key)) {
|
|
3270
|
+
const proxyCallback = mergedProxyDocumentProps.get(key);
|
|
3271
|
+
proxyCallback(value);
|
|
2989
3272
|
}
|
|
2990
3273
|
else if (key !== 'microAppElement') {
|
|
2991
3274
|
/**
|
|
@@ -3018,7 +3301,8 @@ function createMicroDocument(appName, proxyDocument) {
|
|
|
3018
3301
|
class MicroDocument {
|
|
3019
3302
|
static [Symbol.hasInstance](target) {
|
|
3020
3303
|
let proto = target;
|
|
3021
|
-
while (proto
|
|
3304
|
+
while (proto) {
|
|
3305
|
+
proto = Object.getPrototypeOf(proto);
|
|
3022
3306
|
if (proto === MicroDocument.prototype) {
|
|
3023
3307
|
return true;
|
|
3024
3308
|
}
|
|
@@ -3061,7 +3345,7 @@ function createMicroDocument(appName, proxyDocument) {
|
|
|
3061
3345
|
function patchWindow(appName, microAppWindow, sandbox) {
|
|
3062
3346
|
patchWindowProperty(microAppWindow);
|
|
3063
3347
|
createProxyWindow(appName, microAppWindow, sandbox);
|
|
3064
|
-
return patchWindowEffect(microAppWindow);
|
|
3348
|
+
return patchWindowEffect(microAppWindow, appName);
|
|
3065
3349
|
}
|
|
3066
3350
|
/**
|
|
3067
3351
|
* rewrite special properties of window
|
|
@@ -3072,7 +3356,7 @@ function patchWindowProperty(microAppWindow) {
|
|
|
3072
3356
|
const rawWindow = globalEnv.rawWindow;
|
|
3073
3357
|
Object.getOwnPropertyNames(rawWindow)
|
|
3074
3358
|
.filter((key) => {
|
|
3075
|
-
return /^on/.test(key) && !
|
|
3359
|
+
return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_WITH.includes(key);
|
|
3076
3360
|
})
|
|
3077
3361
|
.forEach((eventName) => {
|
|
3078
3362
|
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(rawWindow, eventName) || {
|
|
@@ -3102,22 +3386,22 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
|
|
|
3102
3386
|
throttleDeferForSetAppName(appName);
|
|
3103
3387
|
if (Reflect.has(target, key) ||
|
|
3104
3388
|
(isString(key) && /^__MICRO_APP_/.test(key)) ||
|
|
3105
|
-
sandbox.scopeProperties
|
|
3106
|
-
if (
|
|
3389
|
+
includes(sandbox.scopeProperties, key)) {
|
|
3390
|
+
if (includes(RAW_GLOBAL_TARGET, key))
|
|
3107
3391
|
removeDomScope();
|
|
3108
3392
|
return Reflect.get(target, key);
|
|
3109
3393
|
}
|
|
3110
3394
|
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
3111
3395
|
},
|
|
3112
3396
|
set: (target, key, value) => {
|
|
3113
|
-
if (sandbox.
|
|
3397
|
+
if (includes(sandbox.rawWindowScopeKeyList, key)) {
|
|
3114
3398
|
Reflect.set(rawWindow, key, value);
|
|
3115
3399
|
}
|
|
3116
3400
|
else if (
|
|
3117
3401
|
// target.hasOwnProperty has been rewritten
|
|
3118
3402
|
!rawHasOwnProperty.call(target, key) &&
|
|
3119
3403
|
rawHasOwnProperty.call(rawWindow, key) &&
|
|
3120
|
-
!sandbox.scopeProperties
|
|
3404
|
+
!includes(sandbox.scopeProperties, key)) {
|
|
3121
3405
|
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
3122
3406
|
const { configurable, enumerable, writable, set } = descriptor;
|
|
3123
3407
|
// set value because it can be set
|
|
@@ -3130,32 +3414,37 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
|
|
|
3130
3414
|
sandbox.injectedKeys.add(key);
|
|
3131
3415
|
}
|
|
3132
3416
|
else {
|
|
3133
|
-
|
|
3417
|
+
// all scopeProperties will add to injectedKeys, use for key in window (Proxy.has)
|
|
3418
|
+
if (!Reflect.has(target, key) || includes(sandbox.scopeProperties, key)) {
|
|
3419
|
+
sandbox.injectedKeys.add(key);
|
|
3420
|
+
}
|
|
3134
3421
|
Reflect.set(target, key, value);
|
|
3135
3422
|
}
|
|
3136
|
-
if ((sandbox.escapeProperties
|
|
3137
|
-
(
|
|
3423
|
+
if ((includes(sandbox.escapeProperties, key) ||
|
|
3424
|
+
(
|
|
3425
|
+
// TODO: staticEscapeProperties 合并到 escapeProperties
|
|
3426
|
+
includes(sandbox.staticEscapeProperties, key) &&
|
|
3138
3427
|
!Reflect.has(rawWindow, key))) &&
|
|
3139
|
-
!sandbox.scopeProperties
|
|
3428
|
+
!includes(sandbox.scopeProperties, key)) {
|
|
3140
3429
|
!Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
|
|
3141
3430
|
Reflect.set(rawWindow, key, value);
|
|
3142
3431
|
}
|
|
3143
3432
|
return true;
|
|
3144
3433
|
},
|
|
3145
3434
|
has: (target, key) => {
|
|
3146
|
-
|
|
3147
|
-
|
|
3148
|
-
|
|
3149
|
-
|
|
3150
|
-
|
|
3151
|
-
|
|
3152
|
-
|
|
3153
|
-
if (sandbox.
|
|
3154
|
-
return
|
|
3435
|
+
/**
|
|
3436
|
+
* Some keywords, such as Vue, need to meet two conditions at the same time:
|
|
3437
|
+
* 1. window.Vue --> undefined
|
|
3438
|
+
* 2. 'Vue' in window --> false
|
|
3439
|
+
* Issue https://github.com/micro-zoe/micro-app/issues/686
|
|
3440
|
+
*/
|
|
3441
|
+
if (includes(sandbox.scopeProperties, key)) {
|
|
3442
|
+
if (sandbox.injectedKeys.has(key)) {
|
|
3443
|
+
return Reflect.has(target, key); // true
|
|
3155
3444
|
}
|
|
3156
|
-
return key
|
|
3445
|
+
return !!target[key]; // false
|
|
3157
3446
|
}
|
|
3158
|
-
return
|
|
3447
|
+
return Reflect.has(target, key) || Reflect.has(rawWindow, key);
|
|
3159
3448
|
},
|
|
3160
3449
|
// Object.getOwnPropertyDescriptor(window, key)
|
|
3161
3450
|
getOwnPropertyDescriptor: (target, key) => {
|
|
@@ -3200,14 +3489,26 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
|
|
|
3200
3489
|
* Rewrite side-effect events
|
|
3201
3490
|
* @param microAppWindow micro window
|
|
3202
3491
|
*/
|
|
3203
|
-
function patchWindowEffect(microAppWindow) {
|
|
3492
|
+
function patchWindowEffect(microAppWindow, appName) {
|
|
3204
3493
|
const eventListenerMap = new Map();
|
|
3205
3494
|
const sstEventListenerMap = new Map();
|
|
3206
3495
|
const intervalIdMap = new Map();
|
|
3207
3496
|
const timeoutIdMap = new Map();
|
|
3208
3497
|
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, } = globalEnv;
|
|
3498
|
+
/**
|
|
3499
|
+
* All events will bind to microAppElement or rawWindow
|
|
3500
|
+
* Some special events, such as popstate、load、unmount、appstate-change、statechange..., bind to microAppElement, others bind to rawWindow
|
|
3501
|
+
* NOTE:
|
|
3502
|
+
* 1、At first, microAppWindow = new EventTarget(), but it can not compatible with iOS 14 or below, so microAppElement was used instead. (2024.1.22)
|
|
3503
|
+
* @param type event name
|
|
3504
|
+
* @returns microAppElement/rawWindow
|
|
3505
|
+
*/
|
|
3209
3506
|
function getEventTarget(type) {
|
|
3210
|
-
|
|
3507
|
+
var _a;
|
|
3508
|
+
if (SCOPE_WINDOW_EVENT_OF_WITH.includes(type) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
3509
|
+
return getRootContainer(appInstanceMap.get(appName).container);
|
|
3510
|
+
}
|
|
3511
|
+
return rawWindow;
|
|
3211
3512
|
}
|
|
3212
3513
|
/**
|
|
3213
3514
|
* listener may be null, e.g test-passive
|
|
@@ -3217,6 +3518,7 @@ function patchWindowEffect(microAppWindow) {
|
|
|
3217
3518
|
* window.addEventListener.call(非window, type, listener, options)
|
|
3218
3519
|
*/
|
|
3219
3520
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3521
|
+
type = formatEventType(type, appName);
|
|
3220
3522
|
const listenerList = eventListenerMap.get(type);
|
|
3221
3523
|
if (listenerList) {
|
|
3222
3524
|
listenerList.add(listener);
|
|
@@ -3228,6 +3530,7 @@ function patchWindowEffect(microAppWindow) {
|
|
|
3228
3530
|
rawAddEventListener.call(getEventTarget(type), type, listener, options);
|
|
3229
3531
|
};
|
|
3230
3532
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3533
|
+
type = formatEventType(type, appName);
|
|
3231
3534
|
const listenerList = eventListenerMap.get(type);
|
|
3232
3535
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3233
3536
|
listenerList.delete(listener);
|
|
@@ -3320,42 +3623,44 @@ function patchWindowEffect(microAppWindow) {
|
|
|
3320
3623
|
}
|
|
3321
3624
|
|
|
3322
3625
|
// set micro app state to origin state
|
|
3323
|
-
function setMicroState(appName, microState) {
|
|
3324
|
-
|
|
3325
|
-
|
|
3326
|
-
|
|
3327
|
-
|
|
3328
|
-
|
|
3329
|
-
|
|
3330
|
-
|
|
3331
|
-
|
|
3332
|
-
|
|
3333
|
-
|
|
3334
|
-
|
|
3626
|
+
function setMicroState(appName, microState, targetLocation) {
|
|
3627
|
+
// TODO: 验证native模式下修改state nextjs路由是否正常
|
|
3628
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3629
|
+
const additionalState = {
|
|
3630
|
+
__MICRO_APP_STATE__: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__, {
|
|
3631
|
+
[appName]: {
|
|
3632
|
+
fullPath: targetLocation ? targetLocation.pathname + targetLocation.search + targetLocation.hash : null,
|
|
3633
|
+
state: microState !== null && microState !== void 0 ? microState : null,
|
|
3634
|
+
mode: getRouterMode(appName),
|
|
3635
|
+
}
|
|
3636
|
+
}),
|
|
3637
|
+
};
|
|
3638
|
+
// create new state object
|
|
3639
|
+
return assign({}, rawState, additionalState);
|
|
3335
3640
|
}
|
|
3336
3641
|
// delete micro app state form origin state
|
|
3337
3642
|
function removeMicroState(appName, rawState) {
|
|
3338
|
-
if (
|
|
3339
|
-
if (
|
|
3340
|
-
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
delete rawState.microAppState;
|
|
3345
|
-
}
|
|
3643
|
+
if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__)) {
|
|
3644
|
+
if (!isUndefined(rawState.__MICRO_APP_STATE__[appName])) {
|
|
3645
|
+
delete rawState.__MICRO_APP_STATE__[appName];
|
|
3646
|
+
}
|
|
3647
|
+
if (!Object.keys(rawState.__MICRO_APP_STATE__).length) {
|
|
3648
|
+
delete rawState.__MICRO_APP_STATE__;
|
|
3346
3649
|
}
|
|
3347
|
-
return assign({}, rawState);
|
|
3348
3650
|
}
|
|
3349
|
-
return rawState;
|
|
3651
|
+
return !isEmptyObject(rawState) ? assign({}, rawState) : null;
|
|
3350
3652
|
}
|
|
3351
3653
|
// get micro app state form origin state
|
|
3352
3654
|
function getMicroState(appName) {
|
|
3655
|
+
var _a, _b;
|
|
3656
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3657
|
+
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;
|
|
3658
|
+
}
|
|
3659
|
+
// get micro app router info state form origin state
|
|
3660
|
+
function getMicroRouterInfoState(appName) {
|
|
3353
3661
|
var _a;
|
|
3354
3662
|
const rawState = globalEnv.rawWindow.history.state;
|
|
3355
|
-
|
|
3356
|
-
return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
|
|
3357
|
-
}
|
|
3358
|
-
return rawState;
|
|
3663
|
+
return ((_a = rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__) === null || _a === void 0 ? void 0 : _a[appName]) || null;
|
|
3359
3664
|
}
|
|
3360
3665
|
const ENC_AD_RE = /&/g; // %M1
|
|
3361
3666
|
const ENC_EQ_RE = /=/g; // %M2
|
|
@@ -3391,14 +3696,35 @@ function formatQueryAppName(appName) {
|
|
|
3391
3696
|
* @param appName app.name
|
|
3392
3697
|
*/
|
|
3393
3698
|
function getMicroPathFromURL(appName) {
|
|
3394
|
-
var _a, _b;
|
|
3699
|
+
var _a, _b, _c, _d;
|
|
3395
3700
|
const rawLocation = globalEnv.rawWindow.location;
|
|
3396
|
-
|
|
3701
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3702
|
+
if (isRouterModeSearch(appName)) {
|
|
3397
3703
|
const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
|
|
3398
3704
|
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)]);
|
|
3399
3705
|
return isString(microPath) ? decodeMicroPath(microPath) : null;
|
|
3400
3706
|
}
|
|
3401
|
-
|
|
3707
|
+
/**
|
|
3708
|
+
* Get fullPath from __MICRO_APP_STATE__
|
|
3709
|
+
* NOTE:
|
|
3710
|
+
* 1. state mode: all base on __MICRO_APP_STATE__
|
|
3711
|
+
* 2. pure mode: navigate by location.xxx may contain one-time information in __MICRO_APP_STATE__
|
|
3712
|
+
* 3. native mode: vue-router@4 will exec replaceState with history.state before pushState, like:
|
|
3713
|
+
* history.replaceState(
|
|
3714
|
+
* assign({}, history.state, {...}),
|
|
3715
|
+
* title,
|
|
3716
|
+
* history.state.current, <---
|
|
3717
|
+
* )
|
|
3718
|
+
* when base app jump to another page from child page, it will replace child path with base app path
|
|
3719
|
+
* 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
|
|
3720
|
+
* So we take the fullPath as standard
|
|
3721
|
+
*/
|
|
3722
|
+
// 问题:1、同一个页面多个子应用,一个修改后... --- native模式不支持多个子应用同时渲染,多个子应用推荐使用其它模式
|
|
3723
|
+
// if (isRouterModeCustom(appName)) {
|
|
3724
|
+
// return rawLocation.pathname + rawLocation.search + rawLocation.hash
|
|
3725
|
+
// }
|
|
3726
|
+
// return rawState?.__MICRO_APP_STATE__?.[appName]?.fullPath || null
|
|
3727
|
+
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);
|
|
3402
3728
|
}
|
|
3403
3729
|
/**
|
|
3404
3730
|
* Attach child app fullPath to browser url
|
|
@@ -3406,10 +3732,11 @@ function getMicroPathFromURL(appName) {
|
|
|
3406
3732
|
* @param targetLocation location of child app or rawLocation of window
|
|
3407
3733
|
*/
|
|
3408
3734
|
function setMicroPathToURL(appName, targetLocation) {
|
|
3409
|
-
const
|
|
3735
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
3736
|
+
let targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3410
3737
|
let isAttach2Hash = false;
|
|
3411
|
-
if (
|
|
3412
|
-
let { pathname, search, hash } =
|
|
3738
|
+
if (isRouterModeSearch(appName)) {
|
|
3739
|
+
let { pathname, search, hash } = rawLocation;
|
|
3413
3740
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
3414
3741
|
const encodedMicroPath = encodeMicroPath(targetFullPath);
|
|
3415
3742
|
/**
|
|
@@ -3419,6 +3746,7 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3419
3746
|
// If hash exists and search does not exist, it is considered as a hash route
|
|
3420
3747
|
if (hash && !search) {
|
|
3421
3748
|
isAttach2Hash = true;
|
|
3749
|
+
// TODO: 这里和下面的if判断可以简化一下
|
|
3422
3750
|
if (queryObject.hashQuery) {
|
|
3423
3751
|
queryObject.hashQuery[formatQueryAppName(appName)] = encodedMicroPath;
|
|
3424
3752
|
}
|
|
@@ -3446,6 +3774,9 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3446
3774
|
isAttach2Hash,
|
|
3447
3775
|
};
|
|
3448
3776
|
}
|
|
3777
|
+
if (isRouterModeState(appName) || isRouterModePure(appName)) {
|
|
3778
|
+
targetFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
3779
|
+
}
|
|
3449
3780
|
return {
|
|
3450
3781
|
fullPath: targetFullPath,
|
|
3451
3782
|
isAttach2Hash,
|
|
@@ -3454,13 +3785,12 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3454
3785
|
/**
|
|
3455
3786
|
* Delete child app fullPath from browser url
|
|
3456
3787
|
* @param appName app.name
|
|
3457
|
-
* @param targetLocation target Location, default is rawLocation
|
|
3458
3788
|
*/
|
|
3459
|
-
function removeMicroPathFromURL(appName
|
|
3789
|
+
function removeMicroPathFromURL(appName) {
|
|
3460
3790
|
var _a, _b, _c, _d;
|
|
3461
|
-
let { pathname, search, hash } =
|
|
3791
|
+
let { pathname, search, hash } = globalEnv.rawWindow.location;
|
|
3462
3792
|
let isAttach2Hash = false;
|
|
3463
|
-
if (
|
|
3793
|
+
if (isRouterModeSearch(appName)) {
|
|
3464
3794
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
3465
3795
|
if ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) {
|
|
3466
3796
|
isAttach2Hash = true;
|
|
@@ -3521,14 +3851,38 @@ function isEffectiveApp(appName) {
|
|
|
3521
3851
|
return !!(app && !app.isPrefetch);
|
|
3522
3852
|
}
|
|
3523
3853
|
/**
|
|
3524
|
-
* router mode
|
|
3525
|
-
* NOTE:
|
|
3526
|
-
* 1. if sandbox disabled, router mode defaults to custom
|
|
3527
|
-
* 2. if app not exist, router mode defaults to custom
|
|
3854
|
+
* get router mode of app
|
|
3855
|
+
* NOTE: app maybe undefined
|
|
3528
3856
|
*/
|
|
3529
|
-
function
|
|
3530
|
-
|
|
3531
|
-
return
|
|
3857
|
+
function getRouterMode(appName) {
|
|
3858
|
+
var _a;
|
|
3859
|
+
return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.routerMode;
|
|
3860
|
+
}
|
|
3861
|
+
// router mode is search
|
|
3862
|
+
function isRouterModeSearch(appName) {
|
|
3863
|
+
return getRouterMode(appName) === DEFAULT_ROUTER_MODE;
|
|
3864
|
+
}
|
|
3865
|
+
// router mode is state
|
|
3866
|
+
function isRouterModeState(appName) {
|
|
3867
|
+
return getRouterMode(appName) === ROUTER_MODE_STATE;
|
|
3868
|
+
}
|
|
3869
|
+
// router mode is history
|
|
3870
|
+
function isRouterModeNative(appName) {
|
|
3871
|
+
return getRouterMode(appName) === ROUTER_MODE_NATIVE;
|
|
3872
|
+
}
|
|
3873
|
+
// router mode is disable
|
|
3874
|
+
function isRouterModeNativeScope(appName) {
|
|
3875
|
+
return getRouterMode(appName) === ROUTER_MODE_NATIVE_SCOPE;
|
|
3876
|
+
}
|
|
3877
|
+
// router mode is pure
|
|
3878
|
+
function isRouterModePure(appName) {
|
|
3879
|
+
return getRouterMode(appName) === ROUTER_MODE_PURE;
|
|
3880
|
+
}
|
|
3881
|
+
/**
|
|
3882
|
+
* router mode is history or disable
|
|
3883
|
+
*/
|
|
3884
|
+
function isRouterModeCustom(appName) {
|
|
3885
|
+
return isRouterModeNative(appName) || isRouterModeNativeScope(appName);
|
|
3532
3886
|
}
|
|
3533
3887
|
/**
|
|
3534
3888
|
* get memory router mode of child app
|
|
@@ -3536,21 +3890,21 @@ function isRouterModeCustom(appName) {
|
|
|
3536
3890
|
* 1. if microAppElement exists, it means the app render by the micro-app element
|
|
3537
3891
|
* 2. if microAppElement not exists, it means it is prerender app
|
|
3538
3892
|
* @param mode native config
|
|
3539
|
-
* @param
|
|
3540
|
-
* @returns mode
|
|
3893
|
+
* @param inlineDisableMemoryRouter disable-memory-router set by micro-app element or prerender
|
|
3894
|
+
* @returns router mode
|
|
3541
3895
|
*/
|
|
3542
|
-
function
|
|
3543
|
-
let routerMode;
|
|
3896
|
+
function initRouterMode(mode, inlineDisableMemoryRouter) {
|
|
3544
3897
|
/**
|
|
3545
3898
|
* compatible with disable-memory-router in older versions
|
|
3546
|
-
* if disable-memory-router is true, router-mode will be
|
|
3899
|
+
* if disable-memory-router is true, router-mode will be disable
|
|
3900
|
+
* Priority:
|
|
3901
|
+
* inline disable-memory-router > inline router-mode > global disable-memory-router > global router-mode
|
|
3547
3902
|
*/
|
|
3548
|
-
|
|
3549
|
-
|
|
3550
|
-
|
|
3551
|
-
|
|
3552
|
-
|
|
3553
|
-
}
|
|
3903
|
+
const routerMode = ((inlineDisableMemoryRouter && ROUTER_MODE_NATIVE) ||
|
|
3904
|
+
mode ||
|
|
3905
|
+
(microApp.options['disable-memory-router'] && ROUTER_MODE_NATIVE) ||
|
|
3906
|
+
microApp.options['router-mode'] ||
|
|
3907
|
+
DEFAULT_ROUTER_MODE);
|
|
3554
3908
|
return ROUTER_MODE_LIST.includes(routerMode) ? routerMode : DEFAULT_ROUTER_MODE;
|
|
3555
3909
|
}
|
|
3556
3910
|
|
|
@@ -3565,6 +3919,7 @@ function addHistoryListener(appName) {
|
|
|
3565
3919
|
const rawWindow = globalEnv.rawWindow;
|
|
3566
3920
|
// handle popstate event and distribute to child app
|
|
3567
3921
|
const popStateHandler = (e) => {
|
|
3922
|
+
var _a, _b, _c;
|
|
3568
3923
|
/**
|
|
3569
3924
|
* 1. unmount app & hidden keep-alive app will not receive popstate event
|
|
3570
3925
|
* 2. filter out onlyForBrowser
|
|
@@ -3574,7 +3929,28 @@ function addHistoryListener(appName) {
|
|
|
3574
3929
|
excludePreRender: true,
|
|
3575
3930
|
}).includes(appName) &&
|
|
3576
3931
|
!e.onlyForBrowser) {
|
|
3577
|
-
|
|
3932
|
+
/**
|
|
3933
|
+
* 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
|
|
3934
|
+
* 2 solutions:
|
|
3935
|
+
* 1. child app respond to popstateEvent async -- router-event-delay
|
|
3936
|
+
* 2. child app will not respond to popstateEvent in some scenarios (history.state===null || history.state?__MICRO_APP_STATE__[appName])
|
|
3937
|
+
* NOTE 1:
|
|
3938
|
+
* 1. browser back/forward
|
|
3939
|
+
* 2. location.hash/search/pathname = xxx
|
|
3940
|
+
* 3. <a href="/#/xxx">, <a href="/xxx">
|
|
3941
|
+
* 4. history.back/go/forward
|
|
3942
|
+
* 5. history.pushState/replaceState
|
|
3943
|
+
*
|
|
3944
|
+
* NOTE2:
|
|
3945
|
+
* 1、react16 hash mode navigate by location.hash = xxx, history.state is always null, but react16 respond to popstateEvent sync
|
|
3946
|
+
* 2、multiple child apps may has problems
|
|
3947
|
+
*/
|
|
3948
|
+
if (!isRouterModeCustom(appName) ||
|
|
3949
|
+
!globalEnv.rawWindow.history.state ||
|
|
3950
|
+
getMicroRouterInfoState(appName)) {
|
|
3951
|
+
const container = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container;
|
|
3952
|
+
macro(() => updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName)), (_c = (_b = (container && getRootContainer(container))) === null || _b === void 0 ? void 0 : _b.getRouterEventDelay()) !== null && _c !== void 0 ? _c : 0);
|
|
3953
|
+
}
|
|
3578
3954
|
}
|
|
3579
3955
|
};
|
|
3580
3956
|
rawWindow.addEventListener('popstate', popStateHandler);
|
|
@@ -3592,24 +3968,26 @@ function addHistoryListener(appName) {
|
|
|
3592
3968
|
*/
|
|
3593
3969
|
function updateMicroLocationWithEvent(appName, targetFullPath) {
|
|
3594
3970
|
const app = appInstanceMap.get(appName);
|
|
3595
|
-
|
|
3596
|
-
|
|
3597
|
-
|
|
3598
|
-
|
|
3599
|
-
|
|
3600
|
-
|
|
3601
|
-
|
|
3602
|
-
|
|
3603
|
-
|
|
3604
|
-
|
|
3605
|
-
|
|
3606
|
-
|
|
3607
|
-
|
|
3608
|
-
|
|
3609
|
-
|
|
3610
|
-
|
|
3611
|
-
|
|
3612
|
-
|
|
3971
|
+
if (app === null || app === void 0 ? void 0 : app.sandBox) {
|
|
3972
|
+
const proxyWindow = app.sandBox.proxyWindow;
|
|
3973
|
+
const microAppWindow = app.sandBox.microAppWindow;
|
|
3974
|
+
let isHashChange = false;
|
|
3975
|
+
// for hashChangeEvent
|
|
3976
|
+
const oldHref = proxyWindow.location.href;
|
|
3977
|
+
// Do not attach micro state to url when targetFullPath is empty
|
|
3978
|
+
if (targetFullPath) {
|
|
3979
|
+
const oldHash = proxyWindow.location.hash;
|
|
3980
|
+
updateMicroLocation(appName, targetFullPath, microAppWindow.location);
|
|
3981
|
+
isHashChange = proxyWindow.location.hash !== oldHash;
|
|
3982
|
+
}
|
|
3983
|
+
// dispatch formatted popStateEvent to child
|
|
3984
|
+
dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow);
|
|
3985
|
+
// dispatch formatted hashChangeEvent to child when hash change
|
|
3986
|
+
if (isHashChange)
|
|
3987
|
+
dispatchHashChangeEventToMicroApp(appName, proxyWindow, microAppWindow, oldHref);
|
|
3988
|
+
// clear element scope before trigger event of next app
|
|
3989
|
+
removeDomScope();
|
|
3990
|
+
}
|
|
3613
3991
|
}
|
|
3614
3992
|
/**
|
|
3615
3993
|
* dispatch formatted popstate event to microApp
|
|
@@ -3622,14 +4000,18 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
|
|
|
3622
4000
|
* TODO: test
|
|
3623
4001
|
* angular14 takes e.type as type judgment
|
|
3624
4002
|
* when e.type is popstate-appName popstate event will be invalid
|
|
4003
|
+
* Object.defineProperty(newPopStateEvent, 'type', {
|
|
4004
|
+
* value: 'popstate',
|
|
4005
|
+
* writable: true,
|
|
4006
|
+
* configurable: true,
|
|
4007
|
+
* enumerable: true,
|
|
4008
|
+
* })
|
|
4009
|
+
*/
|
|
4010
|
+
/**
|
|
4011
|
+
* create PopStateEvent named popstate-appName with sub app state
|
|
4012
|
+
* TODO: feeling like there's something wrong, check carefully
|
|
4013
|
+
* 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
|
|
3625
4014
|
*/
|
|
3626
|
-
// Object.defineProperty(newPopStateEvent, 'type', {
|
|
3627
|
-
// value: 'popstate',
|
|
3628
|
-
// writable: true,
|
|
3629
|
-
// configurable: true,
|
|
3630
|
-
// enumerable: true,
|
|
3631
|
-
// })
|
|
3632
|
-
// create PopStateEvent named popstate-appName with sub app state
|
|
3633
4015
|
const newPopStateEvent = new PopStateEvent('popstate', { state: getMicroState(appName) });
|
|
3634
4016
|
microAppWindow.dispatchEvent(newPopStateEvent);
|
|
3635
4017
|
if (!isIframeSandbox(appName)) {
|
|
@@ -3696,7 +4078,7 @@ function dispatchNativeEvent(appName, onlyForBrowser, oldHref) {
|
|
|
3696
4078
|
* create proxyHistory for microApp
|
|
3697
4079
|
* MDN https://developer.mozilla.org/en-US/docs/Web/API/History
|
|
3698
4080
|
* @param appName app name
|
|
3699
|
-
* @param microLocation microApp location
|
|
4081
|
+
* @param microLocation microApp location(with: proxyLocation iframe: iframeWindow.location)
|
|
3700
4082
|
*/
|
|
3701
4083
|
function createMicroHistory(appName, microLocation) {
|
|
3702
4084
|
const rawHistory = globalEnv.rawWindow.history;
|
|
@@ -3704,39 +4086,46 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3704
4086
|
return function (...rests) {
|
|
3705
4087
|
var _a, _b, _c;
|
|
3706
4088
|
// TODO: 测试iframe的URL兼容isURL的情况
|
|
3707
|
-
|
|
3708
|
-
|
|
3709
|
-
|
|
3710
|
-
|
|
3711
|
-
|
|
3712
|
-
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3713
|
-
}
|
|
3714
|
-
(_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
4089
|
+
rests[2] = isUndefined(rests[2]) || isNull(rests[2]) || ('' + rests[2] === '') ? microLocation.href : '' + rests[2];
|
|
4090
|
+
const targetLocation = createURL(rests[2], microLocation.href);
|
|
4091
|
+
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
4092
|
+
if (!isRouterModePure(appName)) {
|
|
4093
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0], targetLocation), rests[1]);
|
|
3715
4094
|
}
|
|
3716
|
-
|
|
3717
|
-
|
|
4095
|
+
if (targetFullPath !== microLocation.fullPath) {
|
|
4096
|
+
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3718
4097
|
}
|
|
4098
|
+
(_c = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : (_b = _a.sandBox).updateIframeBase) === null || _c === void 0 ? void 0 : _c.call(_b);
|
|
3719
4099
|
};
|
|
3720
4100
|
}
|
|
3721
|
-
const
|
|
3722
|
-
|
|
3723
|
-
|
|
3724
|
-
|
|
4101
|
+
const originalHistory = {
|
|
4102
|
+
pushState: getMicroHistoryMethod('pushState'),
|
|
4103
|
+
replaceState: getMicroHistoryMethod('replaceState'),
|
|
4104
|
+
};
|
|
4105
|
+
if (isIframeSandbox(appName)) {
|
|
4106
|
+
return assign({
|
|
4107
|
+
go(delta) {
|
|
4108
|
+
return rawHistory.go(delta);
|
|
4109
|
+
}
|
|
4110
|
+
}, originalHistory);
|
|
4111
|
+
}
|
|
3725
4112
|
return new Proxy(rawHistory, {
|
|
3726
4113
|
get(target, key) {
|
|
3727
|
-
if (key === '
|
|
3728
|
-
return
|
|
3729
|
-
}
|
|
3730
|
-
else if (key === 'pushState') {
|
|
3731
|
-
return pushState;
|
|
4114
|
+
if (key === 'pushState' || key === 'replaceState') {
|
|
4115
|
+
return originalHistory[key];
|
|
3732
4116
|
}
|
|
3733
|
-
else if (key === '
|
|
3734
|
-
return
|
|
4117
|
+
else if (key === 'state') {
|
|
4118
|
+
return getMicroState(appName);
|
|
3735
4119
|
}
|
|
3736
4120
|
return bindFunctionToRawTarget(Reflect.get(target, key), target, 'HISTORY');
|
|
3737
4121
|
},
|
|
3738
4122
|
set(target, key, value) {
|
|
3739
|
-
|
|
4123
|
+
if (key === 'pushState' || key === 'replaceState') {
|
|
4124
|
+
originalHistory[key] = value;
|
|
4125
|
+
}
|
|
4126
|
+
else {
|
|
4127
|
+
Reflect.set(target, key, value);
|
|
4128
|
+
}
|
|
3740
4129
|
/**
|
|
3741
4130
|
* If the set() method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
3742
4131
|
* e.g. history.state = {}
|
|
@@ -3784,8 +4173,8 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
|
|
|
3784
4173
|
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
3785
4174
|
// navigate with native history method
|
|
3786
4175
|
nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
|
|
3787
|
-
//
|
|
3788
|
-
if (oldFullPath !== result.fullPath &&
|
|
4176
|
+
// just search mode will dispatch native event
|
|
4177
|
+
if (oldFullPath !== result.fullPath && isRouterModeSearch(appName)) {
|
|
3789
4178
|
dispatchNativeEvent(appName, onlyForBrowser, oldHref);
|
|
3790
4179
|
}
|
|
3791
4180
|
}
|
|
@@ -3801,22 +4190,22 @@ function attachRouteToBrowserURL(appName, result, state) {
|
|
|
3801
4190
|
navigateWithNativeEvent(appName, 'replaceState', result, true, state);
|
|
3802
4191
|
}
|
|
3803
4192
|
/**
|
|
3804
|
-
* When path is same, keep the
|
|
3805
|
-
* Fix bug of missing
|
|
4193
|
+
* When path is same, keep the __MICRO_APP_STATE__ in history.state
|
|
4194
|
+
* Fix bug of missing __MICRO_APP_STATE__ when base app is next.js or angular
|
|
3806
4195
|
* @param method history.pushState/replaceState
|
|
3807
4196
|
*/
|
|
3808
4197
|
function reWriteHistoryMethod(method) {
|
|
3809
4198
|
const rawWindow = globalEnv.rawWindow;
|
|
3810
4199
|
return function (...rests) {
|
|
3811
4200
|
var _a;
|
|
3812
|
-
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.
|
|
3813
|
-
(!isPlainObject(rests[0]) || !rests[0].
|
|
4201
|
+
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.__MICRO_APP_STATE__) &&
|
|
4202
|
+
(!isPlainObject(rests[0]) || !rests[0].__MICRO_APP_STATE__) &&
|
|
3814
4203
|
(isString(rests[2]) || isURL(rests[2]))) {
|
|
3815
4204
|
const currentHref = rawWindow.location.href;
|
|
3816
4205
|
const targetLocation = createURL(rests[2], currentHref);
|
|
3817
4206
|
if (targetLocation.href === currentHref) {
|
|
3818
4207
|
rests[0] = assign({}, rests[0], {
|
|
3819
|
-
|
|
4208
|
+
__MICRO_APP_STATE__: rawWindow.history.state.__MICRO_APP_STATE__,
|
|
3820
4209
|
});
|
|
3821
4210
|
}
|
|
3822
4211
|
}
|
|
@@ -3832,10 +4221,23 @@ function reWriteHistoryMethod(method) {
|
|
|
3832
4221
|
excludeHiddenApp: true,
|
|
3833
4222
|
excludePreRender: true,
|
|
3834
4223
|
}).forEach(appName => {
|
|
3835
|
-
if (
|
|
4224
|
+
if ((isRouterModeSearch(appName) || isRouterModeState(appName)) && !getMicroPathFromURL(appName)) {
|
|
3836
4225
|
const app = appInstanceMap.get(appName);
|
|
3837
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
4226
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
|
|
4227
|
+
}
|
|
4228
|
+
if (isRouterModeCustom(appName) && !getMicroRouterInfoState(appName)) {
|
|
4229
|
+
nativeHistoryNavigate(appName, 'replaceState', rawWindow.location.href, setMicroState(appName));
|
|
3838
4230
|
}
|
|
4231
|
+
// if (isRouterModeCustom(appName) || isRouterModeSearch(appName)) {
|
|
4232
|
+
/**
|
|
4233
|
+
* history.pushState/replaceState后主动触发子应用响应
|
|
4234
|
+
* 问题:子应用的卸载可能是异步的,而跳转的地址不一定在基础路径中,太快响应pushState可能会导致url地址被子应用改变或者子应用404,Promise太快卸载时出问题、setTimeout太慢keep-alive二次渲染后出问题
|
|
4235
|
+
* 1、history.pushState/replaceState执行后,子应用以异步的形式被主应用卸载,Promise响应时子应用还在,导致子应用跳转404后者浏览器url被子应用修改,产生异常
|
|
4236
|
+
* 2、keep-alive应用二次渲染时,由于setTimeout响应过慢,子应用在渲染后才接受到popstate事件,响应新的url,从而导致状态丢失
|
|
4237
|
+
* 3、同一个页面多个子应用,修改地址响应
|
|
4238
|
+
* 4、vue3跳转前会执行一次replace,有没有影响?
|
|
4239
|
+
*/
|
|
4240
|
+
// }
|
|
3839
4241
|
});
|
|
3840
4242
|
// fix bug for nest app
|
|
3841
4243
|
removeDomScope();
|
|
@@ -3843,7 +4245,7 @@ function reWriteHistoryMethod(method) {
|
|
|
3843
4245
|
}
|
|
3844
4246
|
/**
|
|
3845
4247
|
* rewrite history.pushState/replaceState
|
|
3846
|
-
* used to fix the problem that the
|
|
4248
|
+
* used to fix the problem that the __MICRO_APP_STATE__ maybe missing when mainApp navigate to same path
|
|
3847
4249
|
* e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
|
|
3848
4250
|
*/
|
|
3849
4251
|
function patchHistory() {
|
|
@@ -3866,7 +4268,7 @@ function createRouterApi() {
|
|
|
3866
4268
|
* @param state to.state
|
|
3867
4269
|
*/
|
|
3868
4270
|
function navigateWithRawHistory(appName, methodName, targetLocation, state) {
|
|
3869
|
-
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
4271
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null, targetLocation));
|
|
3870
4272
|
// clear element scope after navigate
|
|
3871
4273
|
removeDomScope();
|
|
3872
4274
|
}
|
|
@@ -3884,21 +4286,13 @@ function createRouterApi() {
|
|
|
3884
4286
|
const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
|
|
3885
4287
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3886
4288
|
if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
|
|
3887
|
-
|
|
3888
|
-
|
|
3889
|
-
|
|
3890
|
-
|
|
3891
|
-
|
|
3892
|
-
|
|
3893
|
-
|
|
3894
|
-
* 路由优化方案有两种:
|
|
3895
|
-
* 1、减少对基座的影响,主要是解决vue循环刷新的问题
|
|
3896
|
-
* 2、全局发送popstate事件,解决主、子都是vue3的冲突问题
|
|
3897
|
-
* 两者选一个吧,如果选2,则下面这两行代码可以去掉
|
|
3898
|
-
* NOTE1: history和search模式采用2,这样可以解决vue3的问题,custom采用1,避免vue循环刷新的问题,这样在用户出现问题时各有解决方案。但反过来说,每种方案又分别导致另外的问题,不统一,导致复杂度增高
|
|
3899
|
-
* NOTE2: 关闭虚拟路由,同时发送popstate事件还是无法解决vue3的问题(毕竟history.state理论上还是会冲突),那么就没必要发送popstate事件了。
|
|
3900
|
-
*/
|
|
3901
|
-
if (isRouterModeCustom(appName)) {
|
|
4289
|
+
// pure mode will not call history.pushState/replaceState
|
|
4290
|
+
if (!isRouterModePure(appName)) {
|
|
4291
|
+
const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
|
|
4292
|
+
navigateWithRawHistory(appName, methodName, targetLocation, to.state);
|
|
4293
|
+
}
|
|
4294
|
+
// only search mode will dispatch PopStateEvent to browser
|
|
4295
|
+
if (!isRouterModeSearch(appName)) {
|
|
3902
4296
|
updateMicroLocationWithEvent(appName, targetFullPath);
|
|
3903
4297
|
}
|
|
3904
4298
|
}
|
|
@@ -3913,52 +4307,44 @@ function createRouterApi() {
|
|
|
3913
4307
|
*/
|
|
3914
4308
|
function createNavigationMethod(replace) {
|
|
3915
4309
|
return function (to) {
|
|
3916
|
-
|
|
3917
|
-
|
|
3918
|
-
|
|
3919
|
-
|
|
3920
|
-
|
|
3921
|
-
|
|
3922
|
-
|
|
3923
|
-
|
|
3924
|
-
|
|
3925
|
-
|
|
3926
|
-
|
|
3927
|
-
|
|
3928
|
-
|
|
3929
|
-
|
|
3930
|
-
|
|
3931
|
-
|
|
3932
|
-
|
|
3933
|
-
|
|
4310
|
+
return new Promise((resolve, reject) => {
|
|
4311
|
+
const appName = formatAppName(to.name);
|
|
4312
|
+
if (appName && isString(to.path)) {
|
|
4313
|
+
/**
|
|
4314
|
+
* active apps, exclude prerender app or hidden keep-alive app
|
|
4315
|
+
* NOTE:
|
|
4316
|
+
* 1. prerender app or hidden keep-alive app clear and record popstate event, so we cannot control app jump through the API
|
|
4317
|
+
* 2. disable memory-router
|
|
4318
|
+
*/
|
|
4319
|
+
/**
|
|
4320
|
+
* TODO:
|
|
4321
|
+
* 1、子应用开始渲染但是还没渲染完成,调用跳转改如何处理
|
|
4322
|
+
* 2、iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
|
|
4323
|
+
* 3、hidden app、预渲染 app 是否支持跳转 --- 支持(这里还涉及子应用内部跳转的支持)
|
|
4324
|
+
*/
|
|
4325
|
+
if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
|
|
4326
|
+
const app = appInstanceMap.get(appName);
|
|
4327
|
+
resolve(app.sandBox.sandboxReady.then(() => handleNavigate(appName, app, to, replace)));
|
|
4328
|
+
}
|
|
4329
|
+
else {
|
|
4330
|
+
reject(logError('导航失败,请确保子应用渲染后再调用此方法'));
|
|
4331
|
+
}
|
|
4332
|
+
// const rawLocation = globalEnv.rawWindow.location
|
|
4333
|
+
// const targetLocation = createURL(to.path, rawLocation.origin)
|
|
4334
|
+
// const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
|
|
4335
|
+
// if (getMicroPathFromURL(appName) !== targetFullPath) {
|
|
4336
|
+
// navigateWithRawHistory(
|
|
4337
|
+
// appName,
|
|
4338
|
+
// to.replace === false ? 'pushState' : 'replaceState',
|
|
4339
|
+
// targetLocation,
|
|
4340
|
+
// to.state,
|
|
4341
|
+
// )
|
|
4342
|
+
// }
|
|
3934
4343
|
}
|
|
3935
4344
|
else {
|
|
3936
|
-
|
|
4345
|
+
reject(logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`));
|
|
3937
4346
|
}
|
|
3938
|
-
|
|
3939
|
-
// * app not exit or unmounted, update browser URL with replaceState
|
|
3940
|
-
// * use base app location.origin as baseURL
|
|
3941
|
-
// * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
|
|
3942
|
-
// */
|
|
3943
|
-
// /**
|
|
3944
|
-
// * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
|
|
3945
|
-
// * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
|
|
3946
|
-
// */
|
|
3947
|
-
// const rawLocation = globalEnv.rawWindow.location
|
|
3948
|
-
// const targetLocation = createURL(to.path, rawLocation.origin)
|
|
3949
|
-
// const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
|
|
3950
|
-
// if (getMicroPathFromURL(appName) !== targetFullPath) {
|
|
3951
|
-
// navigateWithRawHistory(
|
|
3952
|
-
// appName,
|
|
3953
|
-
// to.replace === false ? 'pushState' : 'replaceState',
|
|
3954
|
-
// targetLocation,
|
|
3955
|
-
// to.state,
|
|
3956
|
-
// )
|
|
3957
|
-
// }
|
|
3958
|
-
}
|
|
3959
|
-
else {
|
|
3960
|
-
logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`);
|
|
3961
|
-
}
|
|
4347
|
+
});
|
|
3962
4348
|
};
|
|
3963
4349
|
}
|
|
3964
4350
|
// create method of router.go/back/forward
|
|
@@ -4015,9 +4401,9 @@ function createRouterApi() {
|
|
|
4015
4401
|
* 3. router mode is custom
|
|
4016
4402
|
*/
|
|
4017
4403
|
function commonHandlerForAttachToURL(appName) {
|
|
4018
|
-
if (
|
|
4404
|
+
if (isRouterModeSearch(appName) || isRouterModeState(appName)) {
|
|
4019
4405
|
const app = appInstanceMap.get(appName);
|
|
4020
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
4406
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
|
|
4021
4407
|
}
|
|
4022
4408
|
}
|
|
4023
4409
|
/**
|
|
@@ -4116,94 +4502,6 @@ function createRouterApi() {
|
|
|
4116
4502
|
}
|
|
4117
4503
|
const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
|
|
4118
4504
|
|
|
4119
|
-
const escape2RawWindowKeys = [
|
|
4120
|
-
'getComputedStyle',
|
|
4121
|
-
'visualViewport',
|
|
4122
|
-
'matchMedia',
|
|
4123
|
-
// 'DOMParser',
|
|
4124
|
-
'ResizeObserver',
|
|
4125
|
-
'IntersectionObserver',
|
|
4126
|
-
];
|
|
4127
|
-
const escape2RawWindowRegExpKeys = [
|
|
4128
|
-
/animationFrame$/i,
|
|
4129
|
-
/mutationObserver$/i,
|
|
4130
|
-
/height$|width$/i,
|
|
4131
|
-
/offset$/i,
|
|
4132
|
-
// /event$/i,
|
|
4133
|
-
/selection$/i,
|
|
4134
|
-
/^range/i,
|
|
4135
|
-
/^screen/i,
|
|
4136
|
-
/^scroll/i,
|
|
4137
|
-
/X$|Y$/,
|
|
4138
|
-
];
|
|
4139
|
-
const uniqueDocumentElement = [
|
|
4140
|
-
'body',
|
|
4141
|
-
'head',
|
|
4142
|
-
'html',
|
|
4143
|
-
'title',
|
|
4144
|
-
];
|
|
4145
|
-
const hijackMicroLocationKeys = [
|
|
4146
|
-
'host',
|
|
4147
|
-
'hostname',
|
|
4148
|
-
'port',
|
|
4149
|
-
'protocol',
|
|
4150
|
-
'origin',
|
|
4151
|
-
];
|
|
4152
|
-
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
|
|
4153
|
-
const proxy2RawDocOrShadowKeys = [
|
|
4154
|
-
'childElementCount',
|
|
4155
|
-
'children',
|
|
4156
|
-
'firstElementChild',
|
|
4157
|
-
'firstChild',
|
|
4158
|
-
'lastElementChild',
|
|
4159
|
-
'activeElement',
|
|
4160
|
-
'fullscreenElement',
|
|
4161
|
-
'pictureInPictureElement',
|
|
4162
|
-
'pointerLockElement',
|
|
4163
|
-
'styleSheets',
|
|
4164
|
-
];
|
|
4165
|
-
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
|
|
4166
|
-
const proxy2RawDocOrShadowMethods = [
|
|
4167
|
-
'append',
|
|
4168
|
-
'contains',
|
|
4169
|
-
'replaceChildren',
|
|
4170
|
-
'createRange',
|
|
4171
|
-
'getSelection',
|
|
4172
|
-
'elementFromPoint',
|
|
4173
|
-
'elementsFromPoint',
|
|
4174
|
-
'getAnimations',
|
|
4175
|
-
];
|
|
4176
|
-
// 直接代理到原生document上 (属性)
|
|
4177
|
-
const proxy2RawDocumentKeys = [
|
|
4178
|
-
'characterSet',
|
|
4179
|
-
'compatMode',
|
|
4180
|
-
'contentType',
|
|
4181
|
-
'designMode',
|
|
4182
|
-
'dir',
|
|
4183
|
-
'doctype',
|
|
4184
|
-
'embeds',
|
|
4185
|
-
'fullscreenEnabled',
|
|
4186
|
-
'hidden',
|
|
4187
|
-
'implementation',
|
|
4188
|
-
'lastModified',
|
|
4189
|
-
'pictureInPictureEnabled',
|
|
4190
|
-
'plugins',
|
|
4191
|
-
'readyState',
|
|
4192
|
-
'referrer',
|
|
4193
|
-
'visibilityState',
|
|
4194
|
-
'fonts',
|
|
4195
|
-
];
|
|
4196
|
-
// 直接代理到原生document上 (方法)
|
|
4197
|
-
const proxy2RawDocumentMethods = [
|
|
4198
|
-
'execCommand',
|
|
4199
|
-
'createRange',
|
|
4200
|
-
'exitFullscreen',
|
|
4201
|
-
'exitPictureInPicture',
|
|
4202
|
-
'getElementsByTagNameNS',
|
|
4203
|
-
'hasFocus',
|
|
4204
|
-
'prepend',
|
|
4205
|
-
];
|
|
4206
|
-
|
|
4207
4505
|
// origin is readonly, so we ignore when updateMicroLocation
|
|
4208
4506
|
const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
|
|
4209
4507
|
// origin, fullPath is necessary for guardLocation
|
|
@@ -4248,38 +4546,46 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4248
4546
|
const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
|
|
4249
4547
|
// if disable memory-router, navigate directly through rawLocation
|
|
4250
4548
|
if (!isRouterModeCustom(appName)) {
|
|
4549
|
+
methodName = isRouterModePure(appName) ? 'replaceState' : methodName;
|
|
4251
4550
|
/**
|
|
4252
4551
|
* change hash with location.href will not trigger the browser reload
|
|
4253
4552
|
* so we use pushState & reload to imitate href behavior
|
|
4254
4553
|
* NOTE:
|
|
4255
|
-
* 1. if child app only change hash, it
|
|
4256
|
-
* 2. if address is same and has hash, it
|
|
4554
|
+
* 1. if child app only change hash, it will not reload browser
|
|
4555
|
+
* 2. if address is same and has hash, it will not add route stack
|
|
4257
4556
|
*/
|
|
4258
4557
|
if (targetLocation.pathname === proxyLocation.pathname &&
|
|
4259
4558
|
targetLocation.search === proxyLocation.search) {
|
|
4260
4559
|
let oldHref = null;
|
|
4261
|
-
if
|
|
4262
|
-
|
|
4560
|
+
// NOTE: if pathname & search is same, it should record router info to history.state in pure mode
|
|
4561
|
+
if (targetLocation.hash !== proxyLocation.hash || isRouterModePure(appName)) {
|
|
4562
|
+
// search mode only
|
|
4563
|
+
if (setMicroPathResult.isAttach2Hash) {
|
|
4263
4564
|
oldHref = rawLocation.href;
|
|
4264
|
-
|
|
4565
|
+
}
|
|
4566
|
+
// if router mode is pure and targetLocation.hash exist, it will not call nativeHistoryNavigate
|
|
4567
|
+
if (!isRouterModePure(appName) || !targetLocation.hash) {
|
|
4568
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4569
|
+
}
|
|
4265
4570
|
}
|
|
4266
4571
|
if (targetLocation.hash) {
|
|
4267
|
-
|
|
4572
|
+
if (isRouterModeSearch(appName)) {
|
|
4573
|
+
dispatchNativeEvent(appName, false, oldHref);
|
|
4574
|
+
}
|
|
4575
|
+
else {
|
|
4576
|
+
updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
|
|
4577
|
+
}
|
|
4268
4578
|
}
|
|
4269
4579
|
else {
|
|
4270
4580
|
reload();
|
|
4271
4581
|
}
|
|
4272
4582
|
return void 0;
|
|
4273
|
-
/**
|
|
4274
|
-
* when baseApp is hash router, address change of child can not reload browser
|
|
4275
|
-
* so we imitate behavior of browser (reload) manually
|
|
4276
|
-
*/
|
|
4277
|
-
}
|
|
4278
|
-
else if (setMicroPathResult.isAttach2Hash) {
|
|
4279
|
-
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
4280
|
-
reload();
|
|
4281
|
-
return void 0;
|
|
4282
4583
|
}
|
|
4584
|
+
// when pathname or search change, simulate behavior of browser (reload) manually
|
|
4585
|
+
// TODO: state模式下pushState会带上上一个页面的state,会不会有问题,尤其是vue3,应不应该将主应用的state设置为null
|
|
4586
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4587
|
+
reload();
|
|
4588
|
+
return void 0;
|
|
4283
4589
|
}
|
|
4284
4590
|
return setMicroPathResult.fullPath;
|
|
4285
4591
|
}
|
|
@@ -4304,7 +4610,9 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4304
4610
|
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
4305
4611
|
* search: ?query ==> ?query#hash
|
|
4306
4612
|
*/
|
|
4307
|
-
nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key]
|
|
4613
|
+
nativeHistoryNavigate(appName, (targetLocation[key] === proxyLocation[key] || isRouterModePure(appName))
|
|
4614
|
+
? 'replaceState'
|
|
4615
|
+
: 'pushState', setMicroPathToURL(appName, targetLocation).fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4308
4616
|
reload();
|
|
4309
4617
|
}
|
|
4310
4618
|
}
|
|
@@ -4333,16 +4641,6 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4333
4641
|
const proxyLocation = new Proxy({}, {
|
|
4334
4642
|
get: (_, key) => {
|
|
4335
4643
|
const target = getTarget();
|
|
4336
|
-
if (isIframe) {
|
|
4337
|
-
// host hostname port protocol
|
|
4338
|
-
if (hijackMicroLocationKeys.includes(key)) {
|
|
4339
|
-
return childStaticLocation[key];
|
|
4340
|
-
}
|
|
4341
|
-
if (key === 'href') {
|
|
4342
|
-
// do not use target, because target may be deleted
|
|
4343
|
-
return target[key].replace(browserHost, childHost);
|
|
4344
|
-
}
|
|
4345
|
-
}
|
|
4346
4644
|
if (key === 'assign')
|
|
4347
4645
|
return assign;
|
|
4348
4646
|
if (key === 'replace')
|
|
@@ -4351,21 +4649,47 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4351
4649
|
return reload;
|
|
4352
4650
|
if (key === 'self')
|
|
4353
4651
|
return target;
|
|
4652
|
+
if (key === 'fullPath')
|
|
4653
|
+
return target.fullPath;
|
|
4654
|
+
/**
|
|
4655
|
+
* Special keys: host, hostname, port, protocol, origin, href
|
|
4656
|
+
* NOTE:
|
|
4657
|
+
* 1. In native mode this keys point to browser, in other mode this keys point to child app origin
|
|
4658
|
+
* 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
|
|
4659
|
+
* 3. In other modes, origin points to child app
|
|
4660
|
+
*/
|
|
4661
|
+
if (HIJACK_LOCATION_KEYS.includes(key)) {
|
|
4662
|
+
if (isRouterModeNative(appName)) {
|
|
4663
|
+
return rawLocation[key];
|
|
4664
|
+
}
|
|
4665
|
+
if (isIframe) {
|
|
4666
|
+
return childStaticLocation[key];
|
|
4667
|
+
}
|
|
4668
|
+
}
|
|
4669
|
+
if (key === 'href') {
|
|
4670
|
+
if (isRouterModeNative(appName)) {
|
|
4671
|
+
return target[key].replace(target.origin, rawLocation.origin);
|
|
4672
|
+
}
|
|
4673
|
+
if (isIframe) {
|
|
4674
|
+
// target may be deleted
|
|
4675
|
+
return target[key].replace(browserHost, childHost);
|
|
4676
|
+
}
|
|
4677
|
+
}
|
|
4354
4678
|
return bindFunctionToRawTarget(Reflect.get(target, key), target, 'LOCATION');
|
|
4355
4679
|
},
|
|
4356
4680
|
set: (_, key, value) => {
|
|
4357
4681
|
if (isEffectiveApp(appName)) {
|
|
4358
4682
|
const target = getTarget();
|
|
4359
4683
|
if (key === 'href') {
|
|
4360
|
-
const targetPath = commonHandler(value, 'pushState');
|
|
4361
4684
|
/**
|
|
4362
4685
|
* In vite, targetPath without origin will be completed with child origin
|
|
4363
4686
|
* So we use browser origin to complete targetPath to avoid this problem
|
|
4364
|
-
*
|
|
4365
|
-
*
|
|
4366
|
-
*
|
|
4367
|
-
*
|
|
4687
|
+
* NOTE:
|
|
4688
|
+
* 1. history mode & value is childOrigin + path ==> jump to browserOrigin + path
|
|
4689
|
+
* 2. disable mode & value is childOrigin + path ==> jump to childOrigin + path
|
|
4690
|
+
* 3. search mode & value is browserOrigin + path ==> jump to browserOrigin + path
|
|
4368
4691
|
*/
|
|
4692
|
+
const targetPath = commonHandler(value, 'pushState');
|
|
4369
4693
|
if (targetPath) {
|
|
4370
4694
|
rawLocation.href = createURL(targetPath, rawLocation.origin).href;
|
|
4371
4695
|
}
|
|
@@ -4397,7 +4721,12 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4397
4721
|
const targetLocation = createURL(targetPath, url);
|
|
4398
4722
|
// The same hash will not trigger popStateEvent
|
|
4399
4723
|
if (targetLocation.hash !== proxyLocation.hash) {
|
|
4400
|
-
|
|
4724
|
+
if (!isRouterModePure(appName)) {
|
|
4725
|
+
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, null, targetLocation));
|
|
4726
|
+
}
|
|
4727
|
+
if (!isRouterModeSearch(appName)) {
|
|
4728
|
+
updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
|
|
4729
|
+
}
|
|
4401
4730
|
}
|
|
4402
4731
|
}
|
|
4403
4732
|
}
|
|
@@ -4439,20 +4768,36 @@ function autoTriggerNavigationGuard(appName, microLocation) {
|
|
|
4439
4768
|
* @param microLocation micro app location
|
|
4440
4769
|
* @param type auto prevent
|
|
4441
4770
|
*/
|
|
4442
|
-
function updateMicroLocation(appName,
|
|
4771
|
+
function updateMicroLocation(appName, targetFullPath, microLocation, type) {
|
|
4443
4772
|
var _a;
|
|
4444
4773
|
// record old values of microLocation to `from`
|
|
4445
4774
|
const from = createGuardLocation(appName, microLocation);
|
|
4446
4775
|
// if is iframeSandbox, microLocation muse be rawLocation of iframe, not proxyLocation
|
|
4447
|
-
const newLocation = createURL(
|
|
4776
|
+
const newLocation = createURL(targetFullPath, microLocation.href);
|
|
4448
4777
|
if (isIframeSandbox(appName)) {
|
|
4449
4778
|
const microAppWindow = appInstanceMap.get(appName).sandBox.microAppWindow;
|
|
4450
4779
|
(_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
|
|
4451
4780
|
}
|
|
4452
4781
|
else {
|
|
4453
|
-
|
|
4454
|
-
|
|
4782
|
+
let targetHref = newLocation.href;
|
|
4783
|
+
if (microLocation.self.origin !== newLocation.origin) {
|
|
4784
|
+
targetHref = targetHref.replace(newLocation.origin, microLocation.self.origin);
|
|
4455
4785
|
}
|
|
4786
|
+
microLocation.self.href = targetHref;
|
|
4787
|
+
}
|
|
4788
|
+
/**
|
|
4789
|
+
* The native mode also base of history.state, and the modification of the browser url cannot be controlled. It is very likely that the browser url and __MICRO_APP_STATE__ are different.
|
|
4790
|
+
* Especially during init of child or forward and backward of browser, because vue-router@4 will actively modify the browser URL, the above situation often occurs
|
|
4791
|
+
* To solve this problem, after child app is initialized and responds to the popstateEvent, it is determined whether __MICRO_APP_STATE__ and the browser url are different. If they are different, the browser url will updated to the address of __MICRO_APP_STATE__
|
|
4792
|
+
* NOTE:
|
|
4793
|
+
* 1. If __MICRO_APP_STATE__ is different from the URL, then the operation of updating the URL is correct, otherwise there will be a problem of inconsistency between the URL and the rendered page
|
|
4794
|
+
* 2. When there are multiple child app in native mode, if one of them changes the URL address, the other one will not change __MICRO_APP_STATE__, and refresh browser will cause problems
|
|
4795
|
+
*/
|
|
4796
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
4797
|
+
if (isRouterModeCustom(appName) &&
|
|
4798
|
+
(targetFullPath !== rawLocation.pathname + rawLocation.search + rawLocation.hash) &&
|
|
4799
|
+
type !== 'prevent') {
|
|
4800
|
+
nativeHistoryNavigate(appName, 'replaceState', targetFullPath, globalEnv.rawWindow.history.state);
|
|
4456
4801
|
}
|
|
4457
4802
|
// update latest values of microLocation to `to`
|
|
4458
4803
|
const to = createGuardLocation(appName, microLocation);
|
|
@@ -4462,15 +4807,6 @@ function updateMicroLocation(appName, path, microLocation, type) {
|
|
|
4462
4807
|
}
|
|
4463
4808
|
}
|
|
4464
4809
|
|
|
4465
|
-
/**
|
|
4466
|
-
* TODO: 关于关闭虚拟路由系统的临时笔记 - 即custom模式,虚拟路由不支持关闭
|
|
4467
|
-
* 1. with沙箱关闭虚拟路由最好和iframe保持一致
|
|
4468
|
-
* 2. default-page无法使用,但是用基座的地址可以实现一样的效果
|
|
4469
|
-
* 3. keep-router-state功能失效,因为始终为true
|
|
4470
|
-
* 4. 基座控制子应用跳转地址改变,正确的值为:baseRoute + 子应用地址,这要在文档中说明,否则很容易出错,确实也很难理解
|
|
4471
|
-
* 5. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
|
|
4472
|
-
* 6. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
|
|
4473
|
-
*/
|
|
4474
4810
|
/**
|
|
4475
4811
|
* The router system has two operations: read and write
|
|
4476
4812
|
* Read through location and write through history & location
|
|
@@ -4495,6 +4831,9 @@ function initRouteStateWithURL(appName, microLocation, defaultPage) {
|
|
|
4495
4831
|
const microPath = getMicroPathFromURL(appName);
|
|
4496
4832
|
if (microPath) {
|
|
4497
4833
|
updateMicroLocation(appName, microPath, microLocation, 'auto');
|
|
4834
|
+
if (isRouterModePure(appName)) {
|
|
4835
|
+
removePathFromBrowser(appName);
|
|
4836
|
+
}
|
|
4498
4837
|
}
|
|
4499
4838
|
else {
|
|
4500
4839
|
updateBrowserURLWithLocation(appName, microLocation, defaultPage);
|
|
@@ -4510,8 +4849,10 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4510
4849
|
// update microLocation with defaultPage
|
|
4511
4850
|
if (defaultPage)
|
|
4512
4851
|
updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
|
|
4513
|
-
|
|
4514
|
-
|
|
4852
|
+
if (!isRouterModePure(appName)) {
|
|
4853
|
+
// attach microApp route info to browser URL
|
|
4854
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null, microLocation));
|
|
4855
|
+
}
|
|
4515
4856
|
// trigger guards after change browser URL
|
|
4516
4857
|
autoTriggerNavigationGuard(appName, microLocation);
|
|
4517
4858
|
}
|
|
@@ -4523,11 +4864,12 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4523
4864
|
* @param keepRouteState keep-router-state is only used to control whether to clear the location of microApp, default is false
|
|
4524
4865
|
*/
|
|
4525
4866
|
function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
|
|
4526
|
-
|
|
4527
|
-
|
|
4528
|
-
|
|
4529
|
-
|
|
4530
|
-
|
|
4867
|
+
// TODO: keep-router-state 功能太弱,是否可以增加优先级,或者去掉
|
|
4868
|
+
if (!keepRouteState && !isRouterModeCustom(appName)) {
|
|
4869
|
+
const { pathname, search, hash } = createURL(url);
|
|
4870
|
+
updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
|
|
4871
|
+
}
|
|
4872
|
+
if (!isRouterModePure(appName)) {
|
|
4531
4873
|
removePathFromBrowser(appName);
|
|
4532
4874
|
}
|
|
4533
4875
|
clearRouterWhenUnmount(appName);
|
|
@@ -4642,32 +4984,26 @@ function useMicroEventSource() {
|
|
|
4642
4984
|
}
|
|
4643
4985
|
|
|
4644
4986
|
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
4645
|
-
class WithSandBox {
|
|
4987
|
+
class WithSandBox extends BaseSandbox {
|
|
4646
4988
|
constructor(appName, url) {
|
|
4989
|
+
super(appName, url);
|
|
4647
4990
|
this.active = false;
|
|
4648
|
-
|
|
4649
|
-
|
|
4650
|
-
|
|
4651
|
-
|
|
4652
|
-
|
|
4653
|
-
|
|
4654
|
-
|
|
4655
|
-
|
|
4656
|
-
|
|
4657
|
-
|
|
4658
|
-
|
|
4659
|
-
|
|
4660
|
-
|
|
4661
|
-
|
|
4662
|
-
|
|
4663
|
-
|
|
4664
|
-
this.patchRouter(appName, url, this.microAppWindow);
|
|
4665
|
-
// patch window of child app
|
|
4666
|
-
this.windowEffect = patchWindow(appName, this.microAppWindow, this);
|
|
4667
|
-
// patch document of child app
|
|
4668
|
-
this.documentEffect = patchDocument(appName, this.microAppWindow, this);
|
|
4669
|
-
// inject global properties
|
|
4670
|
-
this.initStaticGlobalKeys(appName, url, this.microAppWindow);
|
|
4991
|
+
this.microAppWindow = new CustomWindow(); // Proxy target
|
|
4992
|
+
this.patchWith((resolve) => {
|
|
4993
|
+
// get scopeProperties and escapeProperties from plugins
|
|
4994
|
+
this.getSpecialProperties(appName);
|
|
4995
|
+
// create location, history for child app
|
|
4996
|
+
this.patchRouter(appName, url, this.microAppWindow);
|
|
4997
|
+
// patch window of child app
|
|
4998
|
+
this.windowEffect = patchWindow(appName, this.microAppWindow, this);
|
|
4999
|
+
// patch document of child app
|
|
5000
|
+
this.documentEffect = patchDocument(appName, this.microAppWindow, this);
|
|
5001
|
+
// properties associated with the native window
|
|
5002
|
+
this.setMappingPropertiesWithRawDescriptor(this.microAppWindow);
|
|
5003
|
+
// inject global properties
|
|
5004
|
+
this.initStaticGlobalKeys(appName, url, this.microAppWindow);
|
|
5005
|
+
resolve();
|
|
5006
|
+
});
|
|
4671
5007
|
}
|
|
4672
5008
|
/**
|
|
4673
5009
|
* open sandbox and perform some initial actions
|
|
@@ -4685,7 +5021,9 @@ class WithSandBox {
|
|
|
4685
5021
|
this.initRouteState(defaultPage);
|
|
4686
5022
|
// unique listener of popstate event for sub app
|
|
4687
5023
|
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4688
|
-
|
|
5024
|
+
if (isRouterModeCustom(this.microAppWindow.__MICRO_APP_NAME__)) {
|
|
5025
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
5026
|
+
}
|
|
4689
5027
|
/* --- memory router part --- end */
|
|
4690
5028
|
/**
|
|
4691
5029
|
* Target: Ensure default mode action exactly same to first time when render again
|
|
@@ -4729,6 +5067,7 @@ class WithSandBox {
|
|
|
4729
5067
|
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
4730
5068
|
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
4731
5069
|
* 3. umd mode will not delete global keys
|
|
5070
|
+
* 4. mount & unmount hook should delete in default mode when stop
|
|
4732
5071
|
*/
|
|
4733
5072
|
if (!umdMode || destroy) {
|
|
4734
5073
|
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
@@ -4740,6 +5079,7 @@ class WithSandBox {
|
|
|
4740
5079
|
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
4741
5080
|
});
|
|
4742
5081
|
this.escapeKeys.clear();
|
|
5082
|
+
this.clearHijackUmdHooks();
|
|
4743
5083
|
}
|
|
4744
5084
|
if (--globalEnv.activeSandbox === 0) {
|
|
4745
5085
|
releasePatchElementAndDocument();
|
|
@@ -4750,6 +5090,7 @@ class WithSandBox {
|
|
|
4750
5090
|
}
|
|
4751
5091
|
/**
|
|
4752
5092
|
* inject global properties to microAppWindow
|
|
5093
|
+
* TODO: 设置为只读变量
|
|
4753
5094
|
* @param appName app name
|
|
4754
5095
|
* @param url app url
|
|
4755
5096
|
* @param microAppWindow micro window
|
|
@@ -4763,6 +5104,7 @@ class WithSandBox {
|
|
|
4763
5104
|
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
4764
5105
|
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
4765
5106
|
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
5107
|
+
microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
4766
5108
|
microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
4767
5109
|
microAppWindow.__MICRO_APP_SANDBOX_TYPE__ = 'with';
|
|
4768
5110
|
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
@@ -4770,9 +5112,9 @@ class WithSandBox {
|
|
|
4770
5112
|
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
4771
5113
|
removeDomScope,
|
|
4772
5114
|
pureCreateElement,
|
|
5115
|
+
location: microAppWindow.location,
|
|
4773
5116
|
router,
|
|
4774
5117
|
});
|
|
4775
|
-
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
4776
5118
|
}
|
|
4777
5119
|
/**
|
|
4778
5120
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -4855,7 +5197,6 @@ class WithSandBox {
|
|
|
4855
5197
|
*/
|
|
4856
5198
|
getSpecialProperties(appName) {
|
|
4857
5199
|
var _a;
|
|
4858
|
-
this.scopeProperties = this.scopeProperties.concat(this.adapter.staticScopeProperties);
|
|
4859
5200
|
if (isPlainObject(microApp.options.plugins)) {
|
|
4860
5201
|
this.commonActionForSpecialProperties(microApp.options.plugins.global);
|
|
4861
5202
|
this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
@@ -4883,6 +5224,9 @@ class WithSandBox {
|
|
|
4883
5224
|
markUmdMode(state) {
|
|
4884
5225
|
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
4885
5226
|
}
|
|
5227
|
+
patchWith(cb) {
|
|
5228
|
+
this.sandboxReady = new Promise((resolve) => cb(resolve));
|
|
5229
|
+
}
|
|
4886
5230
|
// properties associated with the native window
|
|
4887
5231
|
setMappingPropertiesWithRawDescriptor(microAppWindow) {
|
|
4888
5232
|
let topValue, parentValue;
|
|
@@ -4894,9 +5238,10 @@ class WithSandBox {
|
|
|
4894
5238
|
topValue = rawWindow.top;
|
|
4895
5239
|
parentValue = rawWindow.parent;
|
|
4896
5240
|
}
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
5241
|
+
rawDefineProperties(microAppWindow, {
|
|
5242
|
+
top: this.createDescriptorForMicroAppWindow('top', topValue),
|
|
5243
|
+
parent: this.createDescriptorForMicroAppWindow('parent', parentValue),
|
|
5244
|
+
});
|
|
4900
5245
|
GLOBAL_KEY_TO_WINDOW.forEach((key) => {
|
|
4901
5246
|
rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
|
|
4902
5247
|
});
|
|
@@ -4934,7 +5279,7 @@ class WithSandBox {
|
|
|
4934
5279
|
enumerable: false,
|
|
4935
5280
|
get() {
|
|
4936
5281
|
throttleDeferForSetAppName(appName);
|
|
4937
|
-
return modifiedEval || eval;
|
|
5282
|
+
return modifiedEval || globalEnv.rawWindow.eval;
|
|
4938
5283
|
},
|
|
4939
5284
|
set: (value) => {
|
|
4940
5285
|
modifiedEval = value;
|
|
@@ -5049,22 +5394,80 @@ class WithSandBox {
|
|
|
5049
5394
|
* action before exec scripts when mount
|
|
5050
5395
|
* Actions:
|
|
5051
5396
|
* 1. patch static elements from html
|
|
5397
|
+
* 2. hijack umd hooks -- mount, unmount, micro-app-appName
|
|
5052
5398
|
* @param container micro app container
|
|
5053
5399
|
*/
|
|
5054
|
-
|
|
5400
|
+
actionsBeforeExecScripts(container, handleUmdHooks) {
|
|
5055
5401
|
this.patchStaticElement(container);
|
|
5402
|
+
this.clearHijackUmdHooks = this.hijackUmdHooks(this.appName, this.microAppWindow, handleUmdHooks);
|
|
5403
|
+
}
|
|
5404
|
+
// hijack mount, unmount, micro-app-appName hook to microAppWindow
|
|
5405
|
+
hijackUmdHooks(appName, microAppWindow, handleUmdHooks) {
|
|
5406
|
+
let mount, unmount, microAppLibrary;
|
|
5407
|
+
rawDefineProperties(microAppWindow, {
|
|
5408
|
+
mount: {
|
|
5409
|
+
configurable: true,
|
|
5410
|
+
get: () => mount,
|
|
5411
|
+
set: (value) => {
|
|
5412
|
+
if (this.active && isFunction(value) && !mount) {
|
|
5413
|
+
handleUmdHooks(mount = value, unmount);
|
|
5414
|
+
}
|
|
5415
|
+
}
|
|
5416
|
+
},
|
|
5417
|
+
unmount: {
|
|
5418
|
+
configurable: true,
|
|
5419
|
+
get: () => unmount,
|
|
5420
|
+
set: (value) => {
|
|
5421
|
+
if (this.active && isFunction(value) && !unmount) {
|
|
5422
|
+
handleUmdHooks(mount, unmount = value);
|
|
5423
|
+
}
|
|
5424
|
+
}
|
|
5425
|
+
},
|
|
5426
|
+
[`micro-app-${appName}`]: {
|
|
5427
|
+
configurable: true,
|
|
5428
|
+
get: () => microAppLibrary,
|
|
5429
|
+
set: (value) => {
|
|
5430
|
+
if (this.active && isPlainObject(value) && !microAppLibrary) {
|
|
5431
|
+
microAppLibrary = value;
|
|
5432
|
+
handleUmdHooks(microAppLibrary.mount, microAppLibrary.unmount);
|
|
5433
|
+
}
|
|
5434
|
+
}
|
|
5435
|
+
}
|
|
5436
|
+
});
|
|
5437
|
+
return () => {
|
|
5438
|
+
mount = unmount = microAppLibrary = null;
|
|
5439
|
+
};
|
|
5440
|
+
}
|
|
5441
|
+
setStaticAppState(state) {
|
|
5442
|
+
this.microAppWindow.__MICRO_APP_STATE__ = state;
|
|
5056
5443
|
}
|
|
5057
5444
|
}
|
|
5058
5445
|
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5059
5446
|
|
|
5060
5447
|
function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
5061
|
-
const
|
|
5448
|
+
const rawHistory = globalEnv.rawWindow.history;
|
|
5449
|
+
const childStaticLocation = createURL(url);
|
|
5062
5450
|
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
5063
5451
|
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
5064
5452
|
// rewrite microAppWindow.history
|
|
5065
5453
|
const microHistory = microAppWindow.history;
|
|
5454
|
+
// save history.replaceState, it will be used in updateMicroLocation
|
|
5066
5455
|
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5456
|
+
// rewrite microAppWindow.history
|
|
5067
5457
|
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5458
|
+
// scrollRestoration proxy to rawHistory
|
|
5459
|
+
rawDefineProperties(microHistory, {
|
|
5460
|
+
scrollRestoration: {
|
|
5461
|
+
configurable: true,
|
|
5462
|
+
enumerable: true,
|
|
5463
|
+
get() {
|
|
5464
|
+
return rawHistory.scrollRestoration;
|
|
5465
|
+
},
|
|
5466
|
+
set(value) {
|
|
5467
|
+
rawHistory.scrollRestoration = value;
|
|
5468
|
+
}
|
|
5469
|
+
}
|
|
5470
|
+
});
|
|
5068
5471
|
/**
|
|
5069
5472
|
* Init microLocation before exec sandbox.start
|
|
5070
5473
|
* NOTE:
|
|
@@ -5076,6 +5479,149 @@ function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
|
5076
5479
|
return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
5077
5480
|
}
|
|
5078
5481
|
|
|
5482
|
+
const escape2RawWindowKeys = [
|
|
5483
|
+
'getComputedStyle',
|
|
5484
|
+
// FIX ISSUE: https://github.com/micro-zoe/micro-app/issues/1292
|
|
5485
|
+
'DOMParser',
|
|
5486
|
+
'visualViewport',
|
|
5487
|
+
'matchMedia',
|
|
5488
|
+
'ResizeObserver',
|
|
5489
|
+
'IntersectionObserver',
|
|
5490
|
+
];
|
|
5491
|
+
const escape2RawWindowRegExpKeys = [
|
|
5492
|
+
/animationFrame$/i,
|
|
5493
|
+
/mutationObserver$/i,
|
|
5494
|
+
/height$|width$/i,
|
|
5495
|
+
/offset$/i,
|
|
5496
|
+
/selection$/i,
|
|
5497
|
+
/^range/i,
|
|
5498
|
+
/^screen/i,
|
|
5499
|
+
/^scroll/i,
|
|
5500
|
+
/X$|Y$/,
|
|
5501
|
+
];
|
|
5502
|
+
const uniqueDocumentElement = [
|
|
5503
|
+
'body',
|
|
5504
|
+
'head',
|
|
5505
|
+
'html',
|
|
5506
|
+
'title',
|
|
5507
|
+
];
|
|
5508
|
+
// proxy to shadowRoot or rawDocument (property)
|
|
5509
|
+
const proxy2RawDocOrShadowKeys = [
|
|
5510
|
+
'childElementCount',
|
|
5511
|
+
'children',
|
|
5512
|
+
'firstElementChild',
|
|
5513
|
+
'firstChild',
|
|
5514
|
+
'lastElementChild',
|
|
5515
|
+
'activeElement',
|
|
5516
|
+
'fullscreenElement',
|
|
5517
|
+
'pictureInPictureElement',
|
|
5518
|
+
'pointerLockElement',
|
|
5519
|
+
'styleSheets',
|
|
5520
|
+
];
|
|
5521
|
+
// proxy to shadowRoot or rawDocument (method)
|
|
5522
|
+
const proxy2RawDocOrShadowMethods = [
|
|
5523
|
+
'append',
|
|
5524
|
+
'contains',
|
|
5525
|
+
'replaceChildren',
|
|
5526
|
+
'createRange',
|
|
5527
|
+
'getSelection',
|
|
5528
|
+
'elementFromPoint',
|
|
5529
|
+
'elementsFromPoint',
|
|
5530
|
+
'getAnimations',
|
|
5531
|
+
];
|
|
5532
|
+
// proxy to rawDocument (property)
|
|
5533
|
+
const proxy2RawDocumentKeys = [
|
|
5534
|
+
'characterSet',
|
|
5535
|
+
'compatMode',
|
|
5536
|
+
'contentType',
|
|
5537
|
+
'designMode',
|
|
5538
|
+
'dir',
|
|
5539
|
+
'doctype',
|
|
5540
|
+
'embeds',
|
|
5541
|
+
'fullscreenEnabled',
|
|
5542
|
+
'hidden',
|
|
5543
|
+
'implementation',
|
|
5544
|
+
'lastModified',
|
|
5545
|
+
'pictureInPictureEnabled',
|
|
5546
|
+
'plugins',
|
|
5547
|
+
'readyState',
|
|
5548
|
+
'referrer',
|
|
5549
|
+
'visibilityState',
|
|
5550
|
+
'fonts',
|
|
5551
|
+
];
|
|
5552
|
+
// proxy to rawDocument (method)
|
|
5553
|
+
const proxy2RawDocumentMethods = [
|
|
5554
|
+
'execCommand',
|
|
5555
|
+
'createRange',
|
|
5556
|
+
'exitFullscreen',
|
|
5557
|
+
'exitPictureInPicture',
|
|
5558
|
+
'getElementsByTagNameNS',
|
|
5559
|
+
'hasFocus',
|
|
5560
|
+
'prepend',
|
|
5561
|
+
];
|
|
5562
|
+
|
|
5563
|
+
// 重写 Worker 构造函数的类型
|
|
5564
|
+
const originalWorker = window.Worker;
|
|
5565
|
+
function isSameOrigin(url) {
|
|
5566
|
+
if (url instanceof URL && url.protocol === 'blob:') {
|
|
5567
|
+
// 如果 url 是 Blob URL,直接返回 true
|
|
5568
|
+
return true;
|
|
5569
|
+
}
|
|
5570
|
+
// 检查 URL 是否与当前页面在同一个源
|
|
5571
|
+
try {
|
|
5572
|
+
const parsedUrl = new URL(url);
|
|
5573
|
+
return (parsedUrl.protocol === window.location.protocol &&
|
|
5574
|
+
parsedUrl.hostname === window.location.hostname &&
|
|
5575
|
+
parsedUrl.port === window.location.port);
|
|
5576
|
+
}
|
|
5577
|
+
catch (error) {
|
|
5578
|
+
return false;
|
|
5579
|
+
}
|
|
5580
|
+
}
|
|
5581
|
+
function urlFromScript(script) {
|
|
5582
|
+
let blob;
|
|
5583
|
+
try {
|
|
5584
|
+
blob = new Blob([script], {
|
|
5585
|
+
type: 'application/javascript'
|
|
5586
|
+
});
|
|
5587
|
+
}
|
|
5588
|
+
catch (e) {
|
|
5589
|
+
const BlobBuilder =
|
|
5590
|
+
// @ts-ignore
|
|
5591
|
+
window.BlobBuilder ||
|
|
5592
|
+
// @ts-ignore
|
|
5593
|
+
window.WebKitBlobBuilder ||
|
|
5594
|
+
// @ts-ignore
|
|
5595
|
+
window.MozBlobBuilder ||
|
|
5596
|
+
// @ts-ignore
|
|
5597
|
+
window.MSBlobBuilder;
|
|
5598
|
+
const blobBuilder = new BlobBuilder();
|
|
5599
|
+
blobBuilder.append(script);
|
|
5600
|
+
blob = blobBuilder.getBlob('application/javascript');
|
|
5601
|
+
}
|
|
5602
|
+
const URL = window.URL || window.webkitURL;
|
|
5603
|
+
return URL.createObjectURL(blob);
|
|
5604
|
+
}
|
|
5605
|
+
// @ts-ignore
|
|
5606
|
+
const WorkerProxy = new Proxy(originalWorker, {
|
|
5607
|
+
construct(Target, args) {
|
|
5608
|
+
const [scriptURL, options] = args;
|
|
5609
|
+
if (!isSameOrigin(scriptURL)) {
|
|
5610
|
+
// 如果 scriptURL 是跨域的,使用 Blob URL 加载并执行 worker
|
|
5611
|
+
const script = `import "${scriptURL}";`;
|
|
5612
|
+
const workerPath = urlFromScript(script);
|
|
5613
|
+
options.type = 'module';
|
|
5614
|
+
return new Target(workerPath, options);
|
|
5615
|
+
}
|
|
5616
|
+
else {
|
|
5617
|
+
// 如果 scriptURL 是同源的,直接使用原生的 Worker 构造函数
|
|
5618
|
+
return new Target(scriptURL, options);
|
|
5619
|
+
}
|
|
5620
|
+
},
|
|
5621
|
+
});
|
|
5622
|
+
// @ts-ignore
|
|
5623
|
+
window.Worker = WorkerProxy;
|
|
5624
|
+
|
|
5079
5625
|
/**
|
|
5080
5626
|
* patch window of child app
|
|
5081
5627
|
* @param appName app name
|
|
@@ -5084,7 +5630,7 @@ function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
|
5084
5630
|
* @returns EffectHook
|
|
5085
5631
|
*/
|
|
5086
5632
|
function patchWindow$1(appName, microAppWindow, sandbox) {
|
|
5087
|
-
patchWindowProperty$1(appName, microAppWindow);
|
|
5633
|
+
patchWindowProperty$1(appName, microAppWindow, sandbox);
|
|
5088
5634
|
createProxyWindow$1(microAppWindow, sandbox);
|
|
5089
5635
|
return patchWindowEffect$1(microAppWindow);
|
|
5090
5636
|
}
|
|
@@ -5093,7 +5639,7 @@ function patchWindow$1(appName, microAppWindow, sandbox) {
|
|
|
5093
5639
|
* @param appName app name
|
|
5094
5640
|
* @param microAppWindow child app microWindow
|
|
5095
5641
|
*/
|
|
5096
|
-
function patchWindowProperty$1(appName, microAppWindow) {
|
|
5642
|
+
function patchWindowProperty$1(appName, microAppWindow, sandbox) {
|
|
5097
5643
|
const rawWindow = globalEnv.rawWindow;
|
|
5098
5644
|
escape2RawWindowKeys.forEach((key) => {
|
|
5099
5645
|
microAppWindow[key] = bindFunctionToRawTarget(rawWindow[key], rawWindow);
|
|
@@ -5123,7 +5669,26 @@ function patchWindowProperty$1(appName, microAppWindow) {
|
|
|
5123
5669
|
}
|
|
5124
5670
|
return false;
|
|
5125
5671
|
});
|
|
5126
|
-
|
|
5672
|
+
/**
|
|
5673
|
+
* In FireFox, iframe Element.prototype will point to native Element.prototype after insert to document
|
|
5674
|
+
* Rewrite all constructor's Symbol.hasInstance of iframeWindow
|
|
5675
|
+
* NOTE:
|
|
5676
|
+
* 1. native event instanceof iframe window.Event
|
|
5677
|
+
* 2. native node instanceof iframe window.Node
|
|
5678
|
+
* 3. native element instanceof iframe window.Element
|
|
5679
|
+
* 4. native url instanceof iframe window.URL
|
|
5680
|
+
* ...
|
|
5681
|
+
*/
|
|
5682
|
+
if (isConstructor(microAppWindow[key]) && key in rawWindow) {
|
|
5683
|
+
rawDefineProperty(microAppWindow[key], Symbol.hasInstance, {
|
|
5684
|
+
configurable: true,
|
|
5685
|
+
enumerable: false,
|
|
5686
|
+
value(target) {
|
|
5687
|
+
return instanceOf(target, rawWindow[key]) || instanceOf(target, microAppWindow[key]);
|
|
5688
|
+
},
|
|
5689
|
+
});
|
|
5690
|
+
}
|
|
5691
|
+
return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_IFRAME.includes(key);
|
|
5127
5692
|
})
|
|
5128
5693
|
.forEach((eventName) => {
|
|
5129
5694
|
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microAppWindow, eventName) || {
|
|
@@ -5143,6 +5708,23 @@ function patchWindowProperty$1(appName, microAppWindow) {
|
|
|
5143
5708
|
logWarn(e, appName);
|
|
5144
5709
|
}
|
|
5145
5710
|
});
|
|
5711
|
+
/**
|
|
5712
|
+
* In esmodule(vite) proxyWindow will not take effect,
|
|
5713
|
+
* escapeProperties should define to microAppWindow
|
|
5714
|
+
*/
|
|
5715
|
+
sandbox.escapeProperties.forEach((key) => {
|
|
5716
|
+
let rawValue = microAppWindow[key];
|
|
5717
|
+
rawDefineProperty(microAppWindow, key, {
|
|
5718
|
+
enumerable: true,
|
|
5719
|
+
configurable: true,
|
|
5720
|
+
get() {
|
|
5721
|
+
return rawValue !== null && rawValue !== void 0 ? rawValue : bindFunctionToRawTarget(rawWindow[key], rawWindow);
|
|
5722
|
+
},
|
|
5723
|
+
set(value) {
|
|
5724
|
+
rawValue = value;
|
|
5725
|
+
}
|
|
5726
|
+
});
|
|
5727
|
+
});
|
|
5146
5728
|
}
|
|
5147
5729
|
/**
|
|
5148
5730
|
* create proxyWindow with Proxy(microAppWindow)
|
|
@@ -5151,18 +5733,43 @@ function patchWindowProperty$1(appName, microAppWindow) {
|
|
|
5151
5733
|
*/
|
|
5152
5734
|
function createProxyWindow$1(microAppWindow, sandbox) {
|
|
5153
5735
|
const rawWindow = globalEnv.rawWindow;
|
|
5154
|
-
const customProperties =
|
|
5736
|
+
const customProperties = new Set();
|
|
5737
|
+
Object.defineProperty(microAppWindow, 'Worker', {
|
|
5738
|
+
value: WorkerProxy,
|
|
5739
|
+
configurable: true,
|
|
5740
|
+
writable: true,
|
|
5741
|
+
});
|
|
5742
|
+
/**
|
|
5743
|
+
* proxyWindow will only take effect in certain scenes, such as window.key
|
|
5744
|
+
* e.g:
|
|
5745
|
+
* 1. window.key in normal app --> fall into proxyWindow
|
|
5746
|
+
* 2. window.key in module app(vite), fall into microAppWindow(iframeWindow)
|
|
5747
|
+
* 3. if (key)... --> fall into microAppWindow(iframeWindow)
|
|
5748
|
+
*/
|
|
5155
5749
|
const proxyWindow = new Proxy(microAppWindow, {
|
|
5156
5750
|
get: (target, key) => {
|
|
5751
|
+
if (key === 'Worker') {
|
|
5752
|
+
return WorkerProxy;
|
|
5753
|
+
}
|
|
5157
5754
|
if (key === 'location') {
|
|
5158
5755
|
return sandbox.proxyLocation;
|
|
5159
5756
|
}
|
|
5160
|
-
if (
|
|
5757
|
+
if (includes(GLOBAL_KEY_TO_WINDOW, key)) {
|
|
5161
5758
|
return proxyWindow;
|
|
5162
5759
|
}
|
|
5163
|
-
if (customProperties.
|
|
5760
|
+
if (customProperties.has(key)) {
|
|
5164
5761
|
return Reflect.get(target, key);
|
|
5165
5762
|
}
|
|
5763
|
+
/**
|
|
5764
|
+
* Same as proxyWindow, escapeProperties will only take effect in certain scenes
|
|
5765
|
+
* e.g:
|
|
5766
|
+
* 1. window.key in normal app --> fall into proxyWindow, escapeProperties will effect
|
|
5767
|
+
* 2. window.key in module app(vite), fall into microAppWindow(iframeWindow), escapeProperties will not take effect
|
|
5768
|
+
* 3. if (key)... --> fall into microAppWindow(iframeWindow), escapeProperties will not take effect
|
|
5769
|
+
*/
|
|
5770
|
+
if (includes(sandbox.escapeProperties, key) && !Reflect.get(target, key)) {
|
|
5771
|
+
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
5772
|
+
}
|
|
5166
5773
|
return bindFunctionToRawTarget(Reflect.get(target, key), target);
|
|
5167
5774
|
},
|
|
5168
5775
|
set: (target, key, value) => {
|
|
@@ -5170,19 +5777,15 @@ function createProxyWindow$1(microAppWindow, sandbox) {
|
|
|
5170
5777
|
return Reflect.set(rawWindow, key, value);
|
|
5171
5778
|
}
|
|
5172
5779
|
if (!Reflect.has(target, key)) {
|
|
5173
|
-
customProperties.
|
|
5780
|
+
customProperties.add(key);
|
|
5174
5781
|
}
|
|
5782
|
+
// sandbox.escapeProperties will not set to rawWindow from rc.9
|
|
5175
5783
|
Reflect.set(target, key, value);
|
|
5176
|
-
if (sandbox.escapeProperties.includes(key)) {
|
|
5177
|
-
!Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
|
|
5178
|
-
Reflect.set(rawWindow, key, value);
|
|
5179
|
-
}
|
|
5180
5784
|
return true;
|
|
5181
5785
|
},
|
|
5182
5786
|
has: (target, key) => key in target,
|
|
5183
5787
|
deleteProperty: (target, key) => {
|
|
5184
5788
|
if (Reflect.has(target, key)) {
|
|
5185
|
-
sandbox.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
5186
5789
|
return Reflect.deleteProperty(target, key);
|
|
5187
5790
|
}
|
|
5188
5791
|
return true;
|
|
@@ -5191,11 +5794,15 @@ function createProxyWindow$1(microAppWindow, sandbox) {
|
|
|
5191
5794
|
sandbox.proxyWindow = proxyWindow;
|
|
5192
5795
|
}
|
|
5193
5796
|
function patchWindowEffect$1(microAppWindow) {
|
|
5194
|
-
const { rawWindow, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5797
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent } = globalEnv;
|
|
5195
5798
|
const eventListenerMap = new Map();
|
|
5196
5799
|
const sstEventListenerMap = new Map();
|
|
5197
5800
|
function getEventTarget(type) {
|
|
5198
|
-
|
|
5801
|
+
/**
|
|
5802
|
+
* TODO: SCOPE_WINDOW_EVENT_OF_IFRAME的事件非常少,有可能导致问题
|
|
5803
|
+
* 1、一些未知的需要绑定到iframe的事件被错误的绑定到原生window上
|
|
5804
|
+
*/
|
|
5805
|
+
return SCOPE_WINDOW_EVENT_OF_IFRAME.includes(type) ? microAppWindow : rawWindow;
|
|
5199
5806
|
}
|
|
5200
5807
|
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
5201
5808
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
@@ -5216,6 +5823,9 @@ function patchWindowEffect$1(microAppWindow) {
|
|
|
5216
5823
|
}
|
|
5217
5824
|
rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
|
|
5218
5825
|
};
|
|
5826
|
+
microAppWindow.dispatchEvent = function (event) {
|
|
5827
|
+
return rawDispatchEvent.call(getEventTarget(event === null || event === void 0 ? void 0 : event.type), event);
|
|
5828
|
+
};
|
|
5219
5829
|
const reset = () => {
|
|
5220
5830
|
sstEventListenerMap.clear();
|
|
5221
5831
|
};
|
|
@@ -5288,7 +5898,9 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5288
5898
|
const microRootDocument = microAppWindow.Document;
|
|
5289
5899
|
const microDocument = microAppWindow.document;
|
|
5290
5900
|
const rawMicroCreateElement = microRootDocument.prototype.createElement;
|
|
5901
|
+
const rawMicroCreateElementNS = microRootDocument.prototype.createElementNS;
|
|
5291
5902
|
const rawMicroCreateTextNode = microRootDocument.prototype.createTextNode;
|
|
5903
|
+
const rawMicroCreateDocumentFragment = microRootDocument.prototype.createDocumentFragment;
|
|
5292
5904
|
const rawMicroCreateComment = microRootDocument.prototype.createComment;
|
|
5293
5905
|
const rawMicroQuerySelector = microRootDocument.prototype.querySelector;
|
|
5294
5906
|
const rawMicroQuerySelectorAll = microRootDocument.prototype.querySelectorAll;
|
|
@@ -5309,42 +5921,71 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5309
5921
|
const element = rawMicroCreateElement.call(this, tagName, options);
|
|
5310
5922
|
return updateElementInfo(element, appName);
|
|
5311
5923
|
};
|
|
5924
|
+
microRootDocument.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
|
|
5925
|
+
const element = rawMicroCreateElementNS.call(this, namespaceURI, name, options);
|
|
5926
|
+
return updateElementInfo(element, appName);
|
|
5927
|
+
};
|
|
5312
5928
|
microRootDocument.prototype.createTextNode = function createTextNode(data) {
|
|
5313
5929
|
const element = rawMicroCreateTextNode.call(this, data);
|
|
5314
5930
|
return updateElementInfo(element, appName);
|
|
5315
5931
|
};
|
|
5932
|
+
microRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
|
|
5933
|
+
const element = rawMicroCreateDocumentFragment.call(this);
|
|
5934
|
+
return updateElementInfo(element, appName);
|
|
5935
|
+
};
|
|
5316
5936
|
microRootDocument.prototype.createComment = function createComment(data) {
|
|
5317
5937
|
const element = rawMicroCreateComment.call(this, data);
|
|
5318
5938
|
return updateElementInfo(element, appName);
|
|
5319
5939
|
};
|
|
5320
|
-
function
|
|
5321
|
-
|
|
5940
|
+
function getBindTarget(target) {
|
|
5941
|
+
/**
|
|
5942
|
+
* handler for:
|
|
5943
|
+
* 1. document.getElementsByTagName('head')[0].querySelector('script')
|
|
5944
|
+
* 2. document.querySelector('body').querySelectorAll('script')
|
|
5945
|
+
* ...
|
|
5946
|
+
*/
|
|
5947
|
+
throttleDeferForIframeAppName(appName);
|
|
5948
|
+
// DOMParser.document !== microDocument
|
|
5949
|
+
return microDocument === target ? rawDocument : target;
|
|
5322
5950
|
}
|
|
5323
5951
|
// query element👇
|
|
5324
5952
|
function querySelector(selectors) {
|
|
5325
|
-
var _a
|
|
5953
|
+
var _a;
|
|
5954
|
+
const _this = getBindTarget(this);
|
|
5326
5955
|
if (!selectors ||
|
|
5327
5956
|
isUniqueElement(selectors) ||
|
|
5328
|
-
|
|
5329
|
-
const _this = getDefaultRawTarget(this);
|
|
5957
|
+
rawDocument !== _this) {
|
|
5330
5958
|
return rawMicroQuerySelector.call(_this, selectors);
|
|
5331
5959
|
}
|
|
5332
|
-
|
|
5960
|
+
/**
|
|
5961
|
+
* The child app cannot query the base element inside iframe
|
|
5962
|
+
* Same for querySelectorAll
|
|
5963
|
+
*
|
|
5964
|
+
* Scenes:
|
|
5965
|
+
* 1. vue-router@4.x --> createWebHistory(base?: string)
|
|
5966
|
+
* const baseEl = document.querySelector('base')
|
|
5967
|
+
* base = (baseEl && baseEl.getAttribute('href')) || '/'
|
|
5968
|
+
*
|
|
5969
|
+
* Issue: https://github.com/micro-zoe/micro-app/issues/1335
|
|
5970
|
+
*/
|
|
5971
|
+
const result = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors);
|
|
5972
|
+
return result || selectors === 'base' ? result : rawMicroQuerySelector.call(microDocument, selectors);
|
|
5333
5973
|
}
|
|
5334
5974
|
function querySelectorAll(selectors) {
|
|
5335
5975
|
var _a, _b;
|
|
5976
|
+
const _this = getBindTarget(this);
|
|
5336
5977
|
if (!selectors ||
|
|
5337
5978
|
isUniqueElement(selectors) ||
|
|
5338
|
-
|
|
5339
|
-
const _this = getDefaultRawTarget(this);
|
|
5979
|
+
rawDocument !== _this) {
|
|
5340
5980
|
return rawMicroQuerySelectorAll.call(_this, selectors);
|
|
5341
5981
|
}
|
|
5342
|
-
|
|
5982
|
+
const result = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
5983
|
+
return result.length || selectors === 'base' ? result : rawMicroQuerySelectorAll.call(microDocument, selectors);
|
|
5343
5984
|
}
|
|
5344
5985
|
microRootDocument.prototype.querySelector = querySelector;
|
|
5345
5986
|
microRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
5346
5987
|
microRootDocument.prototype.getElementById = function getElementById(key) {
|
|
5347
|
-
const _this =
|
|
5988
|
+
const _this = getBindTarget(this);
|
|
5348
5989
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5349
5990
|
return rawMicroGetElementById.call(_this, key);
|
|
5350
5991
|
}
|
|
@@ -5356,7 +5997,7 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5356
5997
|
}
|
|
5357
5998
|
};
|
|
5358
5999
|
microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
5359
|
-
const _this =
|
|
6000
|
+
const _this = getBindTarget(this);
|
|
5360
6001
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5361
6002
|
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5362
6003
|
}
|
|
@@ -5368,22 +6009,24 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5368
6009
|
}
|
|
5369
6010
|
};
|
|
5370
6011
|
microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
5371
|
-
|
|
5372
|
-
const _this = getDefaultRawTarget(this);
|
|
6012
|
+
const _this = getBindTarget(this);
|
|
5373
6013
|
if (isUniqueElement(key) ||
|
|
5374
|
-
isInvalidQuerySelectorKey(key)
|
|
5375
|
-
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
6014
|
+
isInvalidQuerySelectorKey(key)) {
|
|
5376
6015
|
return rawMicroGetElementsByTagName.call(_this, key);
|
|
6016
|
+
// just script, not base
|
|
6017
|
+
}
|
|
6018
|
+
else if (/^script$/i.test(key)) {
|
|
6019
|
+
return rawMicroGetElementsByTagName.call(microDocument, key);
|
|
5377
6020
|
}
|
|
5378
6021
|
try {
|
|
5379
6022
|
return querySelectorAll.call(this, key);
|
|
5380
6023
|
}
|
|
5381
|
-
catch (
|
|
6024
|
+
catch (_a) {
|
|
5382
6025
|
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5383
6026
|
}
|
|
5384
6027
|
};
|
|
5385
6028
|
microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
|
|
5386
|
-
const _this =
|
|
6029
|
+
const _this = getBindTarget(this);
|
|
5387
6030
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5388
6031
|
return rawMicroGetElementsByName.call(_this, key);
|
|
5389
6032
|
}
|
|
@@ -5412,6 +6055,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
|
|
|
5412
6055
|
const createDescriptors = () => {
|
|
5413
6056
|
const result = {};
|
|
5414
6057
|
const descList = [
|
|
6058
|
+
// if disable-memory-router or router-mode='disable', href point to base app
|
|
5415
6059
|
['documentURI', () => sandbox.proxyLocation.href],
|
|
5416
6060
|
['URL', () => sandbox.proxyLocation.href],
|
|
5417
6061
|
['documentElement', () => rawDocument.documentElement],
|
|
@@ -5421,6 +6065,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
|
|
|
5421
6065
|
['links', () => microRootDocument.prototype.querySelectorAll.call(microDocument, 'a')],
|
|
5422
6066
|
// unique keys of micro-app
|
|
5423
6067
|
['microAppElement', () => { var _a; return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container; }],
|
|
6068
|
+
['__MICRO_APP_NAME__', () => appName],
|
|
5424
6069
|
];
|
|
5425
6070
|
descList.forEach((desc) => {
|
|
5426
6071
|
result[desc[0]] = getCommonDescriptor(desc[0], desc[1]);
|
|
@@ -5447,13 +6092,16 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
|
|
|
5447
6092
|
rawDefineProperty(microDocument, tagName, {
|
|
5448
6093
|
enumerable: true,
|
|
5449
6094
|
configurable: true,
|
|
5450
|
-
get: () =>
|
|
6095
|
+
get: () => {
|
|
6096
|
+
throttleDeferForIframeAppName(appName);
|
|
6097
|
+
return rawDocument[tagName];
|
|
6098
|
+
},
|
|
5451
6099
|
set: (value) => { rawDocument[tagName] = value; },
|
|
5452
6100
|
});
|
|
5453
6101
|
});
|
|
5454
6102
|
}
|
|
5455
6103
|
function patchDocumentEffect(appName, microAppWindow) {
|
|
5456
|
-
const { rawDocument, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
6104
|
+
const { rawDocument, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent } = globalEnv;
|
|
5457
6105
|
const eventListenerMap = new Map();
|
|
5458
6106
|
const sstEventListenerMap = new Map();
|
|
5459
6107
|
let onClickHandler = null;
|
|
@@ -5483,6 +6131,9 @@ function patchDocumentEffect(appName, microAppWindow) {
|
|
|
5483
6131
|
const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
|
|
5484
6132
|
rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5485
6133
|
};
|
|
6134
|
+
microRootDocument.prototype.dispatchEvent = function (event) {
|
|
6135
|
+
return rawDispatchEvent.call(getEventTarget(event === null || event === void 0 ? void 0 : event.type, this), event);
|
|
6136
|
+
};
|
|
5486
6137
|
// 重新定义microRootDocument.prototype 上的on开头方法
|
|
5487
6138
|
function createSetterHandler(eventName) {
|
|
5488
6139
|
if (eventName === 'onclick') {
|
|
@@ -5603,12 +6254,18 @@ function patchElement(appName, url, microAppWindow, sandbox) {
|
|
|
5603
6254
|
patchIframeNode(appName, microAppWindow, sandbox);
|
|
5604
6255
|
patchIframeAttribute(url, microAppWindow);
|
|
5605
6256
|
}
|
|
6257
|
+
/**
|
|
6258
|
+
* patch iframe Node/Element
|
|
6259
|
+
*
|
|
6260
|
+
*/
|
|
5606
6261
|
function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
5607
6262
|
const rawRootElement = globalEnv.rawRootElement; // native root Element
|
|
6263
|
+
const rawRootNode = globalEnv.rawRootNode;
|
|
5608
6264
|
const rawDocument = globalEnv.rawDocument;
|
|
5609
6265
|
const microDocument = microAppWindow.document;
|
|
5610
6266
|
const microRootNode = microAppWindow.Node;
|
|
5611
6267
|
const microRootElement = microAppWindow.Element;
|
|
6268
|
+
const microDocumentFragment = microAppWindow.DocumentFragment;
|
|
5612
6269
|
// const rawMicroGetRootNode = microRootNode.prototype.getRootNode
|
|
5613
6270
|
const rawMicroAppendChild = microRootNode.prototype.appendChild;
|
|
5614
6271
|
const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
|
|
@@ -5616,10 +6273,13 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5616
6273
|
const rawMicroRemoveChild = microRootNode.prototype.removeChild;
|
|
5617
6274
|
const rawMicroAppend = microRootElement.prototype.append;
|
|
5618
6275
|
const rawMicroPrepend = microRootElement.prototype.prepend;
|
|
6276
|
+
const rawMicroFragmentAppend = microDocumentFragment.prototype.append;
|
|
6277
|
+
const rawMicroFragmentPrepend = microDocumentFragment.prototype.prepend;
|
|
5619
6278
|
const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
|
|
5620
6279
|
const rawMicroCloneNode = microRootNode.prototype.cloneNode;
|
|
5621
6280
|
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
|
|
5622
|
-
const
|
|
6281
|
+
const rawParentNodeDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
|
|
6282
|
+
const rawOwnerDocumentDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'ownerDocument');
|
|
5623
6283
|
const isPureNode = (target) => {
|
|
5624
6284
|
return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
|
|
5625
6285
|
};
|
|
@@ -5632,41 +6292,34 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5632
6292
|
}
|
|
5633
6293
|
return parent;
|
|
5634
6294
|
};
|
|
5635
|
-
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
5636
|
-
return microDocument;
|
|
5637
|
-
// TODO: 什么情况下返回原生document?
|
|
5638
|
-
// const rootNode = rawMicroGetRootNode.call(this, options)
|
|
5639
|
-
// if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
|
|
5640
|
-
// return rootNode
|
|
5641
|
-
};
|
|
5642
6295
|
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5643
6296
|
updateElementInfo(node, appName);
|
|
5644
6297
|
if (isPureNode(node)) {
|
|
5645
6298
|
return rawMicroAppendChild.call(this, node);
|
|
5646
6299
|
}
|
|
5647
|
-
return
|
|
6300
|
+
return rawRootNode.prototype.appendChild.call(getRawTarget(this), node);
|
|
5648
6301
|
};
|
|
5649
6302
|
microRootNode.prototype.insertBefore = function insertBefore(node, child) {
|
|
5650
6303
|
updateElementInfo(node, appName);
|
|
5651
6304
|
if (isPureNode(node)) {
|
|
5652
6305
|
return rawMicroInsertBefore.call(this, node, child);
|
|
5653
6306
|
}
|
|
5654
|
-
return
|
|
6307
|
+
return rawRootNode.prototype.insertBefore.call(getRawTarget(this), node, child);
|
|
5655
6308
|
};
|
|
5656
6309
|
microRootNode.prototype.replaceChild = function replaceChild(node, child) {
|
|
5657
6310
|
updateElementInfo(node, appName);
|
|
5658
6311
|
if (isPureNode(node)) {
|
|
5659
6312
|
return rawMicroReplaceChild.call(this, node, child);
|
|
5660
6313
|
}
|
|
5661
|
-
return
|
|
6314
|
+
return rawRootNode.prototype.replaceChild.call(getRawTarget(this), node, child);
|
|
5662
6315
|
};
|
|
5663
6316
|
microRootNode.prototype.removeChild = function removeChild(oldChild) {
|
|
5664
6317
|
if (isPureNode(oldChild) || this.contains(oldChild)) {
|
|
5665
6318
|
return rawMicroRemoveChild.call(this, oldChild);
|
|
5666
6319
|
}
|
|
5667
|
-
return
|
|
6320
|
+
return rawRootNode.prototype.removeChild.call(getRawTarget(this), oldChild);
|
|
5668
6321
|
};
|
|
5669
|
-
microRootElement.prototype.append = function append(...nodes) {
|
|
6322
|
+
microDocumentFragment.prototype.append = microRootElement.prototype.append = function append(...nodes) {
|
|
5670
6323
|
let i = 0;
|
|
5671
6324
|
let hasPureNode = false;
|
|
5672
6325
|
while (i < nodes.length) {
|
|
@@ -5676,11 +6329,11 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5676
6329
|
i++;
|
|
5677
6330
|
}
|
|
5678
6331
|
if (hasPureNode) {
|
|
5679
|
-
return rawMicroAppend.call(this, ...nodes);
|
|
6332
|
+
return (isDocumentFragment(this) ? rawMicroFragmentAppend : rawMicroAppend).call(this, ...nodes);
|
|
5680
6333
|
}
|
|
5681
6334
|
return rawRootElement.prototype.append.call(getRawTarget(this), ...nodes);
|
|
5682
6335
|
};
|
|
5683
|
-
microRootElement.prototype.prepend = function prepend(...nodes) {
|
|
6336
|
+
microDocumentFragment.prototype.prepend = microRootElement.prototype.prepend = function prepend(...nodes) {
|
|
5684
6337
|
let i = 0;
|
|
5685
6338
|
let hasPureNode = false;
|
|
5686
6339
|
while (i < nodes.length) {
|
|
@@ -5690,7 +6343,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5690
6343
|
i++;
|
|
5691
6344
|
}
|
|
5692
6345
|
if (hasPureNode) {
|
|
5693
|
-
return rawMicroPrepend.call(this, ...nodes);
|
|
6346
|
+
return (isDocumentFragment(this) ? rawMicroFragmentPrepend : rawMicroPrepend).call(this, ...nodes);
|
|
5694
6347
|
}
|
|
5695
6348
|
return rawRootElement.prototype.prepend.call(getRawTarget(this), ...nodes);
|
|
5696
6349
|
};
|
|
@@ -5706,49 +6359,59 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5706
6359
|
}
|
|
5707
6360
|
return rawRootElement.prototype.insertAdjacentElement.call(getRawTarget(this), where, element);
|
|
5708
6361
|
};
|
|
5709
|
-
|
|
5710
|
-
|
|
5711
|
-
|
|
5712
|
-
|
|
5713
|
-
|
|
5714
|
-
|
|
6362
|
+
/**
|
|
6363
|
+
* Specific prototype properties:
|
|
6364
|
+
* 1. baseURI
|
|
6365
|
+
* 2. ownerDocument
|
|
6366
|
+
* 3. parentNode
|
|
6367
|
+
* 4. innerHTML
|
|
6368
|
+
*/
|
|
6369
|
+
rawDefineProperty(microRootNode.prototype, 'baseURI', {
|
|
5715
6370
|
configurable: true,
|
|
5716
6371
|
enumerable: true,
|
|
5717
6372
|
get() {
|
|
5718
|
-
return
|
|
6373
|
+
return sandbox.proxyWindow.location.href;
|
|
5719
6374
|
},
|
|
5720
|
-
set(code) {
|
|
5721
|
-
rawInnerHTMLDesc.set.call(this, code);
|
|
5722
|
-
Array.from(this.children).forEach((child) => {
|
|
5723
|
-
if (isElement(child)) {
|
|
5724
|
-
updateElementInfo(child, appName);
|
|
5725
|
-
}
|
|
5726
|
-
});
|
|
5727
|
-
}
|
|
5728
6375
|
});
|
|
5729
|
-
|
|
5730
|
-
rawDefineProperty(microRootNode.prototype, 'parentNode', {
|
|
6376
|
+
rawDefineProperty(microRootNode.prototype, 'ownerDocument', {
|
|
5731
6377
|
configurable: true,
|
|
5732
6378
|
enumerable: true,
|
|
5733
6379
|
get() {
|
|
5734
|
-
var _a
|
|
5735
|
-
|
|
5736
|
-
|
|
5737
|
-
|
|
5738
|
-
|
|
5739
|
-
|
|
5740
|
-
|
|
5741
|
-
|
|
5742
|
-
|
|
5743
|
-
|
|
5744
|
-
|
|
5745
|
-
|
|
5746
|
-
|
|
5747
|
-
|
|
5748
|
-
|
|
5749
|
-
|
|
5750
|
-
|
|
6380
|
+
var _a;
|
|
6381
|
+
return this.__PURE_ELEMENT__ || this === microDocument
|
|
6382
|
+
? (_a = rawOwnerDocumentDesc.get) === null || _a === void 0 ? void 0 : _a.call(this) : microDocument;
|
|
6383
|
+
},
|
|
6384
|
+
});
|
|
6385
|
+
// patch parentNode
|
|
6386
|
+
rawDefineProperty(microRootNode.prototype, 'parentNode', getIframeParentNodeDesc(appName, rawParentNodeDesc));
|
|
6387
|
+
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
6388
|
+
return microDocument;
|
|
6389
|
+
// TODO: any case return document?
|
|
6390
|
+
// const rootNode = rawMicroGetRootNode.call(this, options)
|
|
6391
|
+
// if (rootNode === appInstanceMap.get(appName)?.container) return microDocument
|
|
6392
|
+
// return rootNode
|
|
6393
|
+
};
|
|
6394
|
+
// patch cloneNode
|
|
6395
|
+
microRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
6396
|
+
const clonedNode = rawMicroCloneNode.call(this, deep);
|
|
6397
|
+
return updateElementInfo(clonedNode, appName);
|
|
6398
|
+
};
|
|
6399
|
+
rawDefineProperty(microRootElement.prototype, 'innerHTML', {
|
|
6400
|
+
configurable: true,
|
|
6401
|
+
enumerable: true,
|
|
6402
|
+
get() {
|
|
6403
|
+
var _a;
|
|
6404
|
+
return (_a = rawInnerHTMLDesc.get) === null || _a === void 0 ? void 0 : _a.call(this);
|
|
5751
6405
|
},
|
|
6406
|
+
set(code) {
|
|
6407
|
+
var _a;
|
|
6408
|
+
(_a = rawInnerHTMLDesc.set) === null || _a === void 0 ? void 0 : _a.call(this, code);
|
|
6409
|
+
Array.from(this.children).forEach((child) => {
|
|
6410
|
+
if (isElement(child)) {
|
|
6411
|
+
updateElementInfo(child, appName);
|
|
6412
|
+
}
|
|
6413
|
+
});
|
|
6414
|
+
}
|
|
5752
6415
|
});
|
|
5753
6416
|
// Adapt to new image(...) scene
|
|
5754
6417
|
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
@@ -5768,16 +6431,24 @@ function patchIframeAttribute(url, microAppWindow) {
|
|
|
5768
6431
|
const microRootElement = microAppWindow.Element;
|
|
5769
6432
|
const rawMicroSetAttribute = microRootElement.prototype.setAttribute;
|
|
5770
6433
|
microRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
5771
|
-
if (
|
|
5772
|
-
|
|
5773
|
-
|
|
6434
|
+
if (/^micro-app(-\S+)?/i.test(this.tagName) &&
|
|
6435
|
+
key === 'data' &&
|
|
6436
|
+
this.setAttribute !== microRootElement.prototype.setAttribute) {
|
|
6437
|
+
this.setAttribute(key, value);
|
|
6438
|
+
}
|
|
6439
|
+
else {
|
|
6440
|
+
if (((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
6441
|
+
(key === 'href' && /^(a|link|image)$/i.test(this.tagName))) {
|
|
6442
|
+
value = CompletionPath(value, url);
|
|
6443
|
+
}
|
|
6444
|
+
rawMicroSetAttribute.call(this, key, value);
|
|
5774
6445
|
}
|
|
5775
|
-
rawMicroSetAttribute.call(this, key, value);
|
|
5776
6446
|
};
|
|
5777
6447
|
const protoAttrList = [
|
|
5778
6448
|
[microAppWindow.HTMLImageElement.prototype, 'src'],
|
|
5779
6449
|
[microAppWindow.HTMLScriptElement.prototype, 'src'],
|
|
5780
6450
|
[microAppWindow.HTMLLinkElement.prototype, 'href'],
|
|
6451
|
+
[microAppWindow.SVGImageElement.prototype, 'href'],
|
|
5781
6452
|
];
|
|
5782
6453
|
/**
|
|
5783
6454
|
* element.setAttribute does not trigger this actions:
|
|
@@ -5808,16 +6479,17 @@ class IframeSandbox {
|
|
|
5808
6479
|
this.active = false;
|
|
5809
6480
|
// Properties that can be escape to rawWindow
|
|
5810
6481
|
this.escapeProperties = [];
|
|
5811
|
-
//
|
|
5812
|
-
this.escapeKeys = new Set();
|
|
5813
|
-
// TODO: 初始化和每次跳转时都要更新base的href
|
|
6482
|
+
// Update the base.href when initial and each redirect
|
|
5814
6483
|
this.updateIframeBase = () => {
|
|
5815
6484
|
var _a;
|
|
5816
|
-
|
|
6485
|
+
// origin must be child app origin
|
|
6486
|
+
(_a = this.baseElement) === null || _a === void 0 ? void 0 : _a.setAttribute('href', createURL(this.url).origin + this.proxyLocation.pathname);
|
|
5817
6487
|
};
|
|
6488
|
+
this.appName = appName;
|
|
6489
|
+
this.url = url;
|
|
5818
6490
|
const rawLocation = globalEnv.rawWindow.location;
|
|
5819
6491
|
const browserHost = rawLocation.protocol + '//' + rawLocation.host;
|
|
5820
|
-
this.deleteIframeElement = this.createIframeElement(appName, browserHost);
|
|
6492
|
+
this.deleteIframeElement = this.createIframeElement(appName, browserHost + rawLocation.pathname);
|
|
5821
6493
|
this.microAppWindow = this.iframe.contentWindow;
|
|
5822
6494
|
this.patchIframe(this.microAppWindow, (resolve) => {
|
|
5823
6495
|
// create new html to iframe
|
|
@@ -5845,15 +6517,16 @@ class IframeSandbox {
|
|
|
5845
6517
|
/**
|
|
5846
6518
|
* create iframe for sandbox
|
|
5847
6519
|
* @param appName app name
|
|
5848
|
-
* @param
|
|
6520
|
+
* @param browserPath browser origin
|
|
5849
6521
|
* @returns release callback
|
|
5850
6522
|
*/
|
|
5851
|
-
createIframeElement(appName,
|
|
6523
|
+
createIframeElement(appName, browserPath) {
|
|
5852
6524
|
this.iframe = pureCreateElement('iframe');
|
|
5853
6525
|
const iframeAttrs = {
|
|
5854
|
-
src: browserHost,
|
|
5855
|
-
style: 'display: none',
|
|
5856
6526
|
id: appName,
|
|
6527
|
+
src: microApp.options.iframeSrc || browserPath,
|
|
6528
|
+
style: 'display: none',
|
|
6529
|
+
'powered-by': 'micro-app',
|
|
5857
6530
|
};
|
|
5858
6531
|
Object.keys(iframeAttrs).forEach((key) => this.iframe.setAttribute(key, iframeAttrs[key]));
|
|
5859
6532
|
// effect action during construct
|
|
@@ -5887,19 +6560,12 @@ class IframeSandbox {
|
|
|
5887
6560
|
* 1. iframe router and browser router are separated, we should update iframe router manually
|
|
5888
6561
|
* 2. withSandbox location is browser location when disable memory-router, so no need to do anything
|
|
5889
6562
|
*/
|
|
5890
|
-
/**
|
|
5891
|
-
* TODO:
|
|
5892
|
-
* 1. iframe关闭虚拟路由系统后,default-page无法使用,推荐用户直接使用浏览器地址控制首页渲染
|
|
5893
|
-
* 补充:keep-router-state 也无法配置,因为keep-router-state一定为true。
|
|
5894
|
-
* 2. 导航拦截、current.route 可以正常使用
|
|
5895
|
-
* 3. 可以正常控制子应用跳转,方式还是自上而下(也可以是子应用内部跳转,这种方式更好一点,减小对基座的影响,不会导致vue的循环刷新)
|
|
5896
|
-
* 4. 关闭虚拟路由以后会对应 route-mode='custom' 模式,包括with沙箱也会这么做
|
|
5897
|
-
* 5. 关闭虚拟路由是指尽可能模拟没有虚拟路由的情况,子应用直接获取浏览器location和history,控制浏览器跳转
|
|
5898
|
-
*/
|
|
5899
6563
|
this.initRouteState(defaultPage);
|
|
5900
6564
|
// unique listener of popstate event for child app
|
|
5901
6565
|
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
5902
|
-
|
|
6566
|
+
if (isRouterModeCustom(this.microAppWindow.__MICRO_APP_NAME__)) {
|
|
6567
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
6568
|
+
}
|
|
5903
6569
|
/* --- memory router part --- end */
|
|
5904
6570
|
/**
|
|
5905
6571
|
* create base element to iframe
|
|
@@ -5916,6 +6582,7 @@ class IframeSandbox {
|
|
|
5916
6582
|
}
|
|
5917
6583
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
5918
6584
|
var _a;
|
|
6585
|
+
// sandbox.stop may exec before sandbox.start, e.g: iframe sandbox + default mode + remount
|
|
5919
6586
|
if (!this.active)
|
|
5920
6587
|
return;
|
|
5921
6588
|
this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
|
|
@@ -5927,10 +6594,7 @@ class IframeSandbox {
|
|
|
5927
6594
|
/* --- memory router part --- end */
|
|
5928
6595
|
if (!umdMode || destroy) {
|
|
5929
6596
|
this.deleteIframeElement();
|
|
5930
|
-
this.
|
|
5931
|
-
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
5932
|
-
});
|
|
5933
|
-
this.escapeKeys.clear();
|
|
6597
|
+
this.clearHijackUmdHooks();
|
|
5934
6598
|
}
|
|
5935
6599
|
if (--globalEnv.activeSandbox === 0) {
|
|
5936
6600
|
releasePatchElementAndDocument();
|
|
@@ -5944,6 +6608,7 @@ class IframeSandbox {
|
|
|
5944
6608
|
* NOTE:
|
|
5945
6609
|
* 1. execute as early as possible
|
|
5946
6610
|
* 2. run after patchRouter & createProxyWindow
|
|
6611
|
+
* TODO: 设置为只读变量
|
|
5947
6612
|
*/
|
|
5948
6613
|
initStaticGlobalKeys(appName, url, microAppWindow) {
|
|
5949
6614
|
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
@@ -6145,12 +6810,55 @@ class IframeSandbox {
|
|
|
6145
6810
|
patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
|
|
6146
6811
|
}
|
|
6147
6812
|
/**
|
|
6813
|
+
* action before exec scripts when mount
|
|
6148
6814
|
* Actions:
|
|
6149
6815
|
* 1. patch static elements from html
|
|
6816
|
+
* 2. hijack umd hooks -- mount, unmount, micro-app-appName
|
|
6150
6817
|
* @param container micro app container
|
|
6151
6818
|
*/
|
|
6152
|
-
|
|
6819
|
+
actionsBeforeExecScripts(container, handleUmdHooks) {
|
|
6153
6820
|
this.patchStaticElement(container);
|
|
6821
|
+
this.clearHijackUmdHooks = this.hijackUmdHooks(this.appName, this.microAppWindow, handleUmdHooks);
|
|
6822
|
+
}
|
|
6823
|
+
// hijack mount, unmount, micro-app-appName hook to microAppWindow
|
|
6824
|
+
hijackUmdHooks(appName, microAppWindow, handleUmdHooks) {
|
|
6825
|
+
let mount, unmount, microAppLibrary;
|
|
6826
|
+
rawDefineProperties(microAppWindow, {
|
|
6827
|
+
mount: {
|
|
6828
|
+
configurable: true,
|
|
6829
|
+
get: () => mount,
|
|
6830
|
+
set: (value) => {
|
|
6831
|
+
if (this.active && isFunction(value) && !mount) {
|
|
6832
|
+
handleUmdHooks(mount = value, unmount);
|
|
6833
|
+
}
|
|
6834
|
+
}
|
|
6835
|
+
},
|
|
6836
|
+
unmount: {
|
|
6837
|
+
configurable: true,
|
|
6838
|
+
get: () => unmount,
|
|
6839
|
+
set: (value) => {
|
|
6840
|
+
if (this.active && isFunction(value) && !unmount) {
|
|
6841
|
+
handleUmdHooks(mount, unmount = value);
|
|
6842
|
+
}
|
|
6843
|
+
}
|
|
6844
|
+
},
|
|
6845
|
+
[`micro-app-${appName}`]: {
|
|
6846
|
+
configurable: true,
|
|
6847
|
+
get: () => microAppLibrary,
|
|
6848
|
+
set: (value) => {
|
|
6849
|
+
if (this.active && isPlainObject(value) && !microAppLibrary) {
|
|
6850
|
+
microAppLibrary = value;
|
|
6851
|
+
handleUmdHooks(microAppLibrary.mount, microAppLibrary.unmount);
|
|
6852
|
+
}
|
|
6853
|
+
}
|
|
6854
|
+
}
|
|
6855
|
+
});
|
|
6856
|
+
return () => {
|
|
6857
|
+
mount = unmount = microAppLibrary = null;
|
|
6858
|
+
};
|
|
6859
|
+
}
|
|
6860
|
+
setStaticAppState(state) {
|
|
6861
|
+
this.microAppWindow.__MICRO_APP_STATE__ = state;
|
|
6154
6862
|
}
|
|
6155
6863
|
}
|
|
6156
6864
|
IframeSandbox.activeCount = 0; // number of active sandbox
|
|
@@ -6174,8 +6882,9 @@ class CreateApp {
|
|
|
6174
6882
|
this.url = url;
|
|
6175
6883
|
this.useSandbox = useSandbox;
|
|
6176
6884
|
this.scopecss = this.useSandbox && scopecss;
|
|
6177
|
-
|
|
6885
|
+
// exec before getInlineModeState
|
|
6178
6886
|
this.iframe = iframe !== null && iframe !== void 0 ? iframe : false;
|
|
6887
|
+
this.inline = this.getInlineModeState(inline);
|
|
6179
6888
|
/**
|
|
6180
6889
|
* NOTE:
|
|
6181
6890
|
* 1. Navigate after micro-app created, before mount
|
|
@@ -6199,12 +6908,17 @@ class CreateApp {
|
|
|
6199
6908
|
}
|
|
6200
6909
|
/**
|
|
6201
6910
|
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
6911
|
+
* defaultPage disablePatchRequest routerMode baseroute is only for prerender app
|
|
6202
6912
|
*/
|
|
6203
|
-
onLoad(html,
|
|
6913
|
+
onLoad({ html,
|
|
6914
|
+
// below params is only for prerender app
|
|
6915
|
+
defaultPage, routerMode, baseroute, disablePatchRequest, }) {
|
|
6204
6916
|
var _a;
|
|
6205
6917
|
if (++this.loadSourceLevel === 2) {
|
|
6206
6918
|
this.source.html = html;
|
|
6207
|
-
if (
|
|
6919
|
+
if (this.isUnmounted())
|
|
6920
|
+
return;
|
|
6921
|
+
if (!this.isPrefetch) {
|
|
6208
6922
|
getRootContainer(this.container).mount(this);
|
|
6209
6923
|
}
|
|
6210
6924
|
else if (this.isPrerender) {
|
|
@@ -6231,11 +6945,11 @@ class CreateApp {
|
|
|
6231
6945
|
this.mount({
|
|
6232
6946
|
container,
|
|
6233
6947
|
inline: this.inline,
|
|
6234
|
-
routerMode: routerMode,
|
|
6235
|
-
baseroute: baseroute || '',
|
|
6236
6948
|
fiber: true,
|
|
6237
6949
|
defaultPage: defaultPage || '',
|
|
6238
6950
|
disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
|
|
6951
|
+
routerMode: routerMode,
|
|
6952
|
+
baseroute: baseroute || '',
|
|
6239
6953
|
});
|
|
6240
6954
|
}
|
|
6241
6955
|
}
|
|
@@ -6272,6 +6986,11 @@ class CreateApp {
|
|
|
6272
6986
|
this.container = container;
|
|
6273
6987
|
// mount before prerender exec mount (loading source), set isPrerender to false
|
|
6274
6988
|
this.isPrerender = false;
|
|
6989
|
+
// dispatch state event to micro app
|
|
6990
|
+
// TODO: statechange 还是 state-change,保持一致
|
|
6991
|
+
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
6992
|
+
appState: appStates.LOADING
|
|
6993
|
+
});
|
|
6275
6994
|
// reset app state to LOADING
|
|
6276
6995
|
return this.setAppState(appStates.LOADING);
|
|
6277
6996
|
}
|
|
@@ -6292,6 +7011,14 @@ class CreateApp {
|
|
|
6292
7011
|
if (this.isPrerender &&
|
|
6293
7012
|
isDivElement(this.container) &&
|
|
6294
7013
|
this.container.hasAttribute('prerender')) {
|
|
7014
|
+
/**
|
|
7015
|
+
* current this.container is <div prerender='true'></div>
|
|
7016
|
+
* set this.container to <micro-app></micro-app>
|
|
7017
|
+
* NOTE:
|
|
7018
|
+
* 1. must exec before this.sandBox.rebuildEffectSnapshot
|
|
7019
|
+
* 2. must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
7020
|
+
*/
|
|
7021
|
+
this.container = this.cloneContainer(container, this.container, false);
|
|
6295
7022
|
/**
|
|
6296
7023
|
* rebuild effect event of window, document, data center
|
|
6297
7024
|
* explain:
|
|
@@ -6300,14 +7027,6 @@ class CreateApp {
|
|
|
6300
7027
|
* 3. rebuild after js exec end, normal recovery effect event
|
|
6301
7028
|
*/
|
|
6302
7029
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6303
|
-
// current this.container is <div prerender='true'></div>
|
|
6304
|
-
cloneContainer(container, this.container, false);
|
|
6305
|
-
/**
|
|
6306
|
-
* set this.container to <micro-app></micro-app>
|
|
6307
|
-
* NOTE:
|
|
6308
|
-
* must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
6309
|
-
*/
|
|
6310
|
-
this.container = container;
|
|
6311
7030
|
(_b = this.preRenderEvents) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
|
|
6312
7031
|
// reset isPrerender config
|
|
6313
7032
|
this.isPrerender = false;
|
|
@@ -6318,10 +7037,12 @@ class CreateApp {
|
|
|
6318
7037
|
}
|
|
6319
7038
|
else {
|
|
6320
7039
|
this.container = container;
|
|
6321
|
-
this.inline = inline;
|
|
7040
|
+
this.inline = this.getInlineModeState(inline);
|
|
6322
7041
|
this.fiber = fiber;
|
|
6323
7042
|
this.routerMode = routerMode;
|
|
6324
|
-
const dispatchBeforeMount = () =>
|
|
7043
|
+
const dispatchBeforeMount = () => {
|
|
7044
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
7045
|
+
};
|
|
6325
7046
|
if (this.isPrerender) {
|
|
6326
7047
|
((_d = this.preRenderEvents) !== null && _d !== void 0 ? _d : (this.preRenderEvents = [])).push(dispatchBeforeMount);
|
|
6327
7048
|
}
|
|
@@ -6329,8 +7050,12 @@ class CreateApp {
|
|
|
6329
7050
|
dispatchBeforeMount();
|
|
6330
7051
|
}
|
|
6331
7052
|
this.setAppState(appStates.MOUNTING);
|
|
6332
|
-
//
|
|
6333
|
-
|
|
7053
|
+
// dispatch state event to micro app
|
|
7054
|
+
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
7055
|
+
appState: appStates.MOUNTING
|
|
7056
|
+
});
|
|
7057
|
+
// TODO: 兼容shadowRoot的场景
|
|
7058
|
+
this.cloneContainer(this.container, this.source.html, !this.umdMode);
|
|
6334
7059
|
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
6335
7060
|
umdMode: this.umdMode,
|
|
6336
7061
|
baseroute,
|
|
@@ -6338,37 +7063,35 @@ class CreateApp {
|
|
|
6338
7063
|
disablePatchRequest,
|
|
6339
7064
|
});
|
|
6340
7065
|
if (!this.umdMode) {
|
|
6341
|
-
//
|
|
6342
|
-
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
* umdHookUnmount can works in default mode
|
|
6349
|
-
* register through window.unmount
|
|
6350
|
-
*/
|
|
6351
|
-
this.umdHookUnmount = unmount;
|
|
7066
|
+
// patch element info of html
|
|
7067
|
+
(_f = this.sandBox) === null || _f === void 0 ? void 0 : _f.actionsBeforeExecScripts(this.container, (mount, unmount) => {
|
|
7068
|
+
var _a;
|
|
7069
|
+
if (!this.umdMode && !this.isUnmounted()) {
|
|
7070
|
+
this.umdHookMount = isFunction(mount) ? mount : null;
|
|
7071
|
+
// umdHookUnmount can works in default mode, register by window.unmount
|
|
7072
|
+
this.umdHookUnmount = isFunction(unmount) ? unmount : null;
|
|
6352
7073
|
// if mount & unmount is function, the sub app is umd mode
|
|
6353
|
-
if (isFunction(
|
|
6354
|
-
this.
|
|
6355
|
-
// sandbox must exist
|
|
6356
|
-
this.sandBox.markUmdMode(this.umdMode = true);
|
|
7074
|
+
if (isFunction(this.umdHookMount) && isFunction(this.umdHookUnmount)) {
|
|
7075
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.markUmdMode(this.umdMode = true);
|
|
6357
7076
|
try {
|
|
6358
|
-
this.handleMounted
|
|
7077
|
+
// if appState is mounted, it means that isFinished is true and this.handleMounted has already been executed, just exec this.umdHookMount
|
|
7078
|
+
if (this.getAppState() === appStates.MOUNTED) {
|
|
7079
|
+
this.umdHookMount(microApp.getData(this.name, true));
|
|
7080
|
+
}
|
|
7081
|
+
else {
|
|
7082
|
+
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
7083
|
+
}
|
|
6359
7084
|
}
|
|
6360
7085
|
catch (e) {
|
|
6361
|
-
|
|
6362
|
-
* TODO:
|
|
6363
|
-
* 1. 是否应该直接抛出错误
|
|
6364
|
-
* 2. 是否应该触发error生命周期
|
|
6365
|
-
*/
|
|
6366
|
-
logError('An error occurred in window.mount \n', this.name, e);
|
|
7086
|
+
logError('An error occurred when mount \n', this.name, e);
|
|
6367
7087
|
}
|
|
6368
7088
|
}
|
|
6369
|
-
|
|
6370
|
-
|
|
6371
|
-
|
|
7089
|
+
}
|
|
7090
|
+
});
|
|
7091
|
+
// if all js are executed, param isFinished will be true
|
|
7092
|
+
execScripts(this, (isFinished) => {
|
|
7093
|
+
if (!this.umdMode && isFinished === true) {
|
|
7094
|
+
this.handleMounted();
|
|
6372
7095
|
}
|
|
6373
7096
|
});
|
|
6374
7097
|
}
|
|
@@ -6378,13 +7101,22 @@ class CreateApp {
|
|
|
6378
7101
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6379
7102
|
}
|
|
6380
7103
|
catch (e) {
|
|
6381
|
-
logError('An error occurred
|
|
7104
|
+
logError('An error occurred when mount \n', this.name, e);
|
|
6382
7105
|
}
|
|
6383
7106
|
}
|
|
6384
7107
|
}
|
|
6385
7108
|
};
|
|
6386
|
-
|
|
6387
|
-
|
|
7109
|
+
/**
|
|
7110
|
+
* Initialization of sandbox is async, especially iframe sandbox are macro tasks
|
|
7111
|
+
* when child apps switch quickly, we need to pay attention to the following points:
|
|
7112
|
+
* NOTE:
|
|
7113
|
+
* 1. unmount app before exec nextAction (especially: iframe sandbox + default mode + remount)
|
|
7114
|
+
* this.container is null, this.sandBox will not start
|
|
7115
|
+
* 2. remount app of note 1
|
|
7116
|
+
* 3. unmount app during exec js
|
|
7117
|
+
*/
|
|
7118
|
+
// TODO: 可优化?
|
|
7119
|
+
this.sandBox ? this.sandBox.sandboxReady.then(() => !this.isUnmounted() && nextAction()) : nextAction();
|
|
6388
7120
|
}
|
|
6389
7121
|
/**
|
|
6390
7122
|
* handle for promise umdHookMount
|
|
@@ -6393,16 +7125,17 @@ class CreateApp {
|
|
|
6393
7125
|
handleMounted(umdHookMountResult) {
|
|
6394
7126
|
var _a, _b;
|
|
6395
7127
|
const dispatchAction = () => {
|
|
7128
|
+
const nextAction = () => this.actionsAfterMounted();
|
|
6396
7129
|
if (isPromise(umdHookMountResult)) {
|
|
6397
7130
|
umdHookMountResult
|
|
6398
|
-
.then(
|
|
7131
|
+
.then(nextAction)
|
|
6399
7132
|
.catch((e) => {
|
|
6400
7133
|
logError('An error occurred in window.mount \n', this.name, e);
|
|
6401
|
-
|
|
7134
|
+
nextAction();
|
|
6402
7135
|
});
|
|
6403
7136
|
}
|
|
6404
7137
|
else {
|
|
6405
|
-
|
|
7138
|
+
nextAction();
|
|
6406
7139
|
}
|
|
6407
7140
|
};
|
|
6408
7141
|
if (this.isPrerender) {
|
|
@@ -6416,12 +7149,18 @@ class CreateApp {
|
|
|
6416
7149
|
/**
|
|
6417
7150
|
* dispatch mounted event when app run finished
|
|
6418
7151
|
*/
|
|
6419
|
-
|
|
7152
|
+
actionsAfterMounted() {
|
|
6420
7153
|
var _a;
|
|
6421
7154
|
if (!this.isUnmounted()) {
|
|
6422
7155
|
this.setAppState(appStates.MOUNTED);
|
|
6423
7156
|
// call window.onmount of child app
|
|
6424
7157
|
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONMOUNT), this.name, microGlobalEvent.ONMOUNT, microApp.getData(this.name, true));
|
|
7158
|
+
// dispatch state event to micro app
|
|
7159
|
+
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
7160
|
+
appState: appStates.MOUNTED
|
|
7161
|
+
});
|
|
7162
|
+
// dispatch mounted event to micro app
|
|
7163
|
+
dispatchCustomEventToMicroApp(this, 'mounted');
|
|
6425
7164
|
// dispatch event mounted to parent
|
|
6426
7165
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
6427
7166
|
/**
|
|
@@ -6444,6 +7183,8 @@ class CreateApp {
|
|
|
6444
7183
|
* unmount app
|
|
6445
7184
|
* NOTE:
|
|
6446
7185
|
* 1. do not add any params on account of unmountApp
|
|
7186
|
+
* 2. this.container maybe null: Initialization of sandbox is async, child app may unmount before exec nextAction of mount
|
|
7187
|
+
* 3. unmount app when loading files (this.container is not null)
|
|
6447
7188
|
* @param destroy completely destroy, delete cache resources
|
|
6448
7189
|
* @param clearData clear data of dateCenter
|
|
6449
7190
|
* @param keepRouteState keep route state when unmount, default is false
|
|
@@ -6453,25 +7194,12 @@ class CreateApp {
|
|
|
6453
7194
|
var _a;
|
|
6454
7195
|
destroy = destroy || this.state === appStates.LOAD_FAILED;
|
|
6455
7196
|
this.setAppState(appStates.UNMOUNT);
|
|
6456
|
-
let umdHookUnmountResult = null;
|
|
6457
7197
|
try {
|
|
6458
|
-
|
|
6459
|
-
umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
|
|
7198
|
+
this.handleUnmounted(destroy, clearData, keepRouteState, unmountcb, (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true)));
|
|
6460
7199
|
}
|
|
6461
7200
|
catch (e) {
|
|
6462
|
-
logError('An error occurred
|
|
7201
|
+
logError('An error occurred when unmount \n', this.name, e);
|
|
6463
7202
|
}
|
|
6464
|
-
// dispatch unmount event to micro app
|
|
6465
|
-
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
6466
|
-
// call window.onunmount of child app
|
|
6467
|
-
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
6468
|
-
this.handleUnmounted({
|
|
6469
|
-
destroy,
|
|
6470
|
-
clearData,
|
|
6471
|
-
keepRouteState,
|
|
6472
|
-
unmountcb,
|
|
6473
|
-
umdHookUnmountResult,
|
|
6474
|
-
});
|
|
6475
7203
|
}
|
|
6476
7204
|
/**
|
|
6477
7205
|
* handle for promise umdHookUnmount
|
|
@@ -6481,8 +7209,16 @@ class CreateApp {
|
|
|
6481
7209
|
* @param unmountcb callback of unmount
|
|
6482
7210
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6483
7211
|
*/
|
|
6484
|
-
handleUnmounted(
|
|
6485
|
-
|
|
7212
|
+
handleUnmounted(destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult) {
|
|
7213
|
+
// dispatch state event to micro app
|
|
7214
|
+
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
7215
|
+
appState: appStates.UNMOUNT
|
|
7216
|
+
});
|
|
7217
|
+
// dispatch unmount event to micro app
|
|
7218
|
+
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
7219
|
+
// call window.onunmount of child app
|
|
7220
|
+
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
7221
|
+
const nextAction = () => this.actionsAfterUnmounted({
|
|
6486
7222
|
destroy,
|
|
6487
7223
|
clearData,
|
|
6488
7224
|
keepRouteState,
|
|
@@ -6491,7 +7227,12 @@ class CreateApp {
|
|
|
6491
7227
|
if (isPromise(umdHookUnmountResult)) {
|
|
6492
7228
|
// async window.unmount will cause appName bind error in nest app
|
|
6493
7229
|
removeDomScope();
|
|
6494
|
-
umdHookUnmountResult
|
|
7230
|
+
umdHookUnmountResult
|
|
7231
|
+
.then(nextAction)
|
|
7232
|
+
.catch((e) => {
|
|
7233
|
+
logError('An error occurred in window.unmount \n', this.name, e);
|
|
7234
|
+
nextAction();
|
|
7235
|
+
});
|
|
6495
7236
|
}
|
|
6496
7237
|
else {
|
|
6497
7238
|
nextAction();
|
|
@@ -6504,10 +7245,10 @@ class CreateApp {
|
|
|
6504
7245
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6505
7246
|
* @param unmountcb callback of unmount
|
|
6506
7247
|
*/
|
|
6507
|
-
|
|
7248
|
+
actionsAfterUnmounted({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
6508
7249
|
var _a;
|
|
6509
7250
|
if (this.umdMode && this.container && !destroy) {
|
|
6510
|
-
cloneContainer(this.source.html, this.container, false);
|
|
7251
|
+
this.cloneContainer(this.source.html, this.container, false);
|
|
6511
7252
|
}
|
|
6512
7253
|
/**
|
|
6513
7254
|
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
@@ -6527,12 +7268,27 @@ class CreateApp {
|
|
|
6527
7268
|
unmountcb === null || unmountcb === void 0 ? void 0 : unmountcb();
|
|
6528
7269
|
}
|
|
6529
7270
|
clearOptions(destroy) {
|
|
6530
|
-
|
|
6531
|
-
this.container = null;
|
|
7271
|
+
var _a, _b;
|
|
6532
7272
|
this.isPrerender = false;
|
|
6533
7273
|
this.preRenderEvents = null;
|
|
6534
7274
|
this.setKeepAliveState(null);
|
|
7275
|
+
if (this.container) {
|
|
7276
|
+
this.container.innerHTML = '';
|
|
7277
|
+
this.container = null;
|
|
7278
|
+
}
|
|
7279
|
+
else if (!this.umdMode) {
|
|
7280
|
+
/**
|
|
7281
|
+
* this.container is null means sandBox.start has not exec, so sandBox.stop won't exec either
|
|
7282
|
+
* we should remove iframeElement in default mode manually
|
|
7283
|
+
*/
|
|
7284
|
+
(_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.deleteIframeElement) === null || _b === void 0 ? void 0 : _b.call(_a);
|
|
7285
|
+
}
|
|
6535
7286
|
// in iframe sandbox & default mode, delete the sandbox & iframeElement
|
|
7287
|
+
/**
|
|
7288
|
+
* TODO:
|
|
7289
|
+
* 1. with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
|
|
7290
|
+
* 2. 接1.0,this.sandBox置空,还需要注意后续app.sandBox相关操作,比如 scripts.ts --> app.iframe ? app.sandBox!.microBody : app.querySelector('micro-app-body'),如果是fiber或者预加载,会存在卸载后js还在处理的情况
|
|
7291
|
+
*/
|
|
6536
7292
|
if (this.iframe && !this.umdMode)
|
|
6537
7293
|
this.sandBox = null;
|
|
6538
7294
|
if (destroy)
|
|
@@ -6563,7 +7319,7 @@ class CreateApp {
|
|
|
6563
7319
|
});
|
|
6564
7320
|
// dispatch afterHidden event to base app
|
|
6565
7321
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
|
|
6566
|
-
if (this.
|
|
7322
|
+
if (isRouterModeSearch(this.name)) {
|
|
6567
7323
|
// called after lifeCyclesEvent
|
|
6568
7324
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
6569
7325
|
}
|
|
@@ -6574,7 +7330,7 @@ class CreateApp {
|
|
|
6574
7330
|
getRootContainer(this.container).unmount();
|
|
6575
7331
|
}
|
|
6576
7332
|
else {
|
|
6577
|
-
this.container = cloneContainer(pureCreateElement('div'), this.container, false);
|
|
7333
|
+
this.container = this.cloneContainer(pureCreateElement('div'), this.container, false);
|
|
6578
7334
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
|
|
6579
7335
|
}
|
|
6580
7336
|
callback === null || callback === void 0 ? void 0 : callback();
|
|
@@ -6582,6 +7338,14 @@ class CreateApp {
|
|
|
6582
7338
|
// show app when connectedCallback called with keep-alive
|
|
6583
7339
|
showKeepAliveApp(container) {
|
|
6584
7340
|
var _a, _b;
|
|
7341
|
+
/**
|
|
7342
|
+
* NOTE:
|
|
7343
|
+
* 1. this.container must set to container(micro-app element) before exec rebuildEffectSnapshot
|
|
7344
|
+
* ISSUE: https://github.com/micro-zoe/micro-app/issues/1115
|
|
7345
|
+
* 2. rebuildEffectSnapshot must exec before dispatch beforeshow event
|
|
7346
|
+
*/
|
|
7347
|
+
const oldContainer = this.container;
|
|
7348
|
+
this.container = container;
|
|
6585
7349
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6586
7350
|
// dispatch beforeShow event to micro-app
|
|
6587
7351
|
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
@@ -6590,13 +7354,13 @@ class CreateApp {
|
|
|
6590
7354
|
// dispatch beforeShow event to base app
|
|
6591
7355
|
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
6592
7356
|
this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
|
|
6593
|
-
this.
|
|
7357
|
+
this.cloneContainer(this.container, oldContainer, false);
|
|
6594
7358
|
/**
|
|
6595
7359
|
* TODO:
|
|
6596
7360
|
* 问题:当路由模式为custom时,keep-alive应用在重新展示,是否需要根据子应用location信息更新浏览器地址?
|
|
6597
|
-
*
|
|
7361
|
+
* 暂时不这么做,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
|
|
6598
7362
|
*/
|
|
6599
|
-
if (this.
|
|
7363
|
+
if (isRouterModeSearch(this.name)) {
|
|
6600
7364
|
// called before lifeCyclesEvent
|
|
6601
7365
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
|
|
6602
7366
|
}
|
|
@@ -6612,8 +7376,40 @@ class CreateApp {
|
|
|
6612
7376
|
* @param e Error
|
|
6613
7377
|
*/
|
|
6614
7378
|
onerror(e) {
|
|
7379
|
+
// dispatch state event to micro app
|
|
7380
|
+
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
7381
|
+
appState: appStates.LOAD_FAILED
|
|
7382
|
+
});
|
|
6615
7383
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
6616
7384
|
}
|
|
7385
|
+
/**
|
|
7386
|
+
* Parse htmlString to DOM
|
|
7387
|
+
* NOTE: iframe sandbox will use DOMParser of iframeWindow, with sandbox will use DOMParser of base app
|
|
7388
|
+
* @param htmlString DOMString
|
|
7389
|
+
* @returns parsed DOM
|
|
7390
|
+
*/
|
|
7391
|
+
parseHtmlString(htmlString) {
|
|
7392
|
+
var _a;
|
|
7393
|
+
const DOMParser = ((_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) ? this.sandBox.proxyWindow.DOMParser
|
|
7394
|
+
: globalEnv.rawWindow.DOMParser;
|
|
7395
|
+
return (new DOMParser()).parseFromString(htmlString, 'text/html').body;
|
|
7396
|
+
}
|
|
7397
|
+
/**
|
|
7398
|
+
* clone origin elements to target
|
|
7399
|
+
* @param target Accept cloned elements
|
|
7400
|
+
* @param origin Cloned element
|
|
7401
|
+
* @param deep deep clone or transfer dom
|
|
7402
|
+
*/
|
|
7403
|
+
cloneContainer(target, origin, deep) {
|
|
7404
|
+
// 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
|
|
7405
|
+
if (origin && target) {
|
|
7406
|
+
target.innerHTML = '';
|
|
7407
|
+
Array.from(deep ? this.parseHtmlString(origin.innerHTML).childNodes : origin.childNodes).forEach((node) => {
|
|
7408
|
+
target.appendChild(node);
|
|
7409
|
+
});
|
|
7410
|
+
}
|
|
7411
|
+
return target;
|
|
7412
|
+
}
|
|
6617
7413
|
/**
|
|
6618
7414
|
* Scene:
|
|
6619
7415
|
* 1. create app
|
|
@@ -6622,17 +7418,15 @@ class CreateApp {
|
|
|
6622
7418
|
*/
|
|
6623
7419
|
createSandbox() {
|
|
6624
7420
|
if (this.useSandbox && !this.sandBox) {
|
|
6625
|
-
|
|
6626
|
-
this.sandBox = new IframeSandbox(this.name, this.url);
|
|
6627
|
-
}
|
|
6628
|
-
else {
|
|
6629
|
-
this.sandBox = new WithSandBox(this.name, this.url);
|
|
6630
|
-
}
|
|
7421
|
+
this.sandBox = this.iframe ? new IframeSandbox(this.name, this.url) : new WithSandBox(this.name, this.url);
|
|
6631
7422
|
}
|
|
6632
7423
|
}
|
|
6633
7424
|
// set app state
|
|
6634
7425
|
setAppState(state) {
|
|
7426
|
+
var _a;
|
|
6635
7427
|
this.state = state;
|
|
7428
|
+
// set window.__MICRO_APP_STATE__
|
|
7429
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setStaticAppState(state);
|
|
6636
7430
|
}
|
|
6637
7431
|
// get app state
|
|
6638
7432
|
getAppState() {
|
|
@@ -6654,23 +7448,6 @@ class CreateApp {
|
|
|
6654
7448
|
isHidden() {
|
|
6655
7449
|
return keepAliveStates.KEEP_ALIVE_HIDDEN === this.keepAliveState;
|
|
6656
7450
|
}
|
|
6657
|
-
// get umd library, if it not exist, return empty object
|
|
6658
|
-
getUmdLibraryHooks() {
|
|
6659
|
-
// after execScripts, the app maybe unmounted
|
|
6660
|
-
if (!this.isUnmounted() && this.sandBox) {
|
|
6661
|
-
const libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
6662
|
-
const proxyWindow = this.sandBox.proxyWindow;
|
|
6663
|
-
// compatible with pre versions
|
|
6664
|
-
if (isObject(proxyWindow[libraryName])) {
|
|
6665
|
-
return proxyWindow[libraryName];
|
|
6666
|
-
}
|
|
6667
|
-
return {
|
|
6668
|
-
mount: proxyWindow.mount,
|
|
6669
|
-
unmount: proxyWindow.unmount,
|
|
6670
|
-
};
|
|
6671
|
-
}
|
|
6672
|
-
return {};
|
|
6673
|
-
}
|
|
6674
7451
|
getMicroAppGlobalHook(eventName) {
|
|
6675
7452
|
var _a, _b;
|
|
6676
7453
|
const listener = (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) === null || _b === void 0 ? void 0 : _b[eventName];
|
|
@@ -6682,6 +7459,15 @@ class CreateApp {
|
|
|
6682
7459
|
querySelectorAll(selectors) {
|
|
6683
7460
|
return this.container ? globalEnv.rawElementQuerySelectorAll.call(this.container, selectors) : [];
|
|
6684
7461
|
}
|
|
7462
|
+
/**
|
|
7463
|
+
* NOTE:
|
|
7464
|
+
* 1. If the iframe sandbox no longer enforces the use of inline mode in the future, the way getElementsByTagName retrieves the script from the iframe by default needs to be changed, because in non inline mode, the script in the iframe may be empty
|
|
7465
|
+
* @param inline inline mode config
|
|
7466
|
+
*/
|
|
7467
|
+
getInlineModeState(inline) {
|
|
7468
|
+
var _a;
|
|
7469
|
+
return (_a = (this.iframe || inline)) !== null && _a !== void 0 ? _a : false;
|
|
7470
|
+
}
|
|
6685
7471
|
}
|
|
6686
7472
|
// iframe route mode
|
|
6687
7473
|
function isIframeSandbox(appName) {
|
|
@@ -6767,15 +7553,11 @@ function handleNewNode(child, app) {
|
|
|
6767
7553
|
* @param app app
|
|
6768
7554
|
* @param method raw method
|
|
6769
7555
|
* @param parent parent node
|
|
6770
|
-
* @param
|
|
6771
|
-
* @param
|
|
7556
|
+
* @param targetNode target node
|
|
7557
|
+
* @param passiveNode second param of insertBefore and replaceChild
|
|
6772
7558
|
*/
|
|
6773
|
-
function invokePrototypeMethod(app, rawMethod, parent,
|
|
6774
|
-
const hijackParent = getHijackParent(parent,
|
|
6775
|
-
/**
|
|
6776
|
-
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
6777
|
-
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
6778
|
-
*/
|
|
7559
|
+
function invokePrototypeMethod(app, rawMethod, parent, targetNode, passiveNode) {
|
|
7560
|
+
const hijackParent = getHijackParent(parent, targetNode, app);
|
|
6779
7561
|
if (hijackParent) {
|
|
6780
7562
|
/**
|
|
6781
7563
|
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
@@ -6792,9 +7574,9 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
6792
7574
|
if (!isIframeSandbox(app.name) &&
|
|
6793
7575
|
isMicroAppBody(hijackParent) &&
|
|
6794
7576
|
rawMethod !== globalEnv.rawRemoveChild) {
|
|
6795
|
-
const descriptor = Object.getOwnPropertyDescriptor(
|
|
6796
|
-
if ((!descriptor || descriptor.configurable) && !
|
|
6797
|
-
rawDefineProperties(
|
|
7577
|
+
const descriptor = Object.getOwnPropertyDescriptor(targetNode, 'parentNode');
|
|
7578
|
+
if ((!descriptor || descriptor.configurable) && !targetNode.__MICRO_APP_HAS_DPN__) {
|
|
7579
|
+
rawDefineProperties(targetNode, {
|
|
6798
7580
|
parentNode: {
|
|
6799
7581
|
configurable: true,
|
|
6800
7582
|
get() {
|
|
@@ -6814,57 +7596,85 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
6814
7596
|
});
|
|
6815
7597
|
}
|
|
6816
7598
|
}
|
|
7599
|
+
if ((process.env.NODE_ENV !== 'production') &&
|
|
7600
|
+
isIFrameElement(targetNode) &&
|
|
7601
|
+
rawMethod === globalEnv.rawAppendChild) {
|
|
7602
|
+
fixReactHMRConflict(app);
|
|
7603
|
+
}
|
|
6817
7604
|
/**
|
|
6818
|
-
* 1. If
|
|
6819
|
-
* 2. When removeChild,
|
|
7605
|
+
* 1. If passiveNode exists, it must be insertBefore or replaceChild
|
|
7606
|
+
* 2. When removeChild, targetNode may not be in microAppHead or head
|
|
7607
|
+
* NOTE:
|
|
7608
|
+
* 1. If passiveNode not in hijackParent, insertBefore replaceChild will be degraded to appendChild
|
|
7609
|
+
* E.g: document.head.replaceChild(targetNode, document.scripts[0])
|
|
7610
|
+
* 2. If passiveNode not in hijackParent but in parent and method is insertBefore, try insert it into the position corresponding to hijackParent
|
|
7611
|
+
* E.g: document.head.insertBefore(targetNode, document.head.childNodes[0])
|
|
7612
|
+
* ISSUE: https://github.com/micro-zoe/micro-app/issues/1071
|
|
6820
7613
|
*/
|
|
6821
|
-
if (
|
|
6822
|
-
|
|
6823
|
-
|
|
6824
|
-
|
|
6825
|
-
|
|
6826
|
-
|
|
7614
|
+
if (passiveNode && !hijackParent.contains(passiveNode)) {
|
|
7615
|
+
if (rawMethod === globalEnv.rawInsertBefore && parent.contains(passiveNode)) {
|
|
7616
|
+
const indexOfParent = Array.from(parent.childNodes).indexOf(passiveNode);
|
|
7617
|
+
if (hijackParent.childNodes[indexOfParent]) {
|
|
7618
|
+
return invokeRawMethod(rawMethod, hijackParent, targetNode, hijackParent.childNodes[indexOfParent], app);
|
|
7619
|
+
}
|
|
6827
7620
|
}
|
|
6828
|
-
return
|
|
7621
|
+
return globalEnv.rawAppendChild.call(hijackParent, targetNode);
|
|
6829
7622
|
}
|
|
6830
|
-
if (
|
|
6831
|
-
|
|
6832
|
-
|
|
6833
|
-
|
|
7623
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetNode)) {
|
|
7624
|
+
if (parent.contains(targetNode)) {
|
|
7625
|
+
return rawMethod.call(parent, targetNode);
|
|
7626
|
+
}
|
|
7627
|
+
return targetNode;
|
|
6834
7628
|
}
|
|
6835
|
-
return invokeRawMethod(rawMethod, hijackParent,
|
|
7629
|
+
return invokeRawMethod(rawMethod, hijackParent, targetNode, passiveNode, app);
|
|
6836
7630
|
}
|
|
6837
|
-
return invokeRawMethod(rawMethod, parent,
|
|
7631
|
+
return invokeRawMethod(rawMethod, parent, targetNode, passiveNode, app);
|
|
6838
7632
|
}
|
|
6839
7633
|
// head/body map to micro-app-head/micro-app-body
|
|
6840
|
-
function getHijackParent(parent,
|
|
7634
|
+
function getHijackParent(parent, targetNode, app) {
|
|
6841
7635
|
if (app) {
|
|
6842
7636
|
if (parent === document.head) {
|
|
6843
|
-
if (app.iframe && isScriptElement(
|
|
7637
|
+
if (app.iframe && isScriptElement(targetNode)) {
|
|
6844
7638
|
return app.sandBox.microHead;
|
|
6845
7639
|
}
|
|
6846
7640
|
return app.querySelector('micro-app-head');
|
|
6847
7641
|
}
|
|
6848
7642
|
if (parent === document.body || parent === document.body.parentNode) {
|
|
6849
|
-
if (app.iframe && isScriptElement(
|
|
7643
|
+
if (app.iframe && isScriptElement(targetNode)) {
|
|
6850
7644
|
return app.sandBox.microBody;
|
|
6851
7645
|
}
|
|
6852
7646
|
return app.querySelector('micro-app-body');
|
|
6853
7647
|
}
|
|
6854
|
-
if (app.iframe && isScriptElement(
|
|
7648
|
+
if (app.iframe && isScriptElement(targetNode)) {
|
|
6855
7649
|
return app.sandBox.microBody;
|
|
6856
7650
|
}
|
|
6857
7651
|
}
|
|
6858
7652
|
return null;
|
|
6859
7653
|
}
|
|
6860
|
-
function invokeRawMethod(rawMethod, parent,
|
|
7654
|
+
function invokeRawMethod(rawMethod, parent, targetNode, passiveNode, app) {
|
|
6861
7655
|
if (isPendMethod(rawMethod)) {
|
|
6862
|
-
|
|
7656
|
+
/**
|
|
7657
|
+
* In iframe sandbox, script will pend to iframe.body, so we should reset rawMethod, because:
|
|
7658
|
+
* Element.prototype.append === DocumentFragment.prototype.append ==> false
|
|
7659
|
+
* Element.prototype.prepend === DocumentFragment.prototype.prepend ==> false
|
|
7660
|
+
*/
|
|
7661
|
+
if ((app === null || app === void 0 ? void 0 : app.iframe) && isScriptElement(targetNode)) {
|
|
7662
|
+
if (rawMethod === globalEnv.rawFragmentAppend) {
|
|
7663
|
+
rawMethod = globalEnv.rawAppend;
|
|
7664
|
+
}
|
|
7665
|
+
else if (rawMethod === globalEnv.rawFragmentPrepend) {
|
|
7666
|
+
rawMethod = globalEnv.rawPrepend;
|
|
7667
|
+
}
|
|
7668
|
+
}
|
|
7669
|
+
return rawMethod.call(parent, targetNode);
|
|
6863
7670
|
}
|
|
6864
|
-
return rawMethod.call(parent,
|
|
7671
|
+
return rawMethod.call(parent, targetNode, passiveNode);
|
|
6865
7672
|
}
|
|
6866
7673
|
function isPendMethod(method) {
|
|
6867
|
-
return method === globalEnv.rawAppend ||
|
|
7674
|
+
return (method === globalEnv.rawAppend ||
|
|
7675
|
+
method === globalEnv.rawPrepend ||
|
|
7676
|
+
method === globalEnv.rawFragmentAppend ||
|
|
7677
|
+
method === globalEnv.rawFragmentPrepend);
|
|
6868
7678
|
}
|
|
6869
7679
|
/**
|
|
6870
7680
|
* Attempt to complete the static resource address again before insert the node
|
|
@@ -6881,7 +7691,7 @@ function completePathDynamic(app, newChild) {
|
|
|
6881
7691
|
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
6882
7692
|
}
|
|
6883
7693
|
}
|
|
6884
|
-
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
7694
|
+
else if (/^(a|link|image)$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
6885
7695
|
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
6886
7696
|
}
|
|
6887
7697
|
}
|
|
@@ -6890,26 +7700,26 @@ function completePathDynamic(app, newChild) {
|
|
|
6890
7700
|
* method of handle new node
|
|
6891
7701
|
* @param parent parent node
|
|
6892
7702
|
* @param newChild new node
|
|
6893
|
-
* @param
|
|
7703
|
+
* @param passiveNode passive node
|
|
6894
7704
|
* @param rawMethod method
|
|
6895
7705
|
*/
|
|
6896
|
-
function commonElementHandler(parent, newChild,
|
|
7706
|
+
function commonElementHandler(parent, newChild, passiveNode, rawMethod) {
|
|
6897
7707
|
const currentAppName = getCurrentAppName();
|
|
6898
7708
|
if (isNode(newChild) &&
|
|
6899
7709
|
!newChild.__PURE_ELEMENT__ &&
|
|
6900
7710
|
(newChild.__MICRO_APP_NAME__ ||
|
|
6901
7711
|
currentAppName)) {
|
|
6902
|
-
newChild
|
|
7712
|
+
updateElementInfo(newChild, newChild.__MICRO_APP_NAME__ || currentAppName);
|
|
6903
7713
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
6904
7714
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
7715
|
+
if (isStyleElement(newChild)) {
|
|
7716
|
+
parent.getRootNode() instanceof ShadowRoot && newChild.setAttribute('ignore', 'true');
|
|
7717
|
+
}
|
|
6905
7718
|
completePathDynamic(app, newChild);
|
|
6906
|
-
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app),
|
|
7719
|
+
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveNode && getMappingNode(passiveNode));
|
|
6907
7720
|
}
|
|
6908
7721
|
}
|
|
6909
|
-
|
|
6910
|
-
return rawMethod.call(parent, newChild);
|
|
6911
|
-
}
|
|
6912
|
-
return rawMethod.call(parent, newChild, passiveChild);
|
|
7722
|
+
return invokeRawMethod(rawMethod, parent, newChild, passiveNode);
|
|
6913
7723
|
}
|
|
6914
7724
|
/**
|
|
6915
7725
|
* Rewrite element prototype method
|
|
@@ -6917,36 +7727,20 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
6917
7727
|
function patchElementAndDocument() {
|
|
6918
7728
|
patchDocument$2();
|
|
6919
7729
|
const rawRootElement = globalEnv.rawRootElement;
|
|
7730
|
+
const rawRootNode = globalEnv.rawRootNode;
|
|
7731
|
+
const rawDocumentFragment = globalEnv.rawDocumentFragment;
|
|
6920
7732
|
// prototype methods of add element👇
|
|
6921
|
-
|
|
7733
|
+
rawRootNode.prototype.appendChild = function appendChild(newChild) {
|
|
6922
7734
|
return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
|
|
6923
7735
|
};
|
|
6924
|
-
|
|
7736
|
+
rawRootNode.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
6925
7737
|
return commonElementHandler(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
6926
7738
|
};
|
|
6927
|
-
|
|
7739
|
+
rawRootNode.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
6928
7740
|
return commonElementHandler(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
6929
7741
|
};
|
|
6930
|
-
rawRootElement.prototype.append = function append(...nodes) {
|
|
6931
|
-
let i = 0;
|
|
6932
|
-
while (i < nodes.length) {
|
|
6933
|
-
let node = nodes[i];
|
|
6934
|
-
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
6935
|
-
commonElementHandler(this, markElement(node), null, globalEnv.rawAppend);
|
|
6936
|
-
i++;
|
|
6937
|
-
}
|
|
6938
|
-
};
|
|
6939
|
-
rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
6940
|
-
let i = nodes.length;
|
|
6941
|
-
while (i > 0) {
|
|
6942
|
-
let node = nodes[i - 1];
|
|
6943
|
-
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
6944
|
-
commonElementHandler(this, markElement(node), null, globalEnv.rawPrepend);
|
|
6945
|
-
i--;
|
|
6946
|
-
}
|
|
6947
|
-
};
|
|
6948
7742
|
// prototype methods of delete element👇
|
|
6949
|
-
|
|
7743
|
+
rawRootNode.prototype.removeChild = function removeChild(oldChild) {
|
|
6950
7744
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
6951
7745
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
6952
7746
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -6961,6 +7755,24 @@ function patchElementAndDocument() {
|
|
|
6961
7755
|
}
|
|
6962
7756
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
6963
7757
|
};
|
|
7758
|
+
rawDocumentFragment.prototype.append = rawRootElement.prototype.append = function append(...nodes) {
|
|
7759
|
+
let i = 0;
|
|
7760
|
+
while (i < nodes.length) {
|
|
7761
|
+
let node = nodes[i];
|
|
7762
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
7763
|
+
commonElementHandler(this, markElement(node), null, isDocumentFragment(this) ? globalEnv.rawFragmentAppend : globalEnv.rawAppend);
|
|
7764
|
+
i++;
|
|
7765
|
+
}
|
|
7766
|
+
};
|
|
7767
|
+
rawDocumentFragment.prototype.prepend = rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
7768
|
+
let i = nodes.length;
|
|
7769
|
+
while (i > 0) {
|
|
7770
|
+
let node = nodes[i - 1];
|
|
7771
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
7772
|
+
commonElementHandler(this, markElement(node), null, isDocumentFragment(this) ? globalEnv.rawFragmentPrepend : globalEnv.rawPrepend);
|
|
7773
|
+
i--;
|
|
7774
|
+
}
|
|
7775
|
+
};
|
|
6964
7776
|
/**
|
|
6965
7777
|
* The insertAdjacentElement method of the Element interface inserts a given element node at a given position relative to the element it is invoked upon.
|
|
6966
7778
|
* NOTE:
|
|
@@ -6980,48 +7792,81 @@ function patchElementAndDocument() {
|
|
|
6980
7792
|
}
|
|
6981
7793
|
return globalEnv.rawInsertAdjacentElement.call(this, where, element);
|
|
6982
7794
|
};
|
|
6983
|
-
|
|
6984
|
-
|
|
6985
|
-
|
|
6986
|
-
|
|
6987
|
-
|
|
6988
|
-
|
|
6989
|
-
function
|
|
6990
|
-
const currentAppName = getCurrentAppName();
|
|
6991
|
-
if ((
|
|
7795
|
+
/**
|
|
7796
|
+
* document.body(head).querySelector(querySelectorAll) hijack to microAppBody(microAppHead).querySelector(querySelectorAll)
|
|
7797
|
+
* NOTE:
|
|
7798
|
+
* 1. May cause some problems!
|
|
7799
|
+
* 2. Add config options?
|
|
7800
|
+
*/
|
|
7801
|
+
function getElementQueryTarget(targetNode) {
|
|
7802
|
+
const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
|
|
7803
|
+
if ((targetNode === document.body || targetNode === document.head) && currentAppName) {
|
|
6992
7804
|
const app = appInstanceMap.get(currentAppName);
|
|
6993
7805
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
6994
|
-
if (
|
|
7806
|
+
if (targetNode === document.body) {
|
|
6995
7807
|
return app.querySelector('micro-app-body');
|
|
6996
7808
|
}
|
|
6997
|
-
else if (
|
|
7809
|
+
else if (targetNode === document.head) {
|
|
6998
7810
|
return app.querySelector('micro-app-head');
|
|
6999
7811
|
}
|
|
7000
7812
|
}
|
|
7001
7813
|
}
|
|
7002
|
-
return
|
|
7814
|
+
return targetNode;
|
|
7815
|
+
}
|
|
7816
|
+
/**
|
|
7817
|
+
* In iframe sandbox, script will render to iframe instead of micro-app-body
|
|
7818
|
+
* So when query elements, we need to search both micro-app and iframe
|
|
7819
|
+
* @param isEmpty get empty result
|
|
7820
|
+
* @param targetNode targetNode element
|
|
7821
|
+
* @param result origin result
|
|
7822
|
+
* @param selectors selectors
|
|
7823
|
+
* @param methodName querySelector or querySelectorAll
|
|
7824
|
+
*/
|
|
7825
|
+
function getElementQueryResult(isEmpty, targetNode, result, selectors, methodName) {
|
|
7826
|
+
if (isEmpty) {
|
|
7827
|
+
const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
|
|
7828
|
+
if (currentAppName && isIframeSandbox(currentAppName)) {
|
|
7829
|
+
const app = appInstanceMap.get(currentAppName);
|
|
7830
|
+
if (isMicroAppHead(targetNode)) {
|
|
7831
|
+
return app.sandBox.microHead[methodName](selectors);
|
|
7832
|
+
}
|
|
7833
|
+
if (isMicroAppBody(targetNode)) {
|
|
7834
|
+
return app.sandBox.microBody[methodName](selectors);
|
|
7835
|
+
}
|
|
7836
|
+
}
|
|
7837
|
+
}
|
|
7838
|
+
return result;
|
|
7003
7839
|
}
|
|
7004
7840
|
rawRootElement.prototype.querySelector = function querySelector(selectors) {
|
|
7005
7841
|
var _a;
|
|
7006
|
-
const
|
|
7007
|
-
|
|
7842
|
+
const _this = (_a = getElementQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
7843
|
+
const result = globalEnv.rawElementQuerySelector.call(_this, selectors);
|
|
7844
|
+
return getElementQueryResult(isNull(result) && _this !== this, _this, result, selectors, 'querySelector');
|
|
7008
7845
|
};
|
|
7009
7846
|
rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
7010
7847
|
var _a;
|
|
7011
|
-
const
|
|
7012
|
-
|
|
7848
|
+
const _this = (_a = getElementQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
7849
|
+
const result = globalEnv.rawElementQuerySelectorAll.call(_this, selectors);
|
|
7850
|
+
return getElementQueryResult(!result.length && _this !== this, _this, result, selectors, 'querySelectorAll');
|
|
7013
7851
|
};
|
|
7014
7852
|
// rewrite setAttribute, complete resource address
|
|
7015
7853
|
rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
7016
|
-
|
|
7017
|
-
|
|
7018
|
-
|
|
7019
|
-
(
|
|
7020
|
-
|
|
7021
|
-
|
|
7022
|
-
|
|
7854
|
+
if (/^micro-app(-\S+)?/i.test(this.tagName) &&
|
|
7855
|
+
key === 'data' &&
|
|
7856
|
+
this.setAttribute !== rawRootElement.prototype.setAttribute) {
|
|
7857
|
+
this.setAttribute(key, value);
|
|
7858
|
+
}
|
|
7859
|
+
else {
|
|
7860
|
+
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
7861
|
+
if (appName &&
|
|
7862
|
+
appInstanceMap.has(appName) &&
|
|
7863
|
+
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
7864
|
+
(key === 'href' && /^(a|link|image)$/i.test(this.tagName)))) {
|
|
7865
|
+
const app = appInstanceMap.get(appName);
|
|
7866
|
+
value = CompletionPath(value, app.url);
|
|
7867
|
+
}
|
|
7868
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7023
7869
|
}
|
|
7024
|
-
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7025
7870
|
};
|
|
7026
7871
|
/**
|
|
7027
7872
|
* TODO: 兼容直接通过img.src等操作设置的资源
|
|
@@ -7048,7 +7893,7 @@ function patchElementAndDocument() {
|
|
|
7048
7893
|
// return get?.call(this)
|
|
7049
7894
|
// },
|
|
7050
7895
|
// set: function (value) {
|
|
7051
|
-
// const currentAppName = getCurrentAppName()
|
|
7896
|
+
// const currentAppName = this.__MICRO_APP_NAME__ || getCurrentAppName()
|
|
7052
7897
|
// if (currentAppName && appInstanceMap.has(currentAppName)) {
|
|
7053
7898
|
// const app = appInstanceMap.get(currentAppName)
|
|
7054
7899
|
// value = CompletionPath(value, app!.url)
|
|
@@ -7057,6 +7902,43 @@ function patchElementAndDocument() {
|
|
|
7057
7902
|
// },
|
|
7058
7903
|
// })
|
|
7059
7904
|
// })
|
|
7905
|
+
rawDefineProperty(rawRootNode.prototype, 'parentNode', {
|
|
7906
|
+
configurable: true,
|
|
7907
|
+
enumerable: true,
|
|
7908
|
+
get() {
|
|
7909
|
+
var _a, _b, _c;
|
|
7910
|
+
/**
|
|
7911
|
+
* hijack parentNode of html for with sandbox
|
|
7912
|
+
* Scenes:
|
|
7913
|
+
* 1. element-ui@2/lib/utils/popper.js
|
|
7914
|
+
* // root is child app window, so root.document is proxyDocument or microDocument
|
|
7915
|
+
* if (element.parentNode === root.document) ...
|
|
7916
|
+
*/
|
|
7917
|
+
const currentAppName = getIframeCurrentAppName() || getCurrentAppName();
|
|
7918
|
+
if (currentAppName && this === globalEnv.rawDocument.firstElementChild) {
|
|
7919
|
+
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;
|
|
7920
|
+
if (microDocument)
|
|
7921
|
+
return microDocument;
|
|
7922
|
+
}
|
|
7923
|
+
// NOTE: run after hijack html.parentNode
|
|
7924
|
+
const result = globalEnv.rawParentNodeDesc.get.call(this);
|
|
7925
|
+
/**
|
|
7926
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
7927
|
+
* Scenes:
|
|
7928
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
7929
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
7930
|
+
* WARNING:
|
|
7931
|
+
* Will it cause other problems ?
|
|
7932
|
+
* e.g. target.parentNode.remove(target)
|
|
7933
|
+
* BUG:
|
|
7934
|
+
* 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again ) -- Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
|
|
7935
|
+
*/
|
|
7936
|
+
// if (isMicroAppBody(result) && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
|
|
7937
|
+
// return document.body
|
|
7938
|
+
// }
|
|
7939
|
+
return result;
|
|
7940
|
+
},
|
|
7941
|
+
});
|
|
7060
7942
|
rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
|
|
7061
7943
|
configurable: true,
|
|
7062
7944
|
enumerable: true,
|
|
@@ -7065,50 +7947,26 @@ function patchElementAndDocument() {
|
|
|
7065
7947
|
},
|
|
7066
7948
|
set(code) {
|
|
7067
7949
|
globalEnv.rawInnerHTMLDesc.set.call(this, code);
|
|
7068
|
-
const currentAppName = getCurrentAppName();
|
|
7950
|
+
const currentAppName = this.__MICRO_APP_NAME__ || getIframeCurrentAppName() || getCurrentAppName();
|
|
7069
7951
|
Array.from(this.children).forEach((child) => {
|
|
7070
7952
|
if (isElement(child) && currentAppName) {
|
|
7071
|
-
child
|
|
7953
|
+
updateElementInfo(child, currentAppName);
|
|
7072
7954
|
}
|
|
7073
7955
|
});
|
|
7074
7956
|
}
|
|
7075
7957
|
});
|
|
7076
|
-
|
|
7077
|
-
|
|
7078
|
-
|
|
7079
|
-
|
|
7080
|
-
|
|
7081
|
-
// enumerable: true,
|
|
7082
|
-
// get () {
|
|
7083
|
-
// const result = globalEnv.rawParentNodeDesc.get.call(this)
|
|
7084
|
-
// /**
|
|
7085
|
-
// * If parentNode is <micro-app-body>, return rawDocument.body
|
|
7086
|
-
// * Scenes:
|
|
7087
|
-
// * 1. element-ui@2/lib/utils/vue-popper.js
|
|
7088
|
-
// * if (this.popperElm.parentNode === document.body) ...
|
|
7089
|
-
// * WARNING:
|
|
7090
|
-
// * Will it cause other problems ?
|
|
7091
|
-
// * e.g. target.parentNode.remove(target)
|
|
7092
|
-
// * BUG:
|
|
7093
|
-
// * 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again )
|
|
7094
|
-
// */
|
|
7095
|
-
// if (isMicroAppBody(result) && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
|
|
7096
|
-
// return document.body
|
|
7097
|
-
// }
|
|
7098
|
-
// return result
|
|
7099
|
-
// },
|
|
7100
|
-
// set: undefined,
|
|
7101
|
-
// })
|
|
7958
|
+
// patch cloneNode
|
|
7959
|
+
rawRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
7960
|
+
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
7961
|
+
return updateElementInfo(clonedNode, this.__MICRO_APP_NAME__);
|
|
7962
|
+
};
|
|
7102
7963
|
}
|
|
7103
7964
|
/**
|
|
7104
7965
|
* Mark the newly created element in the micro application
|
|
7105
7966
|
* @param element new element
|
|
7106
7967
|
*/
|
|
7107
7968
|
function markElement(element) {
|
|
7108
|
-
|
|
7109
|
-
if (currentAppName)
|
|
7110
|
-
element.__MICRO_APP_NAME__ = currentAppName;
|
|
7111
|
-
return element;
|
|
7969
|
+
return updateElementInfo(element, getCurrentAppName());
|
|
7112
7970
|
}
|
|
7113
7971
|
// methods of document
|
|
7114
7972
|
function patchDocument$2() {
|
|
@@ -7126,14 +7984,15 @@ function patchDocument$2() {
|
|
|
7126
7984
|
const element = globalEnv.rawCreateElementNS.call(getBindTarget(this), namespaceURI, name, options);
|
|
7127
7985
|
return markElement(element);
|
|
7128
7986
|
};
|
|
7129
|
-
|
|
7130
|
-
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
7131
|
-
return markElement(element);
|
|
7132
|
-
};
|
|
7987
|
+
// TODO: 放开
|
|
7133
7988
|
// rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
|
|
7134
7989
|
// const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
|
|
7135
7990
|
// return markElement(element)
|
|
7136
7991
|
// }
|
|
7992
|
+
rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
|
|
7993
|
+
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
7994
|
+
return markElement(element);
|
|
7995
|
+
};
|
|
7137
7996
|
rawRootDocument.prototype.createComment = function createComment(data) {
|
|
7138
7997
|
const element = globalEnv.rawCreateComment.call(getBindTarget(this), data);
|
|
7139
7998
|
return markElement(element);
|
|
@@ -7146,7 +8005,7 @@ function patchDocument$2() {
|
|
|
7146
8005
|
if (!currentAppName ||
|
|
7147
8006
|
!selectors ||
|
|
7148
8007
|
isUniqueElement(selectors) ||
|
|
7149
|
-
//
|
|
8008
|
+
// ISSUE: https://github.com/micro-zoe/micro-app/issues/56
|
|
7150
8009
|
rawDocument !== _this) {
|
|
7151
8010
|
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
7152
8011
|
}
|
|
@@ -7237,16 +8096,18 @@ function releasePatchElementAndDocument() {
|
|
|
7237
8096
|
removeDomScope();
|
|
7238
8097
|
releasePatchDocument();
|
|
7239
8098
|
const rawRootElement = globalEnv.rawRootElement;
|
|
7240
|
-
|
|
7241
|
-
|
|
7242
|
-
|
|
7243
|
-
|
|
8099
|
+
const rawRootNode = globalEnv.rawRootNode;
|
|
8100
|
+
rawRootNode.prototype.appendChild = globalEnv.rawAppendChild;
|
|
8101
|
+
rawRootNode.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
8102
|
+
rawRootNode.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
8103
|
+
rawRootNode.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
8104
|
+
rawRootNode.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
7244
8105
|
rawRootElement.prototype.append = globalEnv.rawAppend;
|
|
7245
8106
|
rawRootElement.prototype.prepend = globalEnv.rawPrepend;
|
|
7246
|
-
rawRootElement.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
7247
8107
|
rawRootElement.prototype.querySelector = globalEnv.rawElementQuerySelector;
|
|
7248
8108
|
rawRootElement.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
|
|
7249
8109
|
rawRootElement.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
8110
|
+
rawDefineProperty(rawRootNode.prototype, 'parentNode', globalEnv.rawParentNodeDesc);
|
|
7250
8111
|
rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
|
|
7251
8112
|
}
|
|
7252
8113
|
// Set the style of micro-app-head and micro-app-body
|
|
@@ -7277,15 +8138,18 @@ function initGlobalEnv() {
|
|
|
7277
8138
|
const rawRootElement = rawWindow.Element;
|
|
7278
8139
|
const rawRootNode = rawWindow.Node;
|
|
7279
8140
|
const rawRootEventTarget = rawWindow.EventTarget;
|
|
8141
|
+
const rawDocumentFragment = rawWindow.DocumentFragment;
|
|
7280
8142
|
// save patch raw methods, pay attention to this binding
|
|
8143
|
+
const rawAppendChild = rawRootNode.prototype.appendChild;
|
|
8144
|
+
const rawInsertBefore = rawRootNode.prototype.insertBefore;
|
|
8145
|
+
const rawReplaceChild = rawRootNode.prototype.replaceChild;
|
|
8146
|
+
const rawRemoveChild = rawRootNode.prototype.removeChild;
|
|
7281
8147
|
const rawSetAttribute = rawRootElement.prototype.setAttribute;
|
|
7282
|
-
const rawAppendChild = rawRootElement.prototype.appendChild;
|
|
7283
|
-
const rawInsertBefore = rawRootElement.prototype.insertBefore;
|
|
7284
|
-
const rawReplaceChild = rawRootElement.prototype.replaceChild;
|
|
7285
|
-
const rawRemoveChild = rawRootElement.prototype.removeChild;
|
|
7286
8148
|
const rawAppend = rawRootElement.prototype.append;
|
|
7287
8149
|
const rawPrepend = rawRootElement.prototype.prepend;
|
|
7288
|
-
const
|
|
8150
|
+
const rawFragmentAppend = rawDocumentFragment.prototype.append;
|
|
8151
|
+
const rawFragmentPrepend = rawDocumentFragment.prototype.prepend;
|
|
8152
|
+
const rawCloneNode = rawRootNode.prototype.cloneNode;
|
|
7289
8153
|
const rawElementQuerySelector = rawRootElement.prototype.querySelector;
|
|
7290
8154
|
const rawElementQuerySelectorAll = rawRootElement.prototype.querySelectorAll;
|
|
7291
8155
|
const rawInsertAdjacentElement = rawRootElement.prototype.insertAdjacentElement;
|
|
@@ -7294,8 +8158,8 @@ function initGlobalEnv() {
|
|
|
7294
8158
|
// Document proto methods
|
|
7295
8159
|
const rawCreateElement = rawRootDocument.prototype.createElement;
|
|
7296
8160
|
const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
|
|
7297
|
-
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
7298
8161
|
const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
|
|
8162
|
+
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
7299
8163
|
const rawCreateComment = rawRootDocument.prototype.createComment;
|
|
7300
8164
|
const rawQuerySelector = rawRootDocument.prototype.querySelector;
|
|
7301
8165
|
const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
|
|
@@ -7303,13 +8167,10 @@ function initGlobalEnv() {
|
|
|
7303
8167
|
const rawGetElementsByClassName = rawRootDocument.prototype.getElementsByClassName;
|
|
7304
8168
|
const rawGetElementsByTagName = rawRootDocument.prototype.getElementsByTagName;
|
|
7305
8169
|
const rawGetElementsByName = rawRootDocument.prototype.getElementsByName;
|
|
7306
|
-
|
|
8170
|
+
// TODO: 将ImageProxy移出去
|
|
8171
|
+
const ImageProxy = new Proxy(rawWindow.Image, {
|
|
7307
8172
|
construct(Target, args) {
|
|
7308
|
-
|
|
7309
|
-
const currentAppName = getCurrentAppName();
|
|
7310
|
-
if (currentAppName)
|
|
7311
|
-
elementImage.__MICRO_APP_NAME__ = currentAppName;
|
|
7312
|
-
return elementImage;
|
|
8173
|
+
return updateElementInfo(new Target(...args), getCurrentAppName());
|
|
7313
8174
|
},
|
|
7314
8175
|
});
|
|
7315
8176
|
/**
|
|
@@ -7335,6 +8196,7 @@ function initGlobalEnv() {
|
|
|
7335
8196
|
rawRootDocument,
|
|
7336
8197
|
rawRootElement,
|
|
7337
8198
|
rawRootNode,
|
|
8199
|
+
rawDocumentFragment,
|
|
7338
8200
|
// source/patch
|
|
7339
8201
|
rawSetAttribute,
|
|
7340
8202
|
rawAppendChild,
|
|
@@ -7343,6 +8205,8 @@ function initGlobalEnv() {
|
|
|
7343
8205
|
rawRemoveChild,
|
|
7344
8206
|
rawAppend,
|
|
7345
8207
|
rawPrepend,
|
|
8208
|
+
rawFragmentAppend,
|
|
8209
|
+
rawFragmentPrepend,
|
|
7346
8210
|
rawCloneNode,
|
|
7347
8211
|
rawElementQuerySelector,
|
|
7348
8212
|
rawElementQuerySelectorAll,
|
|
@@ -7380,7 +8244,7 @@ function initGlobalEnv() {
|
|
|
7380
8244
|
/**
|
|
7381
8245
|
* define element
|
|
7382
8246
|
* @param tagName element name
|
|
7383
|
-
|
|
8247
|
+
*/
|
|
7384
8248
|
function defineElement(tagName) {
|
|
7385
8249
|
class MicroAppElement extends HTMLElement {
|
|
7386
8250
|
constructor() {
|
|
@@ -7447,6 +8311,13 @@ function defineElement(tagName) {
|
|
|
7447
8311
|
// baseRoute: route prefix, default is ''
|
|
7448
8312
|
// keep-alive: open keep-alive mode
|
|
7449
8313
|
connectedCallback() {
|
|
8314
|
+
/**
|
|
8315
|
+
* In FireFox, iframe Node.prototype will point to native Node.prototype after insert to document
|
|
8316
|
+
* If <micro-app>.prototype is not MicroAppElement.prototype, we should reset it
|
|
8317
|
+
*/
|
|
8318
|
+
if (Object.getPrototypeOf(this) !== MicroAppElement.prototype) {
|
|
8319
|
+
Object.setPrototypeOf(this, MicroAppElement.prototype);
|
|
8320
|
+
}
|
|
7450
8321
|
const cacheCount = ++this.connectedCount;
|
|
7451
8322
|
this.connectStateMap.set(cacheCount, true);
|
|
7452
8323
|
/**
|
|
@@ -7508,8 +8379,7 @@ function defineElement(tagName) {
|
|
|
7508
8379
|
if (this.legalAttribute(attr, newVal) &&
|
|
7509
8380
|
this[attr === ObservedAttrName.NAME ? 'appName' : 'appUrl'] !== newVal) {
|
|
7510
8381
|
if (attr === ObservedAttrName.URL && (!this.appUrl ||
|
|
7511
|
-
!this.connectStateMap.get(this.connectedCount)
|
|
7512
|
-
)) {
|
|
8382
|
+
!this.connectStateMap.get(this.connectedCount))) {
|
|
7513
8383
|
newVal = formatAppURL(newVal, this.appName);
|
|
7514
8384
|
if (!newVal) {
|
|
7515
8385
|
return logError(`Invalid attribute url ${newVal}`, this.appName);
|
|
@@ -7518,13 +8388,11 @@ function defineElement(tagName) {
|
|
|
7518
8388
|
this.handleInitialNameAndUrl();
|
|
7519
8389
|
}
|
|
7520
8390
|
else if (attr === ObservedAttrName.NAME && (!this.appName ||
|
|
7521
|
-
!this.connectStateMap.get(this.connectedCount)
|
|
7522
|
-
)) {
|
|
8391
|
+
!this.connectStateMap.get(this.connectedCount))) {
|
|
7523
8392
|
const formatNewName = formatAppName(newVal);
|
|
7524
8393
|
if (!formatNewName) {
|
|
7525
8394
|
return logError(`Invalid attribute name ${newVal}`, this.appName);
|
|
7526
8395
|
}
|
|
7527
|
-
// TODO: 当micro-app还未插入文档中就修改name,逻辑可否再优化一下
|
|
7528
8396
|
if (this.cacheData) {
|
|
7529
8397
|
microApp.setData(formatNewName, this.cacheData);
|
|
7530
8398
|
this.cacheData = null;
|
|
@@ -7579,12 +8447,12 @@ function defineElement(tagName) {
|
|
|
7579
8447
|
/**
|
|
7580
8448
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
7581
8449
|
*/
|
|
7582
|
-
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url
|
|
8450
|
+
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url ${oldAppUrl} replaced by a new app with url ${targetUrl}`, this.appName);
|
|
7583
8451
|
}
|
|
7584
8452
|
this.handleCreateApp();
|
|
7585
8453
|
}
|
|
7586
8454
|
else {
|
|
7587
|
-
logError(`app name conflict, an app named
|
|
8455
|
+
logError(`app name conflict, an app named ${this.appName} with url ${oldAppUrl} is running`);
|
|
7588
8456
|
}
|
|
7589
8457
|
}
|
|
7590
8458
|
else {
|
|
@@ -7828,6 +8696,7 @@ function defineElement(tagName) {
|
|
|
7828
8696
|
}
|
|
7829
8697
|
else {
|
|
7830
8698
|
// get path from browser URL
|
|
8699
|
+
// TODO: 新版本路由系统要重新兼容ssr
|
|
7831
8700
|
let targetPath = getNoHashMicroPathFromURL(this.appName, baseUrl);
|
|
7832
8701
|
const defaultPagePath = this.getDefaultPage();
|
|
7833
8702
|
if (!targetPath && defaultPagePath) {
|
|
@@ -7855,7 +8724,10 @@ function defineElement(tagName) {
|
|
|
7855
8724
|
* @returns router-mode
|
|
7856
8725
|
*/
|
|
7857
8726
|
getMemoryRouterMode() {
|
|
7858
|
-
return
|
|
8727
|
+
return initRouterMode(this.getAttribute('router-mode'),
|
|
8728
|
+
// is micro-app element set disable-memory-router, like <micro-app disable-memory-router></micro-app>
|
|
8729
|
+
// or <micro-app disable-memory-router='false'></micro-app>
|
|
8730
|
+
this.compatibleProperties('disable-memory-router') && this.compatibleDisableProperties('disable-memory-router'));
|
|
7859
8731
|
}
|
|
7860
8732
|
/**
|
|
7861
8733
|
* rewrite micro-app.setAttribute, process attr data
|
|
@@ -7881,6 +8753,17 @@ function defineElement(tagName) {
|
|
|
7881
8753
|
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7882
8754
|
}
|
|
7883
8755
|
}
|
|
8756
|
+
/**
|
|
8757
|
+
* get delay time of router event
|
|
8758
|
+
* @returns delay time
|
|
8759
|
+
*/
|
|
8760
|
+
getRouterEventDelay() {
|
|
8761
|
+
let delay = parseInt(this.getAttribute('router-event-delay'));
|
|
8762
|
+
if (isNaN(delay)) {
|
|
8763
|
+
delay = parseInt((isFunction(microApp.options['router-event-delay']) ? microApp.options['router-event-delay'](this.appName) : microApp.options['router-event-delay']));
|
|
8764
|
+
}
|
|
8765
|
+
return !isNaN(delay) ? delay : 0;
|
|
8766
|
+
}
|
|
7884
8767
|
/**
|
|
7885
8768
|
* Data from the base application
|
|
7886
8769
|
*/
|
|
@@ -7904,8 +8787,20 @@ function defineElement(tagName) {
|
|
|
7904
8787
|
}
|
|
7905
8788
|
return null;
|
|
7906
8789
|
}
|
|
8790
|
+
/**
|
|
8791
|
+
* get publicPath from a valid address,it can used in micro-app-devtools
|
|
8792
|
+
*/
|
|
8793
|
+
get publicPath() {
|
|
8794
|
+
return getEffectivePath(this.appUrl);
|
|
8795
|
+
}
|
|
8796
|
+
/**
|
|
8797
|
+
* get baseRoute from attribute,it can used in micro-app-devtools
|
|
8798
|
+
*/
|
|
8799
|
+
get baseRoute() {
|
|
8800
|
+
return this.getBaseRouteCompatible();
|
|
8801
|
+
}
|
|
7907
8802
|
}
|
|
7908
|
-
|
|
8803
|
+
window.customElements.define(tagName, MicroAppElement);
|
|
7909
8804
|
}
|
|
7910
8805
|
|
|
7911
8806
|
/**
|
|
@@ -7937,7 +8832,7 @@ function preFetch(apps, delay) {
|
|
|
7937
8832
|
const delayTime = isNumber(delay) ? delay : microApp.options.prefetchDelay;
|
|
7938
8833
|
/**
|
|
7939
8834
|
* TODO: remove setTimeout
|
|
7940
|
-
*
|
|
8835
|
+
* 如果要保留setTimeout,则需要考虑清空定时器的情况
|
|
7941
8836
|
*/
|
|
7942
8837
|
setTimeout(() => {
|
|
7943
8838
|
// releasePrefetchEffect()
|
|
@@ -7982,9 +8877,22 @@ function preFetchAction(options) {
|
|
|
7982
8877
|
});
|
|
7983
8878
|
const oldOnload = app.onLoad;
|
|
7984
8879
|
const oldOnLoadError = app.onLoadError;
|
|
7985
|
-
app.onLoad = (
|
|
8880
|
+
app.onLoad = (onLoadParam) => {
|
|
8881
|
+
if (app.isPrerender) {
|
|
8882
|
+
assign(onLoadParam, {
|
|
8883
|
+
defaultPage: options['default-page'],
|
|
8884
|
+
/**
|
|
8885
|
+
* TODO: 预渲染支持disable-memory-router,默认渲染首页即可,文档中也要保留
|
|
8886
|
+
* 问题:
|
|
8887
|
+
* 1、如何确保子应用进行跳转时不影响到浏览器地址??pure??
|
|
8888
|
+
*/
|
|
8889
|
+
routerMode: initRouterMode(options['router-mode']),
|
|
8890
|
+
baseroute: options.baseroute,
|
|
8891
|
+
disablePatchRequest: options['disable-patch-request'],
|
|
8892
|
+
});
|
|
8893
|
+
}
|
|
7986
8894
|
resolve();
|
|
7987
|
-
oldOnload.call(app,
|
|
8895
|
+
oldOnload.call(app, onLoadParam);
|
|
7988
8896
|
};
|
|
7989
8897
|
app.onLoadError = (...rests) => {
|
|
7990
8898
|
resolve();
|
|
@@ -8015,7 +8923,7 @@ function getGlobalAssets(assets) {
|
|
|
8015
8923
|
// TODO: requestIdleCallback for every file
|
|
8016
8924
|
function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
8017
8925
|
if (isArray(resources)) {
|
|
8018
|
-
const effectiveResource = resources.filter((path) => isString(path) && path
|
|
8926
|
+
const effectiveResource = resources.filter((path) => isString(path) && isTargetExtension(path, suffix) && !sourceHandler.hasInfo(path));
|
|
8019
8927
|
const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
|
|
8020
8928
|
// fetch resource with stream
|
|
8021
8929
|
promiseStream(fetchResourcePromise, (res) => {
|
|
@@ -8159,7 +9067,7 @@ function unmountApp(appName, options) {
|
|
|
8159
9067
|
}
|
|
8160
9068
|
}
|
|
8161
9069
|
else {
|
|
8162
|
-
logWarn(`app ${appName} does not exist`);
|
|
9070
|
+
logWarn(`app ${appName} does not exist when unmountApp`);
|
|
8163
9071
|
resolve(false);
|
|
8164
9072
|
}
|
|
8165
9073
|
});
|
|
@@ -8189,7 +9097,7 @@ function reload(appName, destroy) {
|
|
|
8189
9097
|
}
|
|
8190
9098
|
}
|
|
8191
9099
|
else {
|
|
8192
|
-
logWarn(`app ${appName} does not exist`);
|
|
9100
|
+
logWarn(`app ${appName} does not exist when reload app`);
|
|
8193
9101
|
resolve(false);
|
|
8194
9102
|
}
|
|
8195
9103
|
});
|
|
@@ -8282,7 +9190,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
8282
9190
|
}
|
|
8283
9191
|
}
|
|
8284
9192
|
initGlobalEnv();
|
|
8285
|
-
if (
|
|
9193
|
+
if (window.customElements.get(this.tagName)) {
|
|
8286
9194
|
return logWarn(`element ${this.tagName} is already defined`);
|
|
8287
9195
|
}
|
|
8288
9196
|
if (isPlainObject(options)) {
|