@micro-zoe/micro-app 0.5.1 → 0.6.1
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 +9 -6
- package/README.zh-cn.md +11 -8
- package/lib/index.d.ts +81 -2
- package/lib/index.esm.js +693 -447
- 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 +5 -6
- package/polyfill/jsx-custom-event.js +14 -6
- package/polyfill/jsx-custom-event.js.map +1 -1
- package/typings/global.d.ts +14 -4
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '0.
|
|
1
|
+
const version = '0.6.1';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -297,16 +297,16 @@ var ObservedAttrName;
|
|
|
297
297
|
ObservedAttrName["URL"] = "url";
|
|
298
298
|
})(ObservedAttrName || (ObservedAttrName = {}));
|
|
299
299
|
// app status
|
|
300
|
-
var
|
|
301
|
-
(function (
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
})(
|
|
300
|
+
var appStates;
|
|
301
|
+
(function (appStates) {
|
|
302
|
+
appStates["NOT_LOADED"] = "NOT_LOADED";
|
|
303
|
+
appStates["LOADING_SOURCE_CODE"] = "LOADING_SOURCE_CODE";
|
|
304
|
+
appStates["LOAD_SOURCE_FINISHED"] = "LOAD_SOURCE_FINISHED";
|
|
305
|
+
appStates["LOAD_SOURCE_ERROR"] = "LOAD_SOURCE_ERROR";
|
|
306
|
+
appStates["MOUNTING"] = "MOUNTING";
|
|
307
|
+
appStates["MOUNTED"] = "MOUNTED";
|
|
308
|
+
appStates["UNMOUNT"] = "UNMOUNT";
|
|
309
|
+
})(appStates || (appStates = {}));
|
|
310
310
|
// lifecycles
|
|
311
311
|
var lifeCycles;
|
|
312
312
|
(function (lifeCycles) {
|
|
@@ -315,7 +315,17 @@ var lifeCycles;
|
|
|
315
315
|
lifeCycles["MOUNTED"] = "mounted";
|
|
316
316
|
lifeCycles["UNMOUNT"] = "unmount";
|
|
317
317
|
lifeCycles["ERROR"] = "error";
|
|
318
|
+
// 👇 keep-alive only
|
|
319
|
+
lifeCycles["BEFORESHOW"] = "beforeshow";
|
|
320
|
+
lifeCycles["AFTERSHOW"] = "aftershow";
|
|
321
|
+
lifeCycles["AFTERHIDDEN"] = "afterhidden";
|
|
318
322
|
})(lifeCycles || (lifeCycles = {}));
|
|
323
|
+
// keep-alive status
|
|
324
|
+
var keepAliveStates;
|
|
325
|
+
(function (keepAliveStates) {
|
|
326
|
+
keepAliveStates["KEEP_ALIVE_SHOW"] = "KEEP_ALIVE_SHOW";
|
|
327
|
+
keepAliveStates["KEEP_ALIVE_HIDDEN"] = "KEEP_ALIVE_HIDDEN";
|
|
328
|
+
})(keepAliveStates || (keepAliveStates = {}));
|
|
319
329
|
|
|
320
330
|
/**
|
|
321
331
|
* fetch source of html, js, css
|
|
@@ -340,12 +350,13 @@ function initGlobalEnv() {
|
|
|
340
350
|
* pay attention to this binding
|
|
341
351
|
*/
|
|
342
352
|
const rawSetAttribute = Element.prototype.setAttribute;
|
|
343
|
-
const rawAppendChild =
|
|
344
|
-
const rawInsertBefore =
|
|
345
|
-
const rawReplaceChild =
|
|
346
|
-
const rawRemoveChild =
|
|
353
|
+
const rawAppendChild = Element.prototype.appendChild;
|
|
354
|
+
const rawInsertBefore = Element.prototype.insertBefore;
|
|
355
|
+
const rawReplaceChild = Element.prototype.replaceChild;
|
|
356
|
+
const rawRemoveChild = Element.prototype.removeChild;
|
|
347
357
|
const rawAppend = Element.prototype.append;
|
|
348
358
|
const rawPrepend = Element.prototype.prepend;
|
|
359
|
+
const rawCloneNode = Element.prototype.cloneNode;
|
|
349
360
|
const rawCreateElement = Document.prototype.createElement;
|
|
350
361
|
const rawCreateElementNS = Document.prototype.createElementNS;
|
|
351
362
|
const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
|
|
@@ -382,6 +393,7 @@ function initGlobalEnv() {
|
|
|
382
393
|
rawRemoveChild,
|
|
383
394
|
rawAppend,
|
|
384
395
|
rawPrepend,
|
|
396
|
+
rawCloneNode,
|
|
385
397
|
rawCreateElement,
|
|
386
398
|
rawCreateElementNS,
|
|
387
399
|
rawCreateDocumentFragment,
|
|
@@ -1180,305 +1192,6 @@ function extractHtml(app) {
|
|
|
1180
1192
|
});
|
|
1181
1193
|
}
|
|
1182
1194
|
|
|
1183
|
-
const boundedMap = new WeakMap();
|
|
1184
|
-
function isBoundedFunction(value) {
|
|
1185
|
-
if (boundedMap.has(value)) {
|
|
1186
|
-
return boundedMap.get(value);
|
|
1187
|
-
}
|
|
1188
|
-
// bind function
|
|
1189
|
-
const boundFunction = isBoundFunction(value);
|
|
1190
|
-
boundedMap.set(value, boundFunction);
|
|
1191
|
-
return boundFunction;
|
|
1192
|
-
}
|
|
1193
|
-
const constructorMap = new WeakMap();
|
|
1194
|
-
function isConstructor(value) {
|
|
1195
|
-
if (constructorMap.has(value)) {
|
|
1196
|
-
return constructorMap.get(value);
|
|
1197
|
-
}
|
|
1198
|
-
const valueStr = value.toString();
|
|
1199
|
-
const result = (value.prototype &&
|
|
1200
|
-
value.prototype.constructor === value &&
|
|
1201
|
-
Object.getOwnPropertyNames(value.prototype).length > 1) ||
|
|
1202
|
-
/^function\s+[A-Z]/.test(valueStr) ||
|
|
1203
|
-
/^class\s+/.test(valueStr);
|
|
1204
|
-
constructorMap.set(value, result);
|
|
1205
|
-
return result;
|
|
1206
|
-
}
|
|
1207
|
-
const rawWindowMethodMap = new WeakMap();
|
|
1208
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
1209
|
-
function bindFunctionToRawWidow(rawWindow, value) {
|
|
1210
|
-
if (rawWindowMethodMap.has(value)) {
|
|
1211
|
-
return rawWindowMethodMap.get(value);
|
|
1212
|
-
}
|
|
1213
|
-
if (isFunction(value) && !isConstructor(value) && !isBoundedFunction(value)) {
|
|
1214
|
-
const bindRawWindowValue = value.bind(rawWindow);
|
|
1215
|
-
for (const key in value) {
|
|
1216
|
-
bindRawWindowValue[key] = value[key];
|
|
1217
|
-
}
|
|
1218
|
-
if (value.hasOwnProperty('prototype') && !bindRawWindowValue.hasOwnProperty('prototype')) {
|
|
1219
|
-
bindRawWindowValue.prototype = value.prototype;
|
|
1220
|
-
}
|
|
1221
|
-
rawWindowMethodMap.set(value, bindRawWindowValue);
|
|
1222
|
-
return bindRawWindowValue;
|
|
1223
|
-
}
|
|
1224
|
-
return value;
|
|
1225
|
-
}
|
|
1226
|
-
|
|
1227
|
-
// document.onclick binding list, the binding function of each application is unique
|
|
1228
|
-
const documentClickListMap = new Map();
|
|
1229
|
-
let hasRewriteDocumentOnClick = false;
|
|
1230
|
-
/**
|
|
1231
|
-
* Rewrite document.onclick and execute it only once
|
|
1232
|
-
*/
|
|
1233
|
-
function overwriteDocumentOnClick() {
|
|
1234
|
-
hasRewriteDocumentOnClick = true;
|
|
1235
|
-
if (Object.getOwnPropertyDescriptor(document, 'onclick')) {
|
|
1236
|
-
return logWarn('Cannot redefine document property onclick');
|
|
1237
|
-
}
|
|
1238
|
-
const rawOnClick = document.onclick;
|
|
1239
|
-
document.onclick = null;
|
|
1240
|
-
let hasDocumentClickInited = false;
|
|
1241
|
-
function onClickHandler(e) {
|
|
1242
|
-
documentClickListMap.forEach((f) => {
|
|
1243
|
-
isFunction(f) && f.call(document, e);
|
|
1244
|
-
});
|
|
1245
|
-
}
|
|
1246
|
-
Object.defineProperty(document, 'onclick', {
|
|
1247
|
-
configurable: true,
|
|
1248
|
-
enumerable: true,
|
|
1249
|
-
get() {
|
|
1250
|
-
const appName = getCurrentAppName();
|
|
1251
|
-
return appName ? documentClickListMap.get(appName) : documentClickListMap.get('base');
|
|
1252
|
-
},
|
|
1253
|
-
set(f) {
|
|
1254
|
-
const appName = getCurrentAppName();
|
|
1255
|
-
if (appName) {
|
|
1256
|
-
documentClickListMap.set(appName, f);
|
|
1257
|
-
}
|
|
1258
|
-
else {
|
|
1259
|
-
documentClickListMap.set('base', f);
|
|
1260
|
-
}
|
|
1261
|
-
if (!hasDocumentClickInited && isFunction(f)) {
|
|
1262
|
-
hasDocumentClickInited = true;
|
|
1263
|
-
globalEnv.rawDocumentAddEventListener.call(globalEnv.rawDocument, 'click', onClickHandler, false);
|
|
1264
|
-
}
|
|
1265
|
-
}
|
|
1266
|
-
});
|
|
1267
|
-
rawOnClick && (document.onclick = rawOnClick);
|
|
1268
|
-
}
|
|
1269
|
-
/**
|
|
1270
|
-
* The document event is globally, we need to clear these event bindings when micro application unmounted
|
|
1271
|
-
*/
|
|
1272
|
-
const documentEventListenerMap = new Map();
|
|
1273
|
-
function effectDocumentEvent() {
|
|
1274
|
-
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1275
|
-
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
1276
|
-
document.addEventListener = function (type, listener, options) {
|
|
1277
|
-
var _a;
|
|
1278
|
-
const appName = getCurrentAppName();
|
|
1279
|
-
/**
|
|
1280
|
-
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
1281
|
-
*/
|
|
1282
|
-
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1283
|
-
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1284
|
-
if (appListenersMap) {
|
|
1285
|
-
const appListenerList = appListenersMap.get(type);
|
|
1286
|
-
if (appListenerList) {
|
|
1287
|
-
appListenerList.add(listener);
|
|
1288
|
-
}
|
|
1289
|
-
else {
|
|
1290
|
-
appListenersMap.set(type, new Set([listener]));
|
|
1291
|
-
}
|
|
1292
|
-
}
|
|
1293
|
-
else {
|
|
1294
|
-
documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
|
|
1295
|
-
}
|
|
1296
|
-
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1297
|
-
}
|
|
1298
|
-
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
1299
|
-
};
|
|
1300
|
-
document.removeEventListener = function (type, listener, options) {
|
|
1301
|
-
var _a;
|
|
1302
|
-
const appName = getCurrentAppName();
|
|
1303
|
-
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1304
|
-
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1305
|
-
if (appListenersMap) {
|
|
1306
|
-
const appListenerList = appListenersMap.get(type);
|
|
1307
|
-
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
1308
|
-
appListenerList.delete(listener);
|
|
1309
|
-
}
|
|
1310
|
-
}
|
|
1311
|
-
}
|
|
1312
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
1313
|
-
};
|
|
1314
|
-
}
|
|
1315
|
-
// Clear the document event agent
|
|
1316
|
-
function releaseEffectDocumentEvent() {
|
|
1317
|
-
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
1318
|
-
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
1319
|
-
}
|
|
1320
|
-
/**
|
|
1321
|
-
* Format event name
|
|
1322
|
-
* @param type event name
|
|
1323
|
-
* @param microWindow micro window
|
|
1324
|
-
*/
|
|
1325
|
-
function formatEventType(type, microWindow) {
|
|
1326
|
-
if (type === 'unmount') {
|
|
1327
|
-
return `unmount-${microWindow.__MICRO_APP_NAME__}`;
|
|
1328
|
-
}
|
|
1329
|
-
return type;
|
|
1330
|
-
}
|
|
1331
|
-
/**
|
|
1332
|
-
* Rewrite side-effect events
|
|
1333
|
-
* @param microWindow micro window
|
|
1334
|
-
*/
|
|
1335
|
-
function effect(microWindow) {
|
|
1336
|
-
const appName = microWindow.__MICRO_APP_NAME__;
|
|
1337
|
-
const eventListenerMap = new Map();
|
|
1338
|
-
const intervalIdMap = new Map();
|
|
1339
|
-
const timeoutIdMap = new Map();
|
|
1340
|
-
const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1341
|
-
// listener may be null, e.g test-passive
|
|
1342
|
-
microWindow.addEventListener = function (type, listener, options) {
|
|
1343
|
-
type = formatEventType(type, microWindow);
|
|
1344
|
-
const listenerList = eventListenerMap.get(type);
|
|
1345
|
-
if (listenerList) {
|
|
1346
|
-
listenerList.add(listener);
|
|
1347
|
-
}
|
|
1348
|
-
else {
|
|
1349
|
-
eventListenerMap.set(type, new Set([listener]));
|
|
1350
|
-
}
|
|
1351
|
-
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1352
|
-
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
1353
|
-
};
|
|
1354
|
-
microWindow.removeEventListener = function (type, listener, options) {
|
|
1355
|
-
type = formatEventType(type, microWindow);
|
|
1356
|
-
const listenerList = eventListenerMap.get(type);
|
|
1357
|
-
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
1358
|
-
listenerList.delete(listener);
|
|
1359
|
-
}
|
|
1360
|
-
rawWindowRemoveEventListener.call(rawWindow, type, listener, options);
|
|
1361
|
-
};
|
|
1362
|
-
microWindow.setInterval = function (handler, timeout, ...args) {
|
|
1363
|
-
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
1364
|
-
intervalIdMap.set(intervalId, { handler, timeout, args });
|
|
1365
|
-
return intervalId;
|
|
1366
|
-
};
|
|
1367
|
-
microWindow.setTimeout = function (handler, timeout, ...args) {
|
|
1368
|
-
const timeoutId = rawSetTimeout.call(rawWindow, handler, timeout, ...args);
|
|
1369
|
-
timeoutIdMap.set(timeoutId, { handler, timeout, args });
|
|
1370
|
-
return timeoutId;
|
|
1371
|
-
};
|
|
1372
|
-
microWindow.clearInterval = function (intervalId) {
|
|
1373
|
-
intervalIdMap.delete(intervalId);
|
|
1374
|
-
rawClearInterval.call(rawWindow, intervalId);
|
|
1375
|
-
};
|
|
1376
|
-
microWindow.clearTimeout = function (timeoutId) {
|
|
1377
|
-
timeoutIdMap.delete(timeoutId);
|
|
1378
|
-
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1379
|
-
};
|
|
1380
|
-
const umdWindowListenerMap = new Map();
|
|
1381
|
-
const umdDocumentListenerMap = new Map();
|
|
1382
|
-
let umdIntervalIdMap = new Map();
|
|
1383
|
-
let umdTimeoutIdMap = new Map();
|
|
1384
|
-
let umdOnClickHandler;
|
|
1385
|
-
// record event and timer before exec umdMountHook
|
|
1386
|
-
const recordUmdEffect = () => {
|
|
1387
|
-
// record window event
|
|
1388
|
-
eventListenerMap.forEach((listenerList, type) => {
|
|
1389
|
-
if (listenerList.size) {
|
|
1390
|
-
umdWindowListenerMap.set(type, new Set(listenerList));
|
|
1391
|
-
}
|
|
1392
|
-
});
|
|
1393
|
-
// record timers
|
|
1394
|
-
if (intervalIdMap.size) {
|
|
1395
|
-
umdIntervalIdMap = new Map(intervalIdMap);
|
|
1396
|
-
}
|
|
1397
|
-
if (timeoutIdMap.size) {
|
|
1398
|
-
umdTimeoutIdMap = new Map(timeoutIdMap);
|
|
1399
|
-
}
|
|
1400
|
-
// record onclick handler
|
|
1401
|
-
umdOnClickHandler = documentClickListMap.get(appName);
|
|
1402
|
-
// record document event
|
|
1403
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1404
|
-
if (documentAppListenersMap) {
|
|
1405
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1406
|
-
if (listenerList.size) {
|
|
1407
|
-
umdDocumentListenerMap.set(type, new Set(listenerList));
|
|
1408
|
-
}
|
|
1409
|
-
});
|
|
1410
|
-
}
|
|
1411
|
-
};
|
|
1412
|
-
// rebuild event and timer before remount umd app
|
|
1413
|
-
const rebuildUmdEffect = () => {
|
|
1414
|
-
// rebuild window event
|
|
1415
|
-
umdWindowListenerMap.forEach((listenerList, type) => {
|
|
1416
|
-
for (const listener of listenerList) {
|
|
1417
|
-
microWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1418
|
-
}
|
|
1419
|
-
});
|
|
1420
|
-
// rebuild timer
|
|
1421
|
-
umdIntervalIdMap.forEach((info) => {
|
|
1422
|
-
microWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
1423
|
-
});
|
|
1424
|
-
umdTimeoutIdMap.forEach((info) => {
|
|
1425
|
-
microWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
1426
|
-
});
|
|
1427
|
-
// rebuild onclick event
|
|
1428
|
-
umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
|
|
1429
|
-
// rebuild document event
|
|
1430
|
-
setCurrentAppName(appName);
|
|
1431
|
-
umdDocumentListenerMap.forEach((listenerList, type) => {
|
|
1432
|
-
for (const listener of listenerList) {
|
|
1433
|
-
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1434
|
-
}
|
|
1435
|
-
});
|
|
1436
|
-
setCurrentAppName(null);
|
|
1437
|
-
};
|
|
1438
|
-
// release all event listener & interval & timeout when unmount app
|
|
1439
|
-
const releaseEffect = () => {
|
|
1440
|
-
// Clear window binding events
|
|
1441
|
-
if (eventListenerMap.size) {
|
|
1442
|
-
eventListenerMap.forEach((listenerList, type) => {
|
|
1443
|
-
for (const listener of listenerList) {
|
|
1444
|
-
rawWindowRemoveEventListener.call(rawWindow, type, listener);
|
|
1445
|
-
}
|
|
1446
|
-
});
|
|
1447
|
-
eventListenerMap.clear();
|
|
1448
|
-
}
|
|
1449
|
-
// Clear timers
|
|
1450
|
-
if (intervalIdMap.size) {
|
|
1451
|
-
intervalIdMap.forEach((_, intervalId) => {
|
|
1452
|
-
rawClearInterval.call(rawWindow, intervalId);
|
|
1453
|
-
});
|
|
1454
|
-
intervalIdMap.clear();
|
|
1455
|
-
}
|
|
1456
|
-
if (timeoutIdMap.size) {
|
|
1457
|
-
timeoutIdMap.forEach((_, timeoutId) => {
|
|
1458
|
-
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1459
|
-
});
|
|
1460
|
-
timeoutIdMap.clear();
|
|
1461
|
-
}
|
|
1462
|
-
// Clear the function bound by micro application through document.onclick
|
|
1463
|
-
documentClickListMap.delete(appName);
|
|
1464
|
-
// Clear document binding event
|
|
1465
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1466
|
-
if (documentAppListenersMap) {
|
|
1467
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1468
|
-
for (const listener of listenerList) {
|
|
1469
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
1470
|
-
}
|
|
1471
|
-
});
|
|
1472
|
-
documentAppListenersMap.clear();
|
|
1473
|
-
}
|
|
1474
|
-
};
|
|
1475
|
-
return {
|
|
1476
|
-
recordUmdEffect,
|
|
1477
|
-
rebuildUmdEffect,
|
|
1478
|
-
releaseEffect,
|
|
1479
|
-
};
|
|
1480
|
-
}
|
|
1481
|
-
|
|
1482
1195
|
class EventCenter {
|
|
1483
1196
|
constructor() {
|
|
1484
1197
|
this.eventList = new Map();
|
|
@@ -1717,49 +1430,358 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
1717
1430
|
data,
|
|
1718
1431
|
}
|
|
1719
1432
|
});
|
|
1720
|
-
getRootContainer(app.container).dispatchEvent(event);
|
|
1433
|
+
getRootContainer(app.container).dispatchEvent(event);
|
|
1434
|
+
}
|
|
1435
|
+
}
|
|
1436
|
+
/**
|
|
1437
|
+
* clear all listeners
|
|
1438
|
+
*/
|
|
1439
|
+
clearDataListener() {
|
|
1440
|
+
eventCenter.off(formatEventName(this.appName, true));
|
|
1441
|
+
}
|
|
1442
|
+
}
|
|
1443
|
+
/**
|
|
1444
|
+
* Record UMD function before exec umdHookMount
|
|
1445
|
+
* @param microAppEventCneter
|
|
1446
|
+
*/
|
|
1447
|
+
function recordDataCenterSnapshot(microAppEventCneter) {
|
|
1448
|
+
const appName = microAppEventCneter.appName;
|
|
1449
|
+
microAppEventCneter.umdDataListeners = { global: new Set(), normal: new Set() };
|
|
1450
|
+
const globalEventInfo = eventCenter.eventList.get('global');
|
|
1451
|
+
if (globalEventInfo) {
|
|
1452
|
+
for (const cb of globalEventInfo.callbacks) {
|
|
1453
|
+
if (appName === cb.__APP_NAME__) {
|
|
1454
|
+
microAppEventCneter.umdDataListeners.global.add(cb);
|
|
1455
|
+
}
|
|
1456
|
+
}
|
|
1457
|
+
}
|
|
1458
|
+
const subAppEventInfo = eventCenter.eventList.get(formatEventName(appName, true));
|
|
1459
|
+
if (subAppEventInfo) {
|
|
1460
|
+
microAppEventCneter.umdDataListeners.normal = new Set(subAppEventInfo.callbacks);
|
|
1461
|
+
}
|
|
1462
|
+
}
|
|
1463
|
+
/**
|
|
1464
|
+
* Rebind the UMD function of the record before remount
|
|
1465
|
+
* @param microAppEventCneter instance of EventCenterForMicroApp
|
|
1466
|
+
*/
|
|
1467
|
+
function rebuildDataCenterSnapshot(microAppEventCneter) {
|
|
1468
|
+
for (const cb of microAppEventCneter.umdDataListeners.global) {
|
|
1469
|
+
microAppEventCneter.addGlobalDataListener(cb, cb.__AUTO_TRIGGER__);
|
|
1470
|
+
}
|
|
1471
|
+
for (const cb of microAppEventCneter.umdDataListeners.normal) {
|
|
1472
|
+
microAppEventCneter.addDataListener(cb, cb.__AUTO_TRIGGER__);
|
|
1473
|
+
}
|
|
1474
|
+
}
|
|
1475
|
+
|
|
1476
|
+
const boundedMap = new WeakMap();
|
|
1477
|
+
function isBoundedFunction(value) {
|
|
1478
|
+
if (boundedMap.has(value)) {
|
|
1479
|
+
return boundedMap.get(value);
|
|
1480
|
+
}
|
|
1481
|
+
// bind function
|
|
1482
|
+
const boundFunction = isBoundFunction(value);
|
|
1483
|
+
boundedMap.set(value, boundFunction);
|
|
1484
|
+
return boundFunction;
|
|
1485
|
+
}
|
|
1486
|
+
const constructorMap = new WeakMap();
|
|
1487
|
+
function isConstructor(value) {
|
|
1488
|
+
if (constructorMap.has(value)) {
|
|
1489
|
+
return constructorMap.get(value);
|
|
1490
|
+
}
|
|
1491
|
+
const valueStr = value.toString();
|
|
1492
|
+
const result = (value.prototype &&
|
|
1493
|
+
value.prototype.constructor === value &&
|
|
1494
|
+
Object.getOwnPropertyNames(value.prototype).length > 1) ||
|
|
1495
|
+
/^function\s+[A-Z]/.test(valueStr) ||
|
|
1496
|
+
/^class\s+/.test(valueStr);
|
|
1497
|
+
constructorMap.set(value, result);
|
|
1498
|
+
return result;
|
|
1499
|
+
}
|
|
1500
|
+
const rawWindowMethodMap = new WeakMap();
|
|
1501
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
1502
|
+
function bindFunctionToRawWidow(rawWindow, value) {
|
|
1503
|
+
if (rawWindowMethodMap.has(value)) {
|
|
1504
|
+
return rawWindowMethodMap.get(value);
|
|
1505
|
+
}
|
|
1506
|
+
if (isFunction(value) && !isConstructor(value) && !isBoundedFunction(value)) {
|
|
1507
|
+
const bindRawWindowValue = value.bind(rawWindow);
|
|
1508
|
+
for (const key in value) {
|
|
1509
|
+
bindRawWindowValue[key] = value[key];
|
|
1510
|
+
}
|
|
1511
|
+
if (value.hasOwnProperty('prototype') && !bindRawWindowValue.hasOwnProperty('prototype')) {
|
|
1512
|
+
bindRawWindowValue.prototype = value.prototype;
|
|
1513
|
+
}
|
|
1514
|
+
rawWindowMethodMap.set(value, bindRawWindowValue);
|
|
1515
|
+
return bindRawWindowValue;
|
|
1516
|
+
}
|
|
1517
|
+
return value;
|
|
1518
|
+
}
|
|
1519
|
+
|
|
1520
|
+
// document.onclick binding list, the binding function of each application is unique
|
|
1521
|
+
const documentClickListMap = new Map();
|
|
1522
|
+
let hasRewriteDocumentOnClick = false;
|
|
1523
|
+
/**
|
|
1524
|
+
* Rewrite document.onclick and execute it only once
|
|
1525
|
+
*/
|
|
1526
|
+
function overwriteDocumentOnClick() {
|
|
1527
|
+
hasRewriteDocumentOnClick = true;
|
|
1528
|
+
if (Object.getOwnPropertyDescriptor(document, 'onclick')) {
|
|
1529
|
+
return logWarn('Cannot redefine document property onclick');
|
|
1530
|
+
}
|
|
1531
|
+
const rawOnClick = document.onclick;
|
|
1532
|
+
document.onclick = null;
|
|
1533
|
+
let hasDocumentClickInited = false;
|
|
1534
|
+
function onClickHandler(e) {
|
|
1535
|
+
documentClickListMap.forEach((f) => {
|
|
1536
|
+
isFunction(f) && f.call(document, e);
|
|
1537
|
+
});
|
|
1538
|
+
}
|
|
1539
|
+
Object.defineProperty(document, 'onclick', {
|
|
1540
|
+
configurable: true,
|
|
1541
|
+
enumerable: true,
|
|
1542
|
+
get() {
|
|
1543
|
+
const appName = getCurrentAppName();
|
|
1544
|
+
return appName ? documentClickListMap.get(appName) : documentClickListMap.get('base');
|
|
1545
|
+
},
|
|
1546
|
+
set(f) {
|
|
1547
|
+
const appName = getCurrentAppName();
|
|
1548
|
+
if (appName) {
|
|
1549
|
+
documentClickListMap.set(appName, f);
|
|
1550
|
+
}
|
|
1551
|
+
else {
|
|
1552
|
+
documentClickListMap.set('base', f);
|
|
1553
|
+
}
|
|
1554
|
+
if (!hasDocumentClickInited && isFunction(f)) {
|
|
1555
|
+
hasDocumentClickInited = true;
|
|
1556
|
+
globalEnv.rawDocumentAddEventListener.call(globalEnv.rawDocument, 'click', onClickHandler, false);
|
|
1557
|
+
}
|
|
1558
|
+
}
|
|
1559
|
+
});
|
|
1560
|
+
rawOnClick && (document.onclick = rawOnClick);
|
|
1561
|
+
}
|
|
1562
|
+
/**
|
|
1563
|
+
* The document event is globally, we need to clear these event bindings when micro application unmounted
|
|
1564
|
+
*/
|
|
1565
|
+
const documentEventListenerMap = new Map();
|
|
1566
|
+
function effectDocumentEvent() {
|
|
1567
|
+
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1568
|
+
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
1569
|
+
document.addEventListener = function (type, listener, options) {
|
|
1570
|
+
var _a;
|
|
1571
|
+
const appName = getCurrentAppName();
|
|
1572
|
+
/**
|
|
1573
|
+
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
1574
|
+
*/
|
|
1575
|
+
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1576
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1577
|
+
if (appListenersMap) {
|
|
1578
|
+
const appListenerList = appListenersMap.get(type);
|
|
1579
|
+
if (appListenerList) {
|
|
1580
|
+
appListenerList.add(listener);
|
|
1581
|
+
}
|
|
1582
|
+
else {
|
|
1583
|
+
appListenersMap.set(type, new Set([listener]));
|
|
1584
|
+
}
|
|
1585
|
+
}
|
|
1586
|
+
else {
|
|
1587
|
+
documentEventListenerMap.set(appName, new Map([[type, new Set([listener])]]));
|
|
1588
|
+
}
|
|
1589
|
+
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1590
|
+
}
|
|
1591
|
+
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
1592
|
+
};
|
|
1593
|
+
document.removeEventListener = function (type, listener, options) {
|
|
1594
|
+
var _a;
|
|
1595
|
+
const appName = getCurrentAppName();
|
|
1596
|
+
if (appName && !(((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.umdMode) && isBoundFunction(listener))) {
|
|
1597
|
+
const appListenersMap = documentEventListenerMap.get(appName);
|
|
1598
|
+
if (appListenersMap) {
|
|
1599
|
+
const appListenerList = appListenersMap.get(type);
|
|
1600
|
+
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
1601
|
+
appListenerList.delete(listener);
|
|
1602
|
+
}
|
|
1603
|
+
}
|
|
1604
|
+
}
|
|
1605
|
+
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
1606
|
+
};
|
|
1607
|
+
}
|
|
1608
|
+
// Clear the document event agent
|
|
1609
|
+
function releaseEffectDocumentEvent() {
|
|
1610
|
+
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
1611
|
+
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
1612
|
+
}
|
|
1613
|
+
// this events should be sent to the specified app
|
|
1614
|
+
const formatEventList = ['unmount', 'appstate-change'];
|
|
1615
|
+
/**
|
|
1616
|
+
* Format event name
|
|
1617
|
+
* @param type event name
|
|
1618
|
+
* @param microWindow micro window
|
|
1619
|
+
*/
|
|
1620
|
+
function formatEventType(type, microWindow) {
|
|
1621
|
+
if (formatEventList.includes(type)) {
|
|
1622
|
+
return `${type}-${microWindow.__MICRO_APP_NAME__}`;
|
|
1623
|
+
}
|
|
1624
|
+
return type;
|
|
1625
|
+
}
|
|
1626
|
+
/**
|
|
1627
|
+
* Rewrite side-effect events
|
|
1628
|
+
* @param microWindow micro window
|
|
1629
|
+
*/
|
|
1630
|
+
function effect(microWindow) {
|
|
1631
|
+
const appName = microWindow.__MICRO_APP_NAME__;
|
|
1632
|
+
const eventListenerMap = new Map();
|
|
1633
|
+
const intervalIdMap = new Map();
|
|
1634
|
+
const timeoutIdMap = new Map();
|
|
1635
|
+
const { rawWindow, rawDocument, rawWindowAddEventListener, rawWindowRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, rawDocumentRemoveEventListener, } = globalEnv;
|
|
1636
|
+
// listener may be null, e.g test-passive
|
|
1637
|
+
microWindow.addEventListener = function (type, listener, options) {
|
|
1638
|
+
type = formatEventType(type, microWindow);
|
|
1639
|
+
const listenerList = eventListenerMap.get(type);
|
|
1640
|
+
if (listenerList) {
|
|
1641
|
+
listenerList.add(listener);
|
|
1642
|
+
}
|
|
1643
|
+
else {
|
|
1644
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
1645
|
+
}
|
|
1646
|
+
listener && (listener.__MICRO_MARK_OPTIONS__ = options);
|
|
1647
|
+
rawWindowAddEventListener.call(rawWindow, type, listener, options);
|
|
1648
|
+
};
|
|
1649
|
+
microWindow.removeEventListener = function (type, listener, options) {
|
|
1650
|
+
type = formatEventType(type, microWindow);
|
|
1651
|
+
const listenerList = eventListenerMap.get(type);
|
|
1652
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
1653
|
+
listenerList.delete(listener);
|
|
1654
|
+
}
|
|
1655
|
+
rawWindowRemoveEventListener.call(rawWindow, type, listener, options);
|
|
1656
|
+
};
|
|
1657
|
+
microWindow.setInterval = function (handler, timeout, ...args) {
|
|
1658
|
+
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
1659
|
+
intervalIdMap.set(intervalId, { handler, timeout, args });
|
|
1660
|
+
return intervalId;
|
|
1661
|
+
};
|
|
1662
|
+
microWindow.setTimeout = function (handler, timeout, ...args) {
|
|
1663
|
+
const timeoutId = rawSetTimeout.call(rawWindow, handler, timeout, ...args);
|
|
1664
|
+
timeoutIdMap.set(timeoutId, { handler, timeout, args });
|
|
1665
|
+
return timeoutId;
|
|
1666
|
+
};
|
|
1667
|
+
microWindow.clearInterval = function (intervalId) {
|
|
1668
|
+
intervalIdMap.delete(intervalId);
|
|
1669
|
+
rawClearInterval.call(rawWindow, intervalId);
|
|
1670
|
+
};
|
|
1671
|
+
microWindow.clearTimeout = function (timeoutId) {
|
|
1672
|
+
timeoutIdMap.delete(timeoutId);
|
|
1673
|
+
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1674
|
+
};
|
|
1675
|
+
const umdWindowListenerMap = new Map();
|
|
1676
|
+
const umdDocumentListenerMap = new Map();
|
|
1677
|
+
let umdIntervalIdMap = new Map();
|
|
1678
|
+
let umdTimeoutIdMap = new Map();
|
|
1679
|
+
let umdOnClickHandler;
|
|
1680
|
+
// record event and timer before exec umdMountHook
|
|
1681
|
+
const recordUmdEffect = () => {
|
|
1682
|
+
// record window event
|
|
1683
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
1684
|
+
if (listenerList.size) {
|
|
1685
|
+
umdWindowListenerMap.set(type, new Set(listenerList));
|
|
1686
|
+
}
|
|
1687
|
+
});
|
|
1688
|
+
// record timers
|
|
1689
|
+
if (intervalIdMap.size) {
|
|
1690
|
+
umdIntervalIdMap = new Map(intervalIdMap);
|
|
1691
|
+
}
|
|
1692
|
+
if (timeoutIdMap.size) {
|
|
1693
|
+
umdTimeoutIdMap = new Map(timeoutIdMap);
|
|
1694
|
+
}
|
|
1695
|
+
// record onclick handler
|
|
1696
|
+
umdOnClickHandler = documentClickListMap.get(appName);
|
|
1697
|
+
// record document event
|
|
1698
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1699
|
+
if (documentAppListenersMap) {
|
|
1700
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1701
|
+
if (listenerList.size) {
|
|
1702
|
+
umdDocumentListenerMap.set(type, new Set(listenerList));
|
|
1703
|
+
}
|
|
1704
|
+
});
|
|
1721
1705
|
}
|
|
1722
|
-
}
|
|
1723
|
-
|
|
1724
|
-
|
|
1725
|
-
|
|
1726
|
-
|
|
1727
|
-
|
|
1728
|
-
|
|
1729
|
-
}
|
|
1730
|
-
|
|
1731
|
-
|
|
1732
|
-
|
|
1733
|
-
|
|
1734
|
-
|
|
1735
|
-
|
|
1736
|
-
|
|
1737
|
-
|
|
1738
|
-
|
|
1739
|
-
|
|
1740
|
-
|
|
1741
|
-
|
|
1706
|
+
};
|
|
1707
|
+
// rebuild event and timer before remount umd app
|
|
1708
|
+
const rebuildUmdEffect = () => {
|
|
1709
|
+
// rebuild window event
|
|
1710
|
+
umdWindowListenerMap.forEach((listenerList, type) => {
|
|
1711
|
+
for (const listener of listenerList) {
|
|
1712
|
+
microWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1713
|
+
}
|
|
1714
|
+
});
|
|
1715
|
+
// rebuild timer
|
|
1716
|
+
umdIntervalIdMap.forEach((info) => {
|
|
1717
|
+
microWindow.setInterval(info.handler, info.timeout, ...info.args);
|
|
1718
|
+
});
|
|
1719
|
+
umdTimeoutIdMap.forEach((info) => {
|
|
1720
|
+
microWindow.setTimeout(info.handler, info.timeout, ...info.args);
|
|
1721
|
+
});
|
|
1722
|
+
// rebuild onclick event
|
|
1723
|
+
umdOnClickHandler && documentClickListMap.set(appName, umdOnClickHandler);
|
|
1724
|
+
// rebuild document event
|
|
1725
|
+
setCurrentAppName(appName);
|
|
1726
|
+
umdDocumentListenerMap.forEach((listenerList, type) => {
|
|
1727
|
+
for (const listener of listenerList) {
|
|
1728
|
+
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_MARK_OPTIONS__);
|
|
1742
1729
|
}
|
|
1730
|
+
});
|
|
1731
|
+
setCurrentAppName(null);
|
|
1732
|
+
};
|
|
1733
|
+
// release all event listener & interval & timeout when unmount app
|
|
1734
|
+
const releaseEffect = () => {
|
|
1735
|
+
// Clear window binding events
|
|
1736
|
+
if (eventListenerMap.size) {
|
|
1737
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
1738
|
+
for (const listener of listenerList) {
|
|
1739
|
+
rawWindowRemoveEventListener.call(rawWindow, type, listener);
|
|
1740
|
+
}
|
|
1741
|
+
});
|
|
1742
|
+
eventListenerMap.clear();
|
|
1743
1743
|
}
|
|
1744
|
-
|
|
1745
|
-
|
|
1746
|
-
|
|
1747
|
-
|
|
1748
|
-
|
|
1749
|
-
|
|
1750
|
-
|
|
1751
|
-
|
|
1752
|
-
|
|
1753
|
-
|
|
1754
|
-
|
|
1755
|
-
|
|
1756
|
-
|
|
1757
|
-
|
|
1758
|
-
|
|
1759
|
-
|
|
1760
|
-
|
|
1744
|
+
// Clear timers
|
|
1745
|
+
if (intervalIdMap.size) {
|
|
1746
|
+
intervalIdMap.forEach((_, intervalId) => {
|
|
1747
|
+
rawClearInterval.call(rawWindow, intervalId);
|
|
1748
|
+
});
|
|
1749
|
+
intervalIdMap.clear();
|
|
1750
|
+
}
|
|
1751
|
+
if (timeoutIdMap.size) {
|
|
1752
|
+
timeoutIdMap.forEach((_, timeoutId) => {
|
|
1753
|
+
rawClearTimeout.call(rawWindow, timeoutId);
|
|
1754
|
+
});
|
|
1755
|
+
timeoutIdMap.clear();
|
|
1756
|
+
}
|
|
1757
|
+
// Clear the function bound by micro application through document.onclick
|
|
1758
|
+
documentClickListMap.delete(appName);
|
|
1759
|
+
// Clear document binding event
|
|
1760
|
+
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
1761
|
+
if (documentAppListenersMap) {
|
|
1762
|
+
documentAppListenersMap.forEach((listenerList, type) => {
|
|
1763
|
+
for (const listener of listenerList) {
|
|
1764
|
+
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
1765
|
+
}
|
|
1766
|
+
});
|
|
1767
|
+
documentAppListenersMap.clear();
|
|
1768
|
+
}
|
|
1769
|
+
};
|
|
1770
|
+
return {
|
|
1771
|
+
recordUmdEffect,
|
|
1772
|
+
rebuildUmdEffect,
|
|
1773
|
+
releaseEffect,
|
|
1774
|
+
};
|
|
1761
1775
|
}
|
|
1762
1776
|
|
|
1777
|
+
const ImageProxy = new Proxy(Image, {
|
|
1778
|
+
construct(Target, args) {
|
|
1779
|
+
const elementImage = new Target(...args);
|
|
1780
|
+
elementImage.__MICRO_APP_NAME__ = getCurrentAppName();
|
|
1781
|
+
return elementImage;
|
|
1782
|
+
},
|
|
1783
|
+
});
|
|
1784
|
+
|
|
1763
1785
|
// Variables that can escape to rawWindow
|
|
1764
1786
|
const staticEscapeProperties = [
|
|
1765
1787
|
'System',
|
|
@@ -1828,7 +1850,7 @@ class SandBox {
|
|
|
1828
1850
|
}
|
|
1829
1851
|
if (key === 'hasOwnProperty')
|
|
1830
1852
|
return hasOwnProperty;
|
|
1831
|
-
if (key === 'document' || key === 'eval') {
|
|
1853
|
+
if (key === 'document' || key === 'eval' || key === 'Image') {
|
|
1832
1854
|
if (this.active) {
|
|
1833
1855
|
setCurrentAppName(appName);
|
|
1834
1856
|
(macro ? macroTask : defer)(() => setCurrentAppName(null));
|
|
@@ -1838,6 +1860,8 @@ class SandBox {
|
|
|
1838
1860
|
return rawDocument;
|
|
1839
1861
|
case 'eval':
|
|
1840
1862
|
return eval;
|
|
1863
|
+
case 'Image':
|
|
1864
|
+
return ImageProxy;
|
|
1841
1865
|
}
|
|
1842
1866
|
}
|
|
1843
1867
|
if (Reflect.has(target, key)) {
|
|
@@ -1888,12 +1912,15 @@ class SandBox {
|
|
|
1888
1912
|
return key in target;
|
|
1889
1913
|
return key in unscopables || key in target || key in rawWindow;
|
|
1890
1914
|
},
|
|
1915
|
+
// Object.getOwnPropertyDescriptor(window, key)
|
|
1916
|
+
// TODO: use set
|
|
1891
1917
|
getOwnPropertyDescriptor: (target, key) => {
|
|
1892
1918
|
if (target.hasOwnProperty(key)) {
|
|
1893
1919
|
descriptorTargetMap.set(key, 'target');
|
|
1894
1920
|
return Object.getOwnPropertyDescriptor(target, key);
|
|
1895
1921
|
}
|
|
1896
1922
|
if (rawWindow.hasOwnProperty(key)) {
|
|
1923
|
+
// like console, alert ...
|
|
1897
1924
|
descriptorTargetMap.set(key, 'rawWindow');
|
|
1898
1925
|
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
1899
1926
|
if (descriptor && !descriptor.configurable) {
|
|
@@ -1903,6 +1930,7 @@ class SandBox {
|
|
|
1903
1930
|
}
|
|
1904
1931
|
return undefined;
|
|
1905
1932
|
},
|
|
1933
|
+
// Object.defineProperty(window, key, Descriptor)
|
|
1906
1934
|
defineProperty: (target, key, value) => {
|
|
1907
1935
|
const from = descriptorTargetMap.get(key);
|
|
1908
1936
|
if (from === 'rawWindow') {
|
|
@@ -1910,11 +1938,13 @@ class SandBox {
|
|
|
1910
1938
|
}
|
|
1911
1939
|
return Reflect.defineProperty(target, key, value);
|
|
1912
1940
|
},
|
|
1941
|
+
// Object.getOwnPropertyNames(window)
|
|
1913
1942
|
ownKeys: (target) => {
|
|
1914
1943
|
return unique(Reflect.ownKeys(rawWindow).concat(Reflect.ownKeys(target)));
|
|
1915
1944
|
},
|
|
1916
1945
|
deleteProperty: (target, key) => {
|
|
1917
1946
|
if (target.hasOwnProperty(key)) {
|
|
1947
|
+
this.injectedKeys.has(key) && this.injectedKeys.delete(key);
|
|
1918
1948
|
this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
1919
1949
|
return Reflect.deleteProperty(target, key);
|
|
1920
1950
|
}
|
|
@@ -2021,7 +2051,7 @@ class SandBox {
|
|
|
2021
2051
|
}
|
|
2022
2052
|
SandBox.activeCount = 0; // number of active sandbox
|
|
2023
2053
|
|
|
2024
|
-
function
|
|
2054
|
+
function formatEventInfo(event, element) {
|
|
2025
2055
|
Object.defineProperties(event, {
|
|
2026
2056
|
currentTarget: {
|
|
2027
2057
|
get() {
|
|
@@ -2060,7 +2090,7 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2060
2090
|
const event = new CustomEvent(lifecycleName, {
|
|
2061
2091
|
detail,
|
|
2062
2092
|
});
|
|
2063
|
-
|
|
2093
|
+
formatEventInfo(event, element);
|
|
2064
2094
|
// global hooks
|
|
2065
2095
|
// @ts-ignore
|
|
2066
2096
|
if (isFunction((_a = microApp.lifeCycles) === null || _a === void 0 ? void 0 : _a[lifecycleName])) {
|
|
@@ -2070,11 +2100,15 @@ function dispatchLifecyclesEvent(element, appName, lifecycleName, error) {
|
|
|
2070
2100
|
element.dispatchEvent(event);
|
|
2071
2101
|
}
|
|
2072
2102
|
/**
|
|
2073
|
-
* Dispatch
|
|
2074
|
-
* @param
|
|
2103
|
+
* Dispatch custom event to micro app
|
|
2104
|
+
* @param eventName event name
|
|
2105
|
+
* @param appName app name
|
|
2106
|
+
* @param detail event detail
|
|
2075
2107
|
*/
|
|
2076
|
-
function
|
|
2077
|
-
const event = new CustomEvent(
|
|
2108
|
+
function dispatchCustomEventToMicroApp(eventName, appName, detail = {}) {
|
|
2109
|
+
const event = new CustomEvent(`${eventName}-${appName}`, {
|
|
2110
|
+
detail,
|
|
2111
|
+
});
|
|
2078
2112
|
window.dispatchEvent(event);
|
|
2079
2113
|
}
|
|
2080
2114
|
|
|
@@ -2082,7 +2116,9 @@ function dispatchUnmountToMicroApp(appName) {
|
|
|
2082
2116
|
const appInstanceMap = new Map();
|
|
2083
2117
|
class CreateApp {
|
|
2084
2118
|
constructor({ name, url, ssrUrl, container, inline, scopecss, useSandbox, macro, baseroute, }) {
|
|
2085
|
-
this.
|
|
2119
|
+
this.state = appStates.NOT_LOADED;
|
|
2120
|
+
this.keepAliveState = null;
|
|
2121
|
+
this.keepAliveContainer = null;
|
|
2086
2122
|
this.loadSourceLevel = 0;
|
|
2087
2123
|
this.umdHookMount = null;
|
|
2088
2124
|
this.umdHookUnmount = null;
|
|
@@ -2112,7 +2148,7 @@ class CreateApp {
|
|
|
2112
2148
|
}
|
|
2113
2149
|
// Load resources
|
|
2114
2150
|
loadSourceCode() {
|
|
2115
|
-
this.
|
|
2151
|
+
this.state = appStates.LOADING_SOURCE_CODE;
|
|
2116
2152
|
extractHtml(this);
|
|
2117
2153
|
}
|
|
2118
2154
|
/**
|
|
@@ -2121,9 +2157,9 @@ class CreateApp {
|
|
|
2121
2157
|
onLoad(html) {
|
|
2122
2158
|
if (++this.loadSourceLevel === 2) {
|
|
2123
2159
|
this.source.html = html;
|
|
2124
|
-
if (this.isPrefetch ||
|
|
2160
|
+
if (this.isPrefetch || appStates.UNMOUNT === this.state)
|
|
2125
2161
|
return;
|
|
2126
|
-
this.
|
|
2162
|
+
this.state = appStates.LOAD_SOURCE_FINISHED;
|
|
2127
2163
|
this.mount();
|
|
2128
2164
|
}
|
|
2129
2165
|
}
|
|
@@ -2133,9 +2169,9 @@ class CreateApp {
|
|
|
2133
2169
|
*/
|
|
2134
2170
|
onLoadError(e) {
|
|
2135
2171
|
this.loadSourceLevel = -1;
|
|
2136
|
-
if (
|
|
2172
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2137
2173
|
this.onerror(e);
|
|
2138
|
-
this.
|
|
2174
|
+
this.state = appStates.LOAD_SOURCE_ERROR;
|
|
2139
2175
|
}
|
|
2140
2176
|
}
|
|
2141
2177
|
/**
|
|
@@ -2152,11 +2188,11 @@ class CreateApp {
|
|
|
2152
2188
|
this.container = (_a = this.container) !== null && _a !== void 0 ? _a : container;
|
|
2153
2189
|
this.baseroute = baseroute !== null && baseroute !== void 0 ? baseroute : this.baseroute;
|
|
2154
2190
|
if (this.loadSourceLevel !== 2) {
|
|
2155
|
-
this.
|
|
2191
|
+
this.state = appStates.LOADING_SOURCE_CODE;
|
|
2156
2192
|
return;
|
|
2157
2193
|
}
|
|
2158
2194
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.BEFOREMOUNT);
|
|
2159
|
-
this.
|
|
2195
|
+
this.state = appStates.MOUNTING;
|
|
2160
2196
|
cloneContainer(this.source.html, this.container, !this.umdMode);
|
|
2161
2197
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.start(this.baseroute);
|
|
2162
2198
|
let umdHookMountResult; // result of mount function
|
|
@@ -2216,20 +2252,23 @@ class CreateApp {
|
|
|
2216
2252
|
* dispatch mounted event when app run finished
|
|
2217
2253
|
*/
|
|
2218
2254
|
dispatchMountedEvent() {
|
|
2219
|
-
if (
|
|
2220
|
-
this.
|
|
2255
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2256
|
+
this.state = appStates.MOUNTED;
|
|
2221
2257
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
2222
2258
|
}
|
|
2223
2259
|
}
|
|
2224
2260
|
/**
|
|
2225
2261
|
* unmount app
|
|
2226
2262
|
* @param destroy completely destroy, delete cache resources
|
|
2263
|
+
* @param unmountcb callback of unmount
|
|
2227
2264
|
*/
|
|
2228
|
-
unmount(destroy) {
|
|
2229
|
-
if (this.
|
|
2265
|
+
unmount(destroy, unmountcb) {
|
|
2266
|
+
if (this.state === appStates.LOAD_SOURCE_ERROR) {
|
|
2230
2267
|
destroy = true;
|
|
2231
2268
|
}
|
|
2232
|
-
this.
|
|
2269
|
+
this.state = appStates.UNMOUNT;
|
|
2270
|
+
this.keepAliveState = null;
|
|
2271
|
+
this.keepAliveContainer = null;
|
|
2233
2272
|
// result of unmount function
|
|
2234
2273
|
let umdHookUnmountResult;
|
|
2235
2274
|
/**
|
|
@@ -2245,42 +2284,44 @@ class CreateApp {
|
|
|
2245
2284
|
}
|
|
2246
2285
|
}
|
|
2247
2286
|
// dispatch unmount event to micro app
|
|
2248
|
-
|
|
2249
|
-
this.handleUnmounted(destroy, umdHookUnmountResult);
|
|
2287
|
+
dispatchCustomEventToMicroApp('unmount', this.name);
|
|
2288
|
+
this.handleUnmounted(destroy, umdHookUnmountResult, unmountcb);
|
|
2250
2289
|
}
|
|
2251
2290
|
/**
|
|
2252
2291
|
* handle for promise umdHookUnmount
|
|
2292
|
+
* @param destroy completely destroy, delete cache resources
|
|
2253
2293
|
* @param umdHookUnmountResult result of umdHookUnmount
|
|
2294
|
+
* @param unmountcb callback of unmount
|
|
2254
2295
|
*/
|
|
2255
|
-
handleUnmounted(destroy, umdHookUnmountResult) {
|
|
2296
|
+
handleUnmounted(destroy, umdHookUnmountResult, unmountcb) {
|
|
2256
2297
|
if (isPromise(umdHookUnmountResult)) {
|
|
2257
2298
|
umdHookUnmountResult
|
|
2258
|
-
.then(() => this.actionsForUnmount(destroy))
|
|
2259
|
-
.catch(() => this.actionsForUnmount(destroy));
|
|
2299
|
+
.then(() => this.actionsForUnmount(destroy, unmountcb))
|
|
2300
|
+
.catch(() => this.actionsForUnmount(destroy, unmountcb));
|
|
2260
2301
|
}
|
|
2261
2302
|
else {
|
|
2262
|
-
this.actionsForUnmount(destroy);
|
|
2303
|
+
this.actionsForUnmount(destroy, unmountcb);
|
|
2263
2304
|
}
|
|
2264
2305
|
}
|
|
2265
2306
|
/**
|
|
2266
2307
|
* actions for unmount app
|
|
2267
2308
|
* @param destroy completely destroy, delete cache resources
|
|
2309
|
+
* @param unmountcb callback of unmount
|
|
2268
2310
|
*/
|
|
2269
|
-
actionsForUnmount(destroy) {
|
|
2311
|
+
actionsForUnmount(destroy, unmountcb) {
|
|
2270
2312
|
var _a;
|
|
2271
|
-
// dispatch unmount event to base app
|
|
2272
|
-
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
2273
2313
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.stop();
|
|
2274
2314
|
if (destroy) {
|
|
2275
2315
|
this.actionsForCompletelyDestory();
|
|
2276
2316
|
}
|
|
2277
2317
|
else if (this.umdMode && this.container.childElementCount) {
|
|
2278
|
-
/**
|
|
2279
|
-
* In umd mode, ui frameworks will no longer create style elements to head in lazy load page when render again, so we should save container to keep these elements
|
|
2280
|
-
*/
|
|
2281
2318
|
cloneContainer(this.container, this.source.html, false);
|
|
2282
2319
|
}
|
|
2320
|
+
// dispatch unmount event to base app
|
|
2321
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
2322
|
+
this.container.innerHTML = '';
|
|
2283
2323
|
this.container = null;
|
|
2324
|
+
unmountcb && unmountcb();
|
|
2284
2325
|
}
|
|
2285
2326
|
// actions for completely destroy
|
|
2286
2327
|
actionsForCompletelyDestory() {
|
|
@@ -2289,6 +2330,38 @@ class CreateApp {
|
|
|
2289
2330
|
}
|
|
2290
2331
|
appInstanceMap.delete(this.name);
|
|
2291
2332
|
}
|
|
2333
|
+
// hidden app when disconnectedCallback called with keep-alive
|
|
2334
|
+
hiddenKeepAliveApp() {
|
|
2335
|
+
const oldContainer = this.container;
|
|
2336
|
+
cloneContainer(this.container, this.keepAliveContainer ? this.keepAliveContainer : (this.keepAliveContainer = document.createElement('div')), false);
|
|
2337
|
+
this.container = this.keepAliveContainer;
|
|
2338
|
+
this.keepAliveState = keepAliveStates.KEEP_ALIVE_HIDDEN;
|
|
2339
|
+
// event should dispatch before clone node
|
|
2340
|
+
// dispatch afterhidden event to micro-app
|
|
2341
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2342
|
+
appState: 'afterhidden',
|
|
2343
|
+
});
|
|
2344
|
+
// dispatch afterhidden event to base app
|
|
2345
|
+
dispatchLifecyclesEvent(oldContainer, this.name, lifeCycles.AFTERHIDDEN);
|
|
2346
|
+
}
|
|
2347
|
+
// show app when connectedCallback called with keep-alive
|
|
2348
|
+
showKeepAliveApp(container) {
|
|
2349
|
+
// dispatch beforeshow event to micro-app
|
|
2350
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2351
|
+
appState: 'beforeshow',
|
|
2352
|
+
});
|
|
2353
|
+
// dispatch beforeshow event to base app
|
|
2354
|
+
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
2355
|
+
cloneContainer(this.container, container, false);
|
|
2356
|
+
this.container = container;
|
|
2357
|
+
this.keepAliveState = keepAliveStates.KEEP_ALIVE_SHOW;
|
|
2358
|
+
// dispatch aftershow event to micro-app
|
|
2359
|
+
dispatchCustomEventToMicroApp('appstate-change', this.name, {
|
|
2360
|
+
appState: 'aftershow',
|
|
2361
|
+
});
|
|
2362
|
+
// dispatch aftershow event to base app
|
|
2363
|
+
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.AFTERSHOW);
|
|
2364
|
+
}
|
|
2292
2365
|
/**
|
|
2293
2366
|
* app rendering error
|
|
2294
2367
|
* @param e Error
|
|
@@ -2296,15 +2369,19 @@ class CreateApp {
|
|
|
2296
2369
|
onerror(e) {
|
|
2297
2370
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.ERROR, e);
|
|
2298
2371
|
}
|
|
2299
|
-
// get app
|
|
2300
|
-
|
|
2301
|
-
return this.
|
|
2372
|
+
// get app state
|
|
2373
|
+
getAppState() {
|
|
2374
|
+
return this.state;
|
|
2375
|
+
}
|
|
2376
|
+
// get keep-alive state
|
|
2377
|
+
getKeepAliveState() {
|
|
2378
|
+
return this.keepAliveState;
|
|
2302
2379
|
}
|
|
2303
2380
|
// get umd library, if it not exist, return empty object
|
|
2304
2381
|
getUmdLibraryHooks() {
|
|
2305
2382
|
var _a, _b;
|
|
2306
2383
|
// after execScripts, the app maybe unmounted
|
|
2307
|
-
if (
|
|
2384
|
+
if (appStates.UNMOUNT !== this.state) {
|
|
2308
2385
|
const global = ((_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) !== null && _b !== void 0 ? _b : globalEnv.rawWindow);
|
|
2309
2386
|
this.libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
2310
2387
|
// do not use isObject
|
|
@@ -2317,7 +2394,7 @@ class CreateApp {
|
|
|
2317
2394
|
function getActiveApps() {
|
|
2318
2395
|
const activeApps = [];
|
|
2319
2396
|
appInstanceMap.forEach((app, appName) => {
|
|
2320
|
-
if (
|
|
2397
|
+
if (appStates.UNMOUNT !== app.getAppState() && !app.isPrefetch) {
|
|
2321
2398
|
activeApps.push(appName);
|
|
2322
2399
|
}
|
|
2323
2400
|
});
|
|
@@ -2327,6 +2404,78 @@ function getActiveApps() {
|
|
|
2327
2404
|
function getAllApps() {
|
|
2328
2405
|
return Array.from(appInstanceMap.keys());
|
|
2329
2406
|
}
|
|
2407
|
+
/**
|
|
2408
|
+
* unmount app by appname
|
|
2409
|
+
* @param appName
|
|
2410
|
+
* @param options unmountAppParams
|
|
2411
|
+
* @returns Promise<void>
|
|
2412
|
+
*/
|
|
2413
|
+
function unmountApp(appName, options) {
|
|
2414
|
+
const app = appInstanceMap.get(formatAppName(appName));
|
|
2415
|
+
return new Promise((reslove) => {
|
|
2416
|
+
if (app) {
|
|
2417
|
+
if (app.getAppState() === appStates.UNMOUNT || app.isPrefetch) {
|
|
2418
|
+
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
2419
|
+
app.actionsForCompletelyDestory();
|
|
2420
|
+
}
|
|
2421
|
+
reslove();
|
|
2422
|
+
}
|
|
2423
|
+
else if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
2424
|
+
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
2425
|
+
app.unmount(true, reslove);
|
|
2426
|
+
}
|
|
2427
|
+
else if (options === null || options === void 0 ? void 0 : options.clearAliveState) {
|
|
2428
|
+
app.unmount(false, reslove);
|
|
2429
|
+
}
|
|
2430
|
+
else {
|
|
2431
|
+
reslove();
|
|
2432
|
+
}
|
|
2433
|
+
}
|
|
2434
|
+
else {
|
|
2435
|
+
const container = getRootContainer(app.container);
|
|
2436
|
+
const unmountHandler = () => {
|
|
2437
|
+
container.removeEventListener('unmount', unmountHandler);
|
|
2438
|
+
container.removeEventListener('afterhidden', afterhiddenHandler);
|
|
2439
|
+
reslove();
|
|
2440
|
+
};
|
|
2441
|
+
const afterhiddenHandler = () => {
|
|
2442
|
+
container.removeEventListener('unmount', unmountHandler);
|
|
2443
|
+
container.removeEventListener('afterhidden', afterhiddenHandler);
|
|
2444
|
+
reslove();
|
|
2445
|
+
};
|
|
2446
|
+
container.addEventListener('unmount', unmountHandler);
|
|
2447
|
+
container.addEventListener('afterhidden', afterhiddenHandler);
|
|
2448
|
+
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
2449
|
+
let destroyAttrValue, destoryAttrValue;
|
|
2450
|
+
container.hasAttribute('destroy') && (destroyAttrValue = container.getAttribute('destroy'));
|
|
2451
|
+
container.hasAttribute('destory') && (destoryAttrValue = container.getAttribute('destory'));
|
|
2452
|
+
container.setAttribute('destroy', 'true');
|
|
2453
|
+
container.parentNode.removeChild(container);
|
|
2454
|
+
container.removeAttribute('destroy');
|
|
2455
|
+
typeof destroyAttrValue === 'string' && container.setAttribute('destroy', destroyAttrValue);
|
|
2456
|
+
typeof destoryAttrValue === 'string' && container.setAttribute('destory', destoryAttrValue);
|
|
2457
|
+
}
|
|
2458
|
+
else if ((options === null || options === void 0 ? void 0 : options.clearAliveState) && container.hasAttribute('keep-alive')) {
|
|
2459
|
+
const keepAliveAttrValue = container.getAttribute('keep-alive');
|
|
2460
|
+
container.removeAttribute('keep-alive');
|
|
2461
|
+
container.parentNode.removeChild(container);
|
|
2462
|
+
container.setAttribute('keep-alive', keepAliveAttrValue);
|
|
2463
|
+
}
|
|
2464
|
+
else {
|
|
2465
|
+
container.parentNode.removeChild(container);
|
|
2466
|
+
}
|
|
2467
|
+
}
|
|
2468
|
+
}
|
|
2469
|
+
else {
|
|
2470
|
+
logWarn(`app ${appName} does not exist`);
|
|
2471
|
+
reslove();
|
|
2472
|
+
}
|
|
2473
|
+
});
|
|
2474
|
+
}
|
|
2475
|
+
// unmount all apps in turn
|
|
2476
|
+
function unmountAllApps(options) {
|
|
2477
|
+
return Array.from(appInstanceMap.keys()).reduce((pre, next) => pre.then(() => unmountApp(next, options)), Promise.resolve());
|
|
2478
|
+
}
|
|
2330
2479
|
|
|
2331
2480
|
// Record element and map element
|
|
2332
2481
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
@@ -2521,13 +2670,13 @@ function patchElementPrototypeMethods() {
|
|
|
2521
2670
|
}
|
|
2522
2671
|
};
|
|
2523
2672
|
// prototype methods of add element👇
|
|
2524
|
-
|
|
2673
|
+
Element.prototype.appendChild = function appendChild(newChild) {
|
|
2525
2674
|
return commonElementHander(this, newChild, null, globalEnv.rawAppendChild);
|
|
2526
2675
|
};
|
|
2527
|
-
|
|
2676
|
+
Element.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
2528
2677
|
return commonElementHander(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
2529
2678
|
};
|
|
2530
|
-
|
|
2679
|
+
Element.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
2531
2680
|
return commonElementHander(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
2532
2681
|
};
|
|
2533
2682
|
Element.prototype.append = function append(...nodes) {
|
|
@@ -2546,7 +2695,7 @@ function patchElementPrototypeMethods() {
|
|
|
2546
2695
|
}
|
|
2547
2696
|
};
|
|
2548
2697
|
// prototype methods of delete element👇
|
|
2549
|
-
|
|
2698
|
+
Element.prototype.removeChild = function removeChild(oldChild) {
|
|
2550
2699
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
2551
2700
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
2552
2701
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -2556,6 +2705,12 @@ function patchElementPrototypeMethods() {
|
|
|
2556
2705
|
}
|
|
2557
2706
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
2558
2707
|
};
|
|
2708
|
+
// patch cloneNode
|
|
2709
|
+
Element.prototype.cloneNode = function cloneNode(deep) {
|
|
2710
|
+
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
2711
|
+
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
2712
|
+
return clonedNode;
|
|
2713
|
+
};
|
|
2559
2714
|
}
|
|
2560
2715
|
/**
|
|
2561
2716
|
* Mark the newly created element in the micro application
|
|
@@ -2674,12 +2829,13 @@ function releasePatches() {
|
|
|
2674
2829
|
setCurrentAppName(null);
|
|
2675
2830
|
releasePatchDocument();
|
|
2676
2831
|
Element.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
|
|
2832
|
+
Element.prototype.appendChild = globalEnv.rawAppendChild;
|
|
2833
|
+
Element.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
2834
|
+
Element.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
2835
|
+
Element.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
2681
2836
|
Element.prototype.append = globalEnv.rawAppend;
|
|
2682
2837
|
Element.prototype.prepend = globalEnv.rawPrepend;
|
|
2838
|
+
Element.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
2683
2839
|
}
|
|
2684
2840
|
// Set the style of micro-app-head and micro-app-body
|
|
2685
2841
|
let hasRejectMicroAppStyle = false;
|
|
@@ -2694,7 +2850,7 @@ function rejectMicroAppStyle() {
|
|
|
2694
2850
|
}
|
|
2695
2851
|
|
|
2696
2852
|
function unmountNestedApp() {
|
|
2697
|
-
|
|
2853
|
+
releaseUnmountOfNestedApp();
|
|
2698
2854
|
appInstanceMap.forEach(app => {
|
|
2699
2855
|
// @ts-ignore
|
|
2700
2856
|
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
@@ -2712,7 +2868,7 @@ function listenUmountOfNestedApp() {
|
|
|
2712
2868
|
}
|
|
2713
2869
|
}
|
|
2714
2870
|
// release listener
|
|
2715
|
-
function
|
|
2871
|
+
function releaseUnmountOfNestedApp() {
|
|
2716
2872
|
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
2717
2873
|
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
2718
2874
|
}
|
|
@@ -2739,7 +2895,6 @@ function defineElement(tagName) {
|
|
|
2739
2895
|
* handle for change of name an url after element inited
|
|
2740
2896
|
*/
|
|
2741
2897
|
this.handleAttributeUpdate = () => {
|
|
2742
|
-
var _a;
|
|
2743
2898
|
this.isWating = false;
|
|
2744
2899
|
const formatAttrName = formatAppName(this.getAttribute('name'));
|
|
2745
2900
|
const formatAttrUrl = formatAppURL(this.getAttribute('url'), this.appName);
|
|
@@ -2747,44 +2902,27 @@ function defineElement(tagName) {
|
|
|
2747
2902
|
const existApp = appInstanceMap.get(formatAttrName);
|
|
2748
2903
|
if (formatAttrName !== this.appName && existApp) {
|
|
2749
2904
|
// handling of cached and non-prefetch apps
|
|
2750
|
-
if (
|
|
2905
|
+
if (appStates.UNMOUNT !== existApp.getAppState() &&
|
|
2906
|
+
keepAliveStates.KEEP_ALIVE_HIDDEN !== existApp.getKeepAliveState() &&
|
|
2907
|
+
!existApp.isPrefetch) {
|
|
2751
2908
|
this.setAttribute('name', this.appName);
|
|
2752
|
-
return logError(`an app named ${formatAttrName}
|
|
2909
|
+
return logError(`app name conflict, an app named ${formatAttrName} is running`, this.appName);
|
|
2753
2910
|
}
|
|
2754
2911
|
}
|
|
2755
2912
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
*/
|
|
2761
|
-
if (this.getDisposeResult('ssr')) {
|
|
2762
|
-
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
2763
|
-
}
|
|
2764
|
-
else if (this.ssrUrl) {
|
|
2765
|
-
this.ssrUrl = '';
|
|
2766
|
-
}
|
|
2767
|
-
this.appName = formatAttrName;
|
|
2768
|
-
this.appUrl = formatAttrUrl;
|
|
2769
|
-
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
2770
|
-
if (formatAttrName !== this.getAttribute('name')) {
|
|
2771
|
-
this.setAttribute('name', this.appName);
|
|
2913
|
+
if (formatAttrName === this.appName) {
|
|
2914
|
+
this.handleUnmount(true, () => {
|
|
2915
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2916
|
+
});
|
|
2772
2917
|
}
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2776
|
-
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
2777
|
-
* scene3: url is different but ssrUrl is equal
|
|
2778
|
-
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
2779
|
-
*/
|
|
2780
|
-
if (existApp &&
|
|
2781
|
-
existApp.url === this.appUrl &&
|
|
2782
|
-
existApp.ssrUrl === this.ssrUrl) {
|
|
2783
|
-
// mount app
|
|
2784
|
-
this.handleAppMount(existApp);
|
|
2918
|
+
else if (this.getKeepAliveModeResult()) {
|
|
2919
|
+
this.handleHiddenKeepAliveApp();
|
|
2920
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2785
2921
|
}
|
|
2786
2922
|
else {
|
|
2787
|
-
this.
|
|
2923
|
+
this.handleUnmount(this.getDestroyCompatibleResult(), () => {
|
|
2924
|
+
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp);
|
|
2925
|
+
});
|
|
2788
2926
|
}
|
|
2789
2927
|
}
|
|
2790
2928
|
}
|
|
@@ -2810,6 +2948,7 @@ function defineElement(tagName) {
|
|
|
2810
2948
|
// disableSandbox: whether disable sandbox, default is false
|
|
2811
2949
|
// macro: used to solve the async render problem of vue3, default is false
|
|
2812
2950
|
// baseRoute: route prefix, default is ''
|
|
2951
|
+
// keep-alive: open keep-alive mode
|
|
2813
2952
|
connectedCallback() {
|
|
2814
2953
|
this.hasConnected = true;
|
|
2815
2954
|
if (!elementInstanceMap.has(this)) {
|
|
@@ -2820,10 +2959,17 @@ function defineElement(tagName) {
|
|
|
2820
2959
|
}
|
|
2821
2960
|
disconnectedCallback() {
|
|
2822
2961
|
this.hasConnected = false;
|
|
2823
|
-
|
|
2824
|
-
|
|
2825
|
-
|
|
2826
|
-
|
|
2962
|
+
// keep-alive
|
|
2963
|
+
if (this.getKeepAliveModeResult()) {
|
|
2964
|
+
this.handleHiddenKeepAliveApp();
|
|
2965
|
+
}
|
|
2966
|
+
else {
|
|
2967
|
+
elementInstanceMap.delete(this);
|
|
2968
|
+
this.handleUnmount(this.getDestroyCompatibleResult(), () => {
|
|
2969
|
+
if (elementInstanceMap.size === 0) {
|
|
2970
|
+
releasePatches();
|
|
2971
|
+
}
|
|
2972
|
+
});
|
|
2827
2973
|
}
|
|
2828
2974
|
}
|
|
2829
2975
|
attributeChangedCallback(attr, _oldVal, newVal) {
|
|
@@ -2867,7 +3013,7 @@ function defineElement(tagName) {
|
|
|
2867
3013
|
if (elementInstanceMap.set(this, true).size === 1) {
|
|
2868
3014
|
patchElementPrototypeMethods();
|
|
2869
3015
|
rejectMicroAppStyle();
|
|
2870
|
-
|
|
3016
|
+
releaseUnmountOfNestedApp();
|
|
2871
3017
|
listenUmountOfNestedApp();
|
|
2872
3018
|
}
|
|
2873
3019
|
}
|
|
@@ -2886,15 +3032,21 @@ function defineElement(tagName) {
|
|
|
2886
3032
|
else if (this.ssrUrl) {
|
|
2887
3033
|
this.ssrUrl = '';
|
|
2888
3034
|
}
|
|
2889
|
-
|
|
2890
|
-
|
|
3035
|
+
if (appInstanceMap.has(this.appName)) {
|
|
3036
|
+
const app = appInstanceMap.get(this.appName);
|
|
2891
3037
|
const existAppUrl = app.ssrUrl || app.url;
|
|
2892
3038
|
const activeAppUrl = this.ssrUrl || this.appUrl;
|
|
2893
|
-
|
|
2894
|
-
|
|
3039
|
+
// keep-alive don't care about ssrUrl
|
|
3040
|
+
// Even if the keep-alive app is pushed into the background, it is still active and cannot be replaced. Otherwise, it is difficult for developers to troubleshoot in case of conflict and will leave developers at a loss
|
|
3041
|
+
if (app.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
3042
|
+
app.url === this.appUrl) {
|
|
3043
|
+
this.handleShowKeepAliveApp(app);
|
|
3044
|
+
}
|
|
3045
|
+
else if (existAppUrl === activeAppUrl && (app.isPrefetch ||
|
|
3046
|
+
app.getAppState() === appStates.UNMOUNT)) {
|
|
2895
3047
|
this.handleAppMount(app);
|
|
2896
3048
|
}
|
|
2897
|
-
else if (app.isPrefetch || app.
|
|
3049
|
+
else if (app.isPrefetch || app.getAppState() === appStates.UNMOUNT) {
|
|
2898
3050
|
/**
|
|
2899
3051
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
2900
3052
|
*/
|
|
@@ -2902,7 +3054,56 @@ function defineElement(tagName) {
|
|
|
2902
3054
|
this.handleCreateApp();
|
|
2903
3055
|
}
|
|
2904
3056
|
else {
|
|
2905
|
-
logError(`an app named ${this.appName}
|
|
3057
|
+
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
3058
|
+
}
|
|
3059
|
+
}
|
|
3060
|
+
else {
|
|
3061
|
+
this.handleCreateApp();
|
|
3062
|
+
}
|
|
3063
|
+
}
|
|
3064
|
+
// remount app or create app if attribute url or name change
|
|
3065
|
+
actionsForAttributeChange(formatAttrName, formatAttrUrl, existApp) {
|
|
3066
|
+
var _a;
|
|
3067
|
+
/**
|
|
3068
|
+
* change ssrUrl in ssr mode
|
|
3069
|
+
* do not add judgment of formatAttrUrl === this.appUrl
|
|
3070
|
+
*/
|
|
3071
|
+
if (this.getDisposeResult('ssr')) {
|
|
3072
|
+
this.ssrUrl = CompletionPath(globalEnv.rawWindow.location.pathname, formatAttrUrl);
|
|
3073
|
+
}
|
|
3074
|
+
else if (this.ssrUrl) {
|
|
3075
|
+
this.ssrUrl = '';
|
|
3076
|
+
}
|
|
3077
|
+
this.appName = formatAttrName;
|
|
3078
|
+
this.appUrl = formatAttrUrl;
|
|
3079
|
+
((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this).innerHTML = '';
|
|
3080
|
+
if (formatAttrName !== this.getAttribute('name')) {
|
|
3081
|
+
this.setAttribute('name', this.appName);
|
|
3082
|
+
}
|
|
3083
|
+
/**
|
|
3084
|
+
* when existApp not null: this.appName === existApp.name
|
|
3085
|
+
* scene1: if formatAttrName and this.appName are equal: exitApp is the current app, the url must be different, existApp has been unmounted
|
|
3086
|
+
* scene2: if formatAttrName and this.appName are different: existApp must be prefetch or unmounted, if url is equal, then just mount, if url is different, then create new app to replace existApp
|
|
3087
|
+
* scene3: url is different but ssrUrl is equal
|
|
3088
|
+
* scene4: url is equal but ssrUrl is different, if url is equal, name must different
|
|
3089
|
+
* scene5: if existApp is KEEP_ALIVE_HIDDEN, name must different
|
|
3090
|
+
*/
|
|
3091
|
+
if (existApp) {
|
|
3092
|
+
if (existApp.getKeepAliveState() === keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
3093
|
+
if (existApp.url === this.appUrl) {
|
|
3094
|
+
this.handleShowKeepAliveApp(existApp);
|
|
3095
|
+
}
|
|
3096
|
+
else {
|
|
3097
|
+
// the hidden keep-alive app is still active
|
|
3098
|
+
logError(`app name conflict, an app named ${this.appName} is running`, this.appName);
|
|
3099
|
+
}
|
|
3100
|
+
}
|
|
3101
|
+
else if (existApp.url === this.appUrl && existApp.ssrUrl === this.ssrUrl) {
|
|
3102
|
+
// mount app
|
|
3103
|
+
this.handleAppMount(existApp);
|
|
3104
|
+
}
|
|
3105
|
+
else {
|
|
3106
|
+
this.handleCreateApp();
|
|
2906
3107
|
}
|
|
2907
3108
|
}
|
|
2908
3109
|
else {
|
|
@@ -2962,10 +3163,24 @@ function defineElement(tagName) {
|
|
|
2962
3163
|
* unmount app
|
|
2963
3164
|
* @param destroy delete cache resources when unmount
|
|
2964
3165
|
*/
|
|
2965
|
-
handleUnmount(destroy) {
|
|
3166
|
+
handleUnmount(destroy, unmountcb) {
|
|
3167
|
+
const app = appInstanceMap.get(this.appName);
|
|
3168
|
+
if (app &&
|
|
3169
|
+
app.getAppState() !== appStates.UNMOUNT)
|
|
3170
|
+
app.unmount(destroy, unmountcb);
|
|
3171
|
+
}
|
|
3172
|
+
// hidden app when disconnectedCallback called with keep-alive
|
|
3173
|
+
handleHiddenKeepAliveApp() {
|
|
2966
3174
|
const app = appInstanceMap.get(this.appName);
|
|
2967
|
-
if (app &&
|
|
2968
|
-
app.
|
|
3175
|
+
if (app &&
|
|
3176
|
+
app.getAppState() !== appStates.UNMOUNT &&
|
|
3177
|
+
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN)
|
|
3178
|
+
app.hiddenKeepAliveApp();
|
|
3179
|
+
}
|
|
3180
|
+
// show app when connectedCallback called with keep-alive
|
|
3181
|
+
handleShowKeepAliveApp(app) {
|
|
3182
|
+
// must be asnyc
|
|
3183
|
+
defer(() => { var _a; return app.showKeepAliveApp((_a = this.shadowRoot) !== null && _a !== void 0 ? _a : this); });
|
|
2969
3184
|
}
|
|
2970
3185
|
/**
|
|
2971
3186
|
* Get configuration
|
|
@@ -2974,7 +3189,27 @@ function defineElement(tagName) {
|
|
|
2974
3189
|
*/
|
|
2975
3190
|
getDisposeResult(name) {
|
|
2976
3191
|
// @ts-ignore
|
|
2977
|
-
return (this.
|
|
3192
|
+
return (this.compatibleSpecialProperties(name) || microApp[name]) && this.compatibleDisablSpecialProperties(name);
|
|
3193
|
+
}
|
|
3194
|
+
// compatible of disableScopecss & disableSandbox
|
|
3195
|
+
compatibleSpecialProperties(name) {
|
|
3196
|
+
if (name === 'disableScopecss') {
|
|
3197
|
+
return this.hasAttribute('disableScopecss') || this.hasAttribute('disable-scopecss');
|
|
3198
|
+
}
|
|
3199
|
+
else if (name === 'disableSandbox') {
|
|
3200
|
+
return this.hasAttribute('disableSandbox') || this.hasAttribute('disable-sandbox');
|
|
3201
|
+
}
|
|
3202
|
+
return this.hasAttribute(name);
|
|
3203
|
+
}
|
|
3204
|
+
// compatible of disableScopecss & disableSandbox
|
|
3205
|
+
compatibleDisablSpecialProperties(name) {
|
|
3206
|
+
if (name === 'disableScopecss') {
|
|
3207
|
+
return this.getAttribute('disableScopecss') !== 'false' && this.getAttribute('disable-scopecss') !== 'false';
|
|
3208
|
+
}
|
|
3209
|
+
else if (name === 'disableSandbox') {
|
|
3210
|
+
return this.getAttribute('disableSandbox') !== 'false' && this.getAttribute('disable-sandbox') !== 'false';
|
|
3211
|
+
}
|
|
3212
|
+
return this.getAttribute(name) !== 'false';
|
|
2978
3213
|
}
|
|
2979
3214
|
/**
|
|
2980
3215
|
* 2021-09-08
|
|
@@ -2985,6 +3220,16 @@ function defineElement(tagName) {
|
|
|
2985
3220
|
var _a, _b;
|
|
2986
3221
|
return (_b = (_a = this.getAttribute('baseroute')) !== null && _a !== void 0 ? _a : this.getAttribute('baseurl')) !== null && _b !== void 0 ? _b : '';
|
|
2987
3222
|
}
|
|
3223
|
+
// compatible of destroy
|
|
3224
|
+
getDestroyCompatibleResult() {
|
|
3225
|
+
return this.getDisposeResult('destroy') || this.getDisposeResult('destory');
|
|
3226
|
+
}
|
|
3227
|
+
/**
|
|
3228
|
+
* destroy has priority over destroy keep-alive
|
|
3229
|
+
*/
|
|
3230
|
+
getKeepAliveModeResult() {
|
|
3231
|
+
return this.getDisposeResult('keep-alive') && !this.getDestroyCompatibleResult();
|
|
3232
|
+
}
|
|
2988
3233
|
/**
|
|
2989
3234
|
* Data from the base application
|
|
2990
3235
|
*/
|
|
@@ -3141,6 +3386,7 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3141
3386
|
this.disableScopecss = options.disableScopecss;
|
|
3142
3387
|
this.disableSandbox = options.disableSandbox;
|
|
3143
3388
|
this.macro = options.macro;
|
|
3389
|
+
this.ssr = options.ssr;
|
|
3144
3390
|
isFunction(options.fetch) && (this.fetch = options.fetch);
|
|
3145
3391
|
isPlainObject(options.lifeCycles) && (this.lifeCycles = options.lifeCycles);
|
|
3146
3392
|
// load app assets when browser is idle
|
|
@@ -3168,5 +3414,5 @@ class MicroApp extends EventCenterForBaseApp {
|
|
|
3168
3414
|
var microApp = new MicroApp();
|
|
3169
3415
|
|
|
3170
3416
|
export default microApp;
|
|
3171
|
-
export { EventCenterForMicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, version };
|
|
3417
|
+
export { EventCenterForMicroApp, getActiveApps, getAllApps, preFetch, pureCreateElement, removeDomScope, unmountAllApps, unmountApp, version };
|
|
3172
3418
|
//# sourceMappingURL=index.esm.js.map
|