@micro-zoe/micro-app 1.0.0-rc.3 → 1.0.0-rc.5
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/lib/index.d.ts +8 -10
- package/lib/index.esm.js +759 -496
- package/lib/index.esm.js.map +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.min.js.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/typings/global.d.ts +36 -34
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-rc.
|
|
1
|
+
const version = '1.0.0-rc.5';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -116,6 +116,34 @@ function isMicroAppBody(target) {
|
|
|
116
116
|
function isProxyDocument(target) {
|
|
117
117
|
return toTypeString(target) === '[object ProxyDocument]';
|
|
118
118
|
}
|
|
119
|
+
function isTargetExtension(path, suffix) {
|
|
120
|
+
try {
|
|
121
|
+
return createURL(path).pathname.split('.').pop() === suffix;
|
|
122
|
+
}
|
|
123
|
+
catch (_a) {
|
|
124
|
+
return false;
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function includes(target, searchElement, fromIndex) {
|
|
128
|
+
if (target == null) {
|
|
129
|
+
throw new TypeError('includes target is null or undefined');
|
|
130
|
+
}
|
|
131
|
+
const O = Object(target);
|
|
132
|
+
const len = parseInt(O.length, 10) || 0;
|
|
133
|
+
if (len === 0)
|
|
134
|
+
return false;
|
|
135
|
+
// @ts-ignore
|
|
136
|
+
fromIndex = parseInt(fromIndex, 10) || 0;
|
|
137
|
+
let i = Math.max(fromIndex >= 0 ? fromIndex : len + fromIndex, 0);
|
|
138
|
+
while (i < len) {
|
|
139
|
+
// NaN !== NaN
|
|
140
|
+
if (searchElement === O[i] || (searchElement !== searchElement && O[i] !== O[i])) {
|
|
141
|
+
return true;
|
|
142
|
+
}
|
|
143
|
+
i++;
|
|
144
|
+
}
|
|
145
|
+
return false;
|
|
146
|
+
}
|
|
119
147
|
/**
|
|
120
148
|
* format error log
|
|
121
149
|
* @param msg message
|
|
@@ -179,13 +207,13 @@ function formatAppURL(url, appName = null) {
|
|
|
179
207
|
if (!isString(url) || !url)
|
|
180
208
|
return '';
|
|
181
209
|
try {
|
|
182
|
-
const { origin, pathname, search } = createURL(addProtocol(url));
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
const fullPath = `${origin}${pathname}
|
|
188
|
-
return /^https?:\/\//.test(fullPath) ?
|
|
210
|
+
const { origin, pathname, search } = createURL(addProtocol(url), (window.rawWindow || window).location.href);
|
|
211
|
+
/**
|
|
212
|
+
* keep the original url unchanged, such as .html .node .php .net .etc, search, except hash
|
|
213
|
+
* BUG FIX: Never using '/' to complete url, refer to https://github.com/micro-zoe/micro-app/issues/1147
|
|
214
|
+
*/
|
|
215
|
+
const fullPath = `${origin}${pathname}${search}`;
|
|
216
|
+
return /^https?:\/\//.test(fullPath) ? fullPath : '';
|
|
189
217
|
}
|
|
190
218
|
catch (e) {
|
|
191
219
|
logError(e, appName);
|
|
@@ -208,7 +236,9 @@ function formatAppName(name) {
|
|
|
208
236
|
return name.replace(/(^\d+)|([^\w\d-_])/gi, '');
|
|
209
237
|
}
|
|
210
238
|
/**
|
|
211
|
-
* Get valid address, such as
|
|
239
|
+
* Get valid address, such as
|
|
240
|
+
* 1. https://domain/xx/xx.html to https://domain/xx/
|
|
241
|
+
* 2. https://domain/xx to https://domain/xx/
|
|
212
242
|
* @param url app.url
|
|
213
243
|
*/
|
|
214
244
|
function getEffectivePath(url) {
|
|
@@ -318,21 +348,28 @@ let currentMicroAppName = null;
|
|
|
318
348
|
function setCurrentAppName(appName) {
|
|
319
349
|
currentMicroAppName = appName;
|
|
320
350
|
}
|
|
321
|
-
function throttleDeferForSetAppName(appName) {
|
|
322
|
-
if (currentMicroAppName !== appName) {
|
|
323
|
-
setCurrentAppName(appName);
|
|
324
|
-
defer(() => {
|
|
325
|
-
setCurrentAppName(null);
|
|
326
|
-
});
|
|
327
|
-
}
|
|
328
|
-
}
|
|
329
351
|
// get the currently running app.name
|
|
330
352
|
function getCurrentAppName() {
|
|
331
353
|
return currentMicroAppName;
|
|
332
354
|
}
|
|
333
355
|
// Clear appName
|
|
334
|
-
|
|
356
|
+
let preventSetAppName = false;
|
|
357
|
+
function removeDomScope(force) {
|
|
335
358
|
setCurrentAppName(null);
|
|
359
|
+
if (force && !preventSetAppName) {
|
|
360
|
+
preventSetAppName = true;
|
|
361
|
+
defer(() => {
|
|
362
|
+
preventSetAppName = false;
|
|
363
|
+
});
|
|
364
|
+
}
|
|
365
|
+
}
|
|
366
|
+
function throttleDeferForSetAppName(appName) {
|
|
367
|
+
if (currentMicroAppName !== appName && !preventSetAppName) {
|
|
368
|
+
setCurrentAppName(appName);
|
|
369
|
+
defer(() => {
|
|
370
|
+
setCurrentAppName(null);
|
|
371
|
+
});
|
|
372
|
+
}
|
|
336
373
|
}
|
|
337
374
|
/**
|
|
338
375
|
* Create pure elements
|
|
@@ -344,33 +381,6 @@ function pureCreateElement(tagName, options) {
|
|
|
344
381
|
element.__PURE_ELEMENT__ = true;
|
|
345
382
|
return element;
|
|
346
383
|
}
|
|
347
|
-
/**
|
|
348
|
-
* clone origin elements to target
|
|
349
|
-
* @param origin Cloned element
|
|
350
|
-
* @param target Accept cloned elements
|
|
351
|
-
* @param deep deep clone or transfer dom
|
|
352
|
-
*/
|
|
353
|
-
function cloneContainer(target, origin, deep) {
|
|
354
|
-
// 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
|
|
355
|
-
if (origin) {
|
|
356
|
-
target.innerHTML = '';
|
|
357
|
-
if (deep) {
|
|
358
|
-
// TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
|
|
359
|
-
const clonedNode = origin.cloneNode(true);
|
|
360
|
-
const fragment = document.createDocumentFragment();
|
|
361
|
-
Array.from(clonedNode.childNodes).forEach((node) => {
|
|
362
|
-
fragment.appendChild(node);
|
|
363
|
-
});
|
|
364
|
-
target.appendChild(fragment);
|
|
365
|
-
}
|
|
366
|
-
else {
|
|
367
|
-
Array.from(origin.childNodes).forEach((node) => {
|
|
368
|
-
target.appendChild(node);
|
|
369
|
-
});
|
|
370
|
-
}
|
|
371
|
-
}
|
|
372
|
-
return target;
|
|
373
|
-
}
|
|
374
384
|
// is invalid key of querySelector
|
|
375
385
|
function isInvalidQuerySelectorKey(key) {
|
|
376
386
|
return !key || /(^\d)|([^\w\d-_\u4e00-\u9fa5])/gi.test(key);
|
|
@@ -561,6 +571,17 @@ function getBaseHTMLElement() {
|
|
|
561
571
|
var _a;
|
|
562
572
|
return (((_a = window.rawWindow) === null || _a === void 0 ? void 0 : _a.HTMLElement) || window.HTMLElement);
|
|
563
573
|
}
|
|
574
|
+
/**
|
|
575
|
+
* Format event name
|
|
576
|
+
* 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
|
|
577
|
+
* Issue: https://github.com/micro-zoe/micro-app/issues/1161
|
|
578
|
+
* @param type event name
|
|
579
|
+
* @param appName app name
|
|
580
|
+
*/
|
|
581
|
+
const formatEventList = ['mounted', 'unmount'];
|
|
582
|
+
function formatEventType(type, appName) {
|
|
583
|
+
return formatEventList.includes(type) ? `${type}-${appName}` : type;
|
|
584
|
+
}
|
|
564
585
|
|
|
565
586
|
function formatEventInfo(event, element) {
|
|
566
587
|
Object.defineProperties(event, {
|
|
@@ -604,19 +625,19 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
604
625
|
formatEventInfo(event, element);
|
|
605
626
|
// global hooks
|
|
606
627
|
if (isFunction((_a = microApp.options.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
607
|
-
microApp.options.lifeCycles[lifecycleName](event);
|
|
628
|
+
microApp.options.lifeCycles[lifecycleName](event, appName);
|
|
608
629
|
}
|
|
609
630
|
element.dispatchEvent(event);
|
|
610
631
|
}
|
|
611
632
|
/**
|
|
612
633
|
* Dispatch custom event to micro app
|
|
613
634
|
* @param app app
|
|
614
|
-
* @param eventName event name ['unmount', 'appstate-change']
|
|
635
|
+
* @param eventName event name ['mounted', 'unmount', 'appstate-change', 'statechange']
|
|
615
636
|
* @param detail event detail
|
|
616
637
|
*/
|
|
617
638
|
function dispatchCustomEventToMicroApp(app, eventName, detail = {}) {
|
|
618
639
|
var _a;
|
|
619
|
-
const event = new CustomEvent(eventName, {
|
|
640
|
+
const event = new CustomEvent(formatEventType(eventName, app.name), {
|
|
620
641
|
detail,
|
|
621
642
|
});
|
|
622
643
|
(_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.microAppWindow.dispatchEvent(event);
|
|
@@ -660,7 +681,8 @@ class HTMLLoader {
|
|
|
660
681
|
run(app, successCb) {
|
|
661
682
|
const appName = app.name;
|
|
662
683
|
const htmlUrl = app.ssrUrl || app.url;
|
|
663
|
-
const
|
|
684
|
+
const isJsResource = isTargetExtension(htmlUrl, 'js');
|
|
685
|
+
const htmlPromise = isJsResource
|
|
664
686
|
? Promise.resolve(`<micro-app-head><script src='${htmlUrl}'></script></micro-app-head><micro-app-body></micro-app-body>`)
|
|
665
687
|
: fetchSource(htmlUrl, appName, { cache: 'no-cache' });
|
|
666
688
|
htmlPromise.then((htmlStr) => {
|
|
@@ -824,7 +846,7 @@ class CSSParser {
|
|
|
824
846
|
if (!this.scopecssDisableNextLine &&
|
|
825
847
|
(!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
|
|
826
848
|
cssValue = cssValue.replace(/url\(["']?([^)"']+)["']?\)/gm, (all, $1) => {
|
|
827
|
-
if (/^((data|blob)
|
|
849
|
+
if (/^((data|blob):|#|%23)/.test($1) || /^(https?:)?\/\//.test($1)) {
|
|
828
850
|
return all;
|
|
829
851
|
}
|
|
830
852
|
// ./a/b.png ../a/b.png a/b.png
|
|
@@ -1250,7 +1272,7 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
|
1250
1272
|
return { address: href, linkInfo };
|
|
1251
1273
|
}
|
|
1252
1274
|
}
|
|
1253
|
-
else if (rel && ['prefetch', 'preload', 'prerender'].includes(rel)) {
|
|
1275
|
+
else if (rel && ['prefetch', 'preload', 'prerender', 'modulepreload'].includes(rel)) {
|
|
1254
1276
|
// preload prefetch prerender ....
|
|
1255
1277
|
if (isDynamic) {
|
|
1256
1278
|
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
@@ -1295,12 +1317,12 @@ function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
|
1295
1317
|
*/
|
|
1296
1318
|
if (fiberStyleResult) {
|
|
1297
1319
|
fiberStyleResult.then(() => {
|
|
1298
|
-
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1320
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
|
|
1299
1321
|
serialExecFiberTasks(fiberLinkTasks);
|
|
1300
1322
|
});
|
|
1301
1323
|
}
|
|
1302
1324
|
else {
|
|
1303
|
-
app.onLoad(wrapElement);
|
|
1325
|
+
app.onLoad({ html: wrapElement });
|
|
1304
1326
|
}
|
|
1305
1327
|
});
|
|
1306
1328
|
}
|
|
@@ -1470,19 +1492,46 @@ var MicroAppConfig;
|
|
|
1470
1492
|
MicroAppConfig["SSR"] = "ssr";
|
|
1471
1493
|
MicroAppConfig["FIBER"] = "fiber";
|
|
1472
1494
|
})(MicroAppConfig || (MicroAppConfig = {}));
|
|
1495
|
+
/**
|
|
1496
|
+
* global key must be static key, they can not rewrite
|
|
1497
|
+
* e.g.
|
|
1498
|
+
* window.Promise = newValue
|
|
1499
|
+
* new Promise ==> still get old value, not newValue, because they are cached by top function
|
|
1500
|
+
* NOTE:
|
|
1501
|
+
* 1. Do not add fetch, XMLHttpRequest, EventSource
|
|
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';
|
|
1473
1504
|
// prefetch level
|
|
1474
1505
|
const PREFETCH_LEVEL = [1, 2, 3];
|
|
1475
|
-
|
|
1506
|
+
/**
|
|
1507
|
+
* memory router modes
|
|
1508
|
+
* NOTE:
|
|
1509
|
+
* 1. The only difference between native and native-scope is location.origin, in native-scope mode location.origin point to child app
|
|
1510
|
+
* 2. native mode equal to disable-memory-router
|
|
1511
|
+
*/
|
|
1512
|
+
// 临时注释,1.0版本放开,默认模式切换为state
|
|
1513
|
+
// // default mode, sync child app router info to history.state
|
|
1514
|
+
// export const DEFAULT_ROUTER_MODE = 'state'
|
|
1515
|
+
// // sync child app router info to browser url as search
|
|
1516
|
+
// export const ROUTER_MODE_SEARCH = 'search'
|
|
1517
|
+
// 临时放开,1.0版本去除
|
|
1518
|
+
const ROUTER_MODE_STATE = 'state';
|
|
1476
1519
|
const DEFAULT_ROUTER_MODE = 'search';
|
|
1477
|
-
|
|
1478
|
-
const
|
|
1520
|
+
// render base on browser url, and location.origin location.href point to base app
|
|
1521
|
+
const ROUTER_MODE_NATIVE = 'native';
|
|
1522
|
+
// render base on browser url, but location.origin location.href point to child app
|
|
1523
|
+
const ROUTER_MODE_NATIVE_SCOPE = 'native-scope';
|
|
1524
|
+
// search mode, but child router info will not sync to browser url
|
|
1525
|
+
const ROUTER_MODE_PURE = 'pure';
|
|
1479
1526
|
const ROUTER_MODE_LIST = [
|
|
1480
1527
|
DEFAULT_ROUTER_MODE,
|
|
1481
|
-
|
|
1482
|
-
|
|
1528
|
+
ROUTER_MODE_STATE,
|
|
1529
|
+
ROUTER_MODE_NATIVE,
|
|
1530
|
+
ROUTER_MODE_NATIVE_SCOPE,
|
|
1531
|
+
ROUTER_MODE_PURE,
|
|
1483
1532
|
];
|
|
1484
1533
|
// event bound to child app window
|
|
1485
|
-
const
|
|
1534
|
+
const BASE_SCOPE_WINDOW_EVENT = [
|
|
1486
1535
|
'popstate',
|
|
1487
1536
|
'hashchange',
|
|
1488
1537
|
'load',
|
|
@@ -1493,8 +1542,15 @@ const SCOPE_WINDOW_EVENT = [
|
|
|
1493
1542
|
'statechange',
|
|
1494
1543
|
'mounted',
|
|
1495
1544
|
];
|
|
1545
|
+
// bind event of with sandbox
|
|
1546
|
+
const SCOPE_WINDOW_EVENT_OF_WITH = BASE_SCOPE_WINDOW_EVENT;
|
|
1547
|
+
// bind event of iframe sandbox
|
|
1548
|
+
const SCOPE_WINDOW_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_EVENT.concat([
|
|
1549
|
+
'unhandledrejection',
|
|
1550
|
+
]);
|
|
1496
1551
|
// on event bound to child app window
|
|
1497
|
-
|
|
1552
|
+
// TODO: with和iframe处理方式不同,需修改
|
|
1553
|
+
const BASE_SCOPE_WINDOW_ON_EVENT = [
|
|
1498
1554
|
'onpopstate',
|
|
1499
1555
|
'onhashchange',
|
|
1500
1556
|
'onload',
|
|
@@ -1502,6 +1558,12 @@ const SCOPE_WINDOW_ON_EVENT = [
|
|
|
1502
1558
|
'onunload',
|
|
1503
1559
|
'onerror'
|
|
1504
1560
|
];
|
|
1561
|
+
// bind on event of with sandbox
|
|
1562
|
+
const SCOPE_WINDOW_ON_EVENT_OF_WITH = BASE_SCOPE_WINDOW_ON_EVENT;
|
|
1563
|
+
// bind on event of iframe sandbox
|
|
1564
|
+
const SCOPE_WINDOW_ON_EVENT_OF_IFRAME = BASE_SCOPE_WINDOW_ON_EVENT.concat([
|
|
1565
|
+
'onunhandledrejection',
|
|
1566
|
+
]);
|
|
1505
1567
|
// event bound to child app document
|
|
1506
1568
|
const SCOPE_DOCUMENT_EVENT = [
|
|
1507
1569
|
'DOMContentLoaded',
|
|
@@ -1518,15 +1580,13 @@ const GLOBAL_KEY_TO_WINDOW = [
|
|
|
1518
1580
|
'globalThis',
|
|
1519
1581
|
];
|
|
1520
1582
|
const RAW_GLOBAL_TARGET = ['rawWindow', 'rawDocument'];
|
|
1521
|
-
|
|
1522
|
-
|
|
1523
|
-
|
|
1524
|
-
|
|
1525
|
-
|
|
1526
|
-
|
|
1527
|
-
|
|
1528
|
-
*/
|
|
1529
|
-
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';
|
|
1583
|
+
const HIJACK_LOCATION_KEYS = [
|
|
1584
|
+
'host',
|
|
1585
|
+
'hostname',
|
|
1586
|
+
'port',
|
|
1587
|
+
'protocol',
|
|
1588
|
+
'origin',
|
|
1589
|
+
];
|
|
1530
1590
|
|
|
1531
1591
|
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1532
1592
|
// whether use type='module' script
|
|
@@ -1790,16 +1850,16 @@ function fetchScriptsFromHtml(wrapElement, app) {
|
|
|
1790
1850
|
logError(err, app.name);
|
|
1791
1851
|
}, () => {
|
|
1792
1852
|
if (fiberScriptTasks) {
|
|
1793
|
-
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1853
|
+
fiberScriptTasks.push(() => Promise.resolve(app.onLoad({ html: wrapElement })));
|
|
1794
1854
|
serialExecFiberTasks(fiberScriptTasks);
|
|
1795
1855
|
}
|
|
1796
1856
|
else {
|
|
1797
|
-
app.onLoad(wrapElement);
|
|
1857
|
+
app.onLoad({ html: wrapElement });
|
|
1798
1858
|
}
|
|
1799
1859
|
});
|
|
1800
1860
|
}
|
|
1801
1861
|
else {
|
|
1802
|
-
app.onLoad(wrapElement);
|
|
1862
|
+
app.onLoad({ html: wrapElement });
|
|
1803
1863
|
}
|
|
1804
1864
|
}
|
|
1805
1865
|
/**
|
|
@@ -2123,15 +2183,6 @@ function processCode(configs, code, address) {
|
|
|
2123
2183
|
}, code);
|
|
2124
2184
|
}
|
|
2125
2185
|
|
|
2126
|
-
/**
|
|
2127
|
-
* transform html string to dom
|
|
2128
|
-
* @param str string dom
|
|
2129
|
-
*/
|
|
2130
|
-
function getWrapElement(str) {
|
|
2131
|
-
const wrapDiv = pureCreateElement('div');
|
|
2132
|
-
wrapDiv.innerHTML = str;
|
|
2133
|
-
return wrapDiv;
|
|
2134
|
-
}
|
|
2135
2186
|
/**
|
|
2136
2187
|
* Recursively process each child element
|
|
2137
2188
|
* @param parent parent element
|
|
@@ -2188,7 +2239,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2188
2239
|
* @param app app
|
|
2189
2240
|
*/
|
|
2190
2241
|
function extractSourceDom(htmlStr, app) {
|
|
2191
|
-
const wrapElement =
|
|
2242
|
+
const wrapElement = app.parseHtmlString(htmlStr);
|
|
2192
2243
|
const microAppHead = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-head');
|
|
2193
2244
|
const microAppBody = globalEnv.rawElementQuerySelector.call(wrapElement, 'micro-app-body');
|
|
2194
2245
|
if (!microAppHead || !microAppBody) {
|
|
@@ -2206,16 +2257,16 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2206
2257
|
fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult);
|
|
2207
2258
|
}
|
|
2208
2259
|
else if (fiberStyleResult) {
|
|
2209
|
-
fiberStyleResult.then(() => app.onLoad(wrapElement));
|
|
2260
|
+
fiberStyleResult.then(() => app.onLoad({ html: wrapElement }));
|
|
2210
2261
|
}
|
|
2211
2262
|
else {
|
|
2212
|
-
app.onLoad(wrapElement);
|
|
2263
|
+
app.onLoad({ html: wrapElement });
|
|
2213
2264
|
}
|
|
2214
2265
|
if (app.source.scripts.size) {
|
|
2215
2266
|
fetchScriptsFromHtml(wrapElement, app);
|
|
2216
2267
|
}
|
|
2217
2268
|
else {
|
|
2218
|
-
app.onLoad(wrapElement);
|
|
2269
|
+
app.onLoad({ html: wrapElement });
|
|
2219
2270
|
}
|
|
2220
2271
|
}
|
|
2221
2272
|
|
|
@@ -2751,12 +2802,17 @@ function createProxyDocument(appName, sandbox) {
|
|
|
2751
2802
|
const sstEventListenerMap = new Map();
|
|
2752
2803
|
let onClickHandler = null;
|
|
2753
2804
|
let sstOnClickHandler = null;
|
|
2754
|
-
const { rawDocument, rawCreateElement, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
2805
|
+
const { rawDocument, rawCreateElement, rawCreateElementNS, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
2755
2806
|
function createElement(tagName, options) {
|
|
2756
2807
|
const element = rawCreateElement.call(rawDocument, tagName, options);
|
|
2757
2808
|
element.__MICRO_APP_NAME__ = appName;
|
|
2758
2809
|
return element;
|
|
2759
2810
|
}
|
|
2811
|
+
function createElementNS(namespaceURI, name, options) {
|
|
2812
|
+
const element = rawCreateElementNS.call(rawDocument, namespaceURI, name, options);
|
|
2813
|
+
element.__MICRO_APP_NAME__ = appName;
|
|
2814
|
+
return element;
|
|
2815
|
+
}
|
|
2760
2816
|
/**
|
|
2761
2817
|
* TODO:
|
|
2762
2818
|
* 1. listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
@@ -2872,6 +2928,8 @@ function createProxyDocument(appName, sandbox) {
|
|
|
2872
2928
|
// TODO: 转换成数据形式,类似iframe的方式
|
|
2873
2929
|
if (key === 'createElement')
|
|
2874
2930
|
return createElement;
|
|
2931
|
+
if (key === 'createElementNS')
|
|
2932
|
+
return createElementNS;
|
|
2875
2933
|
if (key === Symbol.toStringTag)
|
|
2876
2934
|
return 'ProxyDocument';
|
|
2877
2935
|
if (key === 'defaultView')
|
|
@@ -2968,7 +3026,7 @@ function createMicroDocument(appName, proxyDocument) {
|
|
|
2968
3026
|
function patchWindow(appName, microAppWindow, sandbox) {
|
|
2969
3027
|
patchWindowProperty(microAppWindow);
|
|
2970
3028
|
createProxyWindow(appName, microAppWindow, sandbox);
|
|
2971
|
-
return patchWindowEffect(microAppWindow);
|
|
3029
|
+
return patchWindowEffect(microAppWindow, appName);
|
|
2972
3030
|
}
|
|
2973
3031
|
/**
|
|
2974
3032
|
* rewrite special properties of window
|
|
@@ -2979,7 +3037,7 @@ function patchWindowProperty(microAppWindow) {
|
|
|
2979
3037
|
const rawWindow = globalEnv.rawWindow;
|
|
2980
3038
|
Object.getOwnPropertyNames(rawWindow)
|
|
2981
3039
|
.filter((key) => {
|
|
2982
|
-
return /^on/.test(key) && !
|
|
3040
|
+
return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_WITH.includes(key);
|
|
2983
3041
|
})
|
|
2984
3042
|
.forEach((eventName) => {
|
|
2985
3043
|
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(rawWindow, eventName) || {
|
|
@@ -3009,22 +3067,22 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
|
|
|
3009
3067
|
throttleDeferForSetAppName(appName);
|
|
3010
3068
|
if (Reflect.has(target, key) ||
|
|
3011
3069
|
(isString(key) && /^__MICRO_APP_/.test(key)) ||
|
|
3012
|
-
sandbox.scopeProperties
|
|
3013
|
-
if (
|
|
3070
|
+
includes(sandbox.scopeProperties, key)) {
|
|
3071
|
+
if (includes(RAW_GLOBAL_TARGET, key))
|
|
3014
3072
|
removeDomScope();
|
|
3015
3073
|
return Reflect.get(target, key);
|
|
3016
3074
|
}
|
|
3017
3075
|
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
3018
3076
|
},
|
|
3019
3077
|
set: (target, key, value) => {
|
|
3020
|
-
if (sandbox.
|
|
3078
|
+
if (includes(sandbox.rawWindowScopeKeyList, key)) {
|
|
3021
3079
|
Reflect.set(rawWindow, key, value);
|
|
3022
3080
|
}
|
|
3023
3081
|
else if (
|
|
3024
3082
|
// target.hasOwnProperty has been rewritten
|
|
3025
3083
|
!rawHasOwnProperty.call(target, key) &&
|
|
3026
3084
|
rawHasOwnProperty.call(rawWindow, key) &&
|
|
3027
|
-
!sandbox.scopeProperties
|
|
3085
|
+
!includes(sandbox.scopeProperties, key)) {
|
|
3028
3086
|
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
3029
3087
|
const { configurable, enumerable, writable, set } = descriptor;
|
|
3030
3088
|
// set value because it can be set
|
|
@@ -3037,32 +3095,37 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
|
|
|
3037
3095
|
sandbox.injectedKeys.add(key);
|
|
3038
3096
|
}
|
|
3039
3097
|
else {
|
|
3040
|
-
|
|
3098
|
+
// all scopeProperties will add to injectedKeys, use for key in window (Proxy.has)
|
|
3099
|
+
if (!Reflect.has(target, key) || includes(sandbox.scopeProperties, key)) {
|
|
3100
|
+
sandbox.injectedKeys.add(key);
|
|
3101
|
+
}
|
|
3041
3102
|
Reflect.set(target, key, value);
|
|
3042
3103
|
}
|
|
3043
|
-
if ((sandbox.escapeProperties
|
|
3044
|
-
(
|
|
3104
|
+
if ((includes(sandbox.escapeProperties, key) ||
|
|
3105
|
+
(
|
|
3106
|
+
// TODO: staticEscapeProperties 合并到 escapeProperties
|
|
3107
|
+
includes(sandbox.staticEscapeProperties, key) &&
|
|
3045
3108
|
!Reflect.has(rawWindow, key))) &&
|
|
3046
|
-
!sandbox.scopeProperties
|
|
3109
|
+
!includes(sandbox.scopeProperties, key)) {
|
|
3047
3110
|
!Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
|
|
3048
3111
|
Reflect.set(rawWindow, key, value);
|
|
3049
3112
|
}
|
|
3050
3113
|
return true;
|
|
3051
3114
|
},
|
|
3052
3115
|
has: (target, key) => {
|
|
3053
|
-
|
|
3054
|
-
|
|
3055
|
-
|
|
3056
|
-
|
|
3057
|
-
|
|
3058
|
-
|
|
3059
|
-
|
|
3060
|
-
if (sandbox.
|
|
3061
|
-
return
|
|
3116
|
+
/**
|
|
3117
|
+
* Some keywords, such as Vue, need to meet two conditions at the same time:
|
|
3118
|
+
* 1. window.Vue --> undefined
|
|
3119
|
+
* 2. 'Vue' in window --> false
|
|
3120
|
+
* Issue https://github.com/micro-zoe/micro-app/issues/686
|
|
3121
|
+
*/
|
|
3122
|
+
if (includes(sandbox.scopeProperties, key)) {
|
|
3123
|
+
if (sandbox.injectedKeys.has(key)) {
|
|
3124
|
+
return Reflect.has(target, key); // true
|
|
3062
3125
|
}
|
|
3063
|
-
return key
|
|
3126
|
+
return !!target[key]; // false
|
|
3064
3127
|
}
|
|
3065
|
-
return
|
|
3128
|
+
return Reflect.has(target, key) || Reflect.has(rawWindow, key);
|
|
3066
3129
|
},
|
|
3067
3130
|
// Object.getOwnPropertyDescriptor(window, key)
|
|
3068
3131
|
getOwnPropertyDescriptor: (target, key) => {
|
|
@@ -3107,14 +3170,26 @@ function createProxyWindow(appName, microAppWindow, sandbox) {
|
|
|
3107
3170
|
* Rewrite side-effect events
|
|
3108
3171
|
* @param microAppWindow micro window
|
|
3109
3172
|
*/
|
|
3110
|
-
function patchWindowEffect(microAppWindow) {
|
|
3173
|
+
function patchWindowEffect(microAppWindow, appName) {
|
|
3111
3174
|
const eventListenerMap = new Map();
|
|
3112
3175
|
const sstEventListenerMap = new Map();
|
|
3113
3176
|
const intervalIdMap = new Map();
|
|
3114
3177
|
const timeoutIdMap = new Map();
|
|
3115
3178
|
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawDispatchEvent, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, } = globalEnv;
|
|
3179
|
+
/**
|
|
3180
|
+
* All events will bind to microAppElement or rawWindow
|
|
3181
|
+
* Some special events, such as popstate、load、unmount、appstate-change、statechange..., bind to microAppElement, others bind to rawWindow
|
|
3182
|
+
* NOTE:
|
|
3183
|
+
* 1、At first, microAppWindow = new EventTarget(), but it can not compatible with iOS 14 or below, so microAppElement was used instead. (2024.1.22)
|
|
3184
|
+
* @param type event name
|
|
3185
|
+
* @returns microAppElement/rawWindow
|
|
3186
|
+
*/
|
|
3116
3187
|
function getEventTarget(type) {
|
|
3117
|
-
|
|
3188
|
+
var _a;
|
|
3189
|
+
if (SCOPE_WINDOW_EVENT_OF_WITH.includes(type) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
3190
|
+
return getRootContainer(appInstanceMap.get(appName).container);
|
|
3191
|
+
}
|
|
3192
|
+
return rawWindow;
|
|
3118
3193
|
}
|
|
3119
3194
|
/**
|
|
3120
3195
|
* listener may be null, e.g test-passive
|
|
@@ -3124,6 +3199,7 @@ function patchWindowEffect(microAppWindow) {
|
|
|
3124
3199
|
* window.addEventListener.call(非window, type, listener, options)
|
|
3125
3200
|
*/
|
|
3126
3201
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3202
|
+
type = formatEventType(type, appName);
|
|
3127
3203
|
const listenerList = eventListenerMap.get(type);
|
|
3128
3204
|
if (listenerList) {
|
|
3129
3205
|
listenerList.add(listener);
|
|
@@ -3135,6 +3211,7 @@ function patchWindowEffect(microAppWindow) {
|
|
|
3135
3211
|
rawAddEventListener.call(getEventTarget(type), type, listener, options);
|
|
3136
3212
|
};
|
|
3137
3213
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3214
|
+
type = formatEventType(type, appName);
|
|
3138
3215
|
const listenerList = eventListenerMap.get(type);
|
|
3139
3216
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3140
3217
|
listenerList.delete(listener);
|
|
@@ -3227,42 +3304,39 @@ function patchWindowEffect(microAppWindow) {
|
|
|
3227
3304
|
}
|
|
3228
3305
|
|
|
3229
3306
|
// set micro app state to origin state
|
|
3230
|
-
function setMicroState(appName, microState) {
|
|
3231
|
-
|
|
3232
|
-
|
|
3233
|
-
|
|
3234
|
-
|
|
3235
|
-
|
|
3236
|
-
|
|
3237
|
-
|
|
3238
|
-
|
|
3239
|
-
|
|
3240
|
-
|
|
3241
|
-
|
|
3307
|
+
function setMicroState(appName, microState, targetLocation) {
|
|
3308
|
+
// TODO: 验证native模式下修改state nextjs路由是否正常
|
|
3309
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3310
|
+
const additionalState = {
|
|
3311
|
+
__MICRO_APP_STATE__: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__, {
|
|
3312
|
+
[appName]: {
|
|
3313
|
+
fullPath: targetLocation.pathname + targetLocation.search + targetLocation.hash,
|
|
3314
|
+
state: microState,
|
|
3315
|
+
mode: getRouterMode(appName),
|
|
3316
|
+
}
|
|
3317
|
+
})
|
|
3318
|
+
};
|
|
3319
|
+
// create new state object
|
|
3320
|
+
return assign({}, rawState, additionalState);
|
|
3242
3321
|
}
|
|
3243
3322
|
// delete micro app state form origin state
|
|
3244
3323
|
function removeMicroState(appName, rawState) {
|
|
3245
|
-
if (
|
|
3246
|
-
if (
|
|
3247
|
-
|
|
3248
|
-
|
|
3249
|
-
|
|
3250
|
-
|
|
3251
|
-
delete rawState.microAppState;
|
|
3252
|
-
}
|
|
3324
|
+
if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.__MICRO_APP_STATE__)) {
|
|
3325
|
+
if (!isUndefined(rawState.__MICRO_APP_STATE__[appName])) {
|
|
3326
|
+
delete rawState.__MICRO_APP_STATE__[appName];
|
|
3327
|
+
}
|
|
3328
|
+
if (!Object.keys(rawState.__MICRO_APP_STATE__).length) {
|
|
3329
|
+
delete rawState.__MICRO_APP_STATE__;
|
|
3253
3330
|
}
|
|
3254
|
-
return assign({}, rawState);
|
|
3255
3331
|
}
|
|
3256
|
-
return rawState;
|
|
3332
|
+
return assign({}, rawState);
|
|
3257
3333
|
}
|
|
3258
3334
|
// get micro app state form origin state
|
|
3259
3335
|
function getMicroState(appName) {
|
|
3260
|
-
var _a;
|
|
3336
|
+
var _a, _b;
|
|
3261
3337
|
const rawState = globalEnv.rawWindow.history.state;
|
|
3262
|
-
|
|
3263
|
-
|
|
3264
|
-
}
|
|
3265
|
-
return rawState;
|
|
3338
|
+
// rawState?.__MICRO_APP_STATE__?.[appName]?.state || (isRouterModeCustom(appName) ? rawState : null)
|
|
3339
|
+
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) || (isRouterModeCustom(appName) ? rawState : null);
|
|
3266
3340
|
}
|
|
3267
3341
|
const ENC_AD_RE = /&/g; // %M1
|
|
3268
3342
|
const ENC_EQ_RE = /=/g; // %M2
|
|
@@ -3298,14 +3372,30 @@ function formatQueryAppName(appName) {
|
|
|
3298
3372
|
* @param appName app.name
|
|
3299
3373
|
*/
|
|
3300
3374
|
function getMicroPathFromURL(appName) {
|
|
3301
|
-
var _a, _b;
|
|
3375
|
+
var _a, _b, _c, _d;
|
|
3302
3376
|
const rawLocation = globalEnv.rawWindow.location;
|
|
3303
|
-
|
|
3377
|
+
const rawState = globalEnv.rawWindow.history.state;
|
|
3378
|
+
if (isRouterModeSearch(appName)) {
|
|
3304
3379
|
const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
|
|
3305
3380
|
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)]);
|
|
3306
3381
|
return isString(microPath) ? decodeMicroPath(microPath) : null;
|
|
3307
3382
|
}
|
|
3308
|
-
|
|
3383
|
+
/**
|
|
3384
|
+
* Get fullPath from __MICRO_APP_STATE__
|
|
3385
|
+
* NOTE:
|
|
3386
|
+
* 1. state mode: all base on __MICRO_APP_STATE__
|
|
3387
|
+
* 2. pure mode: navigate by location.xxx may contain one-time information in __MICRO_APP_STATE__
|
|
3388
|
+
* 3. native/scope mode: vue-router@4 will exec replaceState base on state before pushState, like:
|
|
3389
|
+
* history.replaceState(
|
|
3390
|
+
* assign({}, history.state, {...}),
|
|
3391
|
+
* title,
|
|
3392
|
+
* history.state.current, <---
|
|
3393
|
+
* )
|
|
3394
|
+
* when base app jump to another page from child page, it will replace child path with base app path
|
|
3395
|
+
* 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
|
|
3396
|
+
* So we take the fullPath as the standard
|
|
3397
|
+
*/
|
|
3398
|
+
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);
|
|
3309
3399
|
}
|
|
3310
3400
|
/**
|
|
3311
3401
|
* Attach child app fullPath to browser url
|
|
@@ -3313,10 +3403,11 @@ function getMicroPathFromURL(appName) {
|
|
|
3313
3403
|
* @param targetLocation location of child app or rawLocation of window
|
|
3314
3404
|
*/
|
|
3315
3405
|
function setMicroPathToURL(appName, targetLocation) {
|
|
3316
|
-
const
|
|
3406
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
3407
|
+
let targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3317
3408
|
let isAttach2Hash = false;
|
|
3318
|
-
if (
|
|
3319
|
-
let { pathname, search, hash } =
|
|
3409
|
+
if (isRouterModeSearch(appName)) {
|
|
3410
|
+
let { pathname, search, hash } = rawLocation;
|
|
3320
3411
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
3321
3412
|
const encodedMicroPath = encodeMicroPath(targetFullPath);
|
|
3322
3413
|
/**
|
|
@@ -3326,6 +3417,7 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3326
3417
|
// If hash exists and search does not exist, it is considered as a hash route
|
|
3327
3418
|
if (hash && !search) {
|
|
3328
3419
|
isAttach2Hash = true;
|
|
3420
|
+
// TODO: 这里和下面的if判断可以简化一下
|
|
3329
3421
|
if (queryObject.hashQuery) {
|
|
3330
3422
|
queryObject.hashQuery[formatQueryAppName(appName)] = encodedMicroPath;
|
|
3331
3423
|
}
|
|
@@ -3353,6 +3445,9 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3353
3445
|
isAttach2Hash,
|
|
3354
3446
|
};
|
|
3355
3447
|
}
|
|
3448
|
+
if (isRouterModeState(appName) || isRouterModePure(appName)) {
|
|
3449
|
+
targetFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
3450
|
+
}
|
|
3356
3451
|
return {
|
|
3357
3452
|
fullPath: targetFullPath,
|
|
3358
3453
|
isAttach2Hash,
|
|
@@ -3361,13 +3456,12 @@ function setMicroPathToURL(appName, targetLocation) {
|
|
|
3361
3456
|
/**
|
|
3362
3457
|
* Delete child app fullPath from browser url
|
|
3363
3458
|
* @param appName app.name
|
|
3364
|
-
* @param targetLocation target Location, default is rawLocation
|
|
3365
3459
|
*/
|
|
3366
|
-
function removeMicroPathFromURL(appName
|
|
3460
|
+
function removeMicroPathFromURL(appName) {
|
|
3367
3461
|
var _a, _b, _c, _d;
|
|
3368
|
-
let { pathname, search, hash } =
|
|
3462
|
+
let { pathname, search, hash } = globalEnv.rawWindow.location;
|
|
3369
3463
|
let isAttach2Hash = false;
|
|
3370
|
-
if (
|
|
3464
|
+
if (isRouterModeSearch(appName)) {
|
|
3371
3465
|
const queryObject = getQueryObjectFromURL(search, hash);
|
|
3372
3466
|
if ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) {
|
|
3373
3467
|
isAttach2Hash = true;
|
|
@@ -3428,14 +3522,38 @@ function isEffectiveApp(appName) {
|
|
|
3428
3522
|
return !!(app && !app.isPrefetch);
|
|
3429
3523
|
}
|
|
3430
3524
|
/**
|
|
3431
|
-
* router mode
|
|
3432
|
-
* NOTE:
|
|
3433
|
-
|
|
3434
|
-
|
|
3525
|
+
* get router mode of app
|
|
3526
|
+
* NOTE: app maybe undefined
|
|
3527
|
+
*/
|
|
3528
|
+
function getRouterMode(appName) {
|
|
3529
|
+
var _a;
|
|
3530
|
+
return (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.routerMode;
|
|
3531
|
+
}
|
|
3532
|
+
// router mode is search
|
|
3533
|
+
function isRouterModeSearch(appName) {
|
|
3534
|
+
return getRouterMode(appName) === DEFAULT_ROUTER_MODE;
|
|
3535
|
+
}
|
|
3536
|
+
// router mode is state
|
|
3537
|
+
function isRouterModeState(appName) {
|
|
3538
|
+
return getRouterMode(appName) === ROUTER_MODE_STATE;
|
|
3539
|
+
}
|
|
3540
|
+
// router mode is history
|
|
3541
|
+
function isRouterModeNative(appName) {
|
|
3542
|
+
return getRouterMode(appName) === ROUTER_MODE_NATIVE;
|
|
3543
|
+
}
|
|
3544
|
+
// router mode is disable
|
|
3545
|
+
function isRouterModeNativeScope(appName) {
|
|
3546
|
+
return getRouterMode(appName) === ROUTER_MODE_NATIVE_SCOPE;
|
|
3547
|
+
}
|
|
3548
|
+
// router mode is pure
|
|
3549
|
+
function isRouterModePure(appName) {
|
|
3550
|
+
return getRouterMode(appName) === ROUTER_MODE_PURE;
|
|
3551
|
+
}
|
|
3552
|
+
/**
|
|
3553
|
+
* router mode is history or disable
|
|
3435
3554
|
*/
|
|
3436
3555
|
function isRouterModeCustom(appName) {
|
|
3437
|
-
|
|
3438
|
-
return !app || !app.sandBox || app.routerMode === ROUTER_MODE_CUSTOM;
|
|
3556
|
+
return isRouterModeNative(appName) || isRouterModeNativeScope(appName);
|
|
3439
3557
|
}
|
|
3440
3558
|
/**
|
|
3441
3559
|
* get memory router mode of child app
|
|
@@ -3443,21 +3561,21 @@ function isRouterModeCustom(appName) {
|
|
|
3443
3561
|
* 1. if microAppElement exists, it means the app render by the micro-app element
|
|
3444
3562
|
* 2. if microAppElement not exists, it means it is prerender app
|
|
3445
3563
|
* @param mode native config
|
|
3446
|
-
* @param
|
|
3447
|
-
* @returns mode
|
|
3564
|
+
* @param inlineDisableMemoryRouter disable-memory-router set by micro-app element or prerender
|
|
3565
|
+
* @returns router mode
|
|
3448
3566
|
*/
|
|
3449
|
-
function
|
|
3450
|
-
let routerMode;
|
|
3567
|
+
function initRouterMode(mode, inlineDisableMemoryRouter) {
|
|
3451
3568
|
/**
|
|
3452
3569
|
* compatible with disable-memory-router in older versions
|
|
3453
|
-
* if disable-memory-router is true, router-mode will be
|
|
3570
|
+
* if disable-memory-router is true, router-mode will be disable
|
|
3571
|
+
* Priority:
|
|
3572
|
+
* inline disable-memory-router > inline router-mode > global disable-memory-router > global router-mode
|
|
3454
3573
|
*/
|
|
3455
|
-
|
|
3456
|
-
|
|
3457
|
-
|
|
3458
|
-
|
|
3459
|
-
|
|
3460
|
-
}
|
|
3574
|
+
const routerMode = ((inlineDisableMemoryRouter && ROUTER_MODE_NATIVE) ||
|
|
3575
|
+
mode ||
|
|
3576
|
+
(microApp.options['disable-memory-router'] && ROUTER_MODE_NATIVE) ||
|
|
3577
|
+
microApp.options['router-mode'] ||
|
|
3578
|
+
DEFAULT_ROUTER_MODE);
|
|
3461
3579
|
return ROUTER_MODE_LIST.includes(routerMode) ? routerMode : DEFAULT_ROUTER_MODE;
|
|
3462
3580
|
}
|
|
3463
3581
|
|
|
@@ -3481,7 +3599,21 @@ function addHistoryListener(appName) {
|
|
|
3481
3599
|
excludePreRender: true,
|
|
3482
3600
|
}).includes(appName) &&
|
|
3483
3601
|
!e.onlyForBrowser) {
|
|
3602
|
+
/**
|
|
3603
|
+
* TODO: vue-router@4 navigate async when receive popstateEvent, but child may respond to popstateEvent immediately(vue2, react), so when go back throw browser child will not unmount sync, and will respond to popstateEvent before base app, this will cause some problems
|
|
3604
|
+
* __MICRO_APP_BASE_ROUTE__不可控,用户设置的值是随机的且不一定使用,用它作为判断依据太过危险
|
|
3605
|
+
*/
|
|
3606
|
+
// const microAppWindow = appInstanceMap.get(appName)!.sandBox!.microAppWindow
|
|
3607
|
+
// const rawLocation = globalEnv.rawWindow.location
|
|
3608
|
+
// if (
|
|
3609
|
+
// !isRouterModeCustom(appName) ||
|
|
3610
|
+
// !microAppWindow.__MICRO_APP_BASE_ROUTE__ ||
|
|
3611
|
+
// // 主history、子hash,主、子都是hash如何处理
|
|
3612
|
+
// microAppWindow.__MICRO_APP_BASE_ROUTE__.includes('#') ||
|
|
3613
|
+
// `${rawLocation.pathname}/`.startsWith(('/' + microAppWindow.__MICRO_APP_BASE_ROUTE__).replace(/^\/+/, '/'))
|
|
3614
|
+
// ) {
|
|
3484
3615
|
updateMicroLocationWithEvent(appName, getMicroPathFromURL(appName));
|
|
3616
|
+
// }
|
|
3485
3617
|
}
|
|
3486
3618
|
};
|
|
3487
3619
|
rawWindow.addEventListener('popstate', popStateHandler);
|
|
@@ -3529,14 +3661,18 @@ function dispatchPopStateEventToMicroApp(appName, proxyWindow, microAppWindow) {
|
|
|
3529
3661
|
* TODO: test
|
|
3530
3662
|
* angular14 takes e.type as type judgment
|
|
3531
3663
|
* when e.type is popstate-appName popstate event will be invalid
|
|
3664
|
+
* Object.defineProperty(newPopStateEvent, 'type', {
|
|
3665
|
+
* value: 'popstate',
|
|
3666
|
+
* writable: true,
|
|
3667
|
+
* configurable: true,
|
|
3668
|
+
* enumerable: true,
|
|
3669
|
+
* })
|
|
3670
|
+
*/
|
|
3671
|
+
/**
|
|
3672
|
+
* create PopStateEvent named popstate-appName with sub app state
|
|
3673
|
+
* TODO: feeling like there's something wrong, check carefully
|
|
3674
|
+
* 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
|
|
3532
3675
|
*/
|
|
3533
|
-
// Object.defineProperty(newPopStateEvent, 'type', {
|
|
3534
|
-
// value: 'popstate',
|
|
3535
|
-
// writable: true,
|
|
3536
|
-
// configurable: true,
|
|
3537
|
-
// enumerable: true,
|
|
3538
|
-
// })
|
|
3539
|
-
// create PopStateEvent named popstate-appName with sub app state
|
|
3540
3676
|
const newPopStateEvent = new PopStateEvent('popstate', { state: getMicroState(appName) });
|
|
3541
3677
|
microAppWindow.dispatchEvent(newPopStateEvent);
|
|
3542
3678
|
if (!isIframeSandbox(appName)) {
|
|
@@ -3603,7 +3739,7 @@ function dispatchNativeEvent(appName, onlyForBrowser, oldHref) {
|
|
|
3603
3739
|
* create proxyHistory for microApp
|
|
3604
3740
|
* MDN https://developer.mozilla.org/en-US/docs/Web/API/History
|
|
3605
3741
|
* @param appName app name
|
|
3606
|
-
* @param microLocation microApp location
|
|
3742
|
+
* @param microLocation microApp location(with: proxyLocation iframe: iframeWindow.location)
|
|
3607
3743
|
*/
|
|
3608
3744
|
function createMicroHistory(appName, microLocation) {
|
|
3609
3745
|
const rawHistory = globalEnv.rawWindow.history;
|
|
@@ -3614,7 +3750,9 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3614
3750
|
if (isString(rests[2]) || isURL(rests[2])) {
|
|
3615
3751
|
const targetLocation = createURL(rests[2], microLocation.href);
|
|
3616
3752
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3617
|
-
|
|
3753
|
+
if (!isRouterModePure(appName)) {
|
|
3754
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rests[0], targetLocation), rests[1]);
|
|
3755
|
+
}
|
|
3618
3756
|
if (targetFullPath !== microLocation.fullPath) {
|
|
3619
3757
|
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
3620
3758
|
}
|
|
@@ -3627,8 +3765,12 @@ function createMicroHistory(appName, microLocation) {
|
|
|
3627
3765
|
}
|
|
3628
3766
|
const pushState = getMicroHistoryMethod('pushState');
|
|
3629
3767
|
const replaceState = getMicroHistoryMethod('replaceState');
|
|
3630
|
-
if (isIframeSandbox(appName))
|
|
3631
|
-
return {
|
|
3768
|
+
if (isIframeSandbox(appName)) {
|
|
3769
|
+
return {
|
|
3770
|
+
pushState,
|
|
3771
|
+
replaceState,
|
|
3772
|
+
};
|
|
3773
|
+
}
|
|
3632
3774
|
return new Proxy(rawHistory, {
|
|
3633
3775
|
get(target, key) {
|
|
3634
3776
|
if (key === 'state') {
|
|
@@ -3691,12 +3833,8 @@ function navigateWithNativeEvent(appName, methodName, result, onlyForBrowser, st
|
|
|
3691
3833
|
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
3692
3834
|
// navigate with native history method
|
|
3693
3835
|
nativeHistoryNavigate(appName, methodName, result.fullPath, state, title);
|
|
3694
|
-
|
|
3695
|
-
|
|
3696
|
-
* 1. 如果所有模式统一发送popstate事件,则!isRouterModeCustom(appName)要去掉
|
|
3697
|
-
* 2. 如果发送事件,则会导致vue router-view :key='router.path'绑定,无限卸载应用,死循环
|
|
3698
|
-
*/
|
|
3699
|
-
if (oldFullPath !== result.fullPath && !isRouterModeCustom(appName)) {
|
|
3836
|
+
// just search mode will dispatch native event
|
|
3837
|
+
if (oldFullPath !== result.fullPath && isRouterModeSearch(appName)) {
|
|
3700
3838
|
dispatchNativeEvent(appName, onlyForBrowser, oldHref);
|
|
3701
3839
|
}
|
|
3702
3840
|
}
|
|
@@ -3712,22 +3850,22 @@ function attachRouteToBrowserURL(appName, result, state) {
|
|
|
3712
3850
|
navigateWithNativeEvent(appName, 'replaceState', result, true, state);
|
|
3713
3851
|
}
|
|
3714
3852
|
/**
|
|
3715
|
-
* When path is same, keep the
|
|
3716
|
-
* Fix bug of missing
|
|
3853
|
+
* When path is same, keep the __MICRO_APP_STATE__ in history.state
|
|
3854
|
+
* Fix bug of missing __MICRO_APP_STATE__ when base app is next.js or angular
|
|
3717
3855
|
* @param method history.pushState/replaceState
|
|
3718
3856
|
*/
|
|
3719
3857
|
function reWriteHistoryMethod(method) {
|
|
3720
3858
|
const rawWindow = globalEnv.rawWindow;
|
|
3721
3859
|
return function (...rests) {
|
|
3722
3860
|
var _a;
|
|
3723
|
-
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.
|
|
3724
|
-
(!isPlainObject(rests[0]) || !rests[0].
|
|
3861
|
+
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.__MICRO_APP_STATE__) &&
|
|
3862
|
+
(!isPlainObject(rests[0]) || !rests[0].__MICRO_APP_STATE__) &&
|
|
3725
3863
|
(isString(rests[2]) || isURL(rests[2]))) {
|
|
3726
3864
|
const currentHref = rawWindow.location.href;
|
|
3727
3865
|
const targetLocation = createURL(rests[2], currentHref);
|
|
3728
3866
|
if (targetLocation.href === currentHref) {
|
|
3729
3867
|
rests[0] = assign({}, rests[0], {
|
|
3730
|
-
|
|
3868
|
+
__MICRO_APP_STATE__: rawWindow.history.state.__MICRO_APP_STATE__,
|
|
3731
3869
|
});
|
|
3732
3870
|
}
|
|
3733
3871
|
}
|
|
@@ -3743,9 +3881,9 @@ function reWriteHistoryMethod(method) {
|
|
|
3743
3881
|
excludeHiddenApp: true,
|
|
3744
3882
|
excludePreRender: true,
|
|
3745
3883
|
}).forEach(appName => {
|
|
3746
|
-
if (
|
|
3884
|
+
if ((isRouterModeSearch(appName) || isRouterModeState(appName)) && !getMicroPathFromURL(appName)) {
|
|
3747
3885
|
const app = appInstanceMap.get(appName);
|
|
3748
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
3886
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
|
|
3749
3887
|
}
|
|
3750
3888
|
});
|
|
3751
3889
|
// fix bug for nest app
|
|
@@ -3754,7 +3892,7 @@ function reWriteHistoryMethod(method) {
|
|
|
3754
3892
|
}
|
|
3755
3893
|
/**
|
|
3756
3894
|
* rewrite history.pushState/replaceState
|
|
3757
|
-
* used to fix the problem that the
|
|
3895
|
+
* used to fix the problem that the __MICRO_APP_STATE__ maybe missing when mainApp navigate to same path
|
|
3758
3896
|
* e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
|
|
3759
3897
|
*/
|
|
3760
3898
|
function patchHistory() {
|
|
@@ -3777,7 +3915,7 @@ function createRouterApi() {
|
|
|
3777
3915
|
* @param state to.state
|
|
3778
3916
|
*/
|
|
3779
3917
|
function navigateWithRawHistory(appName, methodName, targetLocation, state) {
|
|
3780
|
-
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null));
|
|
3918
|
+
navigateWithNativeEvent(appName, methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, state !== null && state !== void 0 ? state : null, targetLocation));
|
|
3781
3919
|
// clear element scope after navigate
|
|
3782
3920
|
removeDomScope();
|
|
3783
3921
|
}
|
|
@@ -3795,21 +3933,13 @@ function createRouterApi() {
|
|
|
3795
3933
|
const currentFullPath = microLocation.pathname + microLocation.search + microLocation.hash;
|
|
3796
3934
|
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3797
3935
|
if (currentFullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
|
|
3798
|
-
|
|
3799
|
-
|
|
3800
|
-
|
|
3801
|
-
|
|
3802
|
-
|
|
3803
|
-
|
|
3804
|
-
|
|
3805
|
-
* 路由优化方案有两种:
|
|
3806
|
-
* 1、减少对基座的影响,主要是解决vue循环刷新的问题
|
|
3807
|
-
* 2、全局发送popstate事件,解决主、子都是vue3的冲突问题
|
|
3808
|
-
* 两者选一个吧,如果选2,则下面这两行代码可以去掉
|
|
3809
|
-
* NOTE1: history和search模式采用2,这样可以解决vue3的问题,custom采用1,避免vue循环刷新的问题,这样在用户出现问题时各有解决方案。但反过来说,每种方案又分别导致另外的问题,不统一,导致复杂度增高
|
|
3810
|
-
* NOTE2: 关闭虚拟路由,同时发送popstate事件还是无法解决vue3的问题(毕竟history.state理论上还是会冲突),那么就没必要发送popstate事件了。
|
|
3811
|
-
*/
|
|
3812
|
-
if (isRouterModeCustom(appName)) {
|
|
3936
|
+
// pure mode will not call history.pushState/replaceState
|
|
3937
|
+
if (!isRouterModePure(appName)) {
|
|
3938
|
+
const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
|
|
3939
|
+
navigateWithRawHistory(appName, methodName, targetLocation, to.state);
|
|
3940
|
+
}
|
|
3941
|
+
// only search mode will dispatch PopStateEvent to browser
|
|
3942
|
+
if (!isRouterModeSearch(appName)) {
|
|
3813
3943
|
updateMicroLocationWithEvent(appName, targetFullPath);
|
|
3814
3944
|
}
|
|
3815
3945
|
}
|
|
@@ -3834,27 +3964,18 @@ function createRouterApi() {
|
|
|
3834
3964
|
* 2. disable memory-router
|
|
3835
3965
|
*/
|
|
3836
3966
|
/**
|
|
3837
|
-
* TODO:
|
|
3838
|
-
* 1
|
|
3967
|
+
* TODO:
|
|
3968
|
+
* 1、子应用开始渲染但是还没渲染完成,调用跳转改如何处理
|
|
3839
3969
|
* 2、iframe的沙箱还没初始化时执行跳转报错,如何处理。。。
|
|
3840
|
-
* 3、hidden app 是否支持跳转
|
|
3970
|
+
* 3、hidden app、预渲染 app 是否支持跳转 --- 支持(这里还涉及子应用内部跳转的支持)
|
|
3841
3971
|
*/
|
|
3842
3972
|
if (getActiveApps({ excludeHiddenApp: true, excludePreRender: true }).includes(appName)) {
|
|
3843
3973
|
const app = appInstanceMap.get(appName);
|
|
3844
3974
|
resolve(app.sandBox.sandboxReady.then(() => handleNavigate(appName, app, to, replace)));
|
|
3845
3975
|
}
|
|
3846
3976
|
else {
|
|
3847
|
-
reject(logError('
|
|
3977
|
+
reject(logError('导航失败,请确保子应用渲染后再调用此方法'));
|
|
3848
3978
|
}
|
|
3849
|
-
// /**
|
|
3850
|
-
// * app not exit or unmounted, update browser URL with replaceState
|
|
3851
|
-
// * use base app location.origin as baseURL
|
|
3852
|
-
// * 应用不存在或已卸载,依然使用replaceState来更新浏览器地址 -- 不合理
|
|
3853
|
-
// */
|
|
3854
|
-
// /**
|
|
3855
|
-
// * TODO: 应用还没渲染或已经卸载最好不要支持跳转了,我知道这是因为解决一些特殊场景,但这么做是非常反直觉的
|
|
3856
|
-
// * 并且在新版本中有多种路由模式,如果应用不存在,我们根本无法知道是哪种模式,那么这里的操作就无意义了。
|
|
3857
|
-
// */
|
|
3858
3979
|
// const rawLocation = globalEnv.rawWindow.location
|
|
3859
3980
|
// const targetLocation = createURL(to.path, rawLocation.origin)
|
|
3860
3981
|
// const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash
|
|
@@ -3927,9 +4048,9 @@ function createRouterApi() {
|
|
|
3927
4048
|
* 3. router mode is custom
|
|
3928
4049
|
*/
|
|
3929
4050
|
function commonHandlerForAttachToURL(appName) {
|
|
3930
|
-
if (
|
|
4051
|
+
if (isRouterModeSearch(appName) || isRouterModeState(appName)) {
|
|
3931
4052
|
const app = appInstanceMap.get(appName);
|
|
3932
|
-
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName)));
|
|
4053
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, getMicroState(appName), app.sandBox.proxyWindow.location));
|
|
3933
4054
|
}
|
|
3934
4055
|
}
|
|
3935
4056
|
/**
|
|
@@ -4028,94 +4149,6 @@ function createRouterApi() {
|
|
|
4028
4149
|
}
|
|
4029
4150
|
const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
|
|
4030
4151
|
|
|
4031
|
-
const escape2RawWindowKeys = [
|
|
4032
|
-
'getComputedStyle',
|
|
4033
|
-
'visualViewport',
|
|
4034
|
-
'matchMedia',
|
|
4035
|
-
// 'DOMParser',
|
|
4036
|
-
'ResizeObserver',
|
|
4037
|
-
'IntersectionObserver',
|
|
4038
|
-
];
|
|
4039
|
-
const escape2RawWindowRegExpKeys = [
|
|
4040
|
-
/animationFrame$/i,
|
|
4041
|
-
/mutationObserver$/i,
|
|
4042
|
-
/height$|width$/i,
|
|
4043
|
-
/offset$/i,
|
|
4044
|
-
// /event$/i,
|
|
4045
|
-
/selection$/i,
|
|
4046
|
-
/^range/i,
|
|
4047
|
-
/^screen/i,
|
|
4048
|
-
/^scroll/i,
|
|
4049
|
-
/X$|Y$/,
|
|
4050
|
-
];
|
|
4051
|
-
const uniqueDocumentElement = [
|
|
4052
|
-
'body',
|
|
4053
|
-
'head',
|
|
4054
|
-
'html',
|
|
4055
|
-
'title',
|
|
4056
|
-
];
|
|
4057
|
-
const hijackMicroLocationKeys = [
|
|
4058
|
-
'host',
|
|
4059
|
-
'hostname',
|
|
4060
|
-
'port',
|
|
4061
|
-
'protocol',
|
|
4062
|
-
'origin',
|
|
4063
|
-
];
|
|
4064
|
-
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
|
|
4065
|
-
const proxy2RawDocOrShadowKeys = [
|
|
4066
|
-
'childElementCount',
|
|
4067
|
-
'children',
|
|
4068
|
-
'firstElementChild',
|
|
4069
|
-
'firstChild',
|
|
4070
|
-
'lastElementChild',
|
|
4071
|
-
'activeElement',
|
|
4072
|
-
'fullscreenElement',
|
|
4073
|
-
'pictureInPictureElement',
|
|
4074
|
-
'pointerLockElement',
|
|
4075
|
-
'styleSheets',
|
|
4076
|
-
];
|
|
4077
|
-
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
|
|
4078
|
-
const proxy2RawDocOrShadowMethods = [
|
|
4079
|
-
'append',
|
|
4080
|
-
'contains',
|
|
4081
|
-
'replaceChildren',
|
|
4082
|
-
'createRange',
|
|
4083
|
-
'getSelection',
|
|
4084
|
-
'elementFromPoint',
|
|
4085
|
-
'elementsFromPoint',
|
|
4086
|
-
'getAnimations',
|
|
4087
|
-
];
|
|
4088
|
-
// 直接代理到原生document上 (属性)
|
|
4089
|
-
const proxy2RawDocumentKeys = [
|
|
4090
|
-
'characterSet',
|
|
4091
|
-
'compatMode',
|
|
4092
|
-
'contentType',
|
|
4093
|
-
'designMode',
|
|
4094
|
-
'dir',
|
|
4095
|
-
'doctype',
|
|
4096
|
-
'embeds',
|
|
4097
|
-
'fullscreenEnabled',
|
|
4098
|
-
'hidden',
|
|
4099
|
-
'implementation',
|
|
4100
|
-
'lastModified',
|
|
4101
|
-
'pictureInPictureEnabled',
|
|
4102
|
-
'plugins',
|
|
4103
|
-
'readyState',
|
|
4104
|
-
'referrer',
|
|
4105
|
-
'visibilityState',
|
|
4106
|
-
'fonts',
|
|
4107
|
-
];
|
|
4108
|
-
// 直接代理到原生document上 (方法)
|
|
4109
|
-
const proxy2RawDocumentMethods = [
|
|
4110
|
-
'execCommand',
|
|
4111
|
-
'createRange',
|
|
4112
|
-
'exitFullscreen',
|
|
4113
|
-
'exitPictureInPicture',
|
|
4114
|
-
'getElementsByTagNameNS',
|
|
4115
|
-
'hasFocus',
|
|
4116
|
-
'prepend',
|
|
4117
|
-
];
|
|
4118
|
-
|
|
4119
4152
|
// origin is readonly, so we ignore when updateMicroLocation
|
|
4120
4153
|
const locationKeys = ['href', 'pathname', 'search', 'hash', 'host', 'hostname', 'port', 'protocol', 'search'];
|
|
4121
4154
|
// origin, fullPath is necessary for guardLocation
|
|
@@ -4160,38 +4193,46 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4160
4193
|
const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
|
|
4161
4194
|
// if disable memory-router, navigate directly through rawLocation
|
|
4162
4195
|
if (!isRouterModeCustom(appName)) {
|
|
4196
|
+
methodName = isRouterModePure(appName) ? 'replaceState' : methodName;
|
|
4163
4197
|
/**
|
|
4164
4198
|
* change hash with location.href will not trigger the browser reload
|
|
4165
4199
|
* so we use pushState & reload to imitate href behavior
|
|
4166
4200
|
* NOTE:
|
|
4167
|
-
* 1. if child app only change hash, it
|
|
4168
|
-
* 2. if address is same and has hash, it
|
|
4201
|
+
* 1. if child app only change hash, it will not reload browser
|
|
4202
|
+
* 2. if address is same and has hash, it will not add route stack
|
|
4169
4203
|
*/
|
|
4170
4204
|
if (targetLocation.pathname === proxyLocation.pathname &&
|
|
4171
4205
|
targetLocation.search === proxyLocation.search) {
|
|
4172
4206
|
let oldHref = null;
|
|
4173
|
-
if
|
|
4174
|
-
|
|
4207
|
+
// NOTE: if pathname & search is same, it should record router info to history.state in pure mode
|
|
4208
|
+
if (targetLocation.hash !== proxyLocation.hash || isRouterModePure(appName)) {
|
|
4209
|
+
// search mode only
|
|
4210
|
+
if (setMicroPathResult.isAttach2Hash) {
|
|
4175
4211
|
oldHref = rawLocation.href;
|
|
4176
|
-
|
|
4212
|
+
}
|
|
4213
|
+
// if router mode is pure and targetLocation.hash exist, it will not call nativeHistoryNavigate
|
|
4214
|
+
if (!isRouterModePure(appName) || !targetLocation.hash) {
|
|
4215
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4216
|
+
}
|
|
4177
4217
|
}
|
|
4178
4218
|
if (targetLocation.hash) {
|
|
4179
|
-
|
|
4219
|
+
if (isRouterModeSearch(appName)) {
|
|
4220
|
+
dispatchNativeEvent(appName, false, oldHref);
|
|
4221
|
+
}
|
|
4222
|
+
else {
|
|
4223
|
+
updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
|
|
4224
|
+
}
|
|
4180
4225
|
}
|
|
4181
4226
|
else {
|
|
4182
4227
|
reload();
|
|
4183
4228
|
}
|
|
4184
4229
|
return void 0;
|
|
4185
|
-
/**
|
|
4186
|
-
* when baseApp is hash router, address change of child can not reload browser
|
|
4187
|
-
* so we imitate behavior of browser (reload) manually
|
|
4188
|
-
*/
|
|
4189
|
-
}
|
|
4190
|
-
else if (setMicroPathResult.isAttach2Hash) {
|
|
4191
|
-
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath);
|
|
4192
|
-
reload();
|
|
4193
|
-
return void 0;
|
|
4194
4230
|
}
|
|
4231
|
+
// when pathname or search change, simulate behavior of browser (reload) manually
|
|
4232
|
+
// TODO: state模式下pushState会带上上一个页面的state,会不会有问题,尤其是vue3,应不应该将主应用的state设置为null
|
|
4233
|
+
nativeHistoryNavigate(appName, methodName, setMicroPathResult.fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4234
|
+
reload();
|
|
4235
|
+
return void 0;
|
|
4195
4236
|
}
|
|
4196
4237
|
return setMicroPathResult.fullPath;
|
|
4197
4238
|
}
|
|
@@ -4216,7 +4257,9 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4216
4257
|
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
4217
4258
|
* search: ?query ==> ?query#hash
|
|
4218
4259
|
*/
|
|
4219
|
-
nativeHistoryNavigate(appName, targetLocation[key] === proxyLocation[key]
|
|
4260
|
+
nativeHistoryNavigate(appName, (targetLocation[key] === proxyLocation[key] || isRouterModePure(appName))
|
|
4261
|
+
? 'replaceState'
|
|
4262
|
+
: 'pushState', setMicroPathToURL(appName, targetLocation).fullPath, !isRouterModeSearch(appName) ? setMicroState(appName, null, targetLocation) : null);
|
|
4220
4263
|
reload();
|
|
4221
4264
|
}
|
|
4222
4265
|
}
|
|
@@ -4245,16 +4288,6 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4245
4288
|
const proxyLocation = new Proxy({}, {
|
|
4246
4289
|
get: (_, key) => {
|
|
4247
4290
|
const target = getTarget();
|
|
4248
|
-
if (isIframe) {
|
|
4249
|
-
// host hostname port protocol
|
|
4250
|
-
if (hijackMicroLocationKeys.includes(key)) {
|
|
4251
|
-
return childStaticLocation[key];
|
|
4252
|
-
}
|
|
4253
|
-
if (key === 'href') {
|
|
4254
|
-
// do not use target, because target may be deleted
|
|
4255
|
-
return target[key].replace(browserHost, childHost);
|
|
4256
|
-
}
|
|
4257
|
-
}
|
|
4258
4291
|
if (key === 'assign')
|
|
4259
4292
|
return assign;
|
|
4260
4293
|
if (key === 'replace')
|
|
@@ -4263,21 +4296,47 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4263
4296
|
return reload;
|
|
4264
4297
|
if (key === 'self')
|
|
4265
4298
|
return target;
|
|
4299
|
+
if (key === 'fullPath')
|
|
4300
|
+
return target.fullPath;
|
|
4301
|
+
/**
|
|
4302
|
+
* Special keys: host, hostname, port, protocol, origin, href
|
|
4303
|
+
* NOTE:
|
|
4304
|
+
* 1. In native mode this keys point to browser, in other mode this keys point to child app origin
|
|
4305
|
+
* 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
|
|
4306
|
+
* 3. In other modes, origin points to child app
|
|
4307
|
+
*/
|
|
4308
|
+
if (HIJACK_LOCATION_KEYS.includes(key)) {
|
|
4309
|
+
if (isRouterModeNative(appName)) {
|
|
4310
|
+
return rawLocation[key];
|
|
4311
|
+
}
|
|
4312
|
+
if (isIframe) {
|
|
4313
|
+
return childStaticLocation[key];
|
|
4314
|
+
}
|
|
4315
|
+
}
|
|
4316
|
+
if (key === 'href') {
|
|
4317
|
+
if (isRouterModeNative(appName)) {
|
|
4318
|
+
return target[key].replace(target.origin, rawLocation.origin);
|
|
4319
|
+
}
|
|
4320
|
+
if (isIframe) {
|
|
4321
|
+
// target may be deleted
|
|
4322
|
+
return target[key].replace(browserHost, childHost);
|
|
4323
|
+
}
|
|
4324
|
+
}
|
|
4266
4325
|
return bindFunctionToRawTarget(Reflect.get(target, key), target, 'LOCATION');
|
|
4267
4326
|
},
|
|
4268
4327
|
set: (_, key, value) => {
|
|
4269
4328
|
if (isEffectiveApp(appName)) {
|
|
4270
4329
|
const target = getTarget();
|
|
4271
4330
|
if (key === 'href') {
|
|
4272
|
-
const targetPath = commonHandler(value, 'pushState');
|
|
4273
4331
|
/**
|
|
4274
4332
|
* In vite, targetPath without origin will be completed with child origin
|
|
4275
4333
|
* So we use browser origin to complete targetPath to avoid this problem
|
|
4276
|
-
*
|
|
4277
|
-
*
|
|
4278
|
-
*
|
|
4279
|
-
*
|
|
4334
|
+
* NOTE:
|
|
4335
|
+
* 1. history mode & value is childOrigin + path ==> jump to browserOrigin + path
|
|
4336
|
+
* 2. disable mode & value is childOrigin + path ==> jump to childOrigin + path
|
|
4337
|
+
* 3. search mode & value is browserOrigin + path ==> jump to browserOrigin + path
|
|
4280
4338
|
*/
|
|
4339
|
+
const targetPath = commonHandler(value, 'pushState');
|
|
4281
4340
|
if (targetPath) {
|
|
4282
4341
|
rawLocation.href = createURL(targetPath, rawLocation.origin).href;
|
|
4283
4342
|
}
|
|
@@ -4309,7 +4368,12 @@ function createMicroLocation(appName, url, microAppWindow, childStaticLocation,
|
|
|
4309
4368
|
const targetLocation = createURL(targetPath, url);
|
|
4310
4369
|
// The same hash will not trigger popStateEvent
|
|
4311
4370
|
if (targetLocation.hash !== proxyLocation.hash) {
|
|
4312
|
-
|
|
4371
|
+
if (!isRouterModePure(appName)) {
|
|
4372
|
+
navigateWithNativeEvent(appName, 'pushState', setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, null, targetLocation));
|
|
4373
|
+
}
|
|
4374
|
+
if (!isRouterModeSearch(appName)) {
|
|
4375
|
+
updateMicroLocationWithEvent(appName, targetLocation.pathname + targetLocation.search + targetLocation.hash);
|
|
4376
|
+
}
|
|
4313
4377
|
}
|
|
4314
4378
|
}
|
|
4315
4379
|
}
|
|
@@ -4362,9 +4426,11 @@ function updateMicroLocation(appName, path, microLocation, type) {
|
|
|
4362
4426
|
(_a = microAppWindow.rawReplaceState) === null || _a === void 0 ? void 0 : _a.call(microAppWindow.history, getMicroState(appName), '', newLocation.href);
|
|
4363
4427
|
}
|
|
4364
4428
|
else {
|
|
4365
|
-
|
|
4366
|
-
|
|
4429
|
+
let targetHref = newLocation.href;
|
|
4430
|
+
if (microLocation.self.origin !== newLocation.origin) {
|
|
4431
|
+
targetHref = targetHref.replace(newLocation.origin, microLocation.self.origin);
|
|
4367
4432
|
}
|
|
4433
|
+
microLocation.self.href = targetHref;
|
|
4368
4434
|
}
|
|
4369
4435
|
// update latest values of microLocation to `to`
|
|
4370
4436
|
const to = createGuardLocation(appName, microLocation);
|
|
@@ -4374,15 +4440,6 @@ function updateMicroLocation(appName, path, microLocation, type) {
|
|
|
4374
4440
|
}
|
|
4375
4441
|
}
|
|
4376
4442
|
|
|
4377
|
-
/**
|
|
4378
|
-
* TODO: 关于关闭虚拟路由系统的临时笔记 - 即custom模式,虚拟路由不支持关闭
|
|
4379
|
-
* 1. with沙箱关闭虚拟路由最好和iframe保持一致
|
|
4380
|
-
* 2. default-page无法使用,但是用基座的地址可以实现一样的效果
|
|
4381
|
-
* 3. keep-router-state功能失效,因为始终为true
|
|
4382
|
-
* 4. 基座控制子应用跳转地址改变,正确的值为:baseRoute + 子应用地址,这要在文档中说明,否则很容易出错,确实也很难理解
|
|
4383
|
-
* 5. 是否需要发送popstate事件,为了减小对基座的影响,现在不发送
|
|
4384
|
-
* 6. 关闭后导致的vue3路由冲突问题需要在文档中明确指出(2处:在关闭虚拟路由系统的配置那里着重说明,在vue常见问题中说明)
|
|
4385
|
-
*/
|
|
4386
4443
|
/**
|
|
4387
4444
|
* The router system has two operations: read and write
|
|
4388
4445
|
* Read through location and write through history & location
|
|
@@ -4407,6 +4464,9 @@ function initRouteStateWithURL(appName, microLocation, defaultPage) {
|
|
|
4407
4464
|
const microPath = getMicroPathFromURL(appName);
|
|
4408
4465
|
if (microPath) {
|
|
4409
4466
|
updateMicroLocation(appName, microPath, microLocation, 'auto');
|
|
4467
|
+
if (isRouterModePure(appName)) {
|
|
4468
|
+
removePathFromBrowser(appName);
|
|
4469
|
+
}
|
|
4410
4470
|
}
|
|
4411
4471
|
else {
|
|
4412
4472
|
updateBrowserURLWithLocation(appName, microLocation, defaultPage);
|
|
@@ -4422,8 +4482,10 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4422
4482
|
// update microLocation with defaultPage
|
|
4423
4483
|
if (defaultPage)
|
|
4424
4484
|
updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
|
|
4425
|
-
|
|
4426
|
-
|
|
4485
|
+
if (!isRouterModePure(appName)) {
|
|
4486
|
+
// attach microApp route info to browser URL
|
|
4487
|
+
attachRouteToBrowserURL(appName, setMicroPathToURL(appName, microLocation), setMicroState(appName, null, microLocation));
|
|
4488
|
+
}
|
|
4427
4489
|
// trigger guards after change browser URL
|
|
4428
4490
|
autoTriggerNavigationGuard(appName, microLocation);
|
|
4429
4491
|
}
|
|
@@ -4435,11 +4497,12 @@ function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
|
4435
4497
|
* @param keepRouteState keep-router-state is only used to control whether to clear the location of microApp, default is false
|
|
4436
4498
|
*/
|
|
4437
4499
|
function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
|
|
4438
|
-
|
|
4439
|
-
|
|
4440
|
-
|
|
4441
|
-
|
|
4442
|
-
|
|
4500
|
+
// TODO: keep-router-state 功能太弱,是否可以增加优先级,或者去掉
|
|
4501
|
+
if (!keepRouteState && !isRouterModeCustom(appName)) {
|
|
4502
|
+
const { pathname, search, hash } = createURL(url);
|
|
4503
|
+
updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
|
|
4504
|
+
}
|
|
4505
|
+
if (!isRouterModePure(appName)) {
|
|
4443
4506
|
removePathFromBrowser(appName);
|
|
4444
4507
|
}
|
|
4445
4508
|
clearRouterWhenUnmount(appName);
|
|
@@ -4452,10 +4515,10 @@ function removePathFromBrowser(appName) {
|
|
|
4452
4515
|
attachRouteToBrowserURL(appName, removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
4453
4516
|
}
|
|
4454
4517
|
|
|
4455
|
-
class
|
|
4518
|
+
class BaseSandbox {
|
|
4456
4519
|
constructor() {
|
|
4457
4520
|
// keys that can only assigned to rawWindow
|
|
4458
|
-
this.
|
|
4521
|
+
this.rawWindowScopeKeyList = [
|
|
4459
4522
|
'location',
|
|
4460
4523
|
];
|
|
4461
4524
|
// keys that can escape to rawWindow
|
|
@@ -4468,7 +4531,18 @@ class Adapter {
|
|
|
4468
4531
|
'webpackJsonp',
|
|
4469
4532
|
'webpackHotUpdate',
|
|
4470
4533
|
'Vue',
|
|
4534
|
+
// TODO: 是否可以和constants/SCOPE_WINDOW_ON_EVENT合并
|
|
4535
|
+
'onpopstate',
|
|
4536
|
+
'onhashchange',
|
|
4471
4537
|
];
|
|
4538
|
+
// Properties that can only get and set in microAppWindow, will not escape to rawWindow
|
|
4539
|
+
this.scopeProperties = Array.from(this.staticScopeProperties);
|
|
4540
|
+
// Properties that can be escape to rawWindow
|
|
4541
|
+
this.escapeProperties = [];
|
|
4542
|
+
// Properties newly added to microAppWindow
|
|
4543
|
+
this.injectedKeys = new Set();
|
|
4544
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
4545
|
+
this.escapeKeys = new Set();
|
|
4472
4546
|
this.injectReactHMRProperty();
|
|
4473
4547
|
}
|
|
4474
4548
|
// adapter for react
|
|
@@ -4486,6 +4560,14 @@ class Adapter {
|
|
|
4486
4560
|
}
|
|
4487
4561
|
}
|
|
4488
4562
|
}
|
|
4563
|
+
/**
|
|
4564
|
+
* TODO:
|
|
4565
|
+
* 1、将class Adapter去掉,改为CustomWindow,或者让CustomWindow继承Adapter
|
|
4566
|
+
* 2、with沙箱中的常量放入CustomWindow,虽然和iframe沙箱不一致,但更合理
|
|
4567
|
+
* 修改时机:在iframe沙箱支持插件后再修改
|
|
4568
|
+
*/
|
|
4569
|
+
class CustomWindow {
|
|
4570
|
+
}
|
|
4489
4571
|
// Fix conflict of babel-polyfill@6.x
|
|
4490
4572
|
function fixBabelPolyfill6() {
|
|
4491
4573
|
if (globalEnv.rawWindow._babelPolyfill)
|
|
@@ -4544,6 +4626,7 @@ function updateElementInfo(node, appName) {
|
|
|
4544
4626
|
rawDefineProperties(node, {
|
|
4545
4627
|
baseURI: {
|
|
4546
4628
|
configurable: true,
|
|
4629
|
+
// if disable-memory-router or router-mode='disable', href point to base app
|
|
4547
4630
|
get: () => proxyWindow.location.href,
|
|
4548
4631
|
},
|
|
4549
4632
|
__MICRO_APP_NAME__: {
|
|
@@ -4552,58 +4635,9 @@ function updateElementInfo(node, appName) {
|
|
|
4552
4635
|
value: appName,
|
|
4553
4636
|
},
|
|
4554
4637
|
});
|
|
4555
|
-
if (isIframeSandbox(appName)) {
|
|
4556
|
-
/**
|
|
4557
|
-
* If HTML built-in node belongs to base app, it needs to be handled separately for parentNode
|
|
4558
|
-
* Fix error for nuxt@2.x + ElementUI@2.x
|
|
4559
|
-
*/
|
|
4560
|
-
if (node instanceof globalEnv.rawRootNode) {
|
|
4561
|
-
rawDefineProperty(node, 'parentNode', {
|
|
4562
|
-
configurable: true,
|
|
4563
|
-
get: createGetterForIframeParentNode(appName, globalEnv.rawParentNodeDesc, true)
|
|
4564
|
-
});
|
|
4565
|
-
}
|
|
4566
|
-
}
|
|
4567
4638
|
}
|
|
4568
4639
|
return node;
|
|
4569
4640
|
}
|
|
4570
|
-
/**
|
|
4571
|
-
* patch iframe node parentNode
|
|
4572
|
-
* Scenes:
|
|
4573
|
-
* 1. iframe common node: patch Node.prototype.parentNode to hijack parentNode
|
|
4574
|
-
* 2. iframe HTML built-in node: belongs to base app, we should rewrite parentNode for every built-in node
|
|
4575
|
-
* NOTE:
|
|
4576
|
-
* 1. HTML built-in node parentNode cannot point to raw body, otherwise Vue2 will render failed
|
|
4577
|
-
* @param appName app name
|
|
4578
|
-
* @param parentNode parentNode Descriptor of iframe or browser
|
|
4579
|
-
* @param HTMLBuildInNode is HTML built-in node
|
|
4580
|
-
*/
|
|
4581
|
-
function createGetterForIframeParentNode(appName, parentNodeDesc, HTMLBuildInNode) {
|
|
4582
|
-
return function () {
|
|
4583
|
-
var _a, _b, _c;
|
|
4584
|
-
/**
|
|
4585
|
-
* set current appName for hijack parentNode of html
|
|
4586
|
-
* NOTE:
|
|
4587
|
-
* 1. Is there a problem with setting the current appName in iframe mode
|
|
4588
|
-
*/
|
|
4589
|
-
throttleDeferForSetAppName(appName);
|
|
4590
|
-
const result = parentNodeDesc.get.call(this);
|
|
4591
|
-
/**
|
|
4592
|
-
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
4593
|
-
* Scenes:
|
|
4594
|
-
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
4595
|
-
* if (this.popperElm.parentNode === document.body) ...
|
|
4596
|
-
* WARNING:
|
|
4597
|
-
* Will it cause other problems ?
|
|
4598
|
-
* e.g. target.parentNode.remove(target)
|
|
4599
|
-
*/
|
|
4600
|
-
if (!HTMLBuildInNode &&
|
|
4601
|
-
isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
4602
|
-
return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
|
|
4603
|
-
}
|
|
4604
|
-
return result;
|
|
4605
|
-
};
|
|
4606
|
-
}
|
|
4607
4641
|
|
|
4608
4642
|
/**
|
|
4609
4643
|
* https://developer.mozilla.org/en-US/docs/Web/API/fetch
|
|
@@ -4707,23 +4741,12 @@ function useMicroEventSource() {
|
|
|
4707
4741
|
}
|
|
4708
4742
|
|
|
4709
4743
|
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
4710
|
-
class WithSandBox {
|
|
4744
|
+
class WithSandBox extends BaseSandbox {
|
|
4711
4745
|
constructor(appName, url) {
|
|
4746
|
+
super();
|
|
4712
4747
|
this.active = false;
|
|
4713
|
-
|
|
4714
|
-
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
4715
|
-
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
4716
|
-
*/
|
|
4717
|
-
this.scopeProperties = [];
|
|
4718
|
-
// Properties that can be escape to rawWindow
|
|
4719
|
-
this.escapeProperties = [];
|
|
4720
|
-
// Properties escape to rawWindow, cleared when unmount
|
|
4721
|
-
this.escapeKeys = new Set();
|
|
4722
|
-
// Properties newly added to microAppWindow
|
|
4723
|
-
this.injectedKeys = new Set();
|
|
4724
|
-
this.microAppWindow = new EventTarget(); // Proxy target
|
|
4748
|
+
this.microAppWindow = new CustomWindow(); // Proxy target
|
|
4725
4749
|
this.patchWith((resolve) => {
|
|
4726
|
-
this.adapter = new Adapter();
|
|
4727
4750
|
// get scopeProperties and escapeProperties from plugins
|
|
4728
4751
|
this.getSpecialProperties(appName);
|
|
4729
4752
|
// create location, history for child app
|
|
@@ -4732,6 +4755,8 @@ class WithSandBox {
|
|
|
4732
4755
|
this.windowEffect = patchWindow(appName, this.microAppWindow, this);
|
|
4733
4756
|
// patch document of child app
|
|
4734
4757
|
this.documentEffect = patchDocument(appName, this.microAppWindow, this);
|
|
4758
|
+
// properties associated with the native window
|
|
4759
|
+
this.setMappingPropertiesWithRawDescriptor(this.microAppWindow);
|
|
4735
4760
|
// inject global properties
|
|
4736
4761
|
this.initStaticGlobalKeys(appName, url, this.microAppWindow);
|
|
4737
4762
|
resolve();
|
|
@@ -4820,6 +4845,7 @@ class WithSandBox {
|
|
|
4820
4845
|
}
|
|
4821
4846
|
/**
|
|
4822
4847
|
* inject global properties to microAppWindow
|
|
4848
|
+
* TODO: 设置为只读变量
|
|
4823
4849
|
* @param appName app name
|
|
4824
4850
|
* @param url app url
|
|
4825
4851
|
* @param microAppWindow micro window
|
|
@@ -4833,6 +4859,7 @@ class WithSandBox {
|
|
|
4833
4859
|
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
4834
4860
|
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
4835
4861
|
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
4862
|
+
microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
4836
4863
|
microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
4837
4864
|
microAppWindow.__MICRO_APP_SANDBOX_TYPE__ = 'with';
|
|
4838
4865
|
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
@@ -4842,7 +4869,6 @@ class WithSandBox {
|
|
|
4842
4869
|
pureCreateElement,
|
|
4843
4870
|
router,
|
|
4844
4871
|
});
|
|
4845
|
-
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
4846
4872
|
}
|
|
4847
4873
|
/**
|
|
4848
4874
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -4925,7 +4951,6 @@ class WithSandBox {
|
|
|
4925
4951
|
*/
|
|
4926
4952
|
getSpecialProperties(appName) {
|
|
4927
4953
|
var _a;
|
|
4928
|
-
this.scopeProperties = this.scopeProperties.concat(this.adapter.staticScopeProperties);
|
|
4929
4954
|
if (isPlainObject(microApp.options.plugins)) {
|
|
4930
4955
|
this.commonActionForSpecialProperties(microApp.options.plugins.global);
|
|
4931
4956
|
this.commonActionForSpecialProperties((_a = microApp.options.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
@@ -4967,9 +4992,10 @@ class WithSandBox {
|
|
|
4967
4992
|
topValue = rawWindow.top;
|
|
4968
4993
|
parentValue = rawWindow.parent;
|
|
4969
4994
|
}
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4995
|
+
rawDefineProperties(microAppWindow, {
|
|
4996
|
+
top: this.createDescriptorForMicroAppWindow('top', topValue),
|
|
4997
|
+
parent: this.createDescriptorForMicroAppWindow('parent', parentValue),
|
|
4998
|
+
});
|
|
4973
4999
|
GLOBAL_KEY_TO_WINDOW.forEach((key) => {
|
|
4974
5000
|
rawDefineProperty(microAppWindow, key, this.createDescriptorForMicroAppWindow(key, this.proxyWindow));
|
|
4975
5001
|
});
|
|
@@ -5134,13 +5160,29 @@ class WithSandBox {
|
|
|
5134
5160
|
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5135
5161
|
|
|
5136
5162
|
function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
5137
|
-
const
|
|
5163
|
+
const rawHistory = globalEnv.rawWindow.history;
|
|
5164
|
+
const childStaticLocation = createURL(url);
|
|
5138
5165
|
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
5139
5166
|
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
5140
5167
|
// rewrite microAppWindow.history
|
|
5141
5168
|
const microHistory = microAppWindow.history;
|
|
5169
|
+
// save history.replaceState, it will be used in updateMicroLocation
|
|
5142
5170
|
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5171
|
+
// rewrite microAppWindow.history
|
|
5143
5172
|
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5173
|
+
// scrollRestoration proxy to rawHistory
|
|
5174
|
+
rawDefineProperties(microHistory, {
|
|
5175
|
+
scrollRestoration: {
|
|
5176
|
+
configurable: true,
|
|
5177
|
+
enumerable: true,
|
|
5178
|
+
get() {
|
|
5179
|
+
return rawHistory.scrollRestoration;
|
|
5180
|
+
},
|
|
5181
|
+
set(value) {
|
|
5182
|
+
rawHistory.scrollRestoration = value;
|
|
5183
|
+
}
|
|
5184
|
+
}
|
|
5185
|
+
});
|
|
5144
5186
|
/**
|
|
5145
5187
|
* Init microLocation before exec sandbox.start
|
|
5146
5188
|
* NOTE:
|
|
@@ -5152,6 +5194,87 @@ function patchRouter(appName, url, microAppWindow, browserHost) {
|
|
|
5152
5194
|
return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
5153
5195
|
}
|
|
5154
5196
|
|
|
5197
|
+
const escape2RawWindowKeys = [
|
|
5198
|
+
'getComputedStyle',
|
|
5199
|
+
'visualViewport',
|
|
5200
|
+
'matchMedia',
|
|
5201
|
+
// 'DOMParser',
|
|
5202
|
+
'ResizeObserver',
|
|
5203
|
+
'IntersectionObserver',
|
|
5204
|
+
];
|
|
5205
|
+
const escape2RawWindowRegExpKeys = [
|
|
5206
|
+
/animationFrame$/i,
|
|
5207
|
+
/mutationObserver$/i,
|
|
5208
|
+
/height$|width$/i,
|
|
5209
|
+
/offset$/i,
|
|
5210
|
+
// /event$/i,
|
|
5211
|
+
/selection$/i,
|
|
5212
|
+
/^range/i,
|
|
5213
|
+
/^screen/i,
|
|
5214
|
+
/^scroll/i,
|
|
5215
|
+
/X$|Y$/,
|
|
5216
|
+
];
|
|
5217
|
+
const uniqueDocumentElement = [
|
|
5218
|
+
'body',
|
|
5219
|
+
'head',
|
|
5220
|
+
'html',
|
|
5221
|
+
'title',
|
|
5222
|
+
];
|
|
5223
|
+
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (属性)
|
|
5224
|
+
const proxy2RawDocOrShadowKeys = [
|
|
5225
|
+
'childElementCount',
|
|
5226
|
+
'children',
|
|
5227
|
+
'firstElementChild',
|
|
5228
|
+
'firstChild',
|
|
5229
|
+
'lastElementChild',
|
|
5230
|
+
'activeElement',
|
|
5231
|
+
'fullscreenElement',
|
|
5232
|
+
'pictureInPictureElement',
|
|
5233
|
+
'pointerLockElement',
|
|
5234
|
+
'styleSheets',
|
|
5235
|
+
];
|
|
5236
|
+
// 有shadowRoot则代理到shadowRoot否则代理到原生document上 (方法)
|
|
5237
|
+
const proxy2RawDocOrShadowMethods = [
|
|
5238
|
+
'append',
|
|
5239
|
+
'contains',
|
|
5240
|
+
'replaceChildren',
|
|
5241
|
+
'createRange',
|
|
5242
|
+
'getSelection',
|
|
5243
|
+
'elementFromPoint',
|
|
5244
|
+
'elementsFromPoint',
|
|
5245
|
+
'getAnimations',
|
|
5246
|
+
];
|
|
5247
|
+
// 直接代理到原生document上 (属性)
|
|
5248
|
+
const proxy2RawDocumentKeys = [
|
|
5249
|
+
'characterSet',
|
|
5250
|
+
'compatMode',
|
|
5251
|
+
'contentType',
|
|
5252
|
+
'designMode',
|
|
5253
|
+
'dir',
|
|
5254
|
+
'doctype',
|
|
5255
|
+
'embeds',
|
|
5256
|
+
'fullscreenEnabled',
|
|
5257
|
+
'hidden',
|
|
5258
|
+
'implementation',
|
|
5259
|
+
'lastModified',
|
|
5260
|
+
'pictureInPictureEnabled',
|
|
5261
|
+
'plugins',
|
|
5262
|
+
'readyState',
|
|
5263
|
+
'referrer',
|
|
5264
|
+
'visibilityState',
|
|
5265
|
+
'fonts',
|
|
5266
|
+
];
|
|
5267
|
+
// 直接代理到原生document上 (方法)
|
|
5268
|
+
const proxy2RawDocumentMethods = [
|
|
5269
|
+
'execCommand',
|
|
5270
|
+
'createRange',
|
|
5271
|
+
'exitFullscreen',
|
|
5272
|
+
'exitPictureInPicture',
|
|
5273
|
+
'getElementsByTagNameNS',
|
|
5274
|
+
'hasFocus',
|
|
5275
|
+
'prepend',
|
|
5276
|
+
];
|
|
5277
|
+
|
|
5155
5278
|
/**
|
|
5156
5279
|
* patch window of child app
|
|
5157
5280
|
* @param appName app name
|
|
@@ -5199,7 +5322,7 @@ function patchWindowProperty$1(appName, microAppWindow) {
|
|
|
5199
5322
|
}
|
|
5200
5323
|
return false;
|
|
5201
5324
|
});
|
|
5202
|
-
return /^on/.test(key) && !
|
|
5325
|
+
return /^on/.test(key) && !SCOPE_WINDOW_ON_EVENT_OF_IFRAME.includes(key);
|
|
5203
5326
|
})
|
|
5204
5327
|
.forEach((eventName) => {
|
|
5205
5328
|
const { enumerable, writable, set } = Object.getOwnPropertyDescriptor(microAppWindow, eventName) || {
|
|
@@ -5227,18 +5350,35 @@ function patchWindowProperty$1(appName, microAppWindow) {
|
|
|
5227
5350
|
*/
|
|
5228
5351
|
function createProxyWindow$1(microAppWindow, sandbox) {
|
|
5229
5352
|
const rawWindow = globalEnv.rawWindow;
|
|
5230
|
-
const customProperties =
|
|
5353
|
+
const customProperties = new Set();
|
|
5354
|
+
/**
|
|
5355
|
+
* proxyWindow will only take effect in certain scenes, such as window.key
|
|
5356
|
+
* e.g:
|
|
5357
|
+
* 1. window.key in normal app --> fall into proxyWindow
|
|
5358
|
+
* 2. window.key in module app(vite), fall into microAppWindow(iframeWindow)
|
|
5359
|
+
* 3. if (key)... --> fall into microAppWindow(iframeWindow)
|
|
5360
|
+
*/
|
|
5231
5361
|
const proxyWindow = new Proxy(microAppWindow, {
|
|
5232
5362
|
get: (target, key) => {
|
|
5233
5363
|
if (key === 'location') {
|
|
5234
5364
|
return sandbox.proxyLocation;
|
|
5235
5365
|
}
|
|
5236
|
-
if (
|
|
5366
|
+
if (includes(GLOBAL_KEY_TO_WINDOW, key)) {
|
|
5237
5367
|
return proxyWindow;
|
|
5238
5368
|
}
|
|
5239
|
-
if (customProperties.
|
|
5369
|
+
if (customProperties.has(key)) {
|
|
5240
5370
|
return Reflect.get(target, key);
|
|
5241
5371
|
}
|
|
5372
|
+
/**
|
|
5373
|
+
* Same as proxyWindow, escapeProperties will only take effect in certain scenes
|
|
5374
|
+
* e.g:
|
|
5375
|
+
* 1. window.key in normal app --> fall into proxyWindow, escapeProperties will effect
|
|
5376
|
+
* 2. window.key in module app(vite), fall into microAppWindow(iframeWindow), escapeProperties will not take effect
|
|
5377
|
+
* 3. if (key)... --> fall into microAppWindow(iframeWindow), escapeProperties will not take effect
|
|
5378
|
+
*/
|
|
5379
|
+
if (includes(sandbox.escapeProperties, key) && !Reflect.has(target, key)) {
|
|
5380
|
+
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
5381
|
+
}
|
|
5242
5382
|
return bindFunctionToRawTarget(Reflect.get(target, key), target);
|
|
5243
5383
|
},
|
|
5244
5384
|
set: (target, key, value) => {
|
|
@@ -5246,10 +5386,10 @@ function createProxyWindow$1(microAppWindow, sandbox) {
|
|
|
5246
5386
|
return Reflect.set(rawWindow, key, value);
|
|
5247
5387
|
}
|
|
5248
5388
|
if (!Reflect.has(target, key)) {
|
|
5249
|
-
customProperties.
|
|
5389
|
+
customProperties.add(key);
|
|
5250
5390
|
}
|
|
5251
5391
|
Reflect.set(target, key, value);
|
|
5252
|
-
if (sandbox.escapeProperties
|
|
5392
|
+
if (includes(sandbox.escapeProperties, key)) {
|
|
5253
5393
|
!Reflect.has(rawWindow, key) && sandbox.escapeKeys.add(key);
|
|
5254
5394
|
Reflect.set(rawWindow, key, value);
|
|
5255
5395
|
}
|
|
@@ -5271,7 +5411,7 @@ function patchWindowEffect$1(microAppWindow) {
|
|
|
5271
5411
|
const eventListenerMap = new Map();
|
|
5272
5412
|
const sstEventListenerMap = new Map();
|
|
5273
5413
|
function getEventTarget(type) {
|
|
5274
|
-
return
|
|
5414
|
+
return SCOPE_WINDOW_EVENT_OF_IFRAME.includes(type) ? microAppWindow : rawWindow;
|
|
5275
5415
|
}
|
|
5276
5416
|
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
5277
5417
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
@@ -5364,7 +5504,9 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5364
5504
|
const microRootDocument = microAppWindow.Document;
|
|
5365
5505
|
const microDocument = microAppWindow.document;
|
|
5366
5506
|
const rawMicroCreateElement = microRootDocument.prototype.createElement;
|
|
5507
|
+
const rawMicroCreateElementNS = microRootDocument.prototype.createElementNS;
|
|
5367
5508
|
const rawMicroCreateTextNode = microRootDocument.prototype.createTextNode;
|
|
5509
|
+
const rawMicroCreateDocumentFragment = microRootDocument.prototype.createDocumentFragment;
|
|
5368
5510
|
const rawMicroCreateComment = microRootDocument.prototype.createComment;
|
|
5369
5511
|
const rawMicroQuerySelector = microRootDocument.prototype.querySelector;
|
|
5370
5512
|
const rawMicroQuerySelectorAll = microRootDocument.prototype.querySelectorAll;
|
|
@@ -5385,10 +5527,18 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5385
5527
|
const element = rawMicroCreateElement.call(this, tagName, options);
|
|
5386
5528
|
return updateElementInfo(element, appName);
|
|
5387
5529
|
};
|
|
5530
|
+
microRootDocument.prototype.createElementNS = function createElementNS(namespaceURI, name, options) {
|
|
5531
|
+
const element = rawMicroCreateElementNS.call(this, namespaceURI, name, options);
|
|
5532
|
+
return updateElementInfo(element, appName);
|
|
5533
|
+
};
|
|
5388
5534
|
microRootDocument.prototype.createTextNode = function createTextNode(data) {
|
|
5389
5535
|
const element = rawMicroCreateTextNode.call(this, data);
|
|
5390
5536
|
return updateElementInfo(element, appName);
|
|
5391
5537
|
};
|
|
5538
|
+
microRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
|
|
5539
|
+
const element = rawMicroCreateDocumentFragment.call(this);
|
|
5540
|
+
return updateElementInfo(element, appName);
|
|
5541
|
+
};
|
|
5392
5542
|
microRootDocument.prototype.createComment = function createComment(data) {
|
|
5393
5543
|
const element = rawMicroCreateComment.call(this, data);
|
|
5394
5544
|
return updateElementInfo(element, appName);
|
|
@@ -5489,6 +5639,7 @@ function patchDocumentProperty(appName, microAppWindow, sandbox) {
|
|
|
5489
5639
|
const createDescriptors = () => {
|
|
5490
5640
|
const result = {};
|
|
5491
5641
|
const descList = [
|
|
5642
|
+
// if disable-memory-router or router-mode='disable', href point to base app
|
|
5492
5643
|
['documentURI', () => sandbox.proxyLocation.href],
|
|
5493
5644
|
['URL', () => sandbox.proxyLocation.href],
|
|
5494
5645
|
['documentElement', () => rawDocument.documentElement],
|
|
@@ -5722,6 +5873,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5722
5873
|
// return rootNode
|
|
5723
5874
|
};
|
|
5724
5875
|
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5876
|
+
// TODO: 有必要执行这么多次updateElementInfo?
|
|
5725
5877
|
updateElementInfo(node, appName);
|
|
5726
5878
|
if (isPureNode(node)) {
|
|
5727
5879
|
return rawMicroAppendChild.call(this, node);
|
|
@@ -5797,7 +5949,7 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5797
5949
|
configurable: true,
|
|
5798
5950
|
enumerable: true,
|
|
5799
5951
|
get() {
|
|
5800
|
-
return this.__PURE_ELEMENT__
|
|
5952
|
+
return this.__PURE_ELEMENT__ || this === microDocument
|
|
5801
5953
|
? rawOwnerDocumentDesc.get.call(this)
|
|
5802
5954
|
: microDocument;
|
|
5803
5955
|
},
|
|
@@ -5821,7 +5973,29 @@ function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
|
5821
5973
|
rawDefineProperty(microRootNode.prototype, 'parentNode', {
|
|
5822
5974
|
configurable: true,
|
|
5823
5975
|
enumerable: true,
|
|
5824
|
-
get
|
|
5976
|
+
get() {
|
|
5977
|
+
var _a, _b, _c;
|
|
5978
|
+
/**
|
|
5979
|
+
* set current appName for hijack parentNode of html
|
|
5980
|
+
* NOTE:
|
|
5981
|
+
* 1. Is there a problem with setting the current appName in iframe mode
|
|
5982
|
+
*/
|
|
5983
|
+
throttleDeferForSetAppName(appName);
|
|
5984
|
+
const result = rawParentNodeDesc.get.call(this);
|
|
5985
|
+
/**
|
|
5986
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
5987
|
+
* Scenes:
|
|
5988
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
5989
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
5990
|
+
* WARNING:
|
|
5991
|
+
* Will it cause other problems ?
|
|
5992
|
+
* e.g. target.parentNode.remove(target)
|
|
5993
|
+
*/
|
|
5994
|
+
if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
5995
|
+
return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || globalEnv.rawDocument.body;
|
|
5996
|
+
}
|
|
5997
|
+
return result;
|
|
5998
|
+
}
|
|
5825
5999
|
});
|
|
5826
6000
|
// Adapt to new image(...) scene
|
|
5827
6001
|
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
@@ -5883,14 +6057,17 @@ class IframeSandbox {
|
|
|
5883
6057
|
this.escapeProperties = [];
|
|
5884
6058
|
// Properties escape to rawWindow, cleared when unmount
|
|
5885
6059
|
this.escapeKeys = new Set();
|
|
5886
|
-
//
|
|
6060
|
+
// 初始化和每次跳转时都要更新base的href
|
|
5887
6061
|
this.updateIframeBase = () => {
|
|
5888
6062
|
var _a;
|
|
5889
|
-
|
|
6063
|
+
// origin must be child app origin
|
|
6064
|
+
(_a = this.baseElement) === null || _a === void 0 ? void 0 : _a.setAttribute('href', createURL(this.url).origin + this.proxyLocation.pathname);
|
|
5890
6065
|
};
|
|
6066
|
+
this.appName = appName;
|
|
6067
|
+
this.url = url;
|
|
5891
6068
|
const rawLocation = globalEnv.rawWindow.location;
|
|
5892
6069
|
const browserHost = rawLocation.protocol + '//' + rawLocation.host;
|
|
5893
|
-
this.deleteIframeElement = this.createIframeElement(appName, browserHost);
|
|
6070
|
+
this.deleteIframeElement = this.createIframeElement(appName, browserHost + rawLocation.pathname);
|
|
5894
6071
|
this.microAppWindow = this.iframe.contentWindow;
|
|
5895
6072
|
this.patchIframe(this.microAppWindow, (resolve) => {
|
|
5896
6073
|
// create new html to iframe
|
|
@@ -5918,13 +6095,13 @@ class IframeSandbox {
|
|
|
5918
6095
|
/**
|
|
5919
6096
|
* create iframe for sandbox
|
|
5920
6097
|
* @param appName app name
|
|
5921
|
-
* @param
|
|
6098
|
+
* @param browserPath browser origin
|
|
5922
6099
|
* @returns release callback
|
|
5923
6100
|
*/
|
|
5924
|
-
createIframeElement(appName,
|
|
6101
|
+
createIframeElement(appName, browserPath) {
|
|
5925
6102
|
this.iframe = pureCreateElement('iframe');
|
|
5926
6103
|
const iframeAttrs = {
|
|
5927
|
-
src:
|
|
6104
|
+
src: microApp.options.iframeSrc || browserPath,
|
|
5928
6105
|
style: 'display: none',
|
|
5929
6106
|
id: appName,
|
|
5930
6107
|
};
|
|
@@ -6019,6 +6196,7 @@ class IframeSandbox {
|
|
|
6019
6196
|
* NOTE:
|
|
6020
6197
|
* 1. execute as early as possible
|
|
6021
6198
|
* 2. run after patchRouter & createProxyWindow
|
|
6199
|
+
* TODO: 设置为只读变量
|
|
6022
6200
|
*/
|
|
6023
6201
|
initStaticGlobalKeys(appName, url, microAppWindow) {
|
|
6024
6202
|
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
@@ -6220,6 +6398,7 @@ class IframeSandbox {
|
|
|
6220
6398
|
patchElementTree(container, this.microAppWindow.__MICRO_APP_NAME__);
|
|
6221
6399
|
}
|
|
6222
6400
|
/**
|
|
6401
|
+
* action before exec scripts when mount
|
|
6223
6402
|
* Actions:
|
|
6224
6403
|
* 1. patch static elements from html
|
|
6225
6404
|
* @param container micro app container
|
|
@@ -6279,8 +6458,11 @@ class CreateApp {
|
|
|
6279
6458
|
}
|
|
6280
6459
|
/**
|
|
6281
6460
|
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
6461
|
+
* defaultPage disablePatchRequest routerMode baseroute is only for prerender app
|
|
6282
6462
|
*/
|
|
6283
|
-
onLoad(html,
|
|
6463
|
+
onLoad({ html,
|
|
6464
|
+
// below params is only for prerender app
|
|
6465
|
+
defaultPage, routerMode, baseroute, disablePatchRequest, }) {
|
|
6284
6466
|
var _a;
|
|
6285
6467
|
if (++this.loadSourceLevel === 2) {
|
|
6286
6468
|
this.source.html = html;
|
|
@@ -6311,11 +6493,11 @@ class CreateApp {
|
|
|
6311
6493
|
this.mount({
|
|
6312
6494
|
container,
|
|
6313
6495
|
inline: this.inline,
|
|
6314
|
-
routerMode: routerMode,
|
|
6315
|
-
baseroute: baseroute || '',
|
|
6316
6496
|
fiber: true,
|
|
6317
6497
|
defaultPage: defaultPage || '',
|
|
6318
6498
|
disablePatchRequest: disablePatchRequest !== null && disablePatchRequest !== void 0 ? disablePatchRequest : false,
|
|
6499
|
+
routerMode: routerMode,
|
|
6500
|
+
baseroute: baseroute || '',
|
|
6319
6501
|
});
|
|
6320
6502
|
}
|
|
6321
6503
|
}
|
|
@@ -6353,6 +6535,7 @@ class CreateApp {
|
|
|
6353
6535
|
// mount before prerender exec mount (loading source), set isPrerender to false
|
|
6354
6536
|
this.isPrerender = false;
|
|
6355
6537
|
// dispatch state event to micro app
|
|
6538
|
+
// TODO: statechange 还是 state-change,保持一致
|
|
6356
6539
|
dispatchCustomEventToMicroApp(this, 'statechange', {
|
|
6357
6540
|
appState: appStates.LOADING
|
|
6358
6541
|
});
|
|
@@ -6376,6 +6559,14 @@ class CreateApp {
|
|
|
6376
6559
|
if (this.isPrerender &&
|
|
6377
6560
|
isDivElement(this.container) &&
|
|
6378
6561
|
this.container.hasAttribute('prerender')) {
|
|
6562
|
+
/**
|
|
6563
|
+
* current this.container is <div prerender='true'></div>
|
|
6564
|
+
* set this.container to <micro-app></micro-app>
|
|
6565
|
+
* NOTE:
|
|
6566
|
+
* 1. must exec before this.sandBox.rebuildEffectSnapshot
|
|
6567
|
+
* 2. must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
6568
|
+
*/
|
|
6569
|
+
this.container = this.cloneContainer(container, this.container, false);
|
|
6379
6570
|
/**
|
|
6380
6571
|
* rebuild effect event of window, document, data center
|
|
6381
6572
|
* explain:
|
|
@@ -6384,14 +6575,6 @@ class CreateApp {
|
|
|
6384
6575
|
* 3. rebuild after js exec end, normal recovery effect event
|
|
6385
6576
|
*/
|
|
6386
6577
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6387
|
-
// current this.container is <div prerender='true'></div>
|
|
6388
|
-
cloneContainer(container, this.container, false);
|
|
6389
|
-
/**
|
|
6390
|
-
* set this.container to <micro-app></micro-app>
|
|
6391
|
-
* NOTE:
|
|
6392
|
-
* must exec before this.preRenderEvents?.forEach((cb) => cb())
|
|
6393
|
-
*/
|
|
6394
|
-
this.container = container;
|
|
6395
6578
|
(_b = this.preRenderEvents) === null || _b === void 0 ? void 0 : _b.forEach((cb) => cb());
|
|
6396
6579
|
// reset isPrerender config
|
|
6397
6580
|
this.isPrerender = false;
|
|
@@ -6421,7 +6604,7 @@ class CreateApp {
|
|
|
6421
6604
|
appState: appStates.MOUNTING
|
|
6422
6605
|
});
|
|
6423
6606
|
// TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
|
|
6424
|
-
cloneContainer(this.container, this.source.html, !this.umdMode);
|
|
6607
|
+
this.cloneContainer(this.container, this.source.html, !this.umdMode);
|
|
6425
6608
|
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
6426
6609
|
umdMode: this.umdMode,
|
|
6427
6610
|
baseroute,
|
|
@@ -6439,6 +6622,7 @@ class CreateApp {
|
|
|
6439
6622
|
* umdHookUnmount can works in default mode
|
|
6440
6623
|
* register through window.unmount
|
|
6441
6624
|
*/
|
|
6625
|
+
// TODO: 不对,这里要改,因为unmount不一定是函数
|
|
6442
6626
|
this.umdHookUnmount = unmount;
|
|
6443
6627
|
// if mount & unmount is function, the sub app is umd mode
|
|
6444
6628
|
if (isFunction(mount) && isFunction(unmount)) {
|
|
@@ -6609,7 +6793,7 @@ class CreateApp {
|
|
|
6609
6793
|
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
6610
6794
|
var _a;
|
|
6611
6795
|
if (this.umdMode && this.container && !destroy) {
|
|
6612
|
-
cloneContainer(this.source.html, this.container, false);
|
|
6796
|
+
this.cloneContainer(this.source.html, this.container, false);
|
|
6613
6797
|
}
|
|
6614
6798
|
/**
|
|
6615
6799
|
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
@@ -6636,6 +6820,7 @@ class CreateApp {
|
|
|
6636
6820
|
this.preRenderEvents = null;
|
|
6637
6821
|
this.setKeepAliveState(null);
|
|
6638
6822
|
// in iframe sandbox & default mode, delete the sandbox & iframeElement
|
|
6823
|
+
// TODO: with沙箱与iframe沙箱保持一致:with沙箱默认模式下删除 或者 iframe沙箱umd模式下保留
|
|
6639
6824
|
if (this.iframe && !this.umdMode)
|
|
6640
6825
|
this.sandBox = null;
|
|
6641
6826
|
if (destroy)
|
|
@@ -6667,7 +6852,7 @@ class CreateApp {
|
|
|
6667
6852
|
this.setLifeCycleState(lifeCycles.AFTERHIDDEN);
|
|
6668
6853
|
// dispatch afterHidden event to base app
|
|
6669
6854
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERHIDDEN);
|
|
6670
|
-
if (this.
|
|
6855
|
+
if (isRouterModeSearch(this.name)) {
|
|
6671
6856
|
// called after lifeCyclesEvent
|
|
6672
6857
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
6673
6858
|
}
|
|
@@ -6678,7 +6863,7 @@ class CreateApp {
|
|
|
6678
6863
|
getRootContainer(this.container).unmount();
|
|
6679
6864
|
}
|
|
6680
6865
|
else {
|
|
6681
|
-
this.container = cloneContainer(pureCreateElement('div'), this.container, false);
|
|
6866
|
+
this.container = this.cloneContainer(pureCreateElement('div'), this.container, false);
|
|
6682
6867
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
|
|
6683
6868
|
}
|
|
6684
6869
|
callback === null || callback === void 0 ? void 0 : callback();
|
|
@@ -6686,6 +6871,14 @@ class CreateApp {
|
|
|
6686
6871
|
// show app when connectedCallback called with keep-alive
|
|
6687
6872
|
showKeepAliveApp(container) {
|
|
6688
6873
|
var _a, _b;
|
|
6874
|
+
/**
|
|
6875
|
+
* NOTE:
|
|
6876
|
+
* 1. this.container must set to container(micro-app element) before exec rebuildEffectSnapshot
|
|
6877
|
+
* ISSUE: https://github.com/micro-zoe/micro-app/issues/1115
|
|
6878
|
+
* 2. rebuildEffectSnapshot must exec before dispatch beforeshow event
|
|
6879
|
+
*/
|
|
6880
|
+
const oldContainer = this.container;
|
|
6881
|
+
this.container = container;
|
|
6689
6882
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6690
6883
|
// dispatch beforeShow event to micro-app
|
|
6691
6884
|
dispatchCustomEventToMicroApp(this, 'appstate-change', {
|
|
@@ -6694,13 +6887,13 @@ class CreateApp {
|
|
|
6694
6887
|
// dispatch beforeShow event to base app
|
|
6695
6888
|
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
6696
6889
|
this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
|
|
6697
|
-
this.
|
|
6890
|
+
this.cloneContainer(this.container, oldContainer, false);
|
|
6698
6891
|
/**
|
|
6699
6892
|
* TODO:
|
|
6700
6893
|
* 问题:当路由模式为custom时,keep-alive应用在重新展示,是否需要根据子应用location信息更新浏览器地址?
|
|
6701
6894
|
* 暂时不这么做吧,因为无法确定二次展示时新旧地址是否相同,是否带有特殊信息
|
|
6702
6895
|
*/
|
|
6703
|
-
if (this.
|
|
6896
|
+
if (isRouterModeSearch(this.name)) {
|
|
6704
6897
|
// called before lifeCyclesEvent
|
|
6705
6898
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
|
|
6706
6899
|
}
|
|
@@ -6724,6 +6917,34 @@ class CreateApp {
|
|
|
6724
6917
|
});
|
|
6725
6918
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
6726
6919
|
}
|
|
6920
|
+
/**
|
|
6921
|
+
* Parse htmlString to DOM
|
|
6922
|
+
* NOTE: iframe sandbox will use DOMParser of iframeWindow, with sandbox will use DOMParser of base app
|
|
6923
|
+
* @param htmlString DOMString
|
|
6924
|
+
* @returns parsed DOM
|
|
6925
|
+
*/
|
|
6926
|
+
parseHtmlString(htmlString) {
|
|
6927
|
+
var _a;
|
|
6928
|
+
const DOMParser = ((_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) ? this.sandBox.proxyWindow.DOMParser
|
|
6929
|
+
: globalEnv.rawWindow.DOMParser;
|
|
6930
|
+
return (new DOMParser()).parseFromString(htmlString, 'text/html').body;
|
|
6931
|
+
}
|
|
6932
|
+
/**
|
|
6933
|
+
* clone origin elements to target
|
|
6934
|
+
* @param origin Cloned element
|
|
6935
|
+
* @param target Accept cloned elements
|
|
6936
|
+
* @param deep deep clone or transfer dom
|
|
6937
|
+
*/
|
|
6938
|
+
cloneContainer(target, origin, deep) {
|
|
6939
|
+
// 在基座接受到afterhidden方法后立即执行unmount,彻底destroy应用时,因为unmount时同步执行,所以this.container为null后才执行cloneContainer
|
|
6940
|
+
if (origin && target) {
|
|
6941
|
+
target.innerHTML = '';
|
|
6942
|
+
Array.from(deep ? this.parseHtmlString(origin.innerHTML).childNodes : origin.childNodes).forEach((node) => {
|
|
6943
|
+
target.appendChild(node);
|
|
6944
|
+
});
|
|
6945
|
+
}
|
|
6946
|
+
return target;
|
|
6947
|
+
}
|
|
6727
6948
|
/**
|
|
6728
6949
|
* Scene:
|
|
6729
6950
|
* 1. create app
|
|
@@ -6732,12 +6953,7 @@ class CreateApp {
|
|
|
6732
6953
|
*/
|
|
6733
6954
|
createSandbox() {
|
|
6734
6955
|
if (this.useSandbox && !this.sandBox) {
|
|
6735
|
-
|
|
6736
|
-
this.sandBox = new IframeSandbox(this.name, this.url);
|
|
6737
|
-
}
|
|
6738
|
-
else {
|
|
6739
|
-
this.sandBox = new WithSandBox(this.name, this.url);
|
|
6740
|
-
}
|
|
6956
|
+
this.sandBox = this.iframe ? new IframeSandbox(this.name, this.url) : new WithSandBox(this.name, this.url);
|
|
6741
6957
|
}
|
|
6742
6958
|
}
|
|
6743
6959
|
// set app state
|
|
@@ -6902,10 +7118,6 @@ function handleNewNode(child, app) {
|
|
|
6902
7118
|
*/
|
|
6903
7119
|
function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
|
|
6904
7120
|
const hijackParent = getHijackParent(parent, targetChild, app);
|
|
6905
|
-
/**
|
|
6906
|
-
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
6907
|
-
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
6908
|
-
*/
|
|
6909
7121
|
if (hijackParent) {
|
|
6910
7122
|
/**
|
|
6911
7123
|
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
@@ -6944,11 +7156,28 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
6944
7156
|
});
|
|
6945
7157
|
}
|
|
6946
7158
|
}
|
|
7159
|
+
if ((process.env.NODE_ENV !== 'production') &&
|
|
7160
|
+
isIFrameElement(targetChild) &&
|
|
7161
|
+
rawMethod === globalEnv.rawAppendChild) {
|
|
7162
|
+
fixReactHMRConflict(app);
|
|
7163
|
+
}
|
|
6947
7164
|
/**
|
|
6948
7165
|
* 1. If passiveChild exists, it must be insertBefore or replaceChild
|
|
6949
7166
|
* 2. When removeChild, targetChild may not be in microAppHead or head
|
|
7167
|
+
* NOTE:
|
|
7168
|
+
* 1. If passiveChild not in hijackParent, insertBefore replaceChild will be degraded to appendChild
|
|
7169
|
+
* E.g: document.head.replaceChild(targetChild, document.scripts[0])
|
|
7170
|
+
* 2. If passiveChild not in hijackParent but in parent and method is insertBefore, try insert it into the position corresponding to hijackParent
|
|
7171
|
+
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
7172
|
+
* ISSUE: https://github.com/micro-zoe/micro-app/issues/1071
|
|
6950
7173
|
*/
|
|
6951
7174
|
if (passiveChild && !hijackParent.contains(passiveChild)) {
|
|
7175
|
+
if (rawMethod === globalEnv.rawInsertBefore && parent.contains(passiveChild)) {
|
|
7176
|
+
const indexOfParent = Array.from(parent.childNodes).indexOf(passiveChild);
|
|
7177
|
+
if (hijackParent.childNodes[indexOfParent]) {
|
|
7178
|
+
return invokeRawMethod(rawMethod, hijackParent, targetChild, hijackParent.childNodes[indexOfParent]);
|
|
7179
|
+
}
|
|
7180
|
+
}
|
|
6952
7181
|
return globalEnv.rawAppendChild.call(hijackParent, targetChild);
|
|
6953
7182
|
}
|
|
6954
7183
|
else if (rawMethod === globalEnv.rawRemoveChild && !hijackParent.contains(targetChild)) {
|
|
@@ -6957,11 +7186,6 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
6957
7186
|
}
|
|
6958
7187
|
return targetChild;
|
|
6959
7188
|
}
|
|
6960
|
-
if ((process.env.NODE_ENV !== 'production') &&
|
|
6961
|
-
isIFrameElement(targetChild) &&
|
|
6962
|
-
rawMethod === globalEnv.rawAppendChild) {
|
|
6963
|
-
fixReactHMRConflict(app);
|
|
6964
|
-
}
|
|
6965
7189
|
return invokeRawMethod(rawMethod, hijackParent, targetChild, passiveChild);
|
|
6966
7190
|
}
|
|
6967
7191
|
return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
|
|
@@ -7031,6 +7255,11 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
7031
7255
|
currentAppName)) {
|
|
7032
7256
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
7033
7257
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
7258
|
+
if (isStyleElement(newChild)) {
|
|
7259
|
+
const isShadowNode = parent.getRootNode();
|
|
7260
|
+
const isShadowEnvironment = isShadowNode instanceof ShadowRoot;
|
|
7261
|
+
isShadowEnvironment && newChild.setAttribute('ignore', 'true');
|
|
7262
|
+
}
|
|
7034
7263
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
7035
7264
|
completePathDynamic(app, newChild);
|
|
7036
7265
|
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
@@ -7117,30 +7346,34 @@ function patchElementAndDocument() {
|
|
|
7117
7346
|
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
7118
7347
|
return clonedNode;
|
|
7119
7348
|
};
|
|
7120
|
-
|
|
7349
|
+
/**
|
|
7350
|
+
* document.body(head).querySelector(querySelectorAll) hijack to microAppBody(microAppHead).querySelector(querySelectorAll)
|
|
7351
|
+
* NOTE:
|
|
7352
|
+
* 1. May cause some problems!
|
|
7353
|
+
* 2. Add config options?
|
|
7354
|
+
*/
|
|
7355
|
+
function getQueryTarget(target) {
|
|
7121
7356
|
const currentAppName = getCurrentAppName();
|
|
7122
|
-
if ((
|
|
7357
|
+
if ((target === document.body || target === document.head) && currentAppName) {
|
|
7123
7358
|
const app = appInstanceMap.get(currentAppName);
|
|
7124
7359
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
7125
|
-
if (
|
|
7360
|
+
if (target === document.body) {
|
|
7126
7361
|
return app.querySelector('micro-app-body');
|
|
7127
7362
|
}
|
|
7128
|
-
else if (
|
|
7363
|
+
else if (target === document.head) {
|
|
7129
7364
|
return app.querySelector('micro-app-head');
|
|
7130
7365
|
}
|
|
7131
7366
|
}
|
|
7132
7367
|
}
|
|
7133
|
-
return
|
|
7368
|
+
return target;
|
|
7134
7369
|
}
|
|
7135
7370
|
rawRootElement.prototype.querySelector = function querySelector(selectors) {
|
|
7136
7371
|
var _a;
|
|
7137
|
-
|
|
7138
|
-
return globalEnv.rawElementQuerySelector.call(target, selectors);
|
|
7372
|
+
return globalEnv.rawElementQuerySelector.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
|
|
7139
7373
|
};
|
|
7140
7374
|
rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
7141
7375
|
var _a;
|
|
7142
|
-
|
|
7143
|
-
return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
|
|
7376
|
+
return globalEnv.rawElementQuerySelectorAll.call((_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this, selectors);
|
|
7144
7377
|
};
|
|
7145
7378
|
// rewrite setAttribute, complete resource address
|
|
7146
7379
|
rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
@@ -7268,14 +7501,15 @@ function patchDocument$2() {
|
|
|
7268
7501
|
const element = globalEnv.rawCreateElementNS.call(getBindTarget(this), namespaceURI, name, options);
|
|
7269
7502
|
return markElement(element);
|
|
7270
7503
|
};
|
|
7271
|
-
|
|
7272
|
-
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
7273
|
-
return markElement(element);
|
|
7274
|
-
};
|
|
7504
|
+
// TODO: 放开
|
|
7275
7505
|
// rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
|
|
7276
7506
|
// const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
|
|
7277
7507
|
// return markElement(element)
|
|
7278
7508
|
// }
|
|
7509
|
+
rawRootDocument.prototype.createDocumentFragment = function createDocumentFragment() {
|
|
7510
|
+
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
7511
|
+
return markElement(element);
|
|
7512
|
+
};
|
|
7279
7513
|
rawRootDocument.prototype.createComment = function createComment(data) {
|
|
7280
7514
|
const element = globalEnv.rawCreateComment.call(getBindTarget(this), data);
|
|
7281
7515
|
return markElement(element);
|
|
@@ -7288,7 +7522,7 @@ function patchDocument$2() {
|
|
|
7288
7522
|
if (!currentAppName ||
|
|
7289
7523
|
!selectors ||
|
|
7290
7524
|
isUniqueElement(selectors) ||
|
|
7291
|
-
//
|
|
7525
|
+
// ISSUE: https://github.com/micro-zoe/micro-app/issues/56
|
|
7292
7526
|
rawDocument !== _this) {
|
|
7293
7527
|
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
7294
7528
|
}
|
|
@@ -7438,8 +7672,8 @@ function initGlobalEnv() {
|
|
|
7438
7672
|
// Document proto methods
|
|
7439
7673
|
const rawCreateElement = rawRootDocument.prototype.createElement;
|
|
7440
7674
|
const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
|
|
7441
|
-
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
7442
7675
|
const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
|
|
7676
|
+
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
7443
7677
|
const rawCreateComment = rawRootDocument.prototype.createComment;
|
|
7444
7678
|
const rawQuerySelector = rawRootDocument.prototype.querySelector;
|
|
7445
7679
|
const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
|
|
@@ -7723,12 +7957,12 @@ function defineElement(tagName) {
|
|
|
7723
7957
|
/**
|
|
7724
7958
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
7725
7959
|
*/
|
|
7726
|
-
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url
|
|
7960
|
+
logWarn(`the ${oldApp.isPrefetch ? 'prefetch' : 'unmounted'} app with url ${oldAppUrl} replaced by a new app with url ${targetUrl}`, this.appName);
|
|
7727
7961
|
}
|
|
7728
7962
|
this.handleCreateApp();
|
|
7729
7963
|
}
|
|
7730
7964
|
else {
|
|
7731
|
-
logError(`app name conflict, an app named
|
|
7965
|
+
logError(`app name conflict, an app named ${this.appName} with url ${oldAppUrl} is running`);
|
|
7732
7966
|
}
|
|
7733
7967
|
}
|
|
7734
7968
|
else {
|
|
@@ -7972,6 +8206,7 @@ function defineElement(tagName) {
|
|
|
7972
8206
|
}
|
|
7973
8207
|
else {
|
|
7974
8208
|
// get path from browser URL
|
|
8209
|
+
// TODO: 新版本路由系统要重新兼容ssr
|
|
7975
8210
|
let targetPath = getNoHashMicroPathFromURL(this.appName, baseUrl);
|
|
7976
8211
|
const defaultPagePath = this.getDefaultPage();
|
|
7977
8212
|
if (!targetPath && defaultPagePath) {
|
|
@@ -7999,7 +8234,10 @@ function defineElement(tagName) {
|
|
|
7999
8234
|
* @returns router-mode
|
|
8000
8235
|
*/
|
|
8001
8236
|
getMemoryRouterMode() {
|
|
8002
|
-
return
|
|
8237
|
+
return initRouterMode(this.getAttribute('router-mode'),
|
|
8238
|
+
// is micro-app element set disable-memory-router, like <micro-app disable-memory-router></micro-app>
|
|
8239
|
+
// or <micro-app disable-memory-router='false'></micro-app>
|
|
8240
|
+
this.compatibleProperties('disable-memory-router') && this.compatibleDisableProperties('disable-memory-router'));
|
|
8003
8241
|
}
|
|
8004
8242
|
/**
|
|
8005
8243
|
* rewrite micro-app.setAttribute, process attr data
|
|
@@ -8048,6 +8286,18 @@ function defineElement(tagName) {
|
|
|
8048
8286
|
}
|
|
8049
8287
|
return null;
|
|
8050
8288
|
}
|
|
8289
|
+
/**
|
|
8290
|
+
* get publicPath from a valid address,it can used in micro-app-devtools
|
|
8291
|
+
*/
|
|
8292
|
+
get publicPath() {
|
|
8293
|
+
return getEffectivePath(this.appUrl);
|
|
8294
|
+
}
|
|
8295
|
+
/**
|
|
8296
|
+
* get baseRoute from attribute,it can used in micro-app-devtools
|
|
8297
|
+
*/
|
|
8298
|
+
get baseRoute() {
|
|
8299
|
+
return this.getBaseRouteCompatible();
|
|
8300
|
+
}
|
|
8051
8301
|
}
|
|
8052
8302
|
globalEnv.rawWindow.customElements.define(tagName, MicroAppElement);
|
|
8053
8303
|
}
|
|
@@ -8126,9 +8376,22 @@ function preFetchAction(options) {
|
|
|
8126
8376
|
});
|
|
8127
8377
|
const oldOnload = app.onLoad;
|
|
8128
8378
|
const oldOnLoadError = app.onLoadError;
|
|
8129
|
-
app.onLoad = (
|
|
8379
|
+
app.onLoad = (onLoadParam) => {
|
|
8380
|
+
if (app.isPrerender) {
|
|
8381
|
+
assign(onLoadParam, {
|
|
8382
|
+
defaultPage: options['default-page'],
|
|
8383
|
+
/**
|
|
8384
|
+
* TODO: 预渲染支持disable-memory-router,默认渲染首页即可,文档中也要保留
|
|
8385
|
+
* 问题:
|
|
8386
|
+
* 1、如何确保子应用进行跳转时不影响到浏览器地址??pure??
|
|
8387
|
+
*/
|
|
8388
|
+
routerMode: initRouterMode(options['router-mode']),
|
|
8389
|
+
baseroute: options.baseroute,
|
|
8390
|
+
disablePatchRequest: options['disable-patch-request'],
|
|
8391
|
+
});
|
|
8392
|
+
}
|
|
8130
8393
|
resolve();
|
|
8131
|
-
oldOnload.call(app,
|
|
8394
|
+
oldOnload.call(app, onLoadParam);
|
|
8132
8395
|
};
|
|
8133
8396
|
app.onLoadError = (...rests) => {
|
|
8134
8397
|
resolve();
|
|
@@ -8159,7 +8422,7 @@ function getGlobalAssets(assets) {
|
|
|
8159
8422
|
// TODO: requestIdleCallback for every file
|
|
8160
8423
|
function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
8161
8424
|
if (isArray(resources)) {
|
|
8162
|
-
const effectiveResource = resources.filter((path) => isString(path) && path
|
|
8425
|
+
const effectiveResource = resources.filter((path) => isString(path) && isTargetExtension(path, suffix) && !sourceHandler.hasInfo(path));
|
|
8163
8426
|
const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
|
|
8164
8427
|
// fetch resource with stream
|
|
8165
8428
|
promiseStream(fetchResourcePromise, (res) => {
|