@micro-zoe/micro-app 0.8.7 → 1.0.0-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -3
- package/README.zh-cn.md +9 -15
- package/lib/index.d.ts +67 -21
- package/lib/index.esm.js +1648 -409
- 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 -3
- package/typings/global.d.ts +188 -16
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '0.
|
|
1
|
+
const version = '1.0.0-alpha.2';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -7,10 +7,24 @@ const globalThis = (typeof global !== 'undefined')
|
|
|
7
7
|
: ((typeof window !== 'undefined')
|
|
8
8
|
? window
|
|
9
9
|
: ((typeof self !== 'undefined') ? self : Function('return this')()));
|
|
10
|
+
const noop = () => { };
|
|
11
|
+
const noopFalse = () => false;
|
|
12
|
+
// Array.isArray
|
|
13
|
+
const isArray = Array.isArray;
|
|
14
|
+
// Object.assign
|
|
15
|
+
const assign = Object.assign;
|
|
16
|
+
// Object prototype methods
|
|
17
|
+
const rawDefineProperty = Object.defineProperty;
|
|
18
|
+
const rawDefineProperties = Object.defineProperties;
|
|
19
|
+
const rawHasOwnProperty = Object.prototype.hasOwnProperty;
|
|
10
20
|
// is Undefined
|
|
11
21
|
function isUndefined(target) {
|
|
12
22
|
return target === undefined;
|
|
13
23
|
}
|
|
24
|
+
// is Null
|
|
25
|
+
function isNull(target) {
|
|
26
|
+
return target === null;
|
|
27
|
+
}
|
|
14
28
|
// is String
|
|
15
29
|
function isString(target) {
|
|
16
30
|
return typeof target === 'string';
|
|
@@ -23,12 +37,14 @@ function isBoolean(target) {
|
|
|
23
37
|
function isFunction(target) {
|
|
24
38
|
return typeof target === 'function';
|
|
25
39
|
}
|
|
26
|
-
// is Array
|
|
27
|
-
const isArray = Array.isArray;
|
|
28
40
|
// is PlainObject
|
|
29
41
|
function isPlainObject(target) {
|
|
30
42
|
return toString.call(target) === '[object Object]';
|
|
31
43
|
}
|
|
44
|
+
// is Object
|
|
45
|
+
function isObject(target) {
|
|
46
|
+
return typeof target === 'object';
|
|
47
|
+
}
|
|
32
48
|
// is Promise
|
|
33
49
|
function isPromise(target) {
|
|
34
50
|
return toString.call(target) === '[object Promise]';
|
|
@@ -37,13 +53,25 @@ function isPromise(target) {
|
|
|
37
53
|
function isBoundFunction(target) {
|
|
38
54
|
return isFunction(target) && target.name.indexOf('bound ') === 0 && !target.hasOwnProperty('prototype');
|
|
39
55
|
}
|
|
56
|
+
// is constructor function
|
|
57
|
+
function isConstructor(target) {
|
|
58
|
+
var _a;
|
|
59
|
+
if (isFunction(target)) {
|
|
60
|
+
const targetStr = target.toString();
|
|
61
|
+
return (((_a = target.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === target &&
|
|
62
|
+
Object.getOwnPropertyNames(target.prototype).length > 1) ||
|
|
63
|
+
/^function\s+[A-Z]/.test(targetStr) ||
|
|
64
|
+
/^class\s+/.test(targetStr);
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
40
68
|
// is ShadowRoot
|
|
41
69
|
function isShadowRoot(target) {
|
|
42
70
|
return typeof ShadowRoot !== 'undefined' && target instanceof ShadowRoot;
|
|
43
71
|
}
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
72
|
+
function isURL(target) {
|
|
73
|
+
return target instanceof URL;
|
|
74
|
+
}
|
|
47
75
|
/**
|
|
48
76
|
* format error log
|
|
49
77
|
* @param msg message
|
|
@@ -80,12 +108,22 @@ function logWarn(msg, appName = null, ...rest) {
|
|
|
80
108
|
function defer(fn, ...args) {
|
|
81
109
|
Promise.resolve().then(fn.bind(null, ...args));
|
|
82
110
|
}
|
|
111
|
+
/**
|
|
112
|
+
* create URL as MicroLocation
|
|
113
|
+
*/
|
|
114
|
+
const createURL = (function () {
|
|
115
|
+
class Location extends URL {
|
|
116
|
+
}
|
|
117
|
+
return (path, base) => {
|
|
118
|
+
return (base ? new Location('' + path, base) : new Location('' + path));
|
|
119
|
+
};
|
|
120
|
+
})();
|
|
83
121
|
/**
|
|
84
122
|
* Add address protocol
|
|
85
123
|
* @param url address
|
|
86
124
|
*/
|
|
87
125
|
function addProtocol(url) {
|
|
88
|
-
return url.startsWith('//') ? `${location.protocol}${url}` : url;
|
|
126
|
+
return url.startsWith('//') ? `${globalThis.location.protocol}${url}` : url;
|
|
89
127
|
}
|
|
90
128
|
/**
|
|
91
129
|
* format URL address
|
|
@@ -97,7 +135,7 @@ function formatAppURL(url, appName = null) {
|
|
|
97
135
|
if (!isString(url) || !url)
|
|
98
136
|
return '';
|
|
99
137
|
try {
|
|
100
|
-
const { origin, pathname, search } =
|
|
138
|
+
const { origin, pathname, search } = createURL(addProtocol(url));
|
|
101
139
|
// If it ends with .html/.node/.php/.net/.etc, don’t need to add /
|
|
102
140
|
if (/\.(\w+)$/.test(pathname)) {
|
|
103
141
|
return `${origin}${pathname}${search}`;
|
|
@@ -118,6 +156,7 @@ function formatAppURL(url, appName = null) {
|
|
|
118
156
|
* 3. event_center -> EventCenterForBaseApp -> all methods
|
|
119
157
|
* 4. preFetch
|
|
120
158
|
* 5. plugins
|
|
159
|
+
* 6. router api (push, replace)
|
|
121
160
|
*/
|
|
122
161
|
function formatAppName(name) {
|
|
123
162
|
if (!isString(name) || !name)
|
|
@@ -129,7 +168,7 @@ function formatAppName(name) {
|
|
|
129
168
|
* @param url app.url
|
|
130
169
|
*/
|
|
131
170
|
function getEffectivePath(url) {
|
|
132
|
-
const { origin, pathname } =
|
|
171
|
+
const { origin, pathname } = createURL(url);
|
|
133
172
|
if (/\.(\w+)$/.test(pathname)) {
|
|
134
173
|
const fullPath = `${origin}${pathname}`;
|
|
135
174
|
const pathArr = fullPath.split('/');
|
|
@@ -148,7 +187,7 @@ function CompletionPath(path, baseURI) {
|
|
|
148
187
|
/^((((ht|f)tps?)|file):)?\/\//.test(path) ||
|
|
149
188
|
/^(data|blob):/.test(path))
|
|
150
189
|
return path;
|
|
151
|
-
return
|
|
190
|
+
return createURL(path, getEffectivePath(addProtocol(baseURI))).toString();
|
|
152
191
|
}
|
|
153
192
|
/**
|
|
154
193
|
* Get the folder where the link resource is located,
|
|
@@ -176,24 +215,15 @@ function promiseStream(promiseList, successCb, errorCb, finallyCb) {
|
|
|
176
215
|
promiseList.forEach((p, i) => {
|
|
177
216
|
if (isPromise(p)) {
|
|
178
217
|
p.then((res) => {
|
|
179
|
-
successCb({
|
|
180
|
-
data: res,
|
|
181
|
-
index: i,
|
|
182
|
-
});
|
|
218
|
+
successCb({ data: res, index: i });
|
|
183
219
|
isFinished();
|
|
184
220
|
}).catch((err) => {
|
|
185
|
-
errorCb({
|
|
186
|
-
error: err,
|
|
187
|
-
index: i,
|
|
188
|
-
});
|
|
221
|
+
errorCb({ error: err, index: i });
|
|
189
222
|
isFinished();
|
|
190
223
|
});
|
|
191
224
|
}
|
|
192
225
|
else {
|
|
193
|
-
successCb({
|
|
194
|
-
data: p,
|
|
195
|
-
index: i,
|
|
196
|
-
});
|
|
226
|
+
successCb({ data: p, index: i });
|
|
197
227
|
isFinished();
|
|
198
228
|
}
|
|
199
229
|
});
|
|
@@ -256,6 +286,7 @@ function pureCreateElement(tagName, options) {
|
|
|
256
286
|
const element = document.createElement(tagName, options);
|
|
257
287
|
if (element.__MICRO_APP_NAME__)
|
|
258
288
|
delete element.__MICRO_APP_NAME__;
|
|
289
|
+
element.__PURE_ELEMENT__ = true;
|
|
259
290
|
return element;
|
|
260
291
|
}
|
|
261
292
|
/**
|
|
@@ -306,6 +337,98 @@ function trim(str) {
|
|
|
306
337
|
function isFireFox() {
|
|
307
338
|
return navigator.userAgent.indexOf('Firefox') > -1;
|
|
308
339
|
}
|
|
340
|
+
/**
|
|
341
|
+
* Transforms a queryString into object.
|
|
342
|
+
* @param search - search string to parse
|
|
343
|
+
* @returns a query object
|
|
344
|
+
*/
|
|
345
|
+
function parseQuery(search) {
|
|
346
|
+
const result = {};
|
|
347
|
+
const queryList = search.split('&');
|
|
348
|
+
// we will not decode the key/value to ensure that the values are consistent when update URL
|
|
349
|
+
for (const queryItem of queryList) {
|
|
350
|
+
const eqPos = queryItem.indexOf('=');
|
|
351
|
+
const key = eqPos < 0 ? queryItem : queryItem.slice(0, eqPos);
|
|
352
|
+
const value = eqPos < 0 ? null : queryItem.slice(eqPos + 1);
|
|
353
|
+
if (key in result) {
|
|
354
|
+
let currentValue = result[key];
|
|
355
|
+
if (!isArray(currentValue)) {
|
|
356
|
+
currentValue = result[key] = [currentValue];
|
|
357
|
+
}
|
|
358
|
+
currentValue.push(value);
|
|
359
|
+
}
|
|
360
|
+
else {
|
|
361
|
+
result[key] = value;
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
return result;
|
|
365
|
+
}
|
|
366
|
+
/**
|
|
367
|
+
* Transforms an object to query string
|
|
368
|
+
* @param queryObject - query object to stringify
|
|
369
|
+
* @returns query string without the leading `?`
|
|
370
|
+
*/
|
|
371
|
+
function stringifyQuery(queryObject) {
|
|
372
|
+
let result = '';
|
|
373
|
+
for (const key in queryObject) {
|
|
374
|
+
const value = queryObject[key];
|
|
375
|
+
if (isNull(value)) {
|
|
376
|
+
result += (result.length ? '&' : '') + key;
|
|
377
|
+
}
|
|
378
|
+
else {
|
|
379
|
+
const valueList = isArray(value) ? value : [value];
|
|
380
|
+
valueList.forEach(value => {
|
|
381
|
+
if (!isUndefined(value)) {
|
|
382
|
+
result += (result.length ? '&' : '') + key;
|
|
383
|
+
if (!isNull(value))
|
|
384
|
+
result += '=' + value;
|
|
385
|
+
}
|
|
386
|
+
});
|
|
387
|
+
}
|
|
388
|
+
}
|
|
389
|
+
return result;
|
|
390
|
+
}
|
|
391
|
+
/**
|
|
392
|
+
* Register or unregister callback/guard with Set
|
|
393
|
+
*/
|
|
394
|
+
function useSetRecord() {
|
|
395
|
+
const handlers = new Set();
|
|
396
|
+
function add(handler) {
|
|
397
|
+
handlers.add(handler);
|
|
398
|
+
return () => {
|
|
399
|
+
if (handlers.has(handler))
|
|
400
|
+
return handlers.delete(handler);
|
|
401
|
+
return false;
|
|
402
|
+
};
|
|
403
|
+
}
|
|
404
|
+
return {
|
|
405
|
+
add,
|
|
406
|
+
list: () => handlers,
|
|
407
|
+
};
|
|
408
|
+
}
|
|
409
|
+
/**
|
|
410
|
+
* record data with Map
|
|
411
|
+
*/
|
|
412
|
+
function useMapRecord() {
|
|
413
|
+
const data = new Map();
|
|
414
|
+
function add(key, value) {
|
|
415
|
+
data.set(key, value);
|
|
416
|
+
return () => {
|
|
417
|
+
if (data.has(key))
|
|
418
|
+
return data.delete(key);
|
|
419
|
+
return false;
|
|
420
|
+
};
|
|
421
|
+
}
|
|
422
|
+
return {
|
|
423
|
+
add,
|
|
424
|
+
get: (key) => data.get(key),
|
|
425
|
+
delete: (key) => {
|
|
426
|
+
if (data.has(key))
|
|
427
|
+
return data.delete(key);
|
|
428
|
+
return false;
|
|
429
|
+
}
|
|
430
|
+
};
|
|
431
|
+
}
|
|
309
432
|
|
|
310
433
|
var ObservedAttrName;
|
|
311
434
|
(function (ObservedAttrName) {
|
|
@@ -315,13 +438,13 @@ var ObservedAttrName;
|
|
|
315
438
|
// app status
|
|
316
439
|
var appStates;
|
|
317
440
|
(function (appStates) {
|
|
318
|
-
appStates["
|
|
319
|
-
appStates["
|
|
320
|
-
appStates["
|
|
321
|
-
appStates["
|
|
322
|
-
appStates["MOUNTING"] = "
|
|
323
|
-
appStates["MOUNTED"] = "
|
|
324
|
-
appStates["UNMOUNT"] = "
|
|
441
|
+
appStates["CREATED"] = "created";
|
|
442
|
+
appStates["LOADING"] = "loading";
|
|
443
|
+
appStates["LOADED"] = "loaded";
|
|
444
|
+
appStates["LOAD_FAILED"] = "load_failed";
|
|
445
|
+
appStates["MOUNTING"] = "mounting";
|
|
446
|
+
appStates["MOUNTED"] = "mounted";
|
|
447
|
+
appStates["UNMOUNT"] = "unmount";
|
|
325
448
|
})(appStates || (appStates = {}));
|
|
326
449
|
// lifecycles
|
|
327
450
|
var lifeCycles;
|
|
@@ -339,86 +462,42 @@ var lifeCycles;
|
|
|
339
462
|
// keep-alive status
|
|
340
463
|
var keepAliveStates;
|
|
341
464
|
(function (keepAliveStates) {
|
|
342
|
-
keepAliveStates["KEEP_ALIVE_SHOW"] = "
|
|
343
|
-
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "
|
|
465
|
+
keepAliveStates["KEEP_ALIVE_SHOW"] = "keep_alive_show";
|
|
466
|
+
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "keep_alive_hidden";
|
|
344
467
|
})(keepAliveStates || (keepAliveStates = {}));
|
|
345
|
-
|
|
468
|
+
/**
|
|
469
|
+
* global key must be static key, they can not rewrite
|
|
470
|
+
* e.g.
|
|
471
|
+
* window.Promise = newValue
|
|
472
|
+
* new Promise ==> still get old value, not newValue, because they are cached by top function
|
|
473
|
+
* NOTE:
|
|
474
|
+
* 1. Do not add fetch, XMLHttpRequest, EventSource
|
|
475
|
+
*/
|
|
476
|
+
const globalKeyToBeCached = 'window,self,globalThis,Array,Object,String,Boolean,Math,Number,Symbol,Date,Function,Proxy,WeakMap,WeakSet,Set,Map,Reflect,Element,Node,Document,RegExp,Error,TypeError,JSON,isNaN,parseFloat,parseInt,performance,console,decodeURI,encodeURI,decodeURIComponent,encodeURIComponent,navigator,undefined,location,history';
|
|
346
477
|
|
|
347
478
|
/**
|
|
348
479
|
* fetch source of html, js, css
|
|
349
480
|
* @param url source path
|
|
350
481
|
* @param appName app name
|
|
351
|
-
* @param config
|
|
482
|
+
* @param config fetch options
|
|
352
483
|
*/
|
|
353
484
|
function fetchSource(url, appName = null, options = {}) {
|
|
485
|
+
/**
|
|
486
|
+
* When child navigate to new async page, click event will scope dom to child and then fetch new source
|
|
487
|
+
* this may cause error when fetch rewrite by baseApp
|
|
488
|
+
* e.g.
|
|
489
|
+
* baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
|
|
490
|
+
*/
|
|
491
|
+
removeDomScope();
|
|
354
492
|
if (isFunction(microApp.fetch)) {
|
|
355
493
|
return microApp.fetch(url, options, appName);
|
|
356
494
|
}
|
|
357
|
-
|
|
495
|
+
// Don’t use globalEnv.rawWindow.fetch, will cause sgm-2.8.0.js throw error in nest app
|
|
496
|
+
return window.fetch(url, options).then((res) => {
|
|
358
497
|
return res.text();
|
|
359
498
|
});
|
|
360
499
|
}
|
|
361
500
|
|
|
362
|
-
class HTMLLoader {
|
|
363
|
-
static getInstance() {
|
|
364
|
-
if (!this.instance) {
|
|
365
|
-
this.instance = new HTMLLoader();
|
|
366
|
-
}
|
|
367
|
-
return this.instance;
|
|
368
|
-
}
|
|
369
|
-
/**
|
|
370
|
-
* run logic of load and format html
|
|
371
|
-
* @param successCb success callback
|
|
372
|
-
* @param errorCb error callback, type: (err: Error, meetFetchErr: boolean) => void
|
|
373
|
-
*/
|
|
374
|
-
run(app, successCb) {
|
|
375
|
-
const appName = app.name;
|
|
376
|
-
const htmlUrl = app.ssrUrl || app.url;
|
|
377
|
-
fetchSource(htmlUrl, appName, { cache: 'no-cache' }).then((htmlStr) => {
|
|
378
|
-
if (!htmlStr) {
|
|
379
|
-
const msg = 'html is empty, please check in detail';
|
|
380
|
-
app.onerror(new Error(msg));
|
|
381
|
-
return logError(msg, appName);
|
|
382
|
-
}
|
|
383
|
-
htmlStr = this.formatHTML(htmlUrl, htmlStr, appName);
|
|
384
|
-
successCb(htmlStr, app);
|
|
385
|
-
}).catch((e) => {
|
|
386
|
-
logError(`Failed to fetch data from ${app.url}, micro-app stop rendering`, appName, e);
|
|
387
|
-
app.onLoadError(e);
|
|
388
|
-
});
|
|
389
|
-
}
|
|
390
|
-
formatHTML(htmlUrl, htmlStr, appName) {
|
|
391
|
-
return this.processHtml(htmlUrl, htmlStr, appName, microApp.plugins)
|
|
392
|
-
.replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
|
|
393
|
-
return match
|
|
394
|
-
.replace(/<head/i, '<micro-app-head')
|
|
395
|
-
.replace(/<\/head>/i, '</micro-app-head>');
|
|
396
|
-
})
|
|
397
|
-
.replace(/<body[^>]*>[\s\S]*?<\/body>/i, (match) => {
|
|
398
|
-
return match
|
|
399
|
-
.replace(/<body/i, '<micro-app-body')
|
|
400
|
-
.replace(/<\/body>/i, '</micro-app-body>');
|
|
401
|
-
});
|
|
402
|
-
}
|
|
403
|
-
processHtml(url, code, appName, plugins) {
|
|
404
|
-
var _a;
|
|
405
|
-
if (!plugins)
|
|
406
|
-
return code;
|
|
407
|
-
const mergedPlugins = [];
|
|
408
|
-
plugins.global && mergedPlugins.push(...plugins.global);
|
|
409
|
-
((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]) && mergedPlugins.push(...plugins.modules[appName]);
|
|
410
|
-
if (mergedPlugins.length > 0) {
|
|
411
|
-
return mergedPlugins.reduce((preCode, plugin) => {
|
|
412
|
-
if (isPlainObject(plugin) && isFunction(plugin.processHtml)) {
|
|
413
|
-
return plugin.processHtml(preCode, url, plugin.options);
|
|
414
|
-
}
|
|
415
|
-
return preCode;
|
|
416
|
-
}, code);
|
|
417
|
-
}
|
|
418
|
-
return code;
|
|
419
|
-
}
|
|
420
|
-
}
|
|
421
|
-
|
|
422
501
|
// common reg
|
|
423
502
|
const rootSelectorREG = /(^|\s+)(html|:root)(?=[\s>~[.#:]+|$)/;
|
|
424
503
|
const bodySelectorREG = /(^|\s+)((html[\s>~]+body)|body)(?=[\s>~[.#:]+|$)/;
|
|
@@ -497,7 +576,7 @@ class CSSParser {
|
|
|
497
576
|
return true;
|
|
498
577
|
}
|
|
499
578
|
formatSelector(skip) {
|
|
500
|
-
const m = this.commonMatch(/^
|
|
579
|
+
const m = this.commonMatch(/^[^{]+/, skip);
|
|
501
580
|
if (!m)
|
|
502
581
|
return false;
|
|
503
582
|
return m[0].replace(/(^|,[\n\s]*)([^,]+)/g, (_, separator, selector) => {
|
|
@@ -577,7 +656,7 @@ class CSSParser {
|
|
|
577
656
|
keyframesRule() {
|
|
578
657
|
if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
|
|
579
658
|
return false;
|
|
580
|
-
if (!this.commonMatch(/^
|
|
659
|
+
if (!this.commonMatch(/^[^{]+/))
|
|
581
660
|
return parseError('@keyframes missing name', this.linkPath);
|
|
582
661
|
this.matchComments();
|
|
583
662
|
if (!this.matchOpenBrace())
|
|
@@ -729,7 +808,7 @@ class CSSParser {
|
|
|
729
808
|
}
|
|
730
809
|
// splice string
|
|
731
810
|
recordResult(strFragment) {
|
|
732
|
-
// Firefox
|
|
811
|
+
// Firefox performance degradation when string contain special characters, see https://github.com/micro-zoe/micro-app/issues/256
|
|
733
812
|
if (isFireFox()) {
|
|
734
813
|
this.result += encodeURIComponent(strFragment);
|
|
735
814
|
}
|
|
@@ -960,6 +1039,85 @@ function formatDynamicLink(url, info, app, originLink, replaceStyle) {
|
|
|
960
1039
|
});
|
|
961
1040
|
}
|
|
962
1041
|
|
|
1042
|
+
class Adapter {
|
|
1043
|
+
constructor() {
|
|
1044
|
+
// keys that can only assigned to rawWindow
|
|
1045
|
+
this.escapeSetterKeyList = [
|
|
1046
|
+
'location',
|
|
1047
|
+
];
|
|
1048
|
+
// keys that can escape to rawWindow
|
|
1049
|
+
this.staticEscapeProperties = [
|
|
1050
|
+
'System',
|
|
1051
|
+
'__cjsWrapper',
|
|
1052
|
+
];
|
|
1053
|
+
// keys that scoped in child app
|
|
1054
|
+
this.staticScopeProperties = [
|
|
1055
|
+
'webpackJsonp',
|
|
1056
|
+
'webpackHotUpdate',
|
|
1057
|
+
'Vue',
|
|
1058
|
+
];
|
|
1059
|
+
this.injectReactHRMProperty();
|
|
1060
|
+
}
|
|
1061
|
+
// TODO: __DEV__ process.env.NODE_ENV !== 'production'
|
|
1062
|
+
// adapter for react
|
|
1063
|
+
injectReactHRMProperty() {
|
|
1064
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1065
|
+
// react child in non-react env
|
|
1066
|
+
this.staticEscapeProperties.push('__REACT_ERROR_OVERLAY_GLOBAL_HOOK__');
|
|
1067
|
+
// in react parent
|
|
1068
|
+
if (globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__) {
|
|
1069
|
+
this.staticScopeProperties = this.staticScopeProperties.concat([
|
|
1070
|
+
'__REACT_ERROR_OVERLAY_GLOBAL_HOOK__',
|
|
1071
|
+
'__reactRefreshInjected',
|
|
1072
|
+
]);
|
|
1073
|
+
}
|
|
1074
|
+
}
|
|
1075
|
+
}
|
|
1076
|
+
}
|
|
1077
|
+
// Fix conflict of babel-polyfill@6.x
|
|
1078
|
+
function fixBabelPolyfill6() {
|
|
1079
|
+
if (globalEnv.rawWindow._babelPolyfill)
|
|
1080
|
+
globalEnv.rawWindow._babelPolyfill = false;
|
|
1081
|
+
}
|
|
1082
|
+
/**
|
|
1083
|
+
* Fix error of hot reload when parent&child created by create-react-app in development environment
|
|
1084
|
+
* Issue: https://github.com/micro-zoe/micro-app/issues/382
|
|
1085
|
+
*/
|
|
1086
|
+
function fixReactHMRConflict(app) {
|
|
1087
|
+
var _a;
|
|
1088
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
1089
|
+
const rawReactErrorHook = globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
1090
|
+
const childReactErrorHook = (_a = app.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__;
|
|
1091
|
+
if (rawReactErrorHook && childReactErrorHook) {
|
|
1092
|
+
globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = childReactErrorHook;
|
|
1093
|
+
defer(() => {
|
|
1094
|
+
globalEnv.rawWindow.__REACT_ERROR_OVERLAY_GLOBAL_HOOK__ = rawReactErrorHook;
|
|
1095
|
+
});
|
|
1096
|
+
}
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
/**
|
|
1100
|
+
* reDefine parentNode of html
|
|
1101
|
+
* Scenes:
|
|
1102
|
+
* 1. element-ui popover.js
|
|
1103
|
+
* if (html.parentNode === document) ...
|
|
1104
|
+
*/
|
|
1105
|
+
function throttleDeferForParentNode(proxyDocument) {
|
|
1106
|
+
const html = globalEnv.rawDocument.firstElementChild;
|
|
1107
|
+
if (html && html.parentNode !== proxyDocument) {
|
|
1108
|
+
setRootParentNode(html, proxyDocument);
|
|
1109
|
+
defer(() => {
|
|
1110
|
+
setRootParentNode(html, globalEnv.rawDocument);
|
|
1111
|
+
});
|
|
1112
|
+
}
|
|
1113
|
+
}
|
|
1114
|
+
function setRootParentNode(root, value) {
|
|
1115
|
+
Object.defineProperty(root, 'parentNode', {
|
|
1116
|
+
value,
|
|
1117
|
+
configurable: true,
|
|
1118
|
+
});
|
|
1119
|
+
}
|
|
1120
|
+
|
|
963
1121
|
// Record element and map element
|
|
964
1122
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
965
1123
|
/**
|
|
@@ -981,12 +1139,12 @@ function handleNewNode(parent, child, app) {
|
|
|
981
1139
|
return child;
|
|
982
1140
|
}
|
|
983
1141
|
else if (child instanceof HTMLLinkElement) {
|
|
984
|
-
if (child.hasAttribute('exclude')
|
|
1142
|
+
if (child.hasAttribute('exclude')) {
|
|
985
1143
|
const linkReplaceComment = document.createComment('link element with exclude attribute ignored by micro-app');
|
|
986
1144
|
dynamicElementInMicroAppMap.set(child, linkReplaceComment);
|
|
987
1145
|
return linkReplaceComment;
|
|
988
1146
|
}
|
|
989
|
-
else if (child.hasAttribute('ignore')
|
|
1147
|
+
else if (child.hasAttribute('ignore')) {
|
|
990
1148
|
return child;
|
|
991
1149
|
}
|
|
992
1150
|
const { url, info, replaceComment } = extractLinkFromHtml(child, parent, app, true);
|
|
@@ -1034,39 +1192,37 @@ function handleNewNode(parent, child, app) {
|
|
|
1034
1192
|
* @param passiveChild second param of insertBefore and replaceChild
|
|
1035
1193
|
*/
|
|
1036
1194
|
function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild) {
|
|
1037
|
-
const
|
|
1195
|
+
const hijackElement = getHijackElement(parent, app);
|
|
1038
1196
|
/**
|
|
1039
1197
|
* If passiveChild is not the child node, insertBefore replaceChild will have a problem, at this time, it will be degraded to appendChild
|
|
1040
1198
|
* E.g: document.head.insertBefore(targetChild, document.head.childNodes[0])
|
|
1041
1199
|
*/
|
|
1042
|
-
if (
|
|
1200
|
+
if (hijackElement) {
|
|
1043
1201
|
/**
|
|
1044
1202
|
* 1. If passiveChild exists, it must be insertBefore or replaceChild
|
|
1045
1203
|
* 2. When removeChild, targetChild may not be in microAppHead or head
|
|
1046
1204
|
*/
|
|
1047
|
-
if (passiveChild && !
|
|
1048
|
-
return globalEnv.rawAppendChild.call(
|
|
1205
|
+
if (passiveChild && !hijackElement.contains(passiveChild)) {
|
|
1206
|
+
return globalEnv.rawAppendChild.call(hijackElement, targetChild);
|
|
1049
1207
|
}
|
|
1050
|
-
else if (rawMethod === globalEnv.rawRemoveChild && !
|
|
1208
|
+
else if (rawMethod === globalEnv.rawRemoveChild && !hijackElement.contains(targetChild)) {
|
|
1051
1209
|
if (parent.contains(targetChild)) {
|
|
1052
1210
|
return rawMethod.call(parent, targetChild);
|
|
1053
1211
|
}
|
|
1054
1212
|
return targetChild;
|
|
1055
1213
|
}
|
|
1056
|
-
|
|
1214
|
+
// TODO: __DEV__
|
|
1215
|
+
if (process.env.NODE_ENV !== 'production' &&
|
|
1216
|
+
targetChild instanceof HTMLIFrameElement &&
|
|
1217
|
+
rawMethod === globalEnv.rawAppendChild) {
|
|
1218
|
+
fixReactHMRConflict(app);
|
|
1219
|
+
}
|
|
1220
|
+
return invokeRawMethod(rawMethod, hijackElement, targetChild, passiveChild);
|
|
1057
1221
|
}
|
|
1058
1222
|
return invokeRawMethod(rawMethod, parent, targetChild, passiveChild);
|
|
1059
1223
|
}
|
|
1060
|
-
|
|
1061
|
-
|
|
1062
|
-
return rawMethod.call(parent, targetChild);
|
|
1063
|
-
}
|
|
1064
|
-
return rawMethod.call(parent, targetChild, passiveChild);
|
|
1065
|
-
}
|
|
1066
|
-
function isPendMethod(method) {
|
|
1067
|
-
return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
|
|
1068
|
-
}
|
|
1069
|
-
function getContainer(node, app) {
|
|
1224
|
+
// head/body map to micro-app-head/micro-app-body
|
|
1225
|
+
function getHijackElement(node, app) {
|
|
1070
1226
|
var _a, _b;
|
|
1071
1227
|
if (node === document.head) {
|
|
1072
1228
|
return (_a = app === null || app === void 0 ? void 0 : app.container) === null || _a === void 0 ? void 0 : _a.querySelector('micro-app-head');
|
|
@@ -1076,6 +1232,15 @@ function getContainer(node, app) {
|
|
|
1076
1232
|
}
|
|
1077
1233
|
return null;
|
|
1078
1234
|
}
|
|
1235
|
+
function invokeRawMethod(rawMethod, parent, targetChild, passiveChild) {
|
|
1236
|
+
if (isPendMethod(rawMethod)) {
|
|
1237
|
+
return rawMethod.call(parent, targetChild);
|
|
1238
|
+
}
|
|
1239
|
+
return rawMethod.call(parent, targetChild, passiveChild);
|
|
1240
|
+
}
|
|
1241
|
+
function isPendMethod(method) {
|
|
1242
|
+
return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
|
|
1243
|
+
}
|
|
1079
1244
|
// Get the map element
|
|
1080
1245
|
function getMappingNode(node) {
|
|
1081
1246
|
var _a;
|
|
@@ -1089,20 +1254,35 @@ function getMappingNode(node) {
|
|
|
1089
1254
|
* @param rawMethod method
|
|
1090
1255
|
*/
|
|
1091
1256
|
function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
1092
|
-
|
|
1257
|
+
const currentAppName = getCurrentAppName();
|
|
1258
|
+
if (newChild instanceof Node &&
|
|
1259
|
+
(newChild.__MICRO_APP_NAME__ ||
|
|
1260
|
+
(currentAppName && !newChild.__PURE_ELEMENT__))) {
|
|
1261
|
+
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1093
1262
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1094
1263
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1264
|
+
if (newChild instanceof Element) {
|
|
1265
|
+
if (/^(img|script)$/i.test(newChild.tagName)) {
|
|
1266
|
+
if (newChild.hasAttribute('src')) {
|
|
1267
|
+
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
1268
|
+
}
|
|
1269
|
+
if (newChild.hasAttribute('srcset')) {
|
|
1270
|
+
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
1271
|
+
}
|
|
1272
|
+
}
|
|
1273
|
+
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
1274
|
+
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
1275
|
+
}
|
|
1276
|
+
}
|
|
1095
1277
|
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(parent, newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
1096
1278
|
}
|
|
1097
1279
|
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1098
1280
|
return rawMethod.call(parent, newChild);
|
|
1099
1281
|
}
|
|
1100
|
-
return rawMethod.call(parent, newChild, passiveChild);
|
|
1101
1282
|
}
|
|
1102
1283
|
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1103
|
-
|
|
1104
|
-
|
|
1105
|
-
const app = appInstanceMap.get(appName);
|
|
1284
|
+
if (!(newChild instanceof Node) && currentAppName) {
|
|
1285
|
+
const app = appInstanceMap.get(currentAppName);
|
|
1106
1286
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1107
1287
|
if (parent === document.head) {
|
|
1108
1288
|
return rawMethod.call(app.container.querySelector('micro-app-head'), newChild);
|
|
@@ -1148,12 +1328,18 @@ function patchElementPrototypeMethods() {
|
|
|
1148
1328
|
};
|
|
1149
1329
|
// prototype methods of delete element👇
|
|
1150
1330
|
Element.prototype.removeChild = function removeChild(oldChild) {
|
|
1331
|
+
var _a;
|
|
1151
1332
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1152
1333
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1153
1334
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1154
1335
|
return invokePrototypeMethod(app, globalEnv.rawRemoveChild, this, getMappingNode(oldChild));
|
|
1155
1336
|
}
|
|
1156
|
-
|
|
1337
|
+
try {
|
|
1338
|
+
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1339
|
+
}
|
|
1340
|
+
catch (_b) {
|
|
1341
|
+
return (_a = oldChild === null || oldChild === void 0 ? void 0 : oldChild.parentNode) === null || _a === void 0 ? void 0 : _a.removeChild(oldChild);
|
|
1342
|
+
}
|
|
1157
1343
|
}
|
|
1158
1344
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1159
1345
|
};
|
|
@@ -1163,36 +1349,15 @@ function patchElementPrototypeMethods() {
|
|
|
1163
1349
|
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
1164
1350
|
return clonedNode;
|
|
1165
1351
|
};
|
|
1166
|
-
// patch getBoundingClientRect
|
|
1167
|
-
// TODO: scenes test
|
|
1168
|
-
// Element.prototype.getBoundingClientRect = function getBoundingClientRect () {
|
|
1169
|
-
// const rawRect: DOMRect = globalEnv.rawGetBoundingClientRect.call(this)
|
|
1170
|
-
// if (this.__MICRO_APP_NAME__) {
|
|
1171
|
-
// const app = appInstanceMap.get(this.__MICRO_APP_NAME__)
|
|
1172
|
-
// if (!app?.container) {
|
|
1173
|
-
// return rawRect
|
|
1174
|
-
// }
|
|
1175
|
-
// const appBody = app.container.querySelector('micro-app-body')
|
|
1176
|
-
// const appBodyRect: DOMRect = globalEnv.rawGetBoundingClientRect.call(appBody)
|
|
1177
|
-
// const computedRect: DOMRect = new DOMRect(
|
|
1178
|
-
// rawRect.x - appBodyRect.x,
|
|
1179
|
-
// rawRect.y - appBodyRect.y,
|
|
1180
|
-
// rawRect.width,
|
|
1181
|
-
// rawRect.height,
|
|
1182
|
-
// )
|
|
1183
|
-
// return computedRect
|
|
1184
|
-
// }
|
|
1185
|
-
// return rawRect
|
|
1186
|
-
// }
|
|
1187
1352
|
}
|
|
1188
1353
|
/**
|
|
1189
1354
|
* Mark the newly created element in the micro application
|
|
1190
1355
|
* @param element new element
|
|
1191
1356
|
*/
|
|
1192
1357
|
function markElement(element) {
|
|
1193
|
-
const
|
|
1194
|
-
if (
|
|
1195
|
-
element.__MICRO_APP_NAME__ =
|
|
1358
|
+
const currentAppName = getCurrentAppName();
|
|
1359
|
+
if (currentAppName)
|
|
1360
|
+
element.__MICRO_APP_NAME__ = currentAppName;
|
|
1196
1361
|
return element;
|
|
1197
1362
|
}
|
|
1198
1363
|
// methods of document
|
|
@@ -1213,27 +1378,29 @@ function patchDocument() {
|
|
|
1213
1378
|
};
|
|
1214
1379
|
// query element👇
|
|
1215
1380
|
function querySelector(selectors) {
|
|
1216
|
-
var _a, _b, _c;
|
|
1217
|
-
const
|
|
1218
|
-
if (!
|
|
1381
|
+
var _a, _b, _c, _d;
|
|
1382
|
+
const currentAppName = getCurrentAppName();
|
|
1383
|
+
if (!currentAppName ||
|
|
1384
|
+
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1219
1385
|
!selectors ||
|
|
1220
1386
|
isUniqueElement(selectors) ||
|
|
1221
1387
|
// see https://github.com/micro-zoe/micro-app/issues/56
|
|
1222
1388
|
rawDocument !== this) {
|
|
1223
1389
|
return globalEnv.rawQuerySelector.call(this, selectors);
|
|
1224
1390
|
}
|
|
1225
|
-
return (
|
|
1391
|
+
return (_d = (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.container) === null || _c === void 0 ? void 0 : _c.querySelector(selectors)) !== null && _d !== void 0 ? _d : null;
|
|
1226
1392
|
}
|
|
1227
1393
|
function querySelectorAll(selectors) {
|
|
1228
|
-
var _a, _b, _c;
|
|
1229
|
-
const
|
|
1230
|
-
if (!
|
|
1394
|
+
var _a, _b, _c, _d;
|
|
1395
|
+
const currentAppName = getCurrentAppName();
|
|
1396
|
+
if (!currentAppName ||
|
|
1397
|
+
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1231
1398
|
!selectors ||
|
|
1232
1399
|
isUniqueElement(selectors) ||
|
|
1233
1400
|
rawDocument !== this) {
|
|
1234
1401
|
return globalEnv.rawQuerySelectorAll.call(this, selectors);
|
|
1235
1402
|
}
|
|
1236
|
-
return (
|
|
1403
|
+
return (_d = (_c = (_b = appInstanceMap.get(currentAppName)) === null || _b === void 0 ? void 0 : _b.container) === null || _c === void 0 ? void 0 : _c.querySelectorAll(selectors)) !== null && _d !== void 0 ? _d : [];
|
|
1237
1404
|
}
|
|
1238
1405
|
Document.prototype.querySelector = querySelector;
|
|
1239
1406
|
Document.prototype.querySelectorAll = querySelectorAll;
|
|
@@ -1261,11 +1428,11 @@ function patchDocument() {
|
|
|
1261
1428
|
};
|
|
1262
1429
|
Document.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
1263
1430
|
var _a;
|
|
1264
|
-
const
|
|
1265
|
-
if (!
|
|
1431
|
+
const currentAppName = getCurrentAppName();
|
|
1432
|
+
if (!currentAppName ||
|
|
1266
1433
|
isUniqueElement(key) ||
|
|
1267
1434
|
isInvalidQuerySelectorKey(key) ||
|
|
1268
|
-
(!((_a = appInstanceMap.get(
|
|
1435
|
+
(!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
1269
1436
|
return globalEnv.rawGetElementsByTagName.call(this, key);
|
|
1270
1437
|
}
|
|
1271
1438
|
try {
|
|
@@ -1301,10 +1468,9 @@ function patchSetAttribute() {
|
|
|
1301
1468
|
if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
|
|
1302
1469
|
if (isPlainObject(value)) {
|
|
1303
1470
|
const cloneValue = {};
|
|
1304
|
-
Object.getOwnPropertyNames(value).forEach((
|
|
1305
|
-
if (!(isString(
|
|
1306
|
-
|
|
1307
|
-
cloneValue[propertyKey] = value[propertyKey];
|
|
1471
|
+
Object.getOwnPropertyNames(value).forEach((ownKey) => {
|
|
1472
|
+
if (!(isString(ownKey) && ownKey.indexOf('__') === 0)) {
|
|
1473
|
+
cloneValue[ownKey] = value[ownKey];
|
|
1308
1474
|
}
|
|
1309
1475
|
});
|
|
1310
1476
|
this.data = cloneValue;
|
|
@@ -1313,14 +1479,15 @@ function patchSetAttribute() {
|
|
|
1313
1479
|
logWarn('property data must be an object', this.getAttribute('name'));
|
|
1314
1480
|
}
|
|
1315
1481
|
}
|
|
1316
|
-
else if ((((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
|
|
1317
|
-
(key === 'href' && /^link$/i.test(this.tagName))) &&
|
|
1318
|
-
this.__MICRO_APP_NAME__ &&
|
|
1319
|
-
appInstanceMap.has(this.__MICRO_APP_NAME__)) {
|
|
1320
|
-
const app = appInstanceMap.get(this.__MICRO_APP_NAME__);
|
|
1321
|
-
globalEnv.rawSetAttribute.call(this, key, CompletionPath(value, app.url));
|
|
1322
|
-
}
|
|
1323
1482
|
else {
|
|
1483
|
+
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
1484
|
+
if (appName &&
|
|
1485
|
+
appInstanceMap.has(appName) &&
|
|
1486
|
+
(((key === 'src' || key === 'srcset') && /^(img|script)$/i.test(this.tagName)) ||
|
|
1487
|
+
(key === 'href' && /^link$/i.test(this.tagName)))) {
|
|
1488
|
+
const app = appInstanceMap.get(appName);
|
|
1489
|
+
value = CompletionPath(value, app.url);
|
|
1490
|
+
}
|
|
1324
1491
|
globalEnv.rawSetAttribute.call(this, key, value);
|
|
1325
1492
|
}
|
|
1326
1493
|
};
|
|
@@ -1351,7 +1518,6 @@ function releasePatches() {
|
|
|
1351
1518
|
Element.prototype.append = globalEnv.rawAppend;
|
|
1352
1519
|
Element.prototype.prepend = globalEnv.rawPrepend;
|
|
1353
1520
|
Element.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
1354
|
-
// Element.prototype.getBoundingClientRect = globalEnv.rawGetBoundingClientRect
|
|
1355
1521
|
}
|
|
1356
1522
|
// Set the style of micro-app-head and micro-app-body
|
|
1357
1523
|
let hasRejectMicroAppStyle = false;
|
|
@@ -1365,53 +1531,6 @@ function rejectMicroAppStyle() {
|
|
|
1365
1531
|
}
|
|
1366
1532
|
}
|
|
1367
1533
|
|
|
1368
|
-
// 管理 app 的单例
|
|
1369
|
-
class AppManager {
|
|
1370
|
-
constructor() {
|
|
1371
|
-
// Todo: appInstanceMap 由 AppManager 来创建,不再由 create_app 管理
|
|
1372
|
-
this.appInstanceMap = appInstanceMap;
|
|
1373
|
-
}
|
|
1374
|
-
static getInstance() {
|
|
1375
|
-
if (!this.instance) {
|
|
1376
|
-
this.instance = new AppManager();
|
|
1377
|
-
}
|
|
1378
|
-
return this.instance;
|
|
1379
|
-
}
|
|
1380
|
-
get(appName) {
|
|
1381
|
-
return this.appInstanceMap.get(appName);
|
|
1382
|
-
}
|
|
1383
|
-
set(appName, app) {
|
|
1384
|
-
this.appInstanceMap.set(appName, app);
|
|
1385
|
-
}
|
|
1386
|
-
getAll() {
|
|
1387
|
-
return Array.from(this.appInstanceMap.values());
|
|
1388
|
-
}
|
|
1389
|
-
clear() {
|
|
1390
|
-
this.appInstanceMap.clear();
|
|
1391
|
-
}
|
|
1392
|
-
}
|
|
1393
|
-
|
|
1394
|
-
function unmountNestedApp() {
|
|
1395
|
-
releaseUnmountOfNestedApp();
|
|
1396
|
-
AppManager.getInstance().getAll().forEach(app => {
|
|
1397
|
-
// @ts-ignore
|
|
1398
|
-
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
1399
|
-
});
|
|
1400
|
-
!window.__MICRO_APP_UMD_MODE__ && AppManager.getInstance().clear();
|
|
1401
|
-
}
|
|
1402
|
-
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
1403
|
-
function listenUmountOfNestedApp() {
|
|
1404
|
-
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
1405
|
-
window.addEventListener('unmount', unmountNestedApp, false);
|
|
1406
|
-
}
|
|
1407
|
-
}
|
|
1408
|
-
// release listener
|
|
1409
|
-
function releaseUnmountOfNestedApp() {
|
|
1410
|
-
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
1411
|
-
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
1412
|
-
}
|
|
1413
|
-
}
|
|
1414
|
-
|
|
1415
1534
|
const globalEnv = {};
|
|
1416
1535
|
/**
|
|
1417
1536
|
* Note loop nesting
|
|
@@ -1431,7 +1550,6 @@ function initGlobalEnv() {
|
|
|
1431
1550
|
const rawAppend = Element.prototype.append;
|
|
1432
1551
|
const rawPrepend = Element.prototype.prepend;
|
|
1433
1552
|
const rawCloneNode = Element.prototype.cloneNode;
|
|
1434
|
-
// const rawGetBoundingClientRect = Element.prototype.getBoundingClientRect
|
|
1435
1553
|
const rawCreateElement = Document.prototype.createElement;
|
|
1436
1554
|
const rawCreateElementNS = Document.prototype.createElementNS;
|
|
1437
1555
|
const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
|
|
@@ -1465,7 +1583,7 @@ function initGlobalEnv() {
|
|
|
1465
1583
|
const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
|
|
1466
1584
|
// mark current application as base application
|
|
1467
1585
|
window.__MICRO_APP_BASE_APPLICATION__ = true;
|
|
1468
|
-
|
|
1586
|
+
assign(globalEnv, {
|
|
1469
1587
|
// source/patch
|
|
1470
1588
|
rawSetAttribute,
|
|
1471
1589
|
rawAppendChild,
|
|
@@ -1475,7 +1593,6 @@ function initGlobalEnv() {
|
|
|
1475
1593
|
rawAppend,
|
|
1476
1594
|
rawPrepend,
|
|
1477
1595
|
rawCloneNode,
|
|
1478
|
-
// rawGetBoundingClientRect,
|
|
1479
1596
|
rawCreateElement,
|
|
1480
1597
|
rawCreateElementNS,
|
|
1481
1598
|
rawCreateDocumentFragment,
|
|
@@ -1502,8 +1619,6 @@ function initGlobalEnv() {
|
|
|
1502
1619
|
});
|
|
1503
1620
|
// global effect
|
|
1504
1621
|
rejectMicroAppStyle();
|
|
1505
|
-
releaseUnmountOfNestedApp();
|
|
1506
|
-
listenUmountOfNestedApp();
|
|
1507
1622
|
}
|
|
1508
1623
|
}
|
|
1509
1624
|
|
|
@@ -1519,14 +1634,11 @@ const globalScripts = new Map();
|
|
|
1519
1634
|
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
1520
1635
|
let replaceComment = null;
|
|
1521
1636
|
let src = script.getAttribute('src');
|
|
1522
|
-
if (
|
|
1523
|
-
src = CompletionPath(src, app.url);
|
|
1524
|
-
}
|
|
1525
|
-
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
1637
|
+
if (script.hasAttribute('exclude')) {
|
|
1526
1638
|
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
1527
1639
|
}
|
|
1528
1640
|
else if ((script.type && !['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module'].includes(script.type)) ||
|
|
1529
|
-
script.hasAttribute('ignore')
|
|
1641
|
+
script.hasAttribute('ignore')) {
|
|
1530
1642
|
return null;
|
|
1531
1643
|
}
|
|
1532
1644
|
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
@@ -1534,6 +1646,7 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
1534
1646
|
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
1535
1647
|
}
|
|
1536
1648
|
else if (src) { // remote script
|
|
1649
|
+
src = CompletionPath(src, app.url);
|
|
1537
1650
|
const info = {
|
|
1538
1651
|
code: '',
|
|
1539
1652
|
isExternal: true,
|
|
@@ -1583,46 +1696,6 @@ function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
|
1583
1696
|
return parent.replaceChild(replaceComment, script);
|
|
1584
1697
|
}
|
|
1585
1698
|
}
|
|
1586
|
-
/**
|
|
1587
|
-
* get assets plugins
|
|
1588
|
-
* @param appName app name
|
|
1589
|
-
*/
|
|
1590
|
-
function getAssetsPlugins(appName) {
|
|
1591
|
-
var _a, _b, _c;
|
|
1592
|
-
const globalPlugins = ((_a = microApp.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
1593
|
-
const modulePlugins = ((_c = (_b = microApp.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
1594
|
-
return [...globalPlugins, ...modulePlugins];
|
|
1595
|
-
}
|
|
1596
|
-
/**
|
|
1597
|
-
* whether the url needs to be excluded
|
|
1598
|
-
* @param url css or js link
|
|
1599
|
-
* @param plugins microApp plugins
|
|
1600
|
-
*/
|
|
1601
|
-
function checkExcludeUrl(url, appName) {
|
|
1602
|
-
if (!url)
|
|
1603
|
-
return false;
|
|
1604
|
-
const plugins = getAssetsPlugins(appName) || [];
|
|
1605
|
-
return plugins.some(plugin => {
|
|
1606
|
-
if (!plugin.excludeChecker)
|
|
1607
|
-
return false;
|
|
1608
|
-
return plugin.excludeChecker(url);
|
|
1609
|
-
});
|
|
1610
|
-
}
|
|
1611
|
-
/**
|
|
1612
|
-
* whether the url needs to be ignore
|
|
1613
|
-
* @param url css or js link
|
|
1614
|
-
* @param plugins microApp plugins
|
|
1615
|
-
*/
|
|
1616
|
-
function checkIgnoreUrl(url, appName) {
|
|
1617
|
-
if (!url)
|
|
1618
|
-
return false;
|
|
1619
|
-
const plugins = getAssetsPlugins(appName) || [];
|
|
1620
|
-
return plugins.some(plugin => {
|
|
1621
|
-
if (!plugin.ignoreChecker)
|
|
1622
|
-
return false;
|
|
1623
|
-
return plugin.ignoreChecker(url);
|
|
1624
|
-
});
|
|
1625
|
-
}
|
|
1626
1699
|
/**
|
|
1627
1700
|
* Get remote resources of script
|
|
1628
1701
|
* @param wrapElement htmlDom
|
|
@@ -1899,10 +1972,10 @@ function flatChildren(parent, app, microAppHead) {
|
|
|
1899
1972
|
});
|
|
1900
1973
|
for (const dom of children) {
|
|
1901
1974
|
if (dom instanceof HTMLLinkElement) {
|
|
1902
|
-
if (dom.hasAttribute('exclude')
|
|
1975
|
+
if (dom.hasAttribute('exclude')) {
|
|
1903
1976
|
parent.replaceChild(document.createComment('link element with exclude attribute ignored by micro-app'), dom);
|
|
1904
1977
|
}
|
|
1905
|
-
else if (!
|
|
1978
|
+
else if (!dom.hasAttribute('ignore')) {
|
|
1906
1979
|
extractLinkFromHtml(dom, parent, app);
|
|
1907
1980
|
}
|
|
1908
1981
|
else if (dom.hasAttribute('href')) {
|
|
@@ -1956,6 +2029,34 @@ function extractSourceDom(htmlStr, app) {
|
|
|
1956
2029
|
app.onLoad(wrapElement);
|
|
1957
2030
|
}
|
|
1958
2031
|
}
|
|
2032
|
+
/**
|
|
2033
|
+
* Get and format html
|
|
2034
|
+
* @param app app
|
|
2035
|
+
*/
|
|
2036
|
+
function extractHtml(app) {
|
|
2037
|
+
fetchSource(app.ssrUrl || app.url, app.name, { cache: 'no-cache' }).then((htmlStr) => {
|
|
2038
|
+
if (!htmlStr) {
|
|
2039
|
+
const msg = 'html is empty, please check in detail';
|
|
2040
|
+
app.onerror(new Error(msg));
|
|
2041
|
+
return logError(msg, app.name);
|
|
2042
|
+
}
|
|
2043
|
+
htmlStr = htmlStr
|
|
2044
|
+
.replace(/<head[^>]*>[\s\S]*?<\/head>/i, (match) => {
|
|
2045
|
+
return match
|
|
2046
|
+
.replace(/<head/i, '<micro-app-head')
|
|
2047
|
+
.replace(/<\/head>/i, '</micro-app-head>');
|
|
2048
|
+
})
|
|
2049
|
+
.replace(/<body[^>]*>[\s\S]*?<\/body>/i, (match) => {
|
|
2050
|
+
return match
|
|
2051
|
+
.replace(/<body/i, '<micro-app-body')
|
|
2052
|
+
.replace(/<\/body>/i, '</micro-app-body>');
|
|
2053
|
+
});
|
|
2054
|
+
extractSourceDom(htmlStr, app);
|
|
2055
|
+
}).catch((e) => {
|
|
2056
|
+
logError(`Failed to fetch data from ${app.url}, micro-app stop rendering`, app.name, e);
|
|
2057
|
+
app.onLoadError(e);
|
|
2058
|
+
});
|
|
2059
|
+
}
|
|
1959
2060
|
|
|
1960
2061
|
class EventCenter {
|
|
1961
2062
|
constructor() {
|
|
@@ -2238,45 +2339,77 @@ function rebuildDataCenterSnapshot(microAppEventCenter) {
|
|
|
2238
2339
|
}
|
|
2239
2340
|
}
|
|
2240
2341
|
|
|
2342
|
+
function unmountNestedApp() {
|
|
2343
|
+
appInstanceMap.forEach(app => {
|
|
2344
|
+
// @ts-ignore
|
|
2345
|
+
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
2346
|
+
});
|
|
2347
|
+
!window.__MICRO_APP_UMD_MODE__ && appInstanceMap.clear();
|
|
2348
|
+
}
|
|
2349
|
+
// release listener
|
|
2350
|
+
function releaseUnmountOfNestedApp() {
|
|
2351
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2352
|
+
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
2353
|
+
}
|
|
2354
|
+
}
|
|
2355
|
+
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
2356
|
+
// unmount event will auto release by sandbox
|
|
2357
|
+
function initEnvOfNestedApp() {
|
|
2358
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2359
|
+
releaseUnmountOfNestedApp();
|
|
2360
|
+
window.addEventListener('unmount', unmountNestedApp, false);
|
|
2361
|
+
}
|
|
2362
|
+
}
|
|
2363
|
+
|
|
2241
2364
|
/* eslint-disable no-return-assign */
|
|
2242
2365
|
function isBoundedFunction(value) {
|
|
2243
2366
|
if (isBoolean(value.__MICRO_APP_IS_BOUND_FUNCTION__))
|
|
2244
2367
|
return value.__MICRO_APP_IS_BOUND_FUNCTION__;
|
|
2245
2368
|
return value.__MICRO_APP_IS_BOUND_FUNCTION__ = isBoundFunction(value);
|
|
2246
2369
|
}
|
|
2247
|
-
function
|
|
2248
|
-
var _a;
|
|
2370
|
+
function isConstructorFunction(value) {
|
|
2249
2371
|
if (isBoolean(value.__MICRO_APP_IS_CONSTRUCTOR__))
|
|
2250
2372
|
return value.__MICRO_APP_IS_CONSTRUCTOR__;
|
|
2251
|
-
|
|
2252
|
-
const result = (((_a = value.prototype) === null || _a === void 0 ? void 0 : _a.constructor) === value &&
|
|
2253
|
-
Object.getOwnPropertyNames(value.prototype).length > 1) ||
|
|
2254
|
-
/^function\s+[A-Z]/.test(valueStr) ||
|
|
2255
|
-
/^class\s+/.test(valueStr);
|
|
2256
|
-
return value.__MICRO_APP_IS_CONSTRUCTOR__ = result;
|
|
2373
|
+
return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
|
|
2257
2374
|
}
|
|
2258
2375
|
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
2259
|
-
function
|
|
2260
|
-
|
|
2261
|
-
|
|
2262
|
-
|
|
2263
|
-
|
|
2376
|
+
function bindFunctionToRawObject(rawObject, value, key = 'WINDOW') {
|
|
2377
|
+
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
2378
|
+
if (value[cacheKey])
|
|
2379
|
+
return value[cacheKey];
|
|
2380
|
+
if (!isConstructorFunction(value) && !isBoundedFunction(value)) {
|
|
2381
|
+
const bindRawObjectValue = value.bind(rawObject);
|
|
2264
2382
|
for (const key in value) {
|
|
2265
|
-
|
|
2383
|
+
bindRawObjectValue[key] = value[key];
|
|
2266
2384
|
}
|
|
2267
2385
|
if (value.hasOwnProperty('prototype')) {
|
|
2268
|
-
rawDefineProperty(
|
|
2386
|
+
rawDefineProperty(bindRawObjectValue, 'prototype', {
|
|
2269
2387
|
value: value.prototype,
|
|
2270
2388
|
configurable: true,
|
|
2271
2389
|
enumerable: false,
|
|
2272
2390
|
writable: true,
|
|
2273
2391
|
});
|
|
2274
2392
|
}
|
|
2275
|
-
return value
|
|
2393
|
+
return value[cacheKey] = bindRawObjectValue;
|
|
2276
2394
|
}
|
|
2277
2395
|
return value;
|
|
2278
2396
|
}
|
|
2279
2397
|
|
|
2398
|
+
// this events should be sent to the specified app
|
|
2399
|
+
const formatEventList = ['unmount', 'appstate-change'];
|
|
2400
|
+
/**
|
|
2401
|
+
* Format event name
|
|
2402
|
+
* @param eventName event name
|
|
2403
|
+
* @param appName app name
|
|
2404
|
+
*/
|
|
2405
|
+
function formatEventName$1(eventName, appName) {
|
|
2406
|
+
var _a;
|
|
2407
|
+
if (formatEventList.includes(eventName) ||
|
|
2408
|
+
((eventName === 'popstate' || eventName === 'hashchange') && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.useMemoryRouter))) {
|
|
2409
|
+
return `${eventName}-${appName}`;
|
|
2410
|
+
}
|
|
2411
|
+
return eventName;
|
|
2412
|
+
}
|
|
2280
2413
|
// document.onclick binding list, the binding function of each application is unique
|
|
2281
2414
|
const documentClickListMap = new Map();
|
|
2282
2415
|
let hasRewriteDocumentOnClick = false;
|
|
@@ -2370,32 +2503,18 @@ function releaseEffectDocumentEvent() {
|
|
|
2370
2503
|
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
2371
2504
|
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
2372
2505
|
}
|
|
2373
|
-
// this events should be sent to the specified app
|
|
2374
|
-
const formatEventList = ['unmount', 'appstate-change'];
|
|
2375
|
-
/**
|
|
2376
|
-
* Format event name
|
|
2377
|
-
* @param type event name
|
|
2378
|
-
* @param microAppWindow micro window
|
|
2379
|
-
*/
|
|
2380
|
-
function formatEventType(type, microAppWindow) {
|
|
2381
|
-
if (formatEventList.includes(type)) {
|
|
2382
|
-
return `${type}-${microAppWindow.__MICRO_APP_NAME__}`;
|
|
2383
|
-
}
|
|
2384
|
-
return type;
|
|
2385
|
-
}
|
|
2386
2506
|
/**
|
|
2387
2507
|
* Rewrite side-effect events
|
|
2388
2508
|
* @param microAppWindow micro window
|
|
2389
2509
|
*/
|
|
2390
|
-
function effect(microAppWindow) {
|
|
2391
|
-
const appName = microAppWindow.__MICRO_APP_NAME__;
|
|
2510
|
+
function effect(appName, microAppWindow) {
|
|
2392
2511
|
const eventListenerMap = new Map();
|
|
2393
2512
|
const intervalIdMap = new Map();
|
|
2394
2513
|
const timeoutIdMap = new Map();
|
|
2395
2514
|
const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
|
|
2396
2515
|
// listener may be null, e.g test-passive
|
|
2397
2516
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
2398
|
-
type =
|
|
2517
|
+
type = formatEventName$1(type, appName);
|
|
2399
2518
|
const listenerList = eventListenerMap.get(type);
|
|
2400
2519
|
if (listenerList) {
|
|
2401
2520
|
listenerList.add(listener);
|
|
@@ -2407,7 +2526,7 @@ function effect(microAppWindow) {
|
|
|
2407
2526
|
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
2408
2527
|
};
|
|
2409
2528
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
2410
|
-
type =
|
|
2529
|
+
type = formatEventName$1(type, appName);
|
|
2411
2530
|
const listenerList = eventListenerMap.get(type);
|
|
2412
2531
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
2413
2532
|
listenerList.delete(listener);
|
|
@@ -2534,59 +2653,1015 @@ function effect(microAppWindow) {
|
|
|
2534
2653
|
};
|
|
2535
2654
|
}
|
|
2536
2655
|
|
|
2537
|
-
//
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
]
|
|
2542
|
-
|
|
2543
|
-
|
|
2544
|
-
|
|
2545
|
-
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2550
|
-
|
|
2551
|
-
|
|
2552
|
-
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
|
|
2557
|
-
|
|
2558
|
-
|
|
2559
|
-
|
|
2656
|
+
// set micro app state to origin state
|
|
2657
|
+
function setMicroState(appName, rawState, microState) {
|
|
2658
|
+
const additionalState = {
|
|
2659
|
+
microAppState: assign({}, rawState === null || rawState === void 0 ? void 0 : rawState.microAppState, {
|
|
2660
|
+
[appName]: microState
|
|
2661
|
+
})
|
|
2662
|
+
};
|
|
2663
|
+
// create new state object
|
|
2664
|
+
return assign({}, rawState, additionalState);
|
|
2665
|
+
}
|
|
2666
|
+
// delete micro app state form origin state
|
|
2667
|
+
function removeMicroState(appName, rawState) {
|
|
2668
|
+
if (isPlainObject(rawState === null || rawState === void 0 ? void 0 : rawState.microAppState)) {
|
|
2669
|
+
if (!isUndefined(rawState.microAppState[appName])) {
|
|
2670
|
+
delete rawState.microAppState[appName];
|
|
2671
|
+
}
|
|
2672
|
+
if (!Object.keys(rawState.microAppState).length) {
|
|
2673
|
+
delete rawState.microAppState;
|
|
2674
|
+
}
|
|
2675
|
+
}
|
|
2676
|
+
// 生成新的state对象
|
|
2677
|
+
return assign({}, rawState);
|
|
2678
|
+
}
|
|
2679
|
+
// get micro app state form origin state
|
|
2680
|
+
function getMicroState(appName, state) {
|
|
2681
|
+
var _a;
|
|
2682
|
+
return ((_a = state === null || state === void 0 ? void 0 : state.microAppState) === null || _a === void 0 ? void 0 : _a[appName]) || null;
|
|
2683
|
+
}
|
|
2684
|
+
const ENC_AD_RE = /&/g; // %M1
|
|
2685
|
+
const ENC_EQ_RE = /=/g; // %M2
|
|
2686
|
+
const DEC_AD_RE = /%M1/g; // &
|
|
2687
|
+
const DEC_EQ_RE = /%M2/g; // =
|
|
2688
|
+
function encodeMicroPath(path) {
|
|
2689
|
+
return encodeURIComponent(commonDecode(path).replace(ENC_AD_RE, '%M1').replace(ENC_EQ_RE, '%M2'));
|
|
2690
|
+
}
|
|
2691
|
+
function decodeMicroPath(path) {
|
|
2692
|
+
return commonDecode(path).replace(DEC_AD_RE, '&').replace(DEC_EQ_RE, '=');
|
|
2693
|
+
}
|
|
2694
|
+
function commonDecode(path) {
|
|
2695
|
+
try {
|
|
2696
|
+
const decPath = decodeURIComponent(path);
|
|
2697
|
+
if (path === decPath || DEC_AD_RE.test(decPath) || DEC_EQ_RE.test(decPath))
|
|
2698
|
+
return decPath;
|
|
2699
|
+
return commonDecode(decPath);
|
|
2700
|
+
}
|
|
2701
|
+
catch (_a) {
|
|
2702
|
+
return path;
|
|
2703
|
+
}
|
|
2704
|
+
}
|
|
2705
|
+
// 格式化query参数key,防止与原有参数的冲突
|
|
2706
|
+
function formatQueryAppName(appName) {
|
|
2707
|
+
return `app-${appName}`;
|
|
2708
|
+
}
|
|
2709
|
+
// 根据浏览器url参数,获取当前子应用的path
|
|
2710
|
+
function getMicroPathFromURL(appName) {
|
|
2711
|
+
var _a, _b;
|
|
2712
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
2713
|
+
const queryObject = getQueryObjectFromURL(rawLocation.search, rawLocation.hash);
|
|
2714
|
+
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)]);
|
|
2715
|
+
return isString(microPath) ? decodeMicroPath(microPath) : null;
|
|
2716
|
+
}
|
|
2717
|
+
// 将name=encodeUrl地址插入到浏览器url上
|
|
2718
|
+
function setMicroPathToURL(appName, microLocation) {
|
|
2719
|
+
let { pathname, search, hash } = globalEnv.rawWindow.location;
|
|
2720
|
+
const queryObject = getQueryObjectFromURL(search, hash);
|
|
2721
|
+
const encodedMicroPath = encodeMicroPath(microLocation.pathname +
|
|
2722
|
+
microLocation.search +
|
|
2723
|
+
microLocation.hash);
|
|
2724
|
+
let isAttach2Hash = false; // 基座是否是hash模式,这个其实也不准,只是表示参数加到了hash上
|
|
2725
|
+
// hash存在且search不存在,则认为是hash路由
|
|
2726
|
+
if (hash && !search) {
|
|
2727
|
+
isAttach2Hash = true;
|
|
2728
|
+
if (queryObject.hashQuery) {
|
|
2729
|
+
queryObject.hashQuery[formatQueryAppName(appName)] = encodedMicroPath;
|
|
2730
|
+
}
|
|
2731
|
+
else {
|
|
2732
|
+
queryObject.hashQuery = {
|
|
2733
|
+
[formatQueryAppName(appName)]: encodedMicroPath
|
|
2734
|
+
};
|
|
2735
|
+
}
|
|
2736
|
+
const baseHash = hash.includes('?') ? hash.slice(0, hash.indexOf('?') + 1) : hash + '?';
|
|
2737
|
+
hash = baseHash + stringifyQuery(queryObject.hashQuery);
|
|
2738
|
+
}
|
|
2739
|
+
else {
|
|
2740
|
+
if (queryObject.searchQuery) {
|
|
2741
|
+
queryObject.searchQuery[formatQueryAppName(appName)] = encodedMicroPath;
|
|
2742
|
+
}
|
|
2743
|
+
else {
|
|
2744
|
+
queryObject.searchQuery = {
|
|
2745
|
+
[formatQueryAppName(appName)]: encodedMicroPath
|
|
2746
|
+
};
|
|
2747
|
+
}
|
|
2748
|
+
search = '?' + stringifyQuery(queryObject.searchQuery);
|
|
2749
|
+
}
|
|
2750
|
+
return {
|
|
2751
|
+
fullPath: pathname + search + hash,
|
|
2752
|
+
isAttach2Hash,
|
|
2753
|
+
};
|
|
2754
|
+
}
|
|
2755
|
+
// 将name=encodeUrl的参数从浏览器url上删除
|
|
2756
|
+
function removeMicroPathFromURL(appName, targetLocation) {
|
|
2757
|
+
var _a, _b, _c, _d;
|
|
2758
|
+
let { pathname, search, hash } = targetLocation || globalEnv.rawWindow.location;
|
|
2759
|
+
const queryObject = getQueryObjectFromURL(search, hash);
|
|
2760
|
+
let isAttach2Hash = false;
|
|
2761
|
+
if ((_a = queryObject.hashQuery) === null || _a === void 0 ? void 0 : _a[formatQueryAppName(appName)]) {
|
|
2762
|
+
isAttach2Hash = true;
|
|
2763
|
+
(_b = queryObject.hashQuery) === null || _b === void 0 ? true : delete _b[formatQueryAppName(appName)];
|
|
2764
|
+
const hashQueryStr = stringifyQuery(queryObject.hashQuery);
|
|
2765
|
+
hash = hash.slice(0, hash.indexOf('?') + Number(Boolean(hashQueryStr))) + hashQueryStr;
|
|
2766
|
+
}
|
|
2767
|
+
else if ((_c = queryObject.searchQuery) === null || _c === void 0 ? void 0 : _c[formatQueryAppName(appName)]) {
|
|
2768
|
+
(_d = queryObject.searchQuery) === null || _d === void 0 ? true : delete _d[formatQueryAppName(appName)];
|
|
2769
|
+
const searchQueryStr = stringifyQuery(queryObject.searchQuery);
|
|
2770
|
+
search = searchQueryStr ? '?' + searchQueryStr : '';
|
|
2771
|
+
}
|
|
2772
|
+
return {
|
|
2773
|
+
fullPath: pathname + search + hash,
|
|
2774
|
+
isAttach2Hash,
|
|
2775
|
+
};
|
|
2776
|
+
}
|
|
2777
|
+
/**
|
|
2778
|
+
* 根据location获取query对象
|
|
2779
|
+
*/
|
|
2780
|
+
function getQueryObjectFromURL(search, hash) {
|
|
2781
|
+
const queryObject = {};
|
|
2782
|
+
if (search !== '' && search !== '?') {
|
|
2783
|
+
queryObject.searchQuery = parseQuery(search.slice(1));
|
|
2784
|
+
}
|
|
2785
|
+
if (hash.includes('?')) {
|
|
2786
|
+
queryObject.hashQuery = parseQuery(hash.slice(hash.indexOf('?') + 1));
|
|
2787
|
+
}
|
|
2788
|
+
return queryObject;
|
|
2789
|
+
}
|
|
2790
|
+
/**
|
|
2791
|
+
* get microApp path from browser URL without hash
|
|
2792
|
+
*/
|
|
2793
|
+
function getNoHashMicroPathFromURL(appName, baseUrl) {
|
|
2794
|
+
const microPath = getMicroPathFromURL(appName);
|
|
2795
|
+
if (!microPath)
|
|
2796
|
+
return '';
|
|
2797
|
+
const formatLocation = createURL(microPath, baseUrl);
|
|
2798
|
+
return formatLocation.origin + formatLocation.pathname + formatLocation.search;
|
|
2799
|
+
}
|
|
2800
|
+
|
|
2801
|
+
/**
|
|
2802
|
+
* dispatch PopStateEvent & HashChangeEvent to child app
|
|
2803
|
+
* each child app will listen for popstate event when sandbox start
|
|
2804
|
+
* and release it when sandbox stop
|
|
2805
|
+
* @param appName app name
|
|
2806
|
+
* @returns release callback
|
|
2807
|
+
*/
|
|
2808
|
+
function addHistoryListener(appName) {
|
|
2809
|
+
const rawWindow = globalEnv.rawWindow;
|
|
2810
|
+
// handle popstate event and distribute to child app
|
|
2811
|
+
const popStateHandler = (e) => {
|
|
2812
|
+
/**
|
|
2813
|
+
* 1. unmount app & hidden keep-alive app will not receive popstate event
|
|
2814
|
+
* 2. filter out onlyForBrowser
|
|
2815
|
+
*/
|
|
2816
|
+
if (getActiveApps(true).includes(appName) && !e.onlyForBrowser) {
|
|
2817
|
+
const microPath = getMicroPathFromURL(appName);
|
|
2818
|
+
const app = appInstanceMap.get(appName);
|
|
2819
|
+
const proxyWindow = app.sandBox.proxyWindow;
|
|
2820
|
+
let isHashChange = false;
|
|
2821
|
+
// for hashChangeEvent
|
|
2822
|
+
const oldHref = proxyWindow.location.href;
|
|
2823
|
+
// Do not attach micro state to url when microPath is empty
|
|
2824
|
+
if (microPath) {
|
|
2825
|
+
const oldHash = proxyWindow.location.hash;
|
|
2826
|
+
updateMicroLocation(appName, microPath, proxyWindow.location);
|
|
2827
|
+
isHashChange = proxyWindow.location.hash !== oldHash;
|
|
2828
|
+
}
|
|
2829
|
+
// dispatch formatted popStateEvent to child
|
|
2830
|
+
dispatchPopStateEventToMicroApp(appName, proxyWindow, rawWindow.history.state);
|
|
2831
|
+
// dispatch formatted hashChangeEvent to child when hash change
|
|
2832
|
+
if (isHashChange)
|
|
2833
|
+
dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref);
|
|
2834
|
+
// clear element scope before trigger event of next app
|
|
2835
|
+
removeDomScope();
|
|
2836
|
+
}
|
|
2837
|
+
};
|
|
2838
|
+
rawWindow.addEventListener('popstate', popStateHandler);
|
|
2839
|
+
return () => {
|
|
2840
|
+
rawWindow.removeEventListener('popstate', popStateHandler);
|
|
2841
|
+
};
|
|
2842
|
+
}
|
|
2843
|
+
/**
|
|
2844
|
+
* dispatch formatted popstate event to microApp
|
|
2845
|
+
* @param appName app name
|
|
2846
|
+
* @param proxyWindow sandbox window
|
|
2847
|
+
* @param eventState history.state
|
|
2848
|
+
*/
|
|
2849
|
+
function dispatchPopStateEventToMicroApp(appName, proxyWindow, eventState) {
|
|
2850
|
+
// create PopStateEvent named popstate-appName with sub app state
|
|
2851
|
+
const newPopStateEvent = new PopStateEvent(formatEventName$1('popstate', appName), { state: getMicroState(appName, eventState) });
|
|
2852
|
+
globalEnv.rawWindow.dispatchEvent(newPopStateEvent);
|
|
2853
|
+
// call function window.onpopstate if it exists
|
|
2854
|
+
typeof proxyWindow.onpopstate === 'function' && proxyWindow.onpopstate(newPopStateEvent);
|
|
2855
|
+
}
|
|
2856
|
+
/**
|
|
2857
|
+
* dispatch formatted hashchange event to microApp
|
|
2858
|
+
* @param appName app name
|
|
2859
|
+
* @param proxyWindow sandbox window
|
|
2860
|
+
* @param oldHref old href
|
|
2861
|
+
*/
|
|
2862
|
+
function dispatchHashChangeEventToMicroApp(appName, proxyWindow, oldHref) {
|
|
2863
|
+
const newHashChangeEvent = new HashChangeEvent(formatEventName$1('hashchange', appName), {
|
|
2864
|
+
newURL: proxyWindow.location.href,
|
|
2865
|
+
oldURL: oldHref,
|
|
2866
|
+
});
|
|
2867
|
+
globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
|
|
2868
|
+
// call function window.onhashchange if it exists
|
|
2869
|
+
typeof proxyWindow.onhashchange === 'function' && proxyWindow.onhashchange(newHashChangeEvent);
|
|
2870
|
+
}
|
|
2871
|
+
/**
|
|
2872
|
+
* dispatch native PopStateEvent, simulate location behavior
|
|
2873
|
+
* @param onlyForBrowser only dispatch PopStateEvent to browser
|
|
2874
|
+
*/
|
|
2875
|
+
function dispatchNativePopStateEvent(onlyForBrowser) {
|
|
2876
|
+
const event = new PopStateEvent('popstate', { state: null });
|
|
2877
|
+
if (onlyForBrowser)
|
|
2878
|
+
event.onlyForBrowser = true;
|
|
2879
|
+
globalEnv.rawWindow.dispatchEvent(event);
|
|
2880
|
+
}
|
|
2881
|
+
/**
|
|
2882
|
+
* dispatch hashchange event to browser
|
|
2883
|
+
* @param oldHref old href of rawWindow.location
|
|
2884
|
+
*/
|
|
2885
|
+
function dispatchNativeHashChangeEvent(oldHref) {
|
|
2886
|
+
const newHashChangeEvent = new HashChangeEvent('hashchange', {
|
|
2887
|
+
newURL: globalEnv.rawWindow.location.href,
|
|
2888
|
+
oldURL: oldHref,
|
|
2889
|
+
});
|
|
2890
|
+
globalEnv.rawWindow.dispatchEvent(newHashChangeEvent);
|
|
2891
|
+
}
|
|
2892
|
+
/**
|
|
2893
|
+
* dispatch popstate & hashchange event to browser
|
|
2894
|
+
* @param onlyForBrowser only dispatch event to browser
|
|
2895
|
+
* @param oldHref old href of rawWindow.location
|
|
2896
|
+
*/
|
|
2897
|
+
function dispatchNativeEvent(onlyForBrowser, oldHref) {
|
|
2898
|
+
// clear element scope before dispatch global event
|
|
2899
|
+
removeDomScope();
|
|
2900
|
+
dispatchNativePopStateEvent(onlyForBrowser);
|
|
2901
|
+
if (oldHref) {
|
|
2902
|
+
dispatchNativeHashChangeEvent(oldHref);
|
|
2903
|
+
}
|
|
2904
|
+
}
|
|
2905
|
+
|
|
2906
|
+
/**
|
|
2907
|
+
* create proxyHistory for microApp
|
|
2908
|
+
* MDN https://developer.mozilla.org/en-US/docs/Web/API/History
|
|
2909
|
+
* @param appName app name
|
|
2910
|
+
* @param microLocation microApp location
|
|
2911
|
+
*/
|
|
2912
|
+
function createMicroHistory(appName, microLocation) {
|
|
2913
|
+
const rawHistory = globalEnv.rawWindow.history;
|
|
2914
|
+
function getMicroHistoryMethod(methodName) {
|
|
2915
|
+
return function (...rests) {
|
|
2916
|
+
if (isString(rests[2]) || isURL(rests[2])) {
|
|
2917
|
+
const targetLocation = createURL(rests[2], microLocation.href);
|
|
2918
|
+
if (targetLocation.origin === microLocation.origin) {
|
|
2919
|
+
navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), true, setMicroState(appName, rawHistory.state, rests[0]), rests[1]);
|
|
2920
|
+
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
2921
|
+
if (targetFullPath !== microLocation.fullPath) {
|
|
2922
|
+
updateMicroLocation(appName, targetFullPath, microLocation);
|
|
2923
|
+
}
|
|
2924
|
+
}
|
|
2925
|
+
else {
|
|
2926
|
+
rawHistory[methodName].apply(rawHistory, rests);
|
|
2927
|
+
}
|
|
2928
|
+
}
|
|
2929
|
+
else {
|
|
2930
|
+
rawHistory[methodName].apply(rawHistory, rests);
|
|
2931
|
+
}
|
|
2932
|
+
};
|
|
2933
|
+
}
|
|
2934
|
+
const pushState = getMicroHistoryMethod('pushState');
|
|
2935
|
+
const replaceState = getMicroHistoryMethod('replaceState');
|
|
2936
|
+
return new Proxy(rawHistory, {
|
|
2937
|
+
get(target, key) {
|
|
2938
|
+
if (key === 'state') {
|
|
2939
|
+
return getMicroState(appName, rawHistory.state);
|
|
2940
|
+
}
|
|
2941
|
+
else if (key === 'pushState') {
|
|
2942
|
+
return pushState;
|
|
2943
|
+
}
|
|
2944
|
+
else if (key === 'replaceState') {
|
|
2945
|
+
return replaceState;
|
|
2946
|
+
}
|
|
2947
|
+
const rawValue = Reflect.get(target, key);
|
|
2948
|
+
return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'HISTORY') : rawValue;
|
|
2949
|
+
}
|
|
2950
|
+
});
|
|
2951
|
+
}
|
|
2952
|
+
/**
|
|
2953
|
+
* navigate to new path base on native method of history
|
|
2954
|
+
* @param methodName pushState/replaceState
|
|
2955
|
+
* @param fullPath full path
|
|
2956
|
+
* @param state history.state, default is null
|
|
2957
|
+
* @param title history.title, default is ''
|
|
2958
|
+
*/
|
|
2959
|
+
function nativeHistoryNavigate(methodName, fullPath, state = null, title = '') {
|
|
2960
|
+
globalEnv.rawWindow.history[methodName](state, title, fullPath);
|
|
2961
|
+
}
|
|
2962
|
+
/**
|
|
2963
|
+
* Navigate to new path, and dispatch native popStateEvent/hashChangeEvent to browser
|
|
2964
|
+
* Use scenes:
|
|
2965
|
+
* 1. mount/unmount through attachRouteToBrowserURL with limited popstateEvent
|
|
2966
|
+
* 2. proxyHistory.pushState/replaceState with limited popstateEvent
|
|
2967
|
+
* 3. api microApp.router.push/replace
|
|
2968
|
+
* 4. proxyLocation.hash = xxx
|
|
2969
|
+
* @param methodName pushState/replaceState
|
|
2970
|
+
* @param result result of add/remove microApp path on browser url
|
|
2971
|
+
* @param onlyForBrowser only dispatch event to browser
|
|
2972
|
+
* @param state history.state, not required
|
|
2973
|
+
* @param title history.title, not required
|
|
2974
|
+
*/
|
|
2975
|
+
function navigateWithNativeEvent(methodName, result, onlyForBrowser, state, title) {
|
|
2976
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
2977
|
+
const oldFullPath = rawLocation.pathname + rawLocation.search + rawLocation.hash;
|
|
2978
|
+
const oldHref = result.isAttach2Hash && oldFullPath !== result.fullPath ? rawLocation.href : null;
|
|
2979
|
+
// navigate with native history method
|
|
2980
|
+
nativeHistoryNavigate(methodName, result.fullPath, state, title);
|
|
2981
|
+
if (oldFullPath !== result.fullPath)
|
|
2982
|
+
dispatchNativeEvent(onlyForBrowser, oldHref);
|
|
2983
|
+
}
|
|
2984
|
+
/**
|
|
2985
|
+
* update browser url when mount/unmount/hidden/show/attachToURL/attachAllToURL
|
|
2986
|
+
* just attach microRoute info to browser, dispatch event to base app(exclude child)
|
|
2987
|
+
* @param result result of add/remove microApp path on browser url
|
|
2988
|
+
* @param state history.state
|
|
2989
|
+
*/
|
|
2990
|
+
function attachRouteToBrowserURL(result, state) {
|
|
2991
|
+
navigateWithNativeEvent('replaceState', result, true, state);
|
|
2992
|
+
}
|
|
2993
|
+
/**
|
|
2994
|
+
* When path is same, keep the microAppState in history.state
|
|
2995
|
+
* Fix bug of missing microAppState in next.js & angular
|
|
2996
|
+
* @param method history.pushState/replaceState
|
|
2997
|
+
*/
|
|
2998
|
+
function patchHistoryState(method) {
|
|
2999
|
+
const rawWindow = globalEnv.rawWindow;
|
|
3000
|
+
return function (...rests) {
|
|
3001
|
+
var _a;
|
|
3002
|
+
if (((_a = rawWindow.history.state) === null || _a === void 0 ? void 0 : _a.microAppState) &&
|
|
3003
|
+
(!isPlainObject(rests[0]) || !rests[0].microAppState) &&
|
|
3004
|
+
(isString(rests[2]) || isURL(rests[2]))) {
|
|
3005
|
+
const currentHref = rawWindow.location.href;
|
|
3006
|
+
const targetLocation = createURL(rests[2], currentHref);
|
|
3007
|
+
if (targetLocation.href === currentHref) {
|
|
3008
|
+
rests[0] = assign({}, rests[0], {
|
|
3009
|
+
microAppState: rawWindow.history.state.microAppState,
|
|
3010
|
+
});
|
|
3011
|
+
}
|
|
3012
|
+
}
|
|
3013
|
+
method.apply(rawWindow.history, rests);
|
|
3014
|
+
};
|
|
3015
|
+
}
|
|
3016
|
+
let isReWriteHistoryState = false;
|
|
3017
|
+
/**
|
|
3018
|
+
* rewrite history.pushState/replaceState
|
|
3019
|
+
* used to fix the problem that the microAppState maybe missing when mainApp navigate to same path
|
|
3020
|
+
* e.g: when nextjs, angular receive popstate event, they will use history.replaceState to update browser url with a new state object
|
|
3021
|
+
*/
|
|
3022
|
+
function rewriteHistoryState() {
|
|
3023
|
+
// filter nest app
|
|
3024
|
+
if (!isReWriteHistoryState && !window.__MICRO_APP_ENVIRONMENT__) {
|
|
3025
|
+
isReWriteHistoryState = true;
|
|
3026
|
+
const rawWindow = globalEnv.rawWindow;
|
|
3027
|
+
rawWindow.history.pushState = patchHistoryState(rawWindow.history.pushState);
|
|
3028
|
+
rawWindow.history.replaceState = patchHistoryState(rawWindow.history.replaceState);
|
|
3029
|
+
}
|
|
3030
|
+
}
|
|
3031
|
+
|
|
3032
|
+
function createRouterApi() {
|
|
3033
|
+
/**
|
|
3034
|
+
* common handler for router.push/router.replace method
|
|
3035
|
+
* @param appName app name
|
|
3036
|
+
* @param methodName replaceState/pushState
|
|
3037
|
+
* @param targetLocation target location
|
|
3038
|
+
* @param state to.state
|
|
3039
|
+
*/
|
|
3040
|
+
function navigateWithRawHistory(appName, methodName, targetLocation, state) {
|
|
3041
|
+
navigateWithNativeEvent(methodName, setMicroPathToURL(appName, targetLocation), false, setMicroState(appName, globalEnv.rawWindow.history.state, state !== null && state !== void 0 ? state : null));
|
|
3042
|
+
// clear element scope after navigate
|
|
3043
|
+
removeDomScope();
|
|
3044
|
+
}
|
|
3045
|
+
/**
|
|
3046
|
+
* create method of router.push/replace
|
|
3047
|
+
* NOTE:
|
|
3048
|
+
* 1. The same fullPath will be blocked
|
|
3049
|
+
* 2. name & path is required
|
|
3050
|
+
* 3. path is fullPath except for the domain (the domain can be taken, but not valid)
|
|
3051
|
+
* @param replace use router.replace?
|
|
3052
|
+
*/
|
|
3053
|
+
function createNavigationMethod(replace) {
|
|
3054
|
+
return function (to) {
|
|
3055
|
+
const appName = formatAppName(to.name);
|
|
3056
|
+
if (appName && isString(to.path)) {
|
|
3057
|
+
const app = appInstanceMap.get(appName);
|
|
3058
|
+
if (app && (!app.sandBox || !app.useMemoryRouter)) {
|
|
3059
|
+
return logError(`navigation failed, memory router of app ${appName} is closed`);
|
|
3060
|
+
}
|
|
3061
|
+
// active apps, include hidden keep-alive app
|
|
3062
|
+
if (getActiveApps().includes(appName)) {
|
|
3063
|
+
const microLocation = app.sandBox.proxyWindow.location;
|
|
3064
|
+
const targetLocation = createURL(to.path, microLocation.href);
|
|
3065
|
+
// Only get path data, even if the origin is different from microApp
|
|
3066
|
+
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3067
|
+
if (microLocation.fullPath !== targetFullPath || getMicroPathFromURL(appName) !== targetFullPath) {
|
|
3068
|
+
const methodName = (replace && to.replace !== false) || to.replace === true ? 'replaceState' : 'pushState';
|
|
3069
|
+
navigateWithRawHistory(appName, methodName, targetLocation, to.state);
|
|
3070
|
+
}
|
|
3071
|
+
}
|
|
3072
|
+
else {
|
|
3073
|
+
/**
|
|
3074
|
+
* app not exit or unmounted, update browser URL with replaceState
|
|
3075
|
+
* use base app location.origin as baseURL
|
|
3076
|
+
*/
|
|
3077
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
3078
|
+
const targetLocation = createURL(to.path, rawLocation.origin);
|
|
3079
|
+
const targetFullPath = targetLocation.pathname + targetLocation.search + targetLocation.hash;
|
|
3080
|
+
if (getMicroPathFromURL(appName) !== targetFullPath) {
|
|
3081
|
+
navigateWithRawHistory(appName, to.replace === false ? 'pushState' : 'replaceState', targetLocation, to.state);
|
|
3082
|
+
}
|
|
3083
|
+
}
|
|
3084
|
+
}
|
|
3085
|
+
else {
|
|
3086
|
+
logError(`navigation failed, name & path are required when use router.${replace ? 'replace' : 'push'}`);
|
|
3087
|
+
}
|
|
3088
|
+
};
|
|
3089
|
+
}
|
|
3090
|
+
// create method of router.go/back/forward
|
|
3091
|
+
function createRawHistoryMethod(methodName) {
|
|
3092
|
+
return function (...rests) {
|
|
3093
|
+
return globalEnv.rawWindow.history[methodName](...rests);
|
|
3094
|
+
};
|
|
3095
|
+
}
|
|
3096
|
+
const beforeGuards = useSetRecord();
|
|
3097
|
+
const afterGuards = useSetRecord();
|
|
3098
|
+
/**
|
|
3099
|
+
* run all of beforeEach/afterEach guards
|
|
3100
|
+
* NOTE:
|
|
3101
|
+
* 1. Modify browser url first, and then run guards,
|
|
3102
|
+
* consistent with the browser forward & back button
|
|
3103
|
+
* 2. Note the element binding
|
|
3104
|
+
* @param appName app name
|
|
3105
|
+
* @param to target location
|
|
3106
|
+
* @param from old location
|
|
3107
|
+
* @param guards guards list
|
|
3108
|
+
*/
|
|
3109
|
+
function runGuards(appName, to, from, guards) {
|
|
3110
|
+
// clear element scope before execute function of parent
|
|
3111
|
+
removeDomScope();
|
|
3112
|
+
for (const guard of guards) {
|
|
3113
|
+
if (isFunction(guard)) {
|
|
3114
|
+
guard(appName, to, from);
|
|
3115
|
+
}
|
|
3116
|
+
else if (isPlainObject(guard) && isFunction(guard[appName])) {
|
|
3117
|
+
guard[appName](to, from);
|
|
3118
|
+
}
|
|
3119
|
+
}
|
|
3120
|
+
}
|
|
3121
|
+
/**
|
|
3122
|
+
* global hook for router
|
|
3123
|
+
* update router information base on microLocation
|
|
3124
|
+
* @param appName app name
|
|
3125
|
+
* @param microLocation location of microApp
|
|
3126
|
+
*/
|
|
3127
|
+
function executeNavigationGuard(appName, to, from) {
|
|
3128
|
+
router.current.set(appName, to);
|
|
3129
|
+
runGuards(appName, to, from, beforeGuards.list());
|
|
3130
|
+
requestIdleCallback(() => {
|
|
3131
|
+
runGuards(appName, to, from, afterGuards.list());
|
|
3132
|
+
});
|
|
3133
|
+
}
|
|
3134
|
+
function clearRouterWhenUnmount(appName) {
|
|
3135
|
+
router.current.delete(appName);
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* NOTE:
|
|
3139
|
+
* 1. sandbox not open
|
|
3140
|
+
* 2. useMemoryRouter is false
|
|
3141
|
+
*/
|
|
3142
|
+
function commonHandlerForAttachToURL(appName) {
|
|
3143
|
+
const app = appInstanceMap.get(appName);
|
|
3144
|
+
if (app.sandBox && app.useMemoryRouter) {
|
|
3145
|
+
attachRouteToBrowserURL(setMicroPathToURL(appName, app.sandBox.proxyWindow.location), setMicroState(appName, globalEnv.rawWindow.history.state, null));
|
|
3146
|
+
}
|
|
3147
|
+
}
|
|
3148
|
+
/**
|
|
3149
|
+
* Attach specified active app router info to browser url
|
|
3150
|
+
* @param appName app name
|
|
3151
|
+
*/
|
|
3152
|
+
function attachToURL(appName) {
|
|
3153
|
+
appName = formatAppName(appName);
|
|
3154
|
+
if (appName && getActiveApps().includes(appName)) {
|
|
3155
|
+
commonHandlerForAttachToURL(appName);
|
|
3156
|
+
}
|
|
3157
|
+
}
|
|
3158
|
+
/**
|
|
3159
|
+
* Attach all active app router info to browser url
|
|
3160
|
+
*/
|
|
3161
|
+
function attachAllToURL() {
|
|
3162
|
+
getActiveApps().forEach(appName => commonHandlerForAttachToURL(appName));
|
|
3163
|
+
}
|
|
3164
|
+
function createDefaultPageApi() {
|
|
3165
|
+
// defaultPage data
|
|
3166
|
+
const defaultPageRecord = useMapRecord();
|
|
3167
|
+
/**
|
|
3168
|
+
* defaultPage only effect when mount, and has lower priority than query on browser url
|
|
3169
|
+
* @param appName app name
|
|
3170
|
+
* @param path page path
|
|
3171
|
+
*/
|
|
3172
|
+
function setDefaultPage(appName, path) {
|
|
3173
|
+
appName = formatAppName(appName);
|
|
3174
|
+
if (!appName || !path) {
|
|
3175
|
+
if (process.env.NODE_ENV !== 'production') {
|
|
3176
|
+
if (!appName) {
|
|
3177
|
+
logWarn(`setDefaultPage: invalid appName "${appName}"`);
|
|
3178
|
+
}
|
|
3179
|
+
else {
|
|
3180
|
+
logWarn('setDefaultPage: path is required');
|
|
3181
|
+
}
|
|
3182
|
+
}
|
|
3183
|
+
return noopFalse;
|
|
3184
|
+
}
|
|
3185
|
+
return defaultPageRecord.add(appName, path);
|
|
3186
|
+
}
|
|
3187
|
+
function removeDefaultPage(appName) {
|
|
3188
|
+
appName = formatAppName(appName);
|
|
3189
|
+
if (!appName)
|
|
3190
|
+
return false;
|
|
3191
|
+
return defaultPageRecord.delete(appName);
|
|
3192
|
+
}
|
|
3193
|
+
return {
|
|
3194
|
+
setDefaultPage,
|
|
3195
|
+
removeDefaultPage,
|
|
3196
|
+
getDefaultPage: defaultPageRecord.get,
|
|
3197
|
+
};
|
|
3198
|
+
}
|
|
3199
|
+
function createBaseRouterApi() {
|
|
3200
|
+
/**
|
|
3201
|
+
* Record base app router, let child app control base app navigation
|
|
3202
|
+
*/
|
|
3203
|
+
let baseRouterProxy = null;
|
|
3204
|
+
function setBaseAppRouter(baseRouter) {
|
|
3205
|
+
if (isObject(baseRouter)) {
|
|
3206
|
+
baseRouterProxy = new Proxy(baseRouter, {
|
|
3207
|
+
get(target, key) {
|
|
3208
|
+
removeDomScope();
|
|
3209
|
+
const rawValue = Reflect.get(target, key);
|
|
3210
|
+
return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'BASEROUTER') : rawValue;
|
|
3211
|
+
}
|
|
3212
|
+
});
|
|
3213
|
+
}
|
|
3214
|
+
else if (process.env.NODE_ENV !== 'production') {
|
|
3215
|
+
logWarn('setBaseAppRouter: Invalid base router');
|
|
3216
|
+
}
|
|
3217
|
+
}
|
|
3218
|
+
return {
|
|
3219
|
+
setBaseAppRouter,
|
|
3220
|
+
getBaseAppRouter: () => baseRouterProxy,
|
|
3221
|
+
};
|
|
3222
|
+
}
|
|
3223
|
+
// Router API for developer
|
|
3224
|
+
const router = Object.assign(Object.assign({ current: new Map(), encode: encodeMicroPath, decode: decodeMicroPath, push: createNavigationMethod(false), replace: createNavigationMethod(true), go: createRawHistoryMethod('go'), back: createRawHistoryMethod('back'), forward: createRawHistoryMethod('forward'), beforeEach: beforeGuards.add, afterEach: afterGuards.add, attachToURL,
|
|
3225
|
+
attachAllToURL }, createDefaultPageApi()), createBaseRouterApi());
|
|
3226
|
+
return {
|
|
3227
|
+
router,
|
|
3228
|
+
executeNavigationGuard,
|
|
3229
|
+
clearRouterWhenUnmount,
|
|
3230
|
+
};
|
|
3231
|
+
}
|
|
3232
|
+
const { router, executeNavigationGuard, clearRouterWhenUnmount, } = createRouterApi();
|
|
3233
|
+
|
|
3234
|
+
const shadowLocationKeys = ['href', 'pathname', 'search', 'hash'];
|
|
3235
|
+
// origin is readonly, so we ignore when updateMicroLocation
|
|
3236
|
+
const locationKeys = [...shadowLocationKeys, 'host', 'hostname', 'port', 'protocol', 'search'];
|
|
3237
|
+
// origin, fullPath is necessary for guardLocation
|
|
3238
|
+
const guardLocationKeys = [...locationKeys, 'origin', 'fullPath'];
|
|
3239
|
+
/**
|
|
3240
|
+
* Create location for microApp, each microApp has only one location object, it is a reference type
|
|
3241
|
+
* MDN https://developer.mozilla.org/en-US/docs/Web/API/Location
|
|
3242
|
+
* @param appName app name
|
|
3243
|
+
* @param url app url
|
|
3244
|
+
*/
|
|
3245
|
+
function createMicroLocation(appName, url) {
|
|
3246
|
+
const rawWindow = globalEnv.rawWindow;
|
|
3247
|
+
const rawLocation = rawWindow.location;
|
|
3248
|
+
// microLocation is the location of child app, it is globally unique
|
|
3249
|
+
const microLocation = createURL(url);
|
|
3250
|
+
// shadowLocation is the current location information (href, pathname, search, hash)
|
|
3251
|
+
const shadowLocation = {
|
|
3252
|
+
href: microLocation.href,
|
|
3253
|
+
pathname: microLocation.pathname,
|
|
3254
|
+
search: microLocation.search,
|
|
3255
|
+
hash: microLocation.hash,
|
|
3256
|
+
};
|
|
3257
|
+
/**
|
|
3258
|
+
* Common handler for href, assign, replace
|
|
3259
|
+
* It is mainly used to deal with special scenes about hash
|
|
3260
|
+
* @param value target path
|
|
3261
|
+
* @param methodName pushState/replaceState
|
|
3262
|
+
* @returns origin value or formatted value
|
|
3263
|
+
*/
|
|
3264
|
+
const commonHandler = (value, methodName) => {
|
|
3265
|
+
const targetLocation = createURL(value, microLocation.href);
|
|
3266
|
+
// Even if the origin is the same, developers still have the possibility of want to jump to a new page
|
|
3267
|
+
if (targetLocation.origin === microLocation.origin) {
|
|
3268
|
+
const setMicroPathResult = setMicroPathToURL(appName, targetLocation);
|
|
3269
|
+
/**
|
|
3270
|
+
* change hash with location.href will not trigger the browser reload
|
|
3271
|
+
* so we use pushState & reload to imitate href behavior
|
|
3272
|
+
* NOTE:
|
|
3273
|
+
* 1. if child app only change hash, it should not trigger browser reload
|
|
3274
|
+
* 2. if address is same and has hash, it should not add route stack
|
|
3275
|
+
*/
|
|
3276
|
+
if (targetLocation.pathname === shadowLocation.pathname &&
|
|
3277
|
+
targetLocation.search === shadowLocation.search) {
|
|
3278
|
+
let oldHref = null;
|
|
3279
|
+
if (targetLocation.hash !== shadowLocation.hash) {
|
|
3280
|
+
if (setMicroPathResult.isAttach2Hash)
|
|
3281
|
+
oldHref = rawLocation.href;
|
|
3282
|
+
nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
|
|
3283
|
+
}
|
|
3284
|
+
if (targetLocation.hash) {
|
|
3285
|
+
dispatchNativeEvent(false, oldHref);
|
|
3286
|
+
}
|
|
3287
|
+
else {
|
|
3288
|
+
rawLocation.reload();
|
|
3289
|
+
}
|
|
3290
|
+
return void 0;
|
|
3291
|
+
/**
|
|
3292
|
+
* when baseApp is hash router, address change of child can not reload browser
|
|
3293
|
+
* so we imitate behavior of browser (reload)
|
|
3294
|
+
*/
|
|
3295
|
+
}
|
|
3296
|
+
else if (setMicroPathResult.isAttach2Hash) {
|
|
3297
|
+
nativeHistoryNavigate(methodName, setMicroPathResult.fullPath);
|
|
3298
|
+
rawLocation.reload();
|
|
3299
|
+
return void 0;
|
|
3300
|
+
}
|
|
3301
|
+
value = setMicroPathResult.fullPath;
|
|
3302
|
+
}
|
|
3303
|
+
return value;
|
|
3304
|
+
};
|
|
3305
|
+
/**
|
|
3306
|
+
* create location PropertyDescriptor (href, pathname, search, hash)
|
|
3307
|
+
* @param key property name
|
|
3308
|
+
* @param setter setter of location property
|
|
3309
|
+
*/
|
|
3310
|
+
function createPropertyDescriptor(getter, setter) {
|
|
3311
|
+
return {
|
|
3312
|
+
enumerable: true,
|
|
3313
|
+
configurable: true,
|
|
3314
|
+
get: getter,
|
|
3315
|
+
set: setter,
|
|
3316
|
+
};
|
|
3317
|
+
}
|
|
3318
|
+
/**
|
|
3319
|
+
* common handler for location.pathname & location.search
|
|
3320
|
+
* @param targetPath target fullPath
|
|
3321
|
+
* @param key pathname/search
|
|
3322
|
+
*/
|
|
3323
|
+
function handleForPathNameAndSearch(targetPath, key) {
|
|
3324
|
+
const targetLocation = createURL(targetPath, url);
|
|
3325
|
+
// When the browser url has a hash value, the same pathname/search will not refresh browser
|
|
3326
|
+
if (targetLocation[key] === shadowLocation[key] && shadowLocation.hash) {
|
|
3327
|
+
// The href has not changed, not need to dispatch hashchange event
|
|
3328
|
+
dispatchNativeEvent(false);
|
|
3329
|
+
}
|
|
3330
|
+
else {
|
|
3331
|
+
/**
|
|
3332
|
+
* When the value is the same, no new route stack will be added
|
|
3333
|
+
* Special scenes such as:
|
|
3334
|
+
* pathname: /path ==> /path#hash, /path ==> /path?query
|
|
3335
|
+
* search: ?query ==> ?query#hash
|
|
3336
|
+
*/
|
|
3337
|
+
nativeHistoryNavigate(targetLocation[key] === shadowLocation[key] ? 'replaceState' : 'pushState', setMicroPathToURL(appName, targetLocation).fullPath);
|
|
3338
|
+
rawLocation.reload();
|
|
3339
|
+
}
|
|
3340
|
+
}
|
|
3341
|
+
/**
|
|
3342
|
+
* Special processing for four keys: href, pathname, search and hash
|
|
3343
|
+
* They take values from shadowLocation, and require special operations when assigning values
|
|
3344
|
+
*/
|
|
3345
|
+
rawDefineProperties(microLocation, {
|
|
3346
|
+
href: createPropertyDescriptor(() => shadowLocation.href, (value) => {
|
|
3347
|
+
const targetPath = commonHandler(value, 'pushState');
|
|
3348
|
+
if (targetPath)
|
|
3349
|
+
rawLocation.href = targetPath;
|
|
3350
|
+
}),
|
|
3351
|
+
pathname: createPropertyDescriptor(() => shadowLocation.pathname, (value) => {
|
|
3352
|
+
const targetPath = ('/' + value).replace(/^\/+/, '/') + shadowLocation.search + shadowLocation.hash;
|
|
3353
|
+
handleForPathNameAndSearch(targetPath, 'pathname');
|
|
3354
|
+
}),
|
|
3355
|
+
search: createPropertyDescriptor(() => shadowLocation.search, (value) => {
|
|
3356
|
+
const targetPath = shadowLocation.pathname + ('?' + value).replace(/^\?+/, '?') + shadowLocation.hash;
|
|
3357
|
+
handleForPathNameAndSearch(targetPath, 'search');
|
|
3358
|
+
}),
|
|
3359
|
+
hash: createPropertyDescriptor(() => shadowLocation.hash, (value) => {
|
|
3360
|
+
const targetPath = shadowLocation.pathname + shadowLocation.search + ('#' + value).replace(/^#+/, '#');
|
|
3361
|
+
const targetLocation = createURL(targetPath, url);
|
|
3362
|
+
// The same hash will not trigger popStateEvent
|
|
3363
|
+
if (targetLocation.hash !== shadowLocation.hash) {
|
|
3364
|
+
navigateWithNativeEvent('pushState', setMicroPathToURL(appName, targetLocation), false);
|
|
3365
|
+
}
|
|
3366
|
+
}),
|
|
3367
|
+
fullPath: createPropertyDescriptor(() => shadowLocation.pathname + shadowLocation.search + shadowLocation.hash, noop),
|
|
3368
|
+
});
|
|
3369
|
+
const createLocationMethod = (locationMethodName) => {
|
|
3370
|
+
return function (value) {
|
|
3371
|
+
const targetPath = commonHandler(value, locationMethodName === 'assign' ? 'pushState' : 'replaceState');
|
|
3372
|
+
if (targetPath)
|
|
3373
|
+
rawLocation[locationMethodName](targetPath);
|
|
3374
|
+
};
|
|
3375
|
+
};
|
|
3376
|
+
return assign(microLocation, {
|
|
3377
|
+
assign: createLocationMethod('assign'),
|
|
3378
|
+
replace: createLocationMethod('replace'),
|
|
3379
|
+
reload: (forcedReload) => rawLocation.reload(forcedReload),
|
|
3380
|
+
shadowLocation,
|
|
3381
|
+
});
|
|
3382
|
+
}
|
|
3383
|
+
/**
|
|
3384
|
+
* create guardLocation by microLocation, used for router guard
|
|
3385
|
+
*/
|
|
3386
|
+
function createGuardLocation(appName, microLocation) {
|
|
3387
|
+
const guardLocation = assign({ name: appName }, microLocation);
|
|
3388
|
+
// The prototype values on the URL needs to be manually transferred
|
|
3389
|
+
for (const key of guardLocationKeys)
|
|
3390
|
+
guardLocation[key] = microLocation[key];
|
|
3391
|
+
return guardLocation;
|
|
3392
|
+
}
|
|
3393
|
+
// for updateBrowserURLWithLocation when initial
|
|
3394
|
+
function autoTriggerNavigationGuard(appName, microLocation) {
|
|
3395
|
+
executeNavigationGuard(appName, createGuardLocation(appName, microLocation), createGuardLocation(appName, microLocation));
|
|
3396
|
+
}
|
|
3397
|
+
/**
|
|
3398
|
+
* The following scenes will trigger location update:
|
|
3399
|
+
* 1. pushState/replaceState
|
|
3400
|
+
* 2. popStateEvent
|
|
3401
|
+
* 3. query on browser url when init sub app
|
|
3402
|
+
* 4. set defaultPage when when init sub app
|
|
3403
|
+
* NOTE:
|
|
3404
|
+
* 1. update browser URL first, and then update microLocation
|
|
3405
|
+
* 2. the same fullPath will not trigger router guards
|
|
3406
|
+
* @param appName app name
|
|
3407
|
+
* @param path target path
|
|
3408
|
+
* @param base base url
|
|
3409
|
+
* @param microLocation micro app location
|
|
3410
|
+
* @param type auto prevent
|
|
3411
|
+
*/
|
|
3412
|
+
function updateMicroLocation(appName, path, microLocation, type) {
|
|
3413
|
+
const newLocation = createURL(path, microLocation.href);
|
|
3414
|
+
// record old values of microLocation to `from`
|
|
3415
|
+
const from = createGuardLocation(appName, microLocation);
|
|
3416
|
+
for (const key of locationKeys) {
|
|
3417
|
+
if (shadowLocationKeys.includes(key)) {
|
|
3418
|
+
// reference of shadowLocation
|
|
3419
|
+
microLocation.shadowLocation[key] = newLocation[key];
|
|
3420
|
+
}
|
|
3421
|
+
else {
|
|
3422
|
+
// @ts-ignore reference of microLocation
|
|
3423
|
+
microLocation[key] = newLocation[key];
|
|
3424
|
+
}
|
|
3425
|
+
}
|
|
3426
|
+
// update latest values of microLocation to `to`
|
|
3427
|
+
const to = createGuardLocation(appName, microLocation);
|
|
3428
|
+
// The hook called only when fullPath changed
|
|
3429
|
+
if (type === 'auto' || (from.fullPath !== to.fullPath && type !== 'prevent')) {
|
|
3430
|
+
executeNavigationGuard(appName, to, from);
|
|
3431
|
+
}
|
|
3432
|
+
}
|
|
3433
|
+
|
|
3434
|
+
/**
|
|
3435
|
+
* The router system has two operations: read and write
|
|
3436
|
+
* Read through location and write through history & location
|
|
3437
|
+
* @param appName app name
|
|
3438
|
+
* @param url app url
|
|
3439
|
+
* @returns MicroRouter
|
|
3440
|
+
*/
|
|
3441
|
+
function createMicroRouter(appName, url) {
|
|
3442
|
+
rewriteHistoryState();
|
|
3443
|
+
const microLocation = createMicroLocation(appName, url);
|
|
3444
|
+
return {
|
|
3445
|
+
microLocation,
|
|
3446
|
+
microHistory: createMicroHistory(appName, microLocation),
|
|
3447
|
+
};
|
|
3448
|
+
}
|
|
3449
|
+
// 当沙箱执行start, 或者隐藏的keep-alive应用重新渲染时时才根据浏览器url更新location 或者 将参数更新到url上
|
|
3450
|
+
function initRouteStateWithURL(appName, microLocation, defaultPage) {
|
|
3451
|
+
const microPath = getMicroPathFromURL(appName);
|
|
3452
|
+
if (microPath) {
|
|
3453
|
+
updateMicroLocation(appName, microPath, microLocation, 'auto');
|
|
3454
|
+
}
|
|
3455
|
+
else {
|
|
3456
|
+
updateBrowserURLWithLocation(appName, microLocation, defaultPage);
|
|
3457
|
+
}
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* initialize browser information according to microLocation
|
|
3461
|
+
* called on sandbox.start or reshow of keep-alive app
|
|
3462
|
+
*/
|
|
3463
|
+
function updateBrowserURLWithLocation(appName, microLocation, defaultPage) {
|
|
3464
|
+
// update microLocation with defaultPage
|
|
3465
|
+
if (defaultPage)
|
|
3466
|
+
updateMicroLocation(appName, defaultPage, microLocation, 'prevent');
|
|
3467
|
+
// attach microApp route info to browser URL
|
|
3468
|
+
attachRouteToBrowserURL(setMicroPathToURL(appName, microLocation), setMicroState(appName, globalEnv.rawWindow.history.state, null));
|
|
3469
|
+
// trigger guards after change browser URL
|
|
3470
|
+
autoTriggerNavigationGuard(appName, microLocation);
|
|
3471
|
+
}
|
|
3472
|
+
/**
|
|
3473
|
+
* In any case, microPath & microState will be removed from browser, but location will be initialized only when keep-router-state is false
|
|
3474
|
+
* @param appName app name
|
|
3475
|
+
* @param url app url
|
|
3476
|
+
* @param microLocation location of microApp
|
|
3477
|
+
* @param keepRouteState keep-router-state is only used to control whether to clear the location of microApp
|
|
3478
|
+
*/
|
|
3479
|
+
function clearRouteStateFromURL(appName, url, microLocation, keepRouteState) {
|
|
3480
|
+
if (!keepRouteState) {
|
|
3481
|
+
const { pathname, search, hash } = createURL(url);
|
|
3482
|
+
updateMicroLocation(appName, pathname + search + hash, microLocation, 'prevent');
|
|
3483
|
+
}
|
|
3484
|
+
removeStateAndPathFromBrowser(appName);
|
|
3485
|
+
clearRouterWhenUnmount(appName);
|
|
3486
|
+
}
|
|
3487
|
+
/**
|
|
3488
|
+
* remove microState from history.state and remove microPath from browserURL
|
|
3489
|
+
* called on sandbox.stop or hidden of keep-alive app
|
|
3490
|
+
*/
|
|
3491
|
+
function removeStateAndPathFromBrowser(appName) {
|
|
3492
|
+
attachRouteToBrowserURL(removeMicroPathFromURL(appName), removeMicroState(appName, globalEnv.rawWindow.history.state));
|
|
3493
|
+
}
|
|
3494
|
+
|
|
3495
|
+
/**
|
|
3496
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/fetch
|
|
3497
|
+
* Promise<Response> fetch(input[, init])
|
|
3498
|
+
* input: string/Request
|
|
3499
|
+
* init?: object
|
|
3500
|
+
* @param url app url
|
|
3501
|
+
* @param target proxy target
|
|
3502
|
+
*/
|
|
3503
|
+
function createMicroFetch(url, target) {
|
|
3504
|
+
const rawFetch = !isUndefined(target) ? target : globalEnv.rawWindow.fetch;
|
|
3505
|
+
if (!isFunction(rawFetch))
|
|
3506
|
+
return rawFetch;
|
|
3507
|
+
return function microFetch(input, init, ...rests) {
|
|
3508
|
+
if (isString(input) || isURL(input)) {
|
|
3509
|
+
input = createURL(input, url).toString();
|
|
3510
|
+
}
|
|
3511
|
+
/**
|
|
3512
|
+
* When fetch rewrite by baseApp, domScope still active when exec rawWindow.fetch
|
|
3513
|
+
* If baseApp operate dom in fetch, it will cause error
|
|
3514
|
+
* The same for XMLHttpRequest, EventSource
|
|
3515
|
+
* e.g.
|
|
3516
|
+
* baseApp: <script crossorigin src="https://sgm-static.jd.com/sgm-2.8.0.js" name="SGMH5" sid="6f88a6e4ba4b4ae5acef2ec22c075085" appKey="jdb-adminb2b-pc"></script>
|
|
3517
|
+
*/
|
|
3518
|
+
removeDomScope();
|
|
3519
|
+
return rawFetch.call(globalEnv.rawWindow, input, init, ...rests);
|
|
3520
|
+
};
|
|
3521
|
+
}
|
|
3522
|
+
/**
|
|
3523
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest
|
|
3524
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/XMLHttpRequest/Using_XMLHttpRequest
|
|
3525
|
+
* @param url app url
|
|
3526
|
+
* @param target proxy target
|
|
3527
|
+
*/
|
|
3528
|
+
function createMicroXMLHttpRequest(url, target) {
|
|
3529
|
+
const rawXMLHttpRequest = !isUndefined(target) ? target : globalEnv.rawWindow.XMLHttpRequest;
|
|
3530
|
+
if (!isConstructor(rawXMLHttpRequest))
|
|
3531
|
+
return rawXMLHttpRequest;
|
|
3532
|
+
return class MicroXMLHttpRequest extends rawXMLHttpRequest {
|
|
3533
|
+
open(method, reqUrl, ...rests) {
|
|
3534
|
+
if ((isString(reqUrl) && !/^f(ile|tp):\/\//.test(reqUrl)) || isURL(reqUrl)) {
|
|
3535
|
+
reqUrl = createURL(reqUrl, url).toString();
|
|
3536
|
+
}
|
|
3537
|
+
removeDomScope();
|
|
3538
|
+
super.open(method, reqUrl, ...rests);
|
|
3539
|
+
}
|
|
3540
|
+
};
|
|
3541
|
+
}
|
|
3542
|
+
function useMicroEventSource() {
|
|
3543
|
+
let eventSourceMap;
|
|
3544
|
+
/**
|
|
3545
|
+
* https://developer.mozilla.org/en-US/docs/Web/API/EventSource
|
|
3546
|
+
* pc = new EventSource(url[, configuration])
|
|
3547
|
+
* url: string/Request
|
|
3548
|
+
* configuration?: object
|
|
3549
|
+
* @param url app url
|
|
3550
|
+
* @param target proxy target
|
|
3551
|
+
*/
|
|
3552
|
+
function createMicroEventSource(appName, url, target) {
|
|
3553
|
+
const rawEventSource = !isUndefined(target) ? target : globalEnv.rawWindow.EventSource;
|
|
3554
|
+
if (!isConstructor(rawEventSource))
|
|
3555
|
+
return rawEventSource;
|
|
3556
|
+
return class MicroEventSource extends rawEventSource {
|
|
3557
|
+
constructor(eventSourceUrl, eventSourceInitDict, ...rests) {
|
|
3558
|
+
if (isString(eventSourceUrl) || isURL(eventSourceUrl)) {
|
|
3559
|
+
eventSourceUrl = createURL(eventSourceUrl, url).toString();
|
|
3560
|
+
}
|
|
3561
|
+
removeDomScope();
|
|
3562
|
+
super(eventSourceUrl, eventSourceInitDict, ...rests);
|
|
3563
|
+
if (eventSourceMap) {
|
|
3564
|
+
const eventSourceList = eventSourceMap.get(appName);
|
|
3565
|
+
if (eventSourceList) {
|
|
3566
|
+
eventSourceList.add(this);
|
|
3567
|
+
}
|
|
3568
|
+
else {
|
|
3569
|
+
eventSourceMap.set(appName, new Set([this]));
|
|
3570
|
+
}
|
|
3571
|
+
}
|
|
3572
|
+
else {
|
|
3573
|
+
eventSourceMap = new Map([[appName, new Set([this])]]);
|
|
3574
|
+
}
|
|
3575
|
+
}
|
|
3576
|
+
close() {
|
|
3577
|
+
var _a;
|
|
3578
|
+
super.close();
|
|
3579
|
+
(_a = eventSourceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.delete(this);
|
|
3580
|
+
}
|
|
3581
|
+
};
|
|
3582
|
+
}
|
|
3583
|
+
function clearMicroEventSource(appName) {
|
|
3584
|
+
const eventSourceList = eventSourceMap === null || eventSourceMap === void 0 ? void 0 : eventSourceMap.get(appName);
|
|
3585
|
+
if (eventSourceList === null || eventSourceList === void 0 ? void 0 : eventSourceList.size) {
|
|
3586
|
+
eventSourceList.forEach(item => {
|
|
3587
|
+
item.close();
|
|
3588
|
+
});
|
|
3589
|
+
eventSourceList.clear();
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
return {
|
|
3593
|
+
createMicroEventSource,
|
|
3594
|
+
clearMicroEventSource,
|
|
3595
|
+
};
|
|
3596
|
+
}
|
|
3597
|
+
|
|
3598
|
+
const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
3599
|
+
const globalPropertyList = ['window', 'self', 'globalThis'];
|
|
3600
|
+
class SandBox {
|
|
3601
|
+
constructor(appName, url, useMemoryRouter = true) {
|
|
3602
|
+
/**
|
|
3603
|
+
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
3604
|
+
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
3605
|
+
*/
|
|
3606
|
+
this.scopeProperties = [];
|
|
3607
|
+
// Properties that can be escape to rawWindow
|
|
3608
|
+
this.escapeProperties = [];
|
|
3609
|
+
// Properties newly added to microAppWindow
|
|
3610
|
+
this.injectedKeys = new Set();
|
|
3611
|
+
// Properties escape to rawWindow, cleared when unmount
|
|
3612
|
+
this.escapeKeys = new Set();
|
|
2560
3613
|
// sandbox state
|
|
2561
3614
|
this.active = false;
|
|
2562
3615
|
this.microAppWindow = {}; // Proxy target
|
|
3616
|
+
this.adapter = new Adapter();
|
|
2563
3617
|
// get scopeProperties and escapeProperties from plugins
|
|
2564
3618
|
this.getSpecialProperties(appName);
|
|
2565
3619
|
// create proxyWindow with Proxy(microAppWindow)
|
|
2566
3620
|
this.proxyWindow = this.createProxyWindow(appName);
|
|
2567
|
-
// inject global properties
|
|
2568
|
-
this.initMicroAppWindow(this.microAppWindow, appName, url);
|
|
2569
3621
|
// Rewrite global event listener & timeout
|
|
2570
|
-
|
|
3622
|
+
assign(this, effect(appName, this.microAppWindow));
|
|
3623
|
+
// inject global properties
|
|
3624
|
+
this.initStaticGlobalKeys(this.microAppWindow, appName, url, useMemoryRouter);
|
|
2571
3625
|
}
|
|
2572
|
-
start(baseRoute) {
|
|
3626
|
+
start(baseRoute, useMemoryRouter = true, defaultPage = '') {
|
|
2573
3627
|
if (!this.active) {
|
|
2574
3628
|
this.active = true;
|
|
2575
|
-
|
|
2576
|
-
|
|
2577
|
-
|
|
3629
|
+
if (useMemoryRouter) {
|
|
3630
|
+
this.initRouteState(defaultPage);
|
|
3631
|
+
// unique listener of popstate event for sub app
|
|
3632
|
+
this.removeHistoryListener = addHistoryListener(this.proxyWindow.__MICRO_APP_NAME__);
|
|
3633
|
+
}
|
|
3634
|
+
else {
|
|
3635
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseRoute;
|
|
3636
|
+
}
|
|
3637
|
+
// prevent the key deleted during sandBox.stop after rewrite
|
|
3638
|
+
this.initGlobalKeysWhenStart(this.microAppWindow, this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__);
|
|
2578
3639
|
if (++SandBox.activeCount === 1) {
|
|
2579
3640
|
effectDocumentEvent();
|
|
2580
3641
|
patchElementPrototypeMethods();
|
|
3642
|
+
initEnvOfNestedApp();
|
|
2581
3643
|
}
|
|
3644
|
+
fixBabelPolyfill6();
|
|
2582
3645
|
}
|
|
2583
3646
|
}
|
|
2584
|
-
stop() {
|
|
3647
|
+
stop(keepRouteState, clearEventSource) {
|
|
2585
3648
|
if (this.active) {
|
|
2586
|
-
this.active = false;
|
|
2587
3649
|
this.releaseEffect();
|
|
2588
3650
|
this.microAppWindow.microApp.clearDataListener();
|
|
2589
3651
|
this.microAppWindow.microApp.clearGlobalDataListener();
|
|
3652
|
+
if (this.removeHistoryListener) {
|
|
3653
|
+
this.clearRouteState(keepRouteState);
|
|
3654
|
+
// release listener of popstate
|
|
3655
|
+
this.removeHistoryListener();
|
|
3656
|
+
}
|
|
3657
|
+
if (clearEventSource) {
|
|
3658
|
+
clearMicroEventSource(this.proxyWindow.__MICRO_APP_NAME__);
|
|
3659
|
+
}
|
|
3660
|
+
/**
|
|
3661
|
+
* NOTE:
|
|
3662
|
+
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
3663
|
+
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
3664
|
+
*/
|
|
2590
3665
|
this.injectedKeys.forEach((key) => {
|
|
2591
3666
|
Reflect.deleteProperty(this.microAppWindow, key);
|
|
2592
3667
|
});
|
|
@@ -2599,6 +3674,7 @@ class SandBox {
|
|
|
2599
3674
|
releaseEffectDocumentEvent();
|
|
2600
3675
|
releasePatches();
|
|
2601
3676
|
}
|
|
3677
|
+
this.active = false;
|
|
2602
3678
|
}
|
|
2603
3679
|
}
|
|
2604
3680
|
// record umd snapshot before the first execution of umdHookMount
|
|
@@ -2620,15 +3696,16 @@ class SandBox {
|
|
|
2620
3696
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
2621
3697
|
}
|
|
2622
3698
|
/**
|
|
2623
|
-
* get scopeProperties and escapeProperties from plugins
|
|
3699
|
+
* get scopeProperties and escapeProperties from plugins & adapter
|
|
2624
3700
|
* @param appName app name
|
|
2625
3701
|
*/
|
|
2626
3702
|
getSpecialProperties(appName) {
|
|
2627
3703
|
var _a;
|
|
2628
|
-
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
3704
|
+
this.scopeProperties = this.scopeProperties.concat(this.adapter.staticScopeProperties);
|
|
3705
|
+
if (isPlainObject(microApp.plugins)) {
|
|
3706
|
+
this.commonActionForSpecialProperties(microApp.plugins.global);
|
|
3707
|
+
this.commonActionForSpecialProperties((_a = microApp.plugins.modules) === null || _a === void 0 ? void 0 : _a[appName]);
|
|
3708
|
+
}
|
|
2632
3709
|
}
|
|
2633
3710
|
// common action for global plugins and module plugins
|
|
2634
3711
|
commonActionForSpecialProperties(plugins) {
|
|
@@ -2658,11 +3735,11 @@ class SandBox {
|
|
|
2658
3735
|
this.scopeProperties.includes(key))
|
|
2659
3736
|
return Reflect.get(target, key);
|
|
2660
3737
|
const rawValue = Reflect.get(rawWindow, key);
|
|
2661
|
-
return isFunction(rawValue) ?
|
|
3738
|
+
return isFunction(rawValue) ? bindFunctionToRawObject(rawWindow, rawValue) : rawValue;
|
|
2662
3739
|
},
|
|
2663
3740
|
set: (target, key, value) => {
|
|
2664
3741
|
if (this.active) {
|
|
2665
|
-
if (escapeSetterKeyList.includes(key)) {
|
|
3742
|
+
if (this.adapter.escapeSetterKeyList.includes(key)) {
|
|
2666
3743
|
Reflect.set(rawWindow, key, value);
|
|
2667
3744
|
}
|
|
2668
3745
|
else if (
|
|
@@ -2686,7 +3763,8 @@ class SandBox {
|
|
|
2686
3763
|
this.injectedKeys.add(key);
|
|
2687
3764
|
}
|
|
2688
3765
|
if ((this.escapeProperties.includes(key) ||
|
|
2689
|
-
(staticEscapeProperties.includes(key) &&
|
|
3766
|
+
(this.adapter.staticEscapeProperties.includes(key) &&
|
|
3767
|
+
!Reflect.has(rawWindow, key))) &&
|
|
2690
3768
|
!this.scopeProperties.includes(key)) {
|
|
2691
3769
|
Reflect.set(rawWindow, key, value);
|
|
2692
3770
|
this.escapeKeys.add(key);
|
|
@@ -2742,21 +3820,37 @@ class SandBox {
|
|
|
2742
3820
|
* @param microAppWindow micro window
|
|
2743
3821
|
* @param appName app name
|
|
2744
3822
|
* @param url app url
|
|
3823
|
+
* @param useMemoryRouter whether use memory router
|
|
2745
3824
|
*/
|
|
2746
|
-
|
|
3825
|
+
initStaticGlobalKeys(microAppWindow, appName, url, useMemoryRouter) {
|
|
2747
3826
|
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
2748
3827
|
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
3828
|
+
microAppWindow.__MICRO_APP_URL__ = url;
|
|
2749
3829
|
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
2750
3830
|
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
2751
|
-
microAppWindow.
|
|
3831
|
+
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
3832
|
+
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
3833
|
+
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
2752
3834
|
removeDomScope,
|
|
2753
3835
|
pureCreateElement,
|
|
3836
|
+
router,
|
|
2754
3837
|
});
|
|
2755
|
-
microAppWindow
|
|
2756
|
-
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
2757
|
-
microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
|
|
3838
|
+
this.setProxyDocument(microAppWindow, appName);
|
|
2758
3839
|
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
2759
|
-
|
|
3840
|
+
if (useMemoryRouter)
|
|
3841
|
+
this.setMicroAppRouter(microAppWindow, appName, url);
|
|
3842
|
+
}
|
|
3843
|
+
setProxyDocument(microAppWindow, appName) {
|
|
3844
|
+
const proxyDocument = this.createProxyDocument(appName);
|
|
3845
|
+
rawDefineProperty(microAppWindow, 'document', {
|
|
3846
|
+
configurable: false,
|
|
3847
|
+
enumerable: true,
|
|
3848
|
+
get() {
|
|
3849
|
+
throttleDeferForSetAppName(appName);
|
|
3850
|
+
// return globalEnv.rawDocument
|
|
3851
|
+
return proxyDocument;
|
|
3852
|
+
},
|
|
3853
|
+
});
|
|
2760
3854
|
}
|
|
2761
3855
|
// properties associated with the native window
|
|
2762
3856
|
setMappingPropertiesWithRawDescriptor(microAppWindow) {
|
|
@@ -2785,19 +3879,24 @@ class SandBox {
|
|
|
2785
3879
|
};
|
|
2786
3880
|
return descriptor;
|
|
2787
3881
|
}
|
|
3882
|
+
/**
|
|
3883
|
+
* init global properties of microAppWindow when exec sandBox.start
|
|
3884
|
+
* @param microAppWindow micro window
|
|
3885
|
+
* @param appName app name
|
|
3886
|
+
* @param url app url
|
|
3887
|
+
*/
|
|
3888
|
+
initGlobalKeysWhenStart(microAppWindow, appName, url) {
|
|
3889
|
+
microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
|
|
3890
|
+
this.setHijackProperty(microAppWindow, appName);
|
|
3891
|
+
this.patchRequestApi(microAppWindow, appName, url);
|
|
3892
|
+
}
|
|
2788
3893
|
// set hijack Properties to microAppWindow
|
|
2789
|
-
|
|
3894
|
+
setHijackProperty(microAppWindow, appName) {
|
|
2790
3895
|
let modifiedEval, modifiedImage;
|
|
2791
3896
|
rawDefineProperties(microAppWindow, {
|
|
2792
|
-
document: {
|
|
2793
|
-
get() {
|
|
2794
|
-
throttleDeferForSetAppName(appName);
|
|
2795
|
-
return globalEnv.rawDocument;
|
|
2796
|
-
},
|
|
2797
|
-
configurable: false,
|
|
2798
|
-
enumerable: true,
|
|
2799
|
-
},
|
|
2800
3897
|
eval: {
|
|
3898
|
+
configurable: true,
|
|
3899
|
+
enumerable: false,
|
|
2801
3900
|
get() {
|
|
2802
3901
|
throttleDeferForSetAppName(appName);
|
|
2803
3902
|
return modifiedEval || eval;
|
|
@@ -2805,10 +3904,10 @@ class SandBox {
|
|
|
2805
3904
|
set: (value) => {
|
|
2806
3905
|
modifiedEval = value;
|
|
2807
3906
|
},
|
|
2808
|
-
configurable: true,
|
|
2809
|
-
enumerable: false,
|
|
2810
3907
|
},
|
|
2811
3908
|
Image: {
|
|
3909
|
+
configurable: true,
|
|
3910
|
+
enumerable: false,
|
|
2812
3911
|
get() {
|
|
2813
3912
|
throttleDeferForSetAppName(appName);
|
|
2814
3913
|
return modifiedImage || globalEnv.ImageProxy;
|
|
@@ -2816,10 +3915,99 @@ class SandBox {
|
|
|
2816
3915
|
set: (value) => {
|
|
2817
3916
|
modifiedImage = value;
|
|
2818
3917
|
},
|
|
3918
|
+
},
|
|
3919
|
+
});
|
|
3920
|
+
}
|
|
3921
|
+
// rewrite fetch, XMLHttpRequest, EventSource
|
|
3922
|
+
patchRequestApi(microAppWindow, appName, url) {
|
|
3923
|
+
let microFetch = createMicroFetch(url);
|
|
3924
|
+
let microXMLHttpRequest = createMicroXMLHttpRequest(url);
|
|
3925
|
+
let microEventSource = createMicroEventSource(appName, url);
|
|
3926
|
+
rawDefineProperties(microAppWindow, {
|
|
3927
|
+
fetch: {
|
|
2819
3928
|
configurable: true,
|
|
2820
|
-
enumerable:
|
|
3929
|
+
enumerable: true,
|
|
3930
|
+
get() {
|
|
3931
|
+
return microFetch;
|
|
3932
|
+
},
|
|
3933
|
+
set(value) {
|
|
3934
|
+
microFetch = createMicroFetch(url, value);
|
|
3935
|
+
},
|
|
3936
|
+
},
|
|
3937
|
+
XMLHttpRequest: {
|
|
3938
|
+
configurable: true,
|
|
3939
|
+
enumerable: true,
|
|
3940
|
+
get() {
|
|
3941
|
+
return microXMLHttpRequest;
|
|
3942
|
+
},
|
|
3943
|
+
set(value) {
|
|
3944
|
+
microXMLHttpRequest = createMicroXMLHttpRequest(url, value);
|
|
3945
|
+
},
|
|
3946
|
+
},
|
|
3947
|
+
EventSource: {
|
|
3948
|
+
configurable: true,
|
|
3949
|
+
enumerable: true,
|
|
3950
|
+
get() {
|
|
3951
|
+
return microEventSource;
|
|
3952
|
+
},
|
|
3953
|
+
set(value) {
|
|
3954
|
+
microEventSource = createMicroEventSource(appName, url, value);
|
|
3955
|
+
},
|
|
3956
|
+
},
|
|
3957
|
+
});
|
|
3958
|
+
}
|
|
3959
|
+
// set location & history for memory router
|
|
3960
|
+
setMicroAppRouter(microAppWindow, appName, url) {
|
|
3961
|
+
const { microLocation, microHistory } = createMicroRouter(appName, url);
|
|
3962
|
+
rawDefineProperties(microAppWindow, {
|
|
3963
|
+
location: {
|
|
3964
|
+
configurable: false,
|
|
3965
|
+
enumerable: true,
|
|
3966
|
+
get() {
|
|
3967
|
+
return microLocation;
|
|
3968
|
+
},
|
|
3969
|
+
set: (value) => {
|
|
3970
|
+
globalEnv.rawWindow.location = value;
|
|
3971
|
+
},
|
|
3972
|
+
},
|
|
3973
|
+
history: {
|
|
3974
|
+
configurable: true,
|
|
3975
|
+
enumerable: true,
|
|
3976
|
+
get() {
|
|
3977
|
+
return microHistory;
|
|
3978
|
+
},
|
|
3979
|
+
},
|
|
3980
|
+
});
|
|
3981
|
+
}
|
|
3982
|
+
initRouteState(defaultPage) {
|
|
3983
|
+
initRouteStateWithURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location, defaultPage);
|
|
3984
|
+
}
|
|
3985
|
+
clearRouteState(keepRouteState) {
|
|
3986
|
+
clearRouteStateFromURL(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.__MICRO_APP_URL__, this.proxyWindow.location, keepRouteState);
|
|
3987
|
+
}
|
|
3988
|
+
setRouteInfoForKeepAliveApp() {
|
|
3989
|
+
updateBrowserURLWithLocation(this.proxyWindow.__MICRO_APP_NAME__, this.proxyWindow.location);
|
|
3990
|
+
}
|
|
3991
|
+
removeRouteInfoForKeepAliveApp() {
|
|
3992
|
+
removeStateAndPathFromBrowser(this.proxyWindow.__MICRO_APP_NAME__);
|
|
3993
|
+
}
|
|
3994
|
+
createProxyDocument(appName) {
|
|
3995
|
+
const createElement = function (tagName, options) {
|
|
3996
|
+
const element = globalEnv.rawCreateElement.call(globalEnv.rawDocument, tagName, options);
|
|
3997
|
+
element.__MICRO_APP_NAME__ = appName;
|
|
3998
|
+
return element;
|
|
3999
|
+
};
|
|
4000
|
+
const proxyDocument = new Proxy(globalEnv.rawDocument, {
|
|
4001
|
+
get(target, key) {
|
|
4002
|
+
throttleDeferForSetAppName(appName);
|
|
4003
|
+
throttleDeferForParentNode(proxyDocument);
|
|
4004
|
+
if (key === 'createElement')
|
|
4005
|
+
return createElement;
|
|
4006
|
+
const rawValue = Reflect.get(target, key);
|
|
4007
|
+
return isFunction(rawValue) ? bindFunctionToRawObject(target, rawValue, 'DOCUMENT') : rawValue;
|
|
2821
4008
|
},
|
|
2822
4009
|
});
|
|
4010
|
+
return proxyDocument;
|
|
2823
4011
|
}
|
|
2824
4012
|
}
|
|
2825
4013
|
SandBox.activeCount = 0; // number of active sandbox
|
|
@@ -2854,7 +4042,7 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2854
4042
|
element = getRootContainer(element);
|
|
2855
4043
|
// clear dom scope before dispatch lifeCycles event to base app, especially mounted & unmount
|
|
2856
4044
|
removeDomScope();
|
|
2857
|
-
const detail =
|
|
4045
|
+
const detail = assign({
|
|
2858
4046
|
name: appName,
|
|
2859
4047
|
container: element,
|
|
2860
4048
|
}, error && {
|
|
@@ -2879,7 +4067,7 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2879
4067
|
* @param detail event detail
|
|
2880
4068
|
*/
|
|
2881
4069
|
function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
2882
|
-
const event = new CustomEvent(
|
|
4070
|
+
const event = new CustomEvent(formatEventName$1(eventName, appName), {
|
|
2883
4071
|
detail,
|
|
2884
4072
|
});
|
|
2885
4073
|
window.dispatchEvent(event);
|
|
@@ -2888,8 +4076,8 @@ function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
|
2888
4076
|
// micro app instances
|
|
2889
4077
|
const appInstanceMap = new Map();
|
|
2890
4078
|
class CreateApp {
|
|
2891
|
-
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, baseroute, }) {
|
|
2892
|
-
this.state = appStates.
|
|
4079
|
+
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, useMemoryRouter, baseroute, keepRouteState, defaultPage, }) {
|
|
4080
|
+
this.state = appStates.CREATED;
|
|
2893
4081
|
this.keepAliveState = null;
|
|
2894
4082
|
this.keepAliveContainer = null;
|
|
2895
4083
|
this.loadSourceLevel = 0;
|
|
@@ -2900,28 +4088,30 @@ class CreateApp {
|
|
|
2900
4088
|
this.isPrefetch = false;
|
|
2901
4089
|
this.prefetchResolve = null;
|
|
2902
4090
|
this.container = null;
|
|
2903
|
-
this.baseroute = '';
|
|
2904
4091
|
this.sandBox = null;
|
|
2905
4092
|
this.container = container !== null && container !== void 0 ? container : null;
|
|
2906
4093
|
this.inline = inline !== null && inline !== void 0 ? inline : false;
|
|
2907
4094
|
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : '';
|
|
4095
|
+
this.keepRouteState = keepRouteState !== null && keepRouteState !== void 0 ? keepRouteState : false;
|
|
2908
4096
|
this.ssrUrl = ssrUrl !== null && ssrUrl !== void 0 ? ssrUrl : '';
|
|
2909
4097
|
// optional during init👆
|
|
2910
4098
|
this.name = name;
|
|
2911
4099
|
this.url = url;
|
|
2912
4100
|
this.useSandbox = useSandbox;
|
|
2913
4101
|
this.scopecss = this.useSandbox && scopecss;
|
|
4102
|
+
this.useMemoryRouter = this.useSandbox && useMemoryRouter;
|
|
4103
|
+
this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : '';
|
|
2914
4104
|
this.source = {
|
|
2915
4105
|
links: new Map(),
|
|
2916
4106
|
scripts: new Map(),
|
|
2917
4107
|
};
|
|
2918
4108
|
this.loadSourceCode();
|
|
2919
|
-
this.useSandbox && (this.sandBox = new SandBox(name, url));
|
|
4109
|
+
this.useSandbox && (this.sandBox = new SandBox(name, url, this.useMemoryRouter));
|
|
2920
4110
|
}
|
|
2921
4111
|
// Load resources
|
|
2922
4112
|
loadSourceCode() {
|
|
2923
|
-
this.state = appStates.
|
|
2924
|
-
|
|
4113
|
+
this.state = appStates.LOADING;
|
|
4114
|
+
extractHtml(this);
|
|
2925
4115
|
}
|
|
2926
4116
|
/**
|
|
2927
4117
|
* When resource is loaded, mount app if it is not prefetch or unmount
|
|
@@ -2935,7 +4125,7 @@ class CreateApp {
|
|
|
2935
4125
|
this.prefetchResolve = null;
|
|
2936
4126
|
}
|
|
2937
4127
|
else if (appStates.UNMOUNT !== this.state) {
|
|
2938
|
-
this.state = appStates.
|
|
4128
|
+
this.state = appStates.LOADED;
|
|
2939
4129
|
this.mount();
|
|
2940
4130
|
}
|
|
2941
4131
|
}
|
|
@@ -2952,7 +4142,7 @@ class CreateApp {
|
|
|
2952
4142
|
}
|
|
2953
4143
|
if (appStates.UNMOUNT !== this.state) {
|
|
2954
4144
|
this.onerror(e);
|
|
2955
|
-
this.state = appStates.
|
|
4145
|
+
this.state = appStates.LOAD_FAILED;
|
|
2956
4146
|
}
|
|
2957
4147
|
}
|
|
2958
4148
|
/**
|
|
@@ -2960,22 +4150,26 @@ class CreateApp {
|
|
|
2960
4150
|
* @param container app container
|
|
2961
4151
|
* @param inline js runs in inline mode
|
|
2962
4152
|
* @param baseroute route prefix, default is ''
|
|
4153
|
+
* @param keepRouteState keep route state when unmount, default is false
|
|
2963
4154
|
*/
|
|
2964
|
-
mount(container, inline, baseroute) {
|
|
4155
|
+
mount(container, inline, baseroute, keepRouteState, defaultPage) {
|
|
2965
4156
|
var _a, _b, _c;
|
|
2966
|
-
if (isBoolean(inline)
|
|
4157
|
+
if (isBoolean(inline))
|
|
2967
4158
|
this.inline = inline;
|
|
2968
|
-
|
|
4159
|
+
// keepRouteState effective on unmount
|
|
4160
|
+
if (isBoolean(keepRouteState))
|
|
4161
|
+
this.keepRouteState = keepRouteState;
|
|
2969
4162
|
this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
|
|
2970
4163
|
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
|
|
4164
|
+
this.defaultPage = defaultPage !== null && defaultPage !== void 0 ? defaultPage : this.defaultPage;
|
|
2971
4165
|
if (this.loadSourceLevel !== 2) {
|
|
2972
|
-
this.state = appStates.
|
|
4166
|
+
this.state = appStates.LOADING;
|
|
2973
4167
|
return;
|
|
2974
4168
|
}
|
|
2975
4169
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
2976
4170
|
this.state = appStates.MOUNTING;
|
|
2977
4171
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
2978
|
-
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute);
|
|
4172
|
+
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute, this.useMemoryRouter, this.defaultPage);
|
|
2979
4173
|
let umdHookMountResult; // result of mount function
|
|
2980
4174
|
if (!this.umdMode) {
|
|
2981
4175
|
let hasDispatchMountedEvent = false;
|
|
@@ -3040,11 +4234,12 @@ class CreateApp {
|
|
|
3040
4234
|
}
|
|
3041
4235
|
/**
|
|
3042
4236
|
* unmount app
|
|
4237
|
+
* NOTE: Do not add any params on account of unmountApp
|
|
3043
4238
|
* @param destroy completely destroy, delete cache resources
|
|
3044
4239
|
* @param unmountcb callback of unmount
|
|
3045
4240
|
*/
|
|
3046
4241
|
unmount(destroy, unmountcb) {
|
|
3047
|
-
if (this.state === appStates.
|
|
4242
|
+
if (this.state === appStates.LOAD_FAILED) {
|
|
3048
4243
|
destroy = true;
|
|
3049
4244
|
}
|
|
3050
4245
|
this.state = appStates.UNMOUNT;
|
|
@@ -3097,8 +4292,13 @@ class CreateApp {
|
|
|
3097
4292
|
else if (this.umdMode && this.container.childElementCount) {
|
|
3098
4293
|
cloneContainer(this.container, this.source.html, false);
|
|
3099
4294
|
}
|
|
3100
|
-
|
|
3101
|
-
|
|
4295
|
+
/**
|
|
4296
|
+
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
4297
|
+
* NOTE:
|
|
4298
|
+
* 1. if destroy is true, clear route state
|
|
4299
|
+
* 2. umd mode and keep-alive will not clear EventSource
|
|
4300
|
+
*/
|
|
4301
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop(this.keepRouteState && !destroy, !this.umdMode || destroy);
|
|
3102
4302
|
if (!getActiveApps().length) {
|
|
3103
4303
|
releasePatchSetAttribute();
|
|
3104
4304
|
}
|
|
@@ -3117,34 +4317,40 @@ class CreateApp {
|
|
|
3117
4317
|
}
|
|
3118
4318
|
// hidden app when disconnectedCallback called with keep-alive
|
|
3119
4319
|
hiddenKeepAliveApp() {
|
|
4320
|
+
var _a;
|
|
3120
4321
|
const oldContainer = this.container;
|
|
3121
4322
|
cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
|
|
3122
4323
|
this.container = this.keepAliveContainer;
|
|
3123
4324
|
this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
|
|
3124
4325
|
// event should dispatch before clone node
|
|
3125
|
-
// dispatch
|
|
4326
|
+
// dispatch afterHidden event to micro-app
|
|
3126
4327
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
3127
4328
|
appState: 'afterhidden',
|
|
3128
4329
|
});
|
|
3129
|
-
// dispatch
|
|
4330
|
+
// dispatch afterHidden event to base app
|
|
3130
4331
|
dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
|
|
4332
|
+
// called after lifeCyclesEvent
|
|
4333
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
3131
4334
|
}
|
|
3132
4335
|
// show app when connectedCallback called with keep-alive
|
|
3133
4336
|
showKeepAliveApp(container) {
|
|
3134
|
-
|
|
4337
|
+
var _a;
|
|
4338
|
+
// dispatch beforeShow event to micro-app
|
|
3135
4339
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
3136
4340
|
appState: 'beforeshow',
|
|
3137
4341
|
});
|
|
3138
|
-
// dispatch
|
|
4342
|
+
// dispatch beforeShow event to base app
|
|
3139
4343
|
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
3140
4344
|
cloneContainer(this.container, container, false);
|
|
3141
4345
|
this.container = container;
|
|
3142
4346
|
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
3143
|
-
//
|
|
4347
|
+
// called before lifeCyclesEvent
|
|
4348
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.setRouteInfoForKeepAliveApp();
|
|
4349
|
+
// dispatch afterShow event to micro-app
|
|
3144
4350
|
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
3145
4351
|
appState: 'aftershow',
|
|
3146
4352
|
});
|
|
3147
|
-
// dispatch
|
|
4353
|
+
// dispatch afterShow event to base app
|
|
3148
4354
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
|
|
3149
4355
|
}
|
|
3150
4356
|
/**
|
|
@@ -3252,12 +4458,17 @@ function defineElement(tagName) {
|
|
|
3252
4458
|
}
|
|
3253
4459
|
disconnectedCallback() {
|
|
3254
4460
|
this.hasConnected = false;
|
|
3255
|
-
|
|
3256
|
-
if (
|
|
3257
|
-
|
|
3258
|
-
|
|
3259
|
-
|
|
3260
|
-
|
|
4461
|
+
const app = appInstanceMap.get(this.appName);
|
|
4462
|
+
if (app &&
|
|
4463
|
+
app.getAppState() !== appStates.UNMOUNT &&
|
|
4464
|
+
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
4465
|
+
// keep-alive
|
|
4466
|
+
if (this.getKeepAliveModeResult()) {
|
|
4467
|
+
this.handleHiddenKeepAliveApp();
|
|
4468
|
+
}
|
|
4469
|
+
else {
|
|
4470
|
+
this.handleUnmount(this.getDestroyCompatibleResult());
|
|
4471
|
+
}
|
|
3261
4472
|
}
|
|
3262
4473
|
}
|
|
3263
4474
|
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
@@ -3305,12 +4516,7 @@ function defineElement(tagName) {
|
|
|
3305
4516
|
if (this.getDisposeResult('shadowDOM') && !this.shadowRoot && isFunction(this.attachShadow)) {
|
|
3306
4517
|
this.attachShadow({ mode: 'open' });
|
|
3307
4518
|
}
|
|
3308
|
-
|
|
3309
|
-
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, this.appUrl);
|
|
3310
|
-
}
|
|
3311
|
-
else if (this.ssrUrl) {
|
|
3312
|
-
this.ssrUrl = '';
|
|
3313
|
-
}
|
|
4519
|
+
this.updateSsrUrl(this.appUrl);
|
|
3314
4520
|
if (appInstanceMap.has(this.appName)) {
|
|
3315
4521
|
const app = appInstanceMap.get(this.appName);
|
|
3316
4522
|
const existAppUrl = app.ssrUrl || app.url;
|
|
@@ -3344,15 +4550,9 @@ function defineElement(tagName) {
|
|
|
3344
4550
|
actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
|
|
3345
4551
|
var _a;
|
|
3346
4552
|
/**
|
|
3347
|
-
* change ssrUrl in ssr mode
|
|
3348
4553
|
* do not add judgment of formatAttrUrl === this.appUrl
|
|
3349
4554
|
*/
|
|
3350
|
-
|
|
3351
|
-
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
3352
|
-
}
|
|
3353
|
-
else if (this.ssrUrl) {
|
|
3354
|
-
this.ssrUrl = '';
|
|
3355
|
-
}
|
|
4555
|
+
this.updateSsrUrl(formatAttrUrl);
|
|
3356
4556
|
this.appName = formatAttrName;
|
|
3357
4557
|
this.appUrl = formatAttrUrl;
|
|
3358
4558
|
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
@@ -3412,14 +4612,14 @@ function defineElement(tagName) {
|
|
|
3412
4612
|
app.isPrefetch = false;
|
|
3413
4613
|
defer(() => {
|
|
3414
4614
|
var _a;
|
|
3415
|
-
return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible());
|
|
4615
|
+
return app.mount((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this, this.getDisposeResult('inline'), this.getBaseRouteCompatible(), this.getDisposeResult('keep-router-state'), this.getDefaultPageValue());
|
|
3416
4616
|
});
|
|
3417
4617
|
}
|
|
3418
4618
|
// create app instance
|
|
3419
4619
|
handleCreateApp() {
|
|
3420
4620
|
var _a;
|
|
3421
4621
|
/**
|
|
3422
|
-
* actions for
|
|
4622
|
+
* actions for destroy old app
|
|
3423
4623
|
* fix of unmounted umd app with disableSandbox
|
|
3424
4624
|
*/
|
|
3425
4625
|
if (appInstanceMap.has(this.appName)) {
|
|
@@ -3433,7 +4633,10 @@ function defineElement(tagName) {
|
|
|
3433
4633
|
inline: this.getDisposeResult('inline'),
|
|
3434
4634
|
scopecss: !(this.getDisposeResult('disableScopecss') || this.getDisposeResult('shadowDOM')),
|
|
3435
4635
|
useSandbox: !this.getDisposeResult('disableSandbox'),
|
|
4636
|
+
useMemoryRouter: !this.getDisposeResult('disable-memory-router'),
|
|
3436
4637
|
baseroute: this.getBaseRouteCompatible(),
|
|
4638
|
+
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
4639
|
+
defaultPage: this.getDefaultPageValue(),
|
|
3437
4640
|
});
|
|
3438
4641
|
appInstanceMap.set(this.appName, instance);
|
|
3439
4642
|
}
|
|
@@ -3441,11 +4644,12 @@ function defineElement(tagName) {
|
|
|
3441
4644
|
* unmount app
|
|
3442
4645
|
* @param destroy delete cache resources when unmount
|
|
3443
4646
|
*/
|
|
3444
|
-
handleUnmount(destroy,
|
|
4647
|
+
handleUnmount(destroy, unmountCb) {
|
|
3445
4648
|
const app = appInstanceMap.get(this.appName);
|
|
3446
4649
|
if (app &&
|
|
3447
|
-
app.getAppState() !== appStates.UNMOUNT)
|
|
3448
|
-
app.unmount(destroy,
|
|
4650
|
+
app.getAppState() !== appStates.UNMOUNT) {
|
|
4651
|
+
app.unmount(destroy, unmountCb);
|
|
4652
|
+
}
|
|
3449
4653
|
}
|
|
3450
4654
|
// hidden app when disconnectedCallback called with keep-alive
|
|
3451
4655
|
handleHiddenKeepAliveApp() {
|
|
@@ -3508,6 +4712,37 @@ function defineElement(tagName) {
|
|
|
3508
4712
|
getKeepAliveModeResult() {
|
|
3509
4713
|
return this.getDisposeResult('keep-alive') && !this.getDestroyCompatibleResult();
|
|
3510
4714
|
}
|
|
4715
|
+
/**
|
|
4716
|
+
* change ssrUrl in ssr mode
|
|
4717
|
+
*/
|
|
4718
|
+
updateSsrUrl(baseUrl) {
|
|
4719
|
+
if (this.getDisposeResult('ssr')) {
|
|
4720
|
+
if (this.getDisposeResult('disable-memory-router') || this.getDisposeResult('disableSandbox')) {
|
|
4721
|
+
const rawLocation = globalEnv.rawWindow.location;
|
|
4722
|
+
this.ssrUrl = CompletionPath(rawLocation.pathname + rawLocation.search, baseUrl);
|
|
4723
|
+
}
|
|
4724
|
+
else {
|
|
4725
|
+
// get path from browser URL
|
|
4726
|
+
let targetPath = getNoHashMicroPathFromURL(this.appName, baseUrl);
|
|
4727
|
+
const defaultPagePath = this.getDefaultPageValue();
|
|
4728
|
+
if (!targetPath && defaultPagePath) {
|
|
4729
|
+
const targetLocation = createURL(defaultPagePath, baseUrl);
|
|
4730
|
+
targetPath = targetLocation.origin + targetLocation.pathname + targetLocation.search;
|
|
4731
|
+
}
|
|
4732
|
+
this.ssrUrl = targetPath;
|
|
4733
|
+
}
|
|
4734
|
+
}
|
|
4735
|
+
else if (this.ssrUrl) {
|
|
4736
|
+
this.ssrUrl = '';
|
|
4737
|
+
}
|
|
4738
|
+
}
|
|
4739
|
+
/**
|
|
4740
|
+
* get config of default page
|
|
4741
|
+
*/
|
|
4742
|
+
getDefaultPageValue() {
|
|
4743
|
+
var _a, _b, _c;
|
|
4744
|
+
return (_c = (_b = (_a = router.getDefaultPage(this.appName)) !== null && _a !== void 0 ? _a : this.getAttribute('default-page')) !== null && _b !== void 0 ? _b : this.getAttribute('defaultPage')) !== null && _c !== void 0 ? _c : '';
|
|
4745
|
+
}
|
|
3511
4746
|
/**
|
|
3512
4747
|
* Data from the base application
|
|
3513
4748
|
*/
|
|
@@ -3542,12 +4777,13 @@ function defineElement(tagName) {
|
|
|
3542
4777
|
* url: string,
|
|
3543
4778
|
* disableScopecss?: boolean,
|
|
3544
4779
|
* disableSandbox?: boolean,
|
|
4780
|
+
* disableMemoryRouter?: boolean,
|
|
3545
4781
|
* },
|
|
3546
4782
|
* ...
|
|
3547
4783
|
* ])
|
|
3548
4784
|
* Note:
|
|
3549
4785
|
* 1: preFetch is asynchronous and is performed only when the browser is idle
|
|
3550
|
-
* 2: disableScopecss, disableSandbox must be same with micro-app element, if conflict, the one who executes first shall prevail
|
|
4786
|
+
* 2: disableScopecss, disableSandbox, disableMemoryRouter must be same with micro-app element, if conflict, the one who executes first shall prevail
|
|
3551
4787
|
* @param apps micro apps
|
|
3552
4788
|
*/
|
|
3553
4789
|
function preFetch(apps) {
|
|
@@ -3565,7 +4801,7 @@ function preFetch(apps) {
|
|
|
3565
4801
|
function preFetchInSerial(prefetchApp) {
|
|
3566
4802
|
return new Promise((resolve) => {
|
|
3567
4803
|
requestIdleCallback(() => {
|
|
3568
|
-
var _a, _b;
|
|
4804
|
+
var _a, _b, _c;
|
|
3569
4805
|
if (isPlainObject(prefetchApp) && navigator.onLine) {
|
|
3570
4806
|
prefetchApp.name = formatAppName(prefetchApp.name);
|
|
3571
4807
|
prefetchApp.url = formatAppURL(prefetchApp.url, prefetchApp.name);
|
|
@@ -3575,6 +4811,7 @@ function preFetchInSerial(prefetchApp) {
|
|
|
3575
4811
|
url: prefetchApp.url,
|
|
3576
4812
|
scopecss: !((_a = prefetchApp.disableScopecss) !== null && _a !== void 0 ? _a : microApp.disableScopecss),
|
|
3577
4813
|
useSandbox: !((_b = prefetchApp.disableSandbox) !== null && _b !== void 0 ? _b : microApp.disableSandbox),
|
|
4814
|
+
useMemoryRouter: !((_c = prefetchApp.disableMemoryRouter) !== null && _c !== void 0 ? _c : microApp.disableMemoryRouter),
|
|
3578
4815
|
});
|
|
3579
4816
|
app.isPrefetch = true;
|
|
3580
4817
|
app.prefetchResolve = resolve;
|
|
@@ -3643,7 +4880,7 @@ function getAllApps() {
|
|
|
3643
4880
|
/**
|
|
3644
4881
|
* unmount app by appName
|
|
3645
4882
|
* @param appName
|
|
3646
|
-
* @param options
|
|
4883
|
+
* @param options unmountAppOptions
|
|
3647
4884
|
* @returns Promise<void>
|
|
3648
4885
|
*/
|
|
3649
4886
|
function unmountApp(appName, options) {
|
|
@@ -3717,6 +4954,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3717
4954
|
super(...arguments);
|
|
3718
4955
|
this.tagName = 'micro-app';
|
|
3719
4956
|
this.preFetch = preFetch;
|
|
4957
|
+
this.router = router;
|
|
3720
4958
|
}
|
|
3721
4959
|
start(options) {
|
|
3722
4960
|
if (!isBrowser || !window.customElements) {
|
|
@@ -3746,6 +4984,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3746
4984
|
this.inline = options.inline;
|
|
3747
4985
|
this.disableScopecss = options.disableScopecss;
|
|
3748
4986
|
this.disableSandbox = options.disableSandbox;
|
|
4987
|
+
this.disableMemoryRouter = options.disableMemoryRouter;
|
|
3749
4988
|
this.ssr = options.ssr;
|
|
3750
4989
|
isFunction(options.fetch) && (this.fetch = options.fetch);
|
|
3751
4990
|
isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);
|