@micro-zoe/micro-app 1.0.0-beta.1 → 1.0.0-beta.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +1 -1
- package/lib/index.esm.js +1647 -1523
- package/lib/index.esm.js.map +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.min.js.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +1 -1
- package/typings/global.d.ts +10 -16
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '1.0.0-beta.
|
|
1
|
+
const version = '1.0.0-beta.3';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -356,7 +356,7 @@ function pureCreateElement(tagName, options) {
|
|
|
356
356
|
* @param target Accept cloned elements
|
|
357
357
|
* @param deep deep clone or transfer dom
|
|
358
358
|
*/
|
|
359
|
-
function cloneContainer(
|
|
359
|
+
function cloneContainer(target, origin, deep) {
|
|
360
360
|
target.innerHTML = '';
|
|
361
361
|
if (deep) {
|
|
362
362
|
// TODO: ShadowRoot兼容,ShadowRoot不能直接使用cloneNode
|
|
@@ -562,7 +562,6 @@ var appStates;
|
|
|
562
562
|
(function (appStates) {
|
|
563
563
|
appStates["CREATED"] = "created";
|
|
564
564
|
appStates["LOADING"] = "loading";
|
|
565
|
-
appStates["LOADED"] = "loaded";
|
|
566
565
|
appStates["LOAD_FAILED"] = "load_failed";
|
|
567
566
|
appStates["MOUNTING"] = "mounting";
|
|
568
567
|
appStates["MOUNTED"] = "mounted";
|
|
@@ -1171,234 +1170,591 @@ function createSourceCenter() {
|
|
|
1171
1170
|
}
|
|
1172
1171
|
var sourceCenter = createSourceCenter();
|
|
1173
1172
|
|
|
1173
|
+
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1174
|
+
// whether use type='module' script
|
|
1175
|
+
function isTypeModule(app, scriptInfo) {
|
|
1176
|
+
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
|
|
1177
|
+
}
|
|
1178
|
+
// special script element
|
|
1179
|
+
function isSpecialScript(app, scriptInfo) {
|
|
1180
|
+
const attrs = scriptInfo.appSpace[app.name].attrs;
|
|
1181
|
+
return attrs.has('id');
|
|
1182
|
+
}
|
|
1174
1183
|
/**
|
|
1175
|
-
*
|
|
1184
|
+
* whether to run js in inline mode
|
|
1185
|
+
* scene:
|
|
1186
|
+
* 1. inline config for app
|
|
1187
|
+
* 2. inline attr in script element
|
|
1188
|
+
* 3. module script
|
|
1189
|
+
* 4. script with special attr
|
|
1190
|
+
*/
|
|
1191
|
+
function isInlineMode(app, scriptInfo) {
|
|
1192
|
+
return (app.inline ||
|
|
1193
|
+
scriptInfo.appSpace[app.name].inline ||
|
|
1194
|
+
isTypeModule(app, scriptInfo) ||
|
|
1195
|
+
isSpecialScript(app, scriptInfo) ||
|
|
1196
|
+
app.iframe);
|
|
1197
|
+
}
|
|
1198
|
+
// TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
|
|
1199
|
+
function getEffectWindow(app) {
|
|
1200
|
+
return app.iframe ? app.sandBox.microAppWindow : globalEnv.rawWindow;
|
|
1201
|
+
}
|
|
1202
|
+
// Convert string code to function
|
|
1203
|
+
function code2Function(app, code) {
|
|
1204
|
+
const targetWindow = getEffectWindow(app);
|
|
1205
|
+
return new targetWindow.Function(code);
|
|
1206
|
+
}
|
|
1207
|
+
/**
|
|
1208
|
+
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
1176
1209
|
* @param appName app.name
|
|
1177
|
-
* @param
|
|
1210
|
+
* @param scriptInfo scriptInfo of current address
|
|
1211
|
+
* @param currentCode pure code of current address
|
|
1178
1212
|
*/
|
|
1179
|
-
function
|
|
1180
|
-
const appSpace =
|
|
1213
|
+
function getExistParseResult(app, scriptInfo, currentCode) {
|
|
1214
|
+
const appSpace = scriptInfo.appSpace;
|
|
1181
1215
|
for (const item in appSpace) {
|
|
1182
|
-
if (item !==
|
|
1216
|
+
if (item !== app.name) {
|
|
1183
1217
|
const appSpaceData = appSpace[item];
|
|
1184
|
-
if (appSpaceData.parsedCode) {
|
|
1185
|
-
return appSpaceData.
|
|
1218
|
+
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
1219
|
+
return appSpaceData.parsedFunction;
|
|
1186
1220
|
}
|
|
1187
1221
|
}
|
|
1188
1222
|
}
|
|
1189
1223
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1224
|
+
/**
|
|
1225
|
+
* get parsedFunction from exist data or parsedCode
|
|
1226
|
+
* @returns parsedFunction
|
|
1227
|
+
*/
|
|
1228
|
+
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
1229
|
+
return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
|
|
1230
|
+
}
|
|
1231
|
+
// Prevent randomly created strings from repeating
|
|
1232
|
+
function getUniqueNonceSrc() {
|
|
1233
|
+
const nonceStr = createNonceSrc();
|
|
1234
|
+
if (sourceCenter.script.hasInfo(nonceStr)) {
|
|
1235
|
+
return getUniqueNonceSrc();
|
|
1236
|
+
}
|
|
1237
|
+
return nonceStr;
|
|
1238
|
+
}
|
|
1239
|
+
// transfer the attributes on the script to convertScript
|
|
1240
|
+
function setConvertScriptAttr(convertScript, attrs) {
|
|
1192
1241
|
attrs.forEach((value, key) => {
|
|
1193
|
-
if (key === '
|
|
1242
|
+
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
1194
1243
|
return;
|
|
1195
|
-
if (key === '
|
|
1196
|
-
key = 'data-origin-
|
|
1197
|
-
|
|
1244
|
+
if (key === 'src')
|
|
1245
|
+
key = 'data-origin-src';
|
|
1246
|
+
globalEnv.rawSetAttribute.call(convertScript, key, value);
|
|
1198
1247
|
});
|
|
1199
1248
|
}
|
|
1249
|
+
// wrap code in sandbox
|
|
1250
|
+
function isWrapInSandBox(app, scriptInfo) {
|
|
1251
|
+
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
1252
|
+
}
|
|
1253
|
+
function getSandboxType(app, scriptInfo) {
|
|
1254
|
+
return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
|
|
1255
|
+
}
|
|
1200
1256
|
/**
|
|
1201
|
-
* Extract
|
|
1202
|
-
* @param
|
|
1203
|
-
* @param parent parent element of
|
|
1257
|
+
* Extract script elements
|
|
1258
|
+
* @param script script element
|
|
1259
|
+
* @param parent parent element of script
|
|
1204
1260
|
* @param app app
|
|
1205
|
-
* @param microAppHead micro-app-head element
|
|
1206
1261
|
* @param isDynamic dynamic insert
|
|
1207
1262
|
*/
|
|
1208
|
-
function
|
|
1209
|
-
|
|
1210
|
-
let href = link.getAttribute('href');
|
|
1263
|
+
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
1264
|
+
var _a;
|
|
1211
1265
|
let replaceComment = null;
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1266
|
+
let src = script.getAttribute('src');
|
|
1267
|
+
if (src)
|
|
1268
|
+
src = CompletionPath(src, app.url);
|
|
1269
|
+
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
1270
|
+
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
1271
|
+
}
|
|
1272
|
+
else if ((script.type &&
|
|
1273
|
+
!scriptTypes.includes(script.type)) ||
|
|
1274
|
+
script.hasAttribute('ignore') ||
|
|
1275
|
+
checkIgnoreUrl(src, app.name)) {
|
|
1276
|
+
// 配置为忽略的脚本,清空 rawDocument.currentScript,避免被忽略的脚本内获取 currentScript 出错
|
|
1277
|
+
if ((_a = globalEnv.rawDocument) === null || _a === void 0 ? void 0 : _a.currentScript) {
|
|
1278
|
+
delete globalEnv.rawDocument.currentScript;
|
|
1279
|
+
}
|
|
1280
|
+
return null;
|
|
1281
|
+
}
|
|
1282
|
+
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
1283
|
+
(!globalEnv.supportModuleScript && script.type === 'module')) {
|
|
1284
|
+
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
1285
|
+
}
|
|
1286
|
+
else if (src) { // remote script
|
|
1287
|
+
let scriptInfo = sourceCenter.script.getInfo(src);
|
|
1215
1288
|
const appSpaceData = {
|
|
1216
|
-
|
|
1289
|
+
async: script.hasAttribute('async'),
|
|
1290
|
+
defer: script.defer || script.type === 'module',
|
|
1291
|
+
module: script.type === 'module',
|
|
1292
|
+
inline: script.hasAttribute('inline'),
|
|
1293
|
+
pure: script.hasAttribute('pure'),
|
|
1294
|
+
attrs: getAttributes(script),
|
|
1217
1295
|
};
|
|
1218
|
-
if (!
|
|
1219
|
-
|
|
1296
|
+
if (!scriptInfo) {
|
|
1297
|
+
scriptInfo = {
|
|
1220
1298
|
code: '',
|
|
1299
|
+
isExternal: true,
|
|
1221
1300
|
appSpace: {
|
|
1222
1301
|
[app.name]: appSpaceData,
|
|
1223
1302
|
}
|
|
1224
1303
|
};
|
|
1225
1304
|
}
|
|
1226
1305
|
else {
|
|
1227
|
-
|
|
1306
|
+
/**
|
|
1307
|
+
* Reuse when appSpace exists
|
|
1308
|
+
* NOTE:
|
|
1309
|
+
* 1. The same static script, appSpace must be the same (in fact, it may be different when url change)
|
|
1310
|
+
* 2. The same dynamic script, appSpace may be the same, but we still reuse appSpace, which should pay attention
|
|
1311
|
+
*/
|
|
1312
|
+
scriptInfo.appSpace[app.name] = scriptInfo.appSpace[app.name] || appSpaceData;
|
|
1228
1313
|
}
|
|
1229
|
-
sourceCenter.
|
|
1314
|
+
sourceCenter.script.setInfo(src, scriptInfo);
|
|
1230
1315
|
if (!isDynamic) {
|
|
1231
|
-
app.source.
|
|
1232
|
-
replaceComment = document.createComment(`
|
|
1233
|
-
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
1316
|
+
app.source.scripts.add(src);
|
|
1317
|
+
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
1234
1318
|
}
|
|
1235
1319
|
else {
|
|
1236
|
-
return { address:
|
|
1320
|
+
return { address: src, scriptInfo };
|
|
1237
1321
|
}
|
|
1238
1322
|
}
|
|
1239
|
-
else if (
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1323
|
+
else if (script.textContent) { // inline script
|
|
1324
|
+
/**
|
|
1325
|
+
* NOTE:
|
|
1326
|
+
* 1. Each inline script is unique
|
|
1327
|
+
* 2. Every dynamic created inline script will be re-executed
|
|
1328
|
+
* ACTION:
|
|
1329
|
+
* 1. Delete dynamic inline script info after exec
|
|
1330
|
+
* 2. Delete static inline script info when destroy
|
|
1331
|
+
*/
|
|
1332
|
+
const nonceStr = getUniqueNonceSrc();
|
|
1333
|
+
const scriptInfo = {
|
|
1334
|
+
code: script.textContent,
|
|
1335
|
+
isExternal: false,
|
|
1336
|
+
appSpace: {
|
|
1337
|
+
[app.name]: {
|
|
1338
|
+
async: false,
|
|
1339
|
+
defer: script.type === 'module',
|
|
1340
|
+
module: script.type === 'module',
|
|
1341
|
+
inline: script.hasAttribute('inline'),
|
|
1342
|
+
pure: script.hasAttribute('pure'),
|
|
1343
|
+
attrs: getAttributes(script),
|
|
1344
|
+
}
|
|
1345
|
+
}
|
|
1346
|
+
};
|
|
1347
|
+
if (!isDynamic) {
|
|
1348
|
+
app.source.scripts.add(nonceStr);
|
|
1349
|
+
sourceCenter.script.setInfo(nonceStr, scriptInfo);
|
|
1350
|
+
replaceComment = document.createComment('inline script extract by micro-app');
|
|
1243
1351
|
}
|
|
1244
1352
|
else {
|
|
1245
|
-
|
|
1353
|
+
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
1354
|
+
return { address: nonceStr, scriptInfo };
|
|
1246
1355
|
}
|
|
1247
1356
|
}
|
|
1248
|
-
else if (
|
|
1249
|
-
|
|
1250
|
-
|
|
1357
|
+
else if (!isDynamic) {
|
|
1358
|
+
/**
|
|
1359
|
+
* script with empty src or empty script.textContent remove in static html
|
|
1360
|
+
* & not removed if it created by dynamic
|
|
1361
|
+
*/
|
|
1362
|
+
replaceComment = document.createComment('script element removed by micro-app');
|
|
1251
1363
|
}
|
|
1252
1364
|
if (isDynamic) {
|
|
1253
1365
|
return { replaceComment };
|
|
1254
1366
|
}
|
|
1255
|
-
else
|
|
1256
|
-
return parent.replaceChild(replaceComment,
|
|
1367
|
+
else {
|
|
1368
|
+
return parent === null || parent === void 0 ? void 0 : parent.replaceChild(replaceComment, script);
|
|
1257
1369
|
}
|
|
1258
1370
|
}
|
|
1259
1371
|
/**
|
|
1260
|
-
*
|
|
1261
|
-
* @param
|
|
1262
|
-
* @param app app
|
|
1263
|
-
* @param microAppHead micro-app-head
|
|
1372
|
+
* get assets plugins
|
|
1373
|
+
* @param appName app name
|
|
1264
1374
|
*/
|
|
1265
|
-
function
|
|
1266
|
-
|
|
1267
|
-
const
|
|
1268
|
-
|
|
1269
|
-
|
|
1270
|
-
|
|
1271
|
-
|
|
1272
|
-
|
|
1273
|
-
|
|
1274
|
-
|
|
1275
|
-
|
|
1276
|
-
|
|
1277
|
-
|
|
1278
|
-
|
|
1279
|
-
|
|
1280
|
-
|
|
1281
|
-
|
|
1282
|
-
|
|
1283
|
-
|
|
1284
|
-
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1285
|
-
serialExecFiberTasks(fiberLinkTasks);
|
|
1286
|
-
});
|
|
1287
|
-
}
|
|
1288
|
-
else {
|
|
1289
|
-
app.onLoad(wrapElement);
|
|
1290
|
-
}
|
|
1375
|
+
function getAssetsPlugins(appName) {
|
|
1376
|
+
var _a, _b, _c;
|
|
1377
|
+
const globalPlugins = ((_a = microApp.options.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
1378
|
+
const modulePlugins = ((_c = (_b = microApp.options.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
1379
|
+
return [...globalPlugins, ...modulePlugins];
|
|
1380
|
+
}
|
|
1381
|
+
/**
|
|
1382
|
+
* whether the address needs to be excluded
|
|
1383
|
+
* @param address css or js link
|
|
1384
|
+
* @param plugins microApp plugins
|
|
1385
|
+
*/
|
|
1386
|
+
function checkExcludeUrl(address, appName) {
|
|
1387
|
+
if (!address)
|
|
1388
|
+
return false;
|
|
1389
|
+
const plugins = getAssetsPlugins(appName) || [];
|
|
1390
|
+
return plugins.some(plugin => {
|
|
1391
|
+
if (!plugin.excludeChecker)
|
|
1392
|
+
return false;
|
|
1393
|
+
return plugin.excludeChecker(address);
|
|
1291
1394
|
});
|
|
1292
1395
|
}
|
|
1293
1396
|
/**
|
|
1294
|
-
*
|
|
1295
|
-
*
|
|
1296
|
-
*
|
|
1297
|
-
* 2. Only handler html link element, not dynamic link or style
|
|
1298
|
-
* 3. The same prefix can reuse parsedCode
|
|
1299
|
-
* 4. Async exec with requestIdleCallback in prefetch or fiber
|
|
1300
|
-
* 5. appSpace[app.name].placeholder/attrs must exist
|
|
1301
|
-
* @param address resource address
|
|
1302
|
-
* @param code link source code
|
|
1303
|
-
* @param microAppHead micro-app-head
|
|
1304
|
-
* @param app app instance
|
|
1397
|
+
* whether the address needs to be ignore
|
|
1398
|
+
* @param address css or js link
|
|
1399
|
+
* @param plugins microApp plugins
|
|
1305
1400
|
*/
|
|
1306
|
-
function
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1401
|
+
function checkIgnoreUrl(address, appName) {
|
|
1402
|
+
if (!address)
|
|
1403
|
+
return false;
|
|
1404
|
+
const plugins = getAssetsPlugins(appName) || [];
|
|
1405
|
+
return plugins.some(plugin => {
|
|
1406
|
+
if (!plugin.ignoreChecker)
|
|
1407
|
+
return false;
|
|
1408
|
+
return plugin.ignoreChecker(address);
|
|
1409
|
+
});
|
|
1410
|
+
}
|
|
1411
|
+
/**
|
|
1412
|
+
* Get remote resources of script
|
|
1413
|
+
* @param wrapElement htmlDom
|
|
1414
|
+
* @param app app
|
|
1415
|
+
*/
|
|
1416
|
+
function fetchScriptsFromHtml(wrapElement, app) {
|
|
1417
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1418
|
+
const fetchScriptPromise = [];
|
|
1419
|
+
const fetchScriptPromiseInfo = [];
|
|
1420
|
+
for (const address of scriptList) {
|
|
1421
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
1422
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1423
|
+
if ((!appSpaceData.defer && !appSpaceData.async) || (app.isPrefetch && !app.isPrerender)) {
|
|
1424
|
+
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
1425
|
+
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
1426
|
+
}
|
|
1427
|
+
}
|
|
1428
|
+
const fiberScriptTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
1429
|
+
if (fetchScriptPromise.length) {
|
|
1430
|
+
promiseStream(fetchScriptPromise, (res) => {
|
|
1431
|
+
injectFiberTask(fiberScriptTasks, () => fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data, app));
|
|
1432
|
+
}, (err) => {
|
|
1433
|
+
logError(err, app.name);
|
|
1434
|
+
}, () => {
|
|
1435
|
+
if (fiberScriptTasks) {
|
|
1436
|
+
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1437
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1438
|
+
}
|
|
1439
|
+
else {
|
|
1440
|
+
app.onLoad(wrapElement);
|
|
1441
|
+
}
|
|
1442
|
+
});
|
|
1443
|
+
}
|
|
1444
|
+
else {
|
|
1445
|
+
app.onLoad(wrapElement);
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
/**
|
|
1449
|
+
* fetch js succeeded, record the code value
|
|
1450
|
+
* @param address script address
|
|
1451
|
+
* @param scriptInfo resource script info
|
|
1452
|
+
* @param data code
|
|
1453
|
+
*/
|
|
1454
|
+
function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
1455
|
+
// reset scriptInfo.code
|
|
1456
|
+
scriptInfo.code = code;
|
|
1315
1457
|
/**
|
|
1316
|
-
*
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1458
|
+
* Pre parse script for prefetch, improve rendering performance
|
|
1459
|
+
* NOTE:
|
|
1460
|
+
* 1. if global parseResult exist, skip this step
|
|
1461
|
+
* 2. if app is inline or script is esmodule, skip this step
|
|
1462
|
+
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
1321
1463
|
*/
|
|
1322
|
-
if (
|
|
1323
|
-
const
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1464
|
+
if (app.isPrefetch && app.prefetchLevel === 2) {
|
|
1465
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1466
|
+
/**
|
|
1467
|
+
* When prefetch app is replaced by a new app in the processing phase, since the scriptInfo is common, when the scriptInfo of the prefetch app is processed, it may have already been processed.
|
|
1468
|
+
* This causes parsedCode to already exist when preloading ends
|
|
1469
|
+
* e.g.
|
|
1470
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
1471
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
1472
|
+
*/
|
|
1473
|
+
if (!appSpaceData.parsedCode) {
|
|
1474
|
+
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
1475
|
+
appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
|
|
1476
|
+
if (!isInlineMode(app, scriptInfo)) {
|
|
1477
|
+
try {
|
|
1478
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
1479
|
+
}
|
|
1480
|
+
catch (err) {
|
|
1481
|
+
logError('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
1482
|
+
}
|
|
1483
|
+
}
|
|
1330
1484
|
}
|
|
1331
|
-
// clear placeholder
|
|
1332
|
-
appSpaceData.placeholder = null;
|
|
1333
1485
|
}
|
|
1334
1486
|
}
|
|
1335
1487
|
/**
|
|
1336
|
-
*
|
|
1337
|
-
*
|
|
1338
|
-
*
|
|
1339
|
-
* 2. record parsedCode
|
|
1340
|
-
* 3. set parsedCode to convertStyle if need
|
|
1341
|
-
* @param app app instance
|
|
1342
|
-
* @param address resource address
|
|
1343
|
-
* @param convertStyle converted style
|
|
1344
|
-
* @param linkInfo linkInfo in sourceCenter
|
|
1345
|
-
* @param attrs attrs of link
|
|
1488
|
+
* Execute js in the mount lifecycle
|
|
1489
|
+
* @param app app
|
|
1490
|
+
* @param initHook callback for umd mode
|
|
1346
1491
|
*/
|
|
1347
|
-
function
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1492
|
+
function execScripts(app, initHook) {
|
|
1493
|
+
const fiberScriptTasks = app.fiber ? [] : null;
|
|
1494
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1495
|
+
const deferScriptPromise = [];
|
|
1496
|
+
const deferScriptInfo = [];
|
|
1497
|
+
for (const address of scriptList) {
|
|
1498
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
1499
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1500
|
+
// Notice the second render
|
|
1501
|
+
if (appSpaceData.defer || appSpaceData.async) {
|
|
1502
|
+
// TODO: defer和module彻底分开,不要混在一起
|
|
1503
|
+
if (scriptInfo.isExternal && !scriptInfo.code && !isTypeModule(app, scriptInfo)) {
|
|
1504
|
+
deferScriptPromise.push(fetchSource(address, app.name));
|
|
1356
1505
|
}
|
|
1357
1506
|
else {
|
|
1358
|
-
|
|
1507
|
+
deferScriptPromise.push(scriptInfo.code);
|
|
1359
1508
|
}
|
|
1360
|
-
|
|
1509
|
+
deferScriptInfo.push([address, scriptInfo]);
|
|
1510
|
+
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
1361
1511
|
}
|
|
1362
1512
|
else {
|
|
1363
|
-
|
|
1513
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
1514
|
+
runScript(address, app, scriptInfo);
|
|
1515
|
+
initHook(false);
|
|
1516
|
+
});
|
|
1364
1517
|
}
|
|
1365
1518
|
}
|
|
1519
|
+
if (deferScriptPromise.length) {
|
|
1520
|
+
promiseStream(deferScriptPromise, (res) => {
|
|
1521
|
+
const scriptInfo = deferScriptInfo[res.index][1];
|
|
1522
|
+
scriptInfo.code = scriptInfo.code || res.data;
|
|
1523
|
+
}, (err) => {
|
|
1524
|
+
initHook.errorCount = initHook.errorCount ? ++initHook.errorCount : 1;
|
|
1525
|
+
logError(err, app.name);
|
|
1526
|
+
}, () => {
|
|
1527
|
+
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
1528
|
+
if (isString(scriptInfo.code)) {
|
|
1529
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
1530
|
+
runScript(address, app, scriptInfo, initHook);
|
|
1531
|
+
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
1532
|
+
});
|
|
1533
|
+
}
|
|
1534
|
+
});
|
|
1535
|
+
/**
|
|
1536
|
+
* Fiber wraps js in requestIdleCallback and executes it in sequence
|
|
1537
|
+
* NOTE:
|
|
1538
|
+
* 1. In order to ensure the execution order, wait for all js loaded and then execute
|
|
1539
|
+
* 2. If js create a dynamic script, it may be errors in the execution order, because the subsequent js is wrapped in requestIdleCallback, even putting dynamic script in requestIdleCallback doesn't solve it
|
|
1540
|
+
*
|
|
1541
|
+
* BUG: NOTE.2 - execution order problem
|
|
1542
|
+
*/
|
|
1543
|
+
if (fiberScriptTasks) {
|
|
1544
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(isUndefined(initHook.moduleCount) ||
|
|
1545
|
+
initHook.errorCount === deferScriptPromise.length)));
|
|
1546
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1547
|
+
}
|
|
1548
|
+
else {
|
|
1549
|
+
initHook(isUndefined(initHook.moduleCount) ||
|
|
1550
|
+
initHook.errorCount === deferScriptPromise.length);
|
|
1551
|
+
}
|
|
1552
|
+
});
|
|
1553
|
+
}
|
|
1366
1554
|
else {
|
|
1367
|
-
|
|
1555
|
+
if (fiberScriptTasks) {
|
|
1556
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
1557
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1558
|
+
}
|
|
1559
|
+
else {
|
|
1560
|
+
initHook(true);
|
|
1561
|
+
}
|
|
1368
1562
|
}
|
|
1369
|
-
setConvertStyleAttr(convertStyle, attrs);
|
|
1370
1563
|
}
|
|
1371
1564
|
/**
|
|
1372
|
-
*
|
|
1373
|
-
* @param address
|
|
1565
|
+
* run code
|
|
1566
|
+
* @param address script address
|
|
1374
1567
|
* @param app app
|
|
1375
|
-
* @param
|
|
1376
|
-
* @param
|
|
1568
|
+
* @param scriptInfo script info
|
|
1569
|
+
* @param callback callback of module script
|
|
1377
1570
|
*/
|
|
1378
|
-
function
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1571
|
+
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
1572
|
+
try {
|
|
1573
|
+
actionsBeforeRunScript(app);
|
|
1574
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1575
|
+
const sandboxType = getSandboxType(app, scriptInfo);
|
|
1576
|
+
/**
|
|
1577
|
+
* NOTE:
|
|
1578
|
+
* 1. plugins and wrapCode will only be executed once
|
|
1579
|
+
* 2. if parsedCode not exist, parsedFunction is not exist
|
|
1580
|
+
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
1581
|
+
*/
|
|
1582
|
+
if (!appSpaceData.parsedCode || appSpaceData.sandboxType !== sandboxType) {
|
|
1583
|
+
appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
|
|
1584
|
+
appSpaceData.sandboxType = sandboxType;
|
|
1585
|
+
appSpaceData.parsedFunction = null;
|
|
1586
|
+
}
|
|
1587
|
+
/**
|
|
1588
|
+
* TODO: 优化逻辑
|
|
1589
|
+
* 是否是内联模式应该由外部传入,这样自外而内更加统一,逻辑更加清晰
|
|
1590
|
+
*/
|
|
1591
|
+
if (isInlineMode(app, scriptInfo)) {
|
|
1592
|
+
const scriptElement = replaceElement || pureCreateElement('script');
|
|
1593
|
+
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
1594
|
+
/**
|
|
1595
|
+
* TODO: 优化逻辑
|
|
1596
|
+
* replaceElement不存在说明是初始化执行,需要主动插入script
|
|
1597
|
+
* 但这里的逻辑不清晰,应该明确声明是什么环境下才需要主动插入,而不是用replaceElement间接判断
|
|
1598
|
+
* replaceElement还有可能是注释类型(一定是在后台执行),这里的判断都是间接判断,不够直观
|
|
1599
|
+
*/
|
|
1600
|
+
if (!replaceElement) {
|
|
1601
|
+
// TEST IGNORE
|
|
1602
|
+
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
1603
|
+
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
1604
|
+
}
|
|
1605
|
+
}
|
|
1606
|
+
else {
|
|
1607
|
+
runParsedFunction(app, scriptInfo);
|
|
1608
|
+
}
|
|
1386
1609
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
linkInfo.code = data;
|
|
1390
|
-
handleDynamicLink();
|
|
1391
|
-
}).catch((err) => {
|
|
1392
|
-
logError(err, app.name);
|
|
1393
|
-
dispatchOnErrorEvent(originLink);
|
|
1394
|
-
});
|
|
1610
|
+
catch (e) {
|
|
1611
|
+
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
1395
1612
|
}
|
|
1396
|
-
return convertStyle;
|
|
1397
1613
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1614
|
+
/**
|
|
1615
|
+
* Get dynamically created remote script
|
|
1616
|
+
* @param address script address
|
|
1617
|
+
* @param app app instance
|
|
1618
|
+
* @param scriptInfo scriptInfo
|
|
1619
|
+
* @param originScript origin script element
|
|
1620
|
+
*/
|
|
1621
|
+
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
1622
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
1623
|
+
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
1624
|
+
const runDynamicScript = () => {
|
|
1625
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
1626
|
+
if (!descriptor || descriptor.configurable) {
|
|
1627
|
+
Object.defineProperty(globalEnv.rawDocument, 'currentScript', {
|
|
1628
|
+
value: originScript,
|
|
1629
|
+
configurable: true,
|
|
1630
|
+
});
|
|
1631
|
+
}
|
|
1632
|
+
runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
|
|
1633
|
+
!isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
|
|
1634
|
+
};
|
|
1635
|
+
if (scriptInfo.code || isTypeModule(app, scriptInfo)) {
|
|
1636
|
+
defer(runDynamicScript);
|
|
1637
|
+
}
|
|
1638
|
+
else {
|
|
1639
|
+
fetchSource(address, app.name).then((code) => {
|
|
1640
|
+
scriptInfo.code = code;
|
|
1641
|
+
runDynamicScript();
|
|
1642
|
+
}).catch((err) => {
|
|
1643
|
+
logError(err, app.name);
|
|
1644
|
+
dispatchOnErrorEvent(originScript);
|
|
1645
|
+
});
|
|
1646
|
+
}
|
|
1647
|
+
return replaceElement;
|
|
1648
|
+
}
|
|
1649
|
+
/**
|
|
1650
|
+
* Get dynamically created inline script
|
|
1651
|
+
* @param address script address
|
|
1652
|
+
* @param app app instance
|
|
1653
|
+
* @param scriptInfo scriptInfo
|
|
1654
|
+
*/
|
|
1655
|
+
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
1656
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
1657
|
+
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
1658
|
+
return replaceElement;
|
|
1659
|
+
}
|
|
1660
|
+
/**
|
|
1661
|
+
* common handle for inline script
|
|
1662
|
+
* @param address script address
|
|
1663
|
+
* @param code bound code
|
|
1664
|
+
* @param module type='module' of script
|
|
1665
|
+
* @param scriptElement target script element
|
|
1666
|
+
* @param attrs attributes of script element
|
|
1667
|
+
* @param callback callback of module script
|
|
1668
|
+
*/
|
|
1669
|
+
function runCode2InlineScript(address, code, module, scriptElement, attrs, callback) {
|
|
1670
|
+
if (module) {
|
|
1671
|
+
// module script is async, transform it to a blob for subsequent operations
|
|
1672
|
+
if (isInlineScript(address)) {
|
|
1673
|
+
const blob = new Blob([code], { type: 'text/javascript' });
|
|
1674
|
+
scriptElement.src = URL.createObjectURL(blob);
|
|
1675
|
+
}
|
|
1676
|
+
else {
|
|
1677
|
+
scriptElement.src = address;
|
|
1678
|
+
}
|
|
1679
|
+
globalEnv.rawSetAttribute.call(scriptElement, 'type', 'module');
|
|
1680
|
+
if (callback) {
|
|
1681
|
+
callback.moduleCount && callback.moduleCount--;
|
|
1682
|
+
/**
|
|
1683
|
+
* module script will execute onload method only after it insert to document/iframe
|
|
1684
|
+
*/
|
|
1685
|
+
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
1686
|
+
}
|
|
1687
|
+
}
|
|
1688
|
+
else {
|
|
1689
|
+
scriptElement.textContent = code;
|
|
1690
|
+
}
|
|
1691
|
+
setConvertScriptAttr(scriptElement, attrs);
|
|
1692
|
+
}
|
|
1693
|
+
// init & run code2Function
|
|
1694
|
+
function runParsedFunction(app, scriptInfo) {
|
|
1695
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1696
|
+
if (!appSpaceData.parsedFunction) {
|
|
1697
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
1698
|
+
}
|
|
1699
|
+
appSpaceData.parsedFunction.call(getEffectWindow(app));
|
|
1700
|
+
}
|
|
1701
|
+
/**
|
|
1702
|
+
* bind js scope
|
|
1703
|
+
* @param app app
|
|
1704
|
+
* @param code code
|
|
1705
|
+
* @param scriptInfo source script info
|
|
1706
|
+
*/
|
|
1707
|
+
function bindScope(address, app, code, scriptInfo) {
|
|
1708
|
+
// TODO: 1、cache 2、esm code is null
|
|
1709
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
1710
|
+
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
1711
|
+
}
|
|
1712
|
+
if (isWrapInSandBox(app, scriptInfo)) {
|
|
1713
|
+
return app.iframe ? `(function(window,self,global,location){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyLocation);` : `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
1714
|
+
}
|
|
1715
|
+
return code;
|
|
1716
|
+
}
|
|
1717
|
+
/**
|
|
1718
|
+
* actions before run script
|
|
1719
|
+
*/
|
|
1720
|
+
function actionsBeforeRunScript(app) {
|
|
1721
|
+
setActiveProxyWindow(app);
|
|
1722
|
+
}
|
|
1723
|
+
/**
|
|
1724
|
+
* set active sandBox.proxyWindow to window.__MICRO_APP_PROXY_WINDOW__
|
|
1725
|
+
*/
|
|
1726
|
+
function setActiveProxyWindow(app) {
|
|
1727
|
+
if (app.sandBox) {
|
|
1728
|
+
globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
|
|
1729
|
+
}
|
|
1730
|
+
}
|
|
1731
|
+
/**
|
|
1732
|
+
* Call the plugin to process the file
|
|
1733
|
+
* @param address script address
|
|
1734
|
+
* @param code code
|
|
1735
|
+
* @param appName app name
|
|
1736
|
+
* @param plugins plugin list
|
|
1737
|
+
*/
|
|
1738
|
+
function usePlugins(address, code, appName, plugins) {
|
|
1739
|
+
var _a;
|
|
1740
|
+
const newCode = processCode(plugins.global, code, address);
|
|
1741
|
+
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, address);
|
|
1742
|
+
}
|
|
1743
|
+
function processCode(configs, code, address) {
|
|
1744
|
+
if (!isArray(configs)) {
|
|
1745
|
+
return code;
|
|
1746
|
+
}
|
|
1747
|
+
return configs.reduce((preCode, config) => {
|
|
1748
|
+
if (isPlainObject(config) && isFunction(config.loader)) {
|
|
1749
|
+
return config.loader(preCode, address);
|
|
1750
|
+
}
|
|
1751
|
+
return preCode;
|
|
1752
|
+
}, code);
|
|
1753
|
+
}
|
|
1754
|
+
|
|
1755
|
+
class Adapter {
|
|
1756
|
+
constructor() {
|
|
1757
|
+
// keys that can only assigned to rawWindow
|
|
1402
1758
|
this.escapeSetterKeyList = [
|
|
1403
1759
|
'location',
|
|
1404
1760
|
];
|
|
@@ -1521,7 +1877,10 @@ function patchElementTree(container, appName) {
|
|
|
1521
1877
|
function updateElementInfo(node, appName) {
|
|
1522
1878
|
var _a, _b;
|
|
1523
1879
|
const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
|
|
1524
|
-
if (
|
|
1880
|
+
if (isNode(node) &&
|
|
1881
|
+
!node.__MICRO_APP_NAME__ &&
|
|
1882
|
+
!node.__PURE_ELEMENT__ &&
|
|
1883
|
+
proxyWindow) {
|
|
1525
1884
|
/**
|
|
1526
1885
|
* TODO:
|
|
1527
1886
|
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
@@ -1552,14 +1911,21 @@ function updateElementInfo(node, appName) {
|
|
|
1552
1911
|
|
|
1553
1912
|
// Record element and map element
|
|
1554
1913
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
1914
|
+
// Get the map element
|
|
1915
|
+
function getMappingNode(node) {
|
|
1916
|
+
var _a;
|
|
1917
|
+
return (_a = dynamicElementInMicroAppMap.get(node)) !== null && _a !== void 0 ? _a : node;
|
|
1918
|
+
}
|
|
1555
1919
|
/**
|
|
1556
1920
|
* Process the new node and format the style, link and script element
|
|
1557
|
-
* @param parent parent node
|
|
1558
1921
|
* @param child new node
|
|
1559
1922
|
* @param app app
|
|
1560
1923
|
*/
|
|
1561
|
-
function handleNewNode(
|
|
1562
|
-
if (
|
|
1924
|
+
function handleNewNode(child, app) {
|
|
1925
|
+
if (dynamicElementInMicroAppMap.has(child)) {
|
|
1926
|
+
return dynamicElementInMicroAppMap.get(child);
|
|
1927
|
+
}
|
|
1928
|
+
else if (isStyleElement(child)) {
|
|
1563
1929
|
if (child.hasAttribute('exclude')) {
|
|
1564
1930
|
const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
|
|
1565
1931
|
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
@@ -1583,7 +1949,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1583
1949
|
microApp.options.excludeAssetFilter(child.href))) {
|
|
1584
1950
|
return child;
|
|
1585
1951
|
}
|
|
1586
|
-
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child,
|
|
1952
|
+
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child, null, app, true);
|
|
1587
1953
|
if (address && linkInfo) {
|
|
1588
1954
|
const replaceStyle = formatDynamicLink(address, app, linkInfo, child);
|
|
1589
1955
|
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
@@ -1601,7 +1967,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1601
1967
|
microApp.options.excludeAssetFilter(child.src)) {
|
|
1602
1968
|
return child;
|
|
1603
1969
|
}
|
|
1604
|
-
const { replaceComment, address, scriptInfo } = extractScriptElement(child,
|
|
1970
|
+
const { replaceComment, address, scriptInfo } = extractScriptElement(child, null, app, true) || {};
|
|
1605
1971
|
if (address && scriptInfo) {
|
|
1606
1972
|
// remote script or inline script
|
|
1607
1973
|
const replaceElement = scriptInfo.isExternal ? runDynamicRemoteScript(address, app, scriptInfo, child) : runDynamicInlineScript(address, app, scriptInfo);
|
|
@@ -1705,6 +2071,9 @@ function getHijackParent(parent, targetChild, app) {
|
|
|
1705
2071
|
}
|
|
1706
2072
|
return app.querySelector('micro-app-body');
|
|
1707
2073
|
}
|
|
2074
|
+
if (app.iframe && isScriptElement(targetChild)) {
|
|
2075
|
+
return app.sandBox.microBody;
|
|
2076
|
+
}
|
|
1708
2077
|
}
|
|
1709
2078
|
return null;
|
|
1710
2079
|
}
|
|
@@ -1717,10 +2086,25 @@ function invokeRawMethod(rawMethod, parent, targetChild, passiveChild) {
|
|
|
1717
2086
|
function isPendMethod(method) {
|
|
1718
2087
|
return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
|
|
1719
2088
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
2089
|
+
/**
|
|
2090
|
+
* Attempt to complete the static resource address again before insert the node
|
|
2091
|
+
* @param app app instance
|
|
2092
|
+
* @param newChild target node
|
|
2093
|
+
*/
|
|
2094
|
+
function completePathDynamic(app, newChild) {
|
|
2095
|
+
if (isElement(newChild)) {
|
|
2096
|
+
if (/^(img|script)$/i.test(newChild.tagName)) {
|
|
2097
|
+
if (newChild.hasAttribute('src')) {
|
|
2098
|
+
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
2099
|
+
}
|
|
2100
|
+
if (newChild.hasAttribute('srcset')) {
|
|
2101
|
+
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
2102
|
+
}
|
|
2103
|
+
}
|
|
2104
|
+
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
2105
|
+
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
2106
|
+
}
|
|
2107
|
+
}
|
|
1724
2108
|
}
|
|
1725
2109
|
/**
|
|
1726
2110
|
* method of handle new node
|
|
@@ -1738,37 +2122,11 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1738
2122
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1739
2123
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1740
2124
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1741
|
-
|
|
1742
|
-
|
|
1743
|
-
if (newChild.hasAttribute('src')) {
|
|
1744
|
-
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
1745
|
-
}
|
|
1746
|
-
if (newChild.hasAttribute('srcset')) {
|
|
1747
|
-
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
1748
|
-
}
|
|
1749
|
-
}
|
|
1750
|
-
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
1751
|
-
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
1752
|
-
}
|
|
1753
|
-
}
|
|
1754
|
-
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(parent, newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
1755
|
-
}
|
|
1756
|
-
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1757
|
-
return rawMethod.call(parent, newChild);
|
|
2125
|
+
completePathDynamic(app, newChild);
|
|
2126
|
+
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
1758
2127
|
}
|
|
1759
2128
|
}
|
|
1760
|
-
|
|
1761
|
-
if (!isNode(newChild) && currentAppName) {
|
|
1762
|
-
const app = appInstanceMap.get(currentAppName);
|
|
1763
|
-
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1764
|
-
if (parent === document.head) {
|
|
1765
|
-
return rawMethod.call(app.querySelector('micro-app-head'), newChild);
|
|
1766
|
-
}
|
|
1767
|
-
else if (parent === document.body) {
|
|
1768
|
-
return rawMethod.call(app.querySelector('micro-app-body'), newChild);
|
|
1769
|
-
}
|
|
1770
|
-
}
|
|
1771
|
-
}
|
|
2129
|
+
if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1772
2130
|
return rawMethod.call(parent, newChild);
|
|
1773
2131
|
}
|
|
1774
2132
|
return rawMethod.call(parent, newChild, passiveChild);
|
|
@@ -1778,33 +2136,37 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1778
2136
|
*/
|
|
1779
2137
|
function patchElementAndDocument() {
|
|
1780
2138
|
patchDocument();
|
|
2139
|
+
const rawRootElement = globalEnv.rawRootElement;
|
|
1781
2140
|
// prototype methods of add element👇
|
|
1782
|
-
|
|
2141
|
+
rawRootElement.prototype.appendChild = function appendChild(newChild) {
|
|
1783
2142
|
return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
|
|
1784
2143
|
};
|
|
1785
|
-
|
|
2144
|
+
rawRootElement.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
1786
2145
|
return commonElementHandler(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
1787
2146
|
};
|
|
1788
|
-
|
|
2147
|
+
rawRootElement.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
1789
2148
|
return commonElementHandler(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
1790
2149
|
};
|
|
1791
|
-
|
|
2150
|
+
rawRootElement.prototype.append = function append(...nodes) {
|
|
1792
2151
|
let i = 0;
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
2152
|
+
while (i < nodes.length) {
|
|
2153
|
+
let node = nodes[i];
|
|
2154
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
2155
|
+
commonElementHandler(this, markElement(node), null, globalEnv.rawAppend);
|
|
1796
2156
|
i++;
|
|
1797
2157
|
}
|
|
1798
2158
|
};
|
|
1799
|
-
|
|
2159
|
+
rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
1800
2160
|
let i = nodes.length;
|
|
1801
2161
|
while (i > 0) {
|
|
1802
|
-
|
|
2162
|
+
let node = nodes[i - 1];
|
|
2163
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
2164
|
+
commonElementHandler(this, markElement(node), null, globalEnv.rawPrepend);
|
|
1803
2165
|
i--;
|
|
1804
2166
|
}
|
|
1805
2167
|
};
|
|
1806
2168
|
// prototype methods of delete element👇
|
|
1807
|
-
|
|
2169
|
+
rawRootElement.prototype.removeChild = function removeChild(oldChild) {
|
|
1808
2170
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1809
2171
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1810
2172
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -1819,8 +2181,27 @@ function patchElementAndDocument() {
|
|
|
1819
2181
|
}
|
|
1820
2182
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1821
2183
|
};
|
|
2184
|
+
/**
|
|
2185
|
+
* The insertAdjacentElement method of the Element interface inserts a given element node at a given position relative to the element it is invoked upon.
|
|
2186
|
+
* NOTE:
|
|
2187
|
+
* 1. parameter 2 of insertAdjacentElement must type 'Element'
|
|
2188
|
+
*/
|
|
2189
|
+
rawRootElement.prototype.insertAdjacentElement = function (where, element) {
|
|
2190
|
+
var _a;
|
|
2191
|
+
if ((element === null || element === void 0 ? void 0 : element.__MICRO_APP_NAME__) && isElement(element)) {
|
|
2192
|
+
const app = appInstanceMap.get(element.__MICRO_APP_NAME__);
|
|
2193
|
+
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
2194
|
+
const processedEle = handleNewNode(element, app);
|
|
2195
|
+
if (!isElement(processedEle))
|
|
2196
|
+
return element;
|
|
2197
|
+
const realParent = (_a = getHijackParent(this, processedEle, app)) !== null && _a !== void 0 ? _a : this;
|
|
2198
|
+
return globalEnv.rawInsertAdjacentElement.call(realParent, where, processedEle);
|
|
2199
|
+
}
|
|
2200
|
+
}
|
|
2201
|
+
return globalEnv.rawInsertAdjacentElement.call(this, where, element);
|
|
2202
|
+
};
|
|
1822
2203
|
// patch cloneNode
|
|
1823
|
-
|
|
2204
|
+
rawRootElement.prototype.cloneNode = function cloneNode(deep) {
|
|
1824
2205
|
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
1825
2206
|
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
1826
2207
|
return clonedNode;
|
|
@@ -1840,17 +2221,63 @@ function patchElementAndDocument() {
|
|
|
1840
2221
|
}
|
|
1841
2222
|
return null;
|
|
1842
2223
|
}
|
|
1843
|
-
|
|
2224
|
+
rawRootElement.prototype.querySelector = function querySelector(selectors) {
|
|
1844
2225
|
var _a;
|
|
1845
2226
|
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1846
2227
|
return globalEnv.rawElementQuerySelector.call(target, selectors);
|
|
1847
2228
|
};
|
|
1848
|
-
|
|
2229
|
+
rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
1849
2230
|
var _a;
|
|
1850
2231
|
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1851
2232
|
return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
|
|
1852
2233
|
};
|
|
1853
|
-
|
|
2234
|
+
// rewrite setAttribute, complete resource address
|
|
2235
|
+
rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
2236
|
+
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
2237
|
+
if (appName &&
|
|
2238
|
+
appInstanceMap.has(appName) &&
|
|
2239
|
+
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
2240
|
+
(key === 'href' && /^link$/i.test(this.tagName)))) {
|
|
2241
|
+
const app = appInstanceMap.get(appName);
|
|
2242
|
+
value = CompletionPath(value, app.url);
|
|
2243
|
+
}
|
|
2244
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
2245
|
+
};
|
|
2246
|
+
/**
|
|
2247
|
+
* TODO: 兼容直接通过img.src等操作设置的资源
|
|
2248
|
+
* NOTE:
|
|
2249
|
+
* 1. 卸载时恢复原始值
|
|
2250
|
+
* 2. 循环嵌套的情况
|
|
2251
|
+
* 3. 放在global_env中统一处理
|
|
2252
|
+
* 4. 是否和completePathDynamic的作用重复?
|
|
2253
|
+
*/
|
|
2254
|
+
// const protoAttrList: Array<[HTMLElement, string]> = [
|
|
2255
|
+
// [HTMLImageElement.prototype, 'src'],
|
|
2256
|
+
// [HTMLScriptElement.prototype, 'src'],
|
|
2257
|
+
// [HTMLLinkElement.prototype, 'href'],
|
|
2258
|
+
// ]
|
|
2259
|
+
// protoAttrList.forEach(([target, attr]) => {
|
|
2260
|
+
// const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
|
|
2261
|
+
// enumerable: true,
|
|
2262
|
+
// configurable: true,
|
|
2263
|
+
// }
|
|
2264
|
+
// rawDefineProperty(target, attr, {
|
|
2265
|
+
// enumerable,
|
|
2266
|
+
// configurable,
|
|
2267
|
+
// get: function () {
|
|
2268
|
+
// return get?.call(this)
|
|
2269
|
+
// },
|
|
2270
|
+
// set: function (value) {
|
|
2271
|
+
// const currentAppName = getCurrentAppName()
|
|
2272
|
+
// if (currentAppName && appInstanceMap.has(currentAppName)) {
|
|
2273
|
+
// const app = appInstanceMap.get(currentAppName)
|
|
2274
|
+
// value = CompletionPath(value, app!.url)
|
|
2275
|
+
// }
|
|
2276
|
+
// set?.call(this, value)
|
|
2277
|
+
// },
|
|
2278
|
+
// })
|
|
2279
|
+
// })
|
|
2280
|
+
rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
|
|
1854
2281
|
configurable: true,
|
|
1855
2282
|
enumerable: true,
|
|
1856
2283
|
get() {
|
|
@@ -1866,7 +2293,9 @@ function patchElementAndDocument() {
|
|
|
1866
2293
|
});
|
|
1867
2294
|
}
|
|
1868
2295
|
});
|
|
1869
|
-
|
|
2296
|
+
/**
|
|
2297
|
+
* NOTE:Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
|
|
2298
|
+
*/
|
|
1870
2299
|
// rawDefineProperty(Node.prototype, 'parentNode', {
|
|
1871
2300
|
// configurable: true,
|
|
1872
2301
|
// enumerable: true,
|
|
@@ -1921,33 +2350,35 @@ function patchDocument() {
|
|
|
1921
2350
|
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
1922
2351
|
return markElement(element);
|
|
1923
2352
|
};
|
|
2353
|
+
// rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
|
|
2354
|
+
// const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
|
|
2355
|
+
// return markElement(element)
|
|
2356
|
+
// }
|
|
1924
2357
|
// query element👇
|
|
1925
2358
|
function querySelector(selectors) {
|
|
1926
|
-
var _a, _b
|
|
2359
|
+
var _a, _b;
|
|
1927
2360
|
const _this = getBindTarget(this);
|
|
1928
2361
|
const currentAppName = getCurrentAppName();
|
|
1929
2362
|
if (!currentAppName ||
|
|
1930
|
-
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1931
2363
|
!selectors ||
|
|
1932
2364
|
isUniqueElement(selectors) ||
|
|
1933
2365
|
// see https://github.com/micro-zoe/micro-app/issues/56
|
|
1934
2366
|
rawDocument !== _this) {
|
|
1935
2367
|
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
1936
2368
|
}
|
|
1937
|
-
return (
|
|
2369
|
+
return (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
1938
2370
|
}
|
|
1939
2371
|
function querySelectorAll(selectors) {
|
|
1940
|
-
var _a, _b
|
|
2372
|
+
var _a, _b;
|
|
1941
2373
|
const _this = getBindTarget(this);
|
|
1942
2374
|
const currentAppName = getCurrentAppName();
|
|
1943
2375
|
if (!currentAppName ||
|
|
1944
|
-
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1945
2376
|
!selectors ||
|
|
1946
2377
|
isUniqueElement(selectors) ||
|
|
1947
2378
|
rawDocument !== _this) {
|
|
1948
2379
|
return globalEnv.rawQuerySelectorAll.call(_this, selectors);
|
|
1949
2380
|
}
|
|
1950
|
-
return (
|
|
2381
|
+
return (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
1951
2382
|
}
|
|
1952
2383
|
rawRootDocument.prototype.querySelector = querySelector;
|
|
1953
2384
|
rawRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
@@ -2005,45 +2436,6 @@ function patchDocument() {
|
|
|
2005
2436
|
}
|
|
2006
2437
|
};
|
|
2007
2438
|
}
|
|
2008
|
-
/**
|
|
2009
|
-
* patchSetAttribute is different from other patch
|
|
2010
|
-
* NOTE:
|
|
2011
|
-
* 1. it not dependent on sandbox
|
|
2012
|
-
* 2. it should exec when first micro-app-element created & release when all app unmounted
|
|
2013
|
-
*/
|
|
2014
|
-
let hasRewriteSetAttribute = false;
|
|
2015
|
-
function patchSetAttribute() {
|
|
2016
|
-
if (hasRewriteSetAttribute)
|
|
2017
|
-
return;
|
|
2018
|
-
hasRewriteSetAttribute = true;
|
|
2019
|
-
Element.prototype.setAttribute = function setAttribute(key, value) {
|
|
2020
|
-
if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
|
|
2021
|
-
if (isPlainObject(value)) {
|
|
2022
|
-
const cloneValue = {};
|
|
2023
|
-
Object.getOwnPropertyNames(value).forEach((ownKey) => {
|
|
2024
|
-
if (!(isString(ownKey) && ownKey.indexOf('__') === 0)) {
|
|
2025
|
-
cloneValue[ownKey] = value[ownKey];
|
|
2026
|
-
}
|
|
2027
|
-
});
|
|
2028
|
-
this.data = cloneValue;
|
|
2029
|
-
}
|
|
2030
|
-
else if (value !== '[object Object]') {
|
|
2031
|
-
logWarn('property data must be an object', this.getAttribute('name'));
|
|
2032
|
-
}
|
|
2033
|
-
}
|
|
2034
|
-
else {
|
|
2035
|
-
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
2036
|
-
if (appName &&
|
|
2037
|
-
appInstanceMap.has(appName) &&
|
|
2038
|
-
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
2039
|
-
(key === 'href' && /^link$/i.test(this.tagName)))) {
|
|
2040
|
-
const app = appInstanceMap.get(appName);
|
|
2041
|
-
value = CompletionPath(value, app.url);
|
|
2042
|
-
}
|
|
2043
|
-
globalEnv.rawSetAttribute.call(this, key, value);
|
|
2044
|
-
}
|
|
2045
|
-
};
|
|
2046
|
-
}
|
|
2047
2439
|
function releasePatchDocument() {
|
|
2048
2440
|
const rawRootDocument = globalEnv.rawRootDocument;
|
|
2049
2441
|
rawRootDocument.prototype.createElement = globalEnv.rawCreateElement;
|
|
@@ -2060,21 +2452,18 @@ function releasePatchDocument() {
|
|
|
2060
2452
|
function releasePatchElementAndDocument() {
|
|
2061
2453
|
removeDomScope();
|
|
2062
2454
|
releasePatchDocument();
|
|
2063
|
-
|
|
2064
|
-
|
|
2065
|
-
|
|
2066
|
-
|
|
2067
|
-
|
|
2068
|
-
|
|
2069
|
-
|
|
2070
|
-
|
|
2071
|
-
|
|
2072
|
-
|
|
2073
|
-
|
|
2074
|
-
|
|
2075
|
-
function releasePatchSetAttribute() {
|
|
2076
|
-
hasRewriteSetAttribute = false;
|
|
2077
|
-
Element.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
2455
|
+
const rawRootElement = globalEnv.rawRootElement;
|
|
2456
|
+
rawRootElement.prototype.appendChild = globalEnv.rawAppendChild;
|
|
2457
|
+
rawRootElement.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
2458
|
+
rawRootElement.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
2459
|
+
rawRootElement.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
2460
|
+
rawRootElement.prototype.append = globalEnv.rawAppend;
|
|
2461
|
+
rawRootElement.prototype.prepend = globalEnv.rawPrepend;
|
|
2462
|
+
rawRootElement.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
2463
|
+
rawRootElement.prototype.querySelector = globalEnv.rawElementQuerySelector;
|
|
2464
|
+
rawRootElement.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
|
|
2465
|
+
rawRootElement.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
2466
|
+
rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
|
|
2078
2467
|
}
|
|
2079
2468
|
// Set the style of micro-app-head and micro-app-body
|
|
2080
2469
|
let hasRejectMicroAppStyle = false;
|
|
@@ -2103,23 +2492,24 @@ function initGlobalEnv() {
|
|
|
2103
2492
|
const rawWindow = window.rawWindow || Function('return window')();
|
|
2104
2493
|
const rawDocument = window.rawDocument || Function('return document')();
|
|
2105
2494
|
const rawRootDocument = rawWindow.Document || Function('return Document')();
|
|
2106
|
-
const
|
|
2107
|
-
|
|
2108
|
-
|
|
2109
|
-
|
|
2110
|
-
|
|
2111
|
-
const
|
|
2112
|
-
const
|
|
2113
|
-
const
|
|
2114
|
-
const
|
|
2115
|
-
const
|
|
2116
|
-
const
|
|
2117
|
-
const
|
|
2118
|
-
const
|
|
2119
|
-
const
|
|
2120
|
-
const
|
|
2121
|
-
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(
|
|
2122
|
-
const rawParentNodeDesc = Object.getOwnPropertyDescriptor(
|
|
2495
|
+
const rawRootElement = rawWindow.Element;
|
|
2496
|
+
const rawRootNode = rawWindow.Node;
|
|
2497
|
+
const rawRootEventTarget = rawWindow.EventTarget;
|
|
2498
|
+
// save patch raw methods, pay attention to this binding
|
|
2499
|
+
const rawSetAttribute = rawRootElement.prototype.setAttribute;
|
|
2500
|
+
const rawAppendChild = rawRootElement.prototype.appendChild;
|
|
2501
|
+
const rawInsertBefore = rawRootElement.prototype.insertBefore;
|
|
2502
|
+
const rawReplaceChild = rawRootElement.prototype.replaceChild;
|
|
2503
|
+
const rawRemoveChild = rawRootElement.prototype.removeChild;
|
|
2504
|
+
const rawAppend = rawRootElement.prototype.append;
|
|
2505
|
+
const rawPrepend = rawRootElement.prototype.prepend;
|
|
2506
|
+
const rawCloneNode = rawRootElement.prototype.cloneNode;
|
|
2507
|
+
const rawElementQuerySelector = rawRootElement.prototype.querySelector;
|
|
2508
|
+
const rawElementQuerySelectorAll = rawRootElement.prototype.querySelectorAll;
|
|
2509
|
+
const rawInsertAdjacentElement = rawRootElement.prototype.insertAdjacentElement;
|
|
2510
|
+
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(rawRootElement.prototype, 'innerHTML');
|
|
2511
|
+
const rawParentNodeDesc = Object.getOwnPropertyDescriptor(rawRootNode.prototype, 'parentNode');
|
|
2512
|
+
// Document proto methods
|
|
2123
2513
|
const rawCreateElement = rawRootDocument.prototype.createElement;
|
|
2124
2514
|
const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
|
|
2125
2515
|
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
@@ -2133,7 +2523,9 @@ function initGlobalEnv() {
|
|
|
2133
2523
|
const ImageProxy = new Proxy(Image, {
|
|
2134
2524
|
construct(Target, args) {
|
|
2135
2525
|
const elementImage = new Target(...args);
|
|
2136
|
-
|
|
2526
|
+
const currentAppName = getCurrentAppName();
|
|
2527
|
+
if (currentAppName)
|
|
2528
|
+
elementImage.__MICRO_APP_NAME__ = currentAppName;
|
|
2137
2529
|
return elementImage;
|
|
2138
2530
|
},
|
|
2139
2531
|
});
|
|
@@ -2147,19 +2539,16 @@ function initGlobalEnv() {
|
|
|
2147
2539
|
const rawClearTimeout = rawWindow.clearTimeout;
|
|
2148
2540
|
const rawPushState = rawWindow.history.pushState;
|
|
2149
2541
|
const rawReplaceState = rawWindow.history.replaceState;
|
|
2150
|
-
const
|
|
2151
|
-
const
|
|
2152
|
-
const rawDocumentAddEventListener = rawDocument.addEventListener;
|
|
2153
|
-
const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
|
|
2154
|
-
// TODO: 统一使用 EventTarget 去掉上面四个
|
|
2155
|
-
const rawAddEventListener = EventTarget.prototype.addEventListener;
|
|
2156
|
-
const rawRemoveEventListener = EventTarget.prototype.removeEventListener;
|
|
2542
|
+
const rawAddEventListener = rawRootEventTarget.prototype.addEventListener;
|
|
2543
|
+
const rawRemoveEventListener = rawRootEventTarget.prototype.removeEventListener;
|
|
2157
2544
|
assign(globalEnv, {
|
|
2545
|
+
supportModuleScript: isSupportModuleScript(),
|
|
2158
2546
|
// common global vars
|
|
2159
2547
|
rawWindow,
|
|
2160
2548
|
rawDocument,
|
|
2161
2549
|
rawRootDocument,
|
|
2162
|
-
|
|
2550
|
+
rawRootElement,
|
|
2551
|
+
rawRootNode,
|
|
2163
2552
|
// source/patch
|
|
2164
2553
|
rawSetAttribute,
|
|
2165
2554
|
rawAppendChild,
|
|
@@ -2171,6 +2560,7 @@ function initGlobalEnv() {
|
|
|
2171
2560
|
rawCloneNode,
|
|
2172
2561
|
rawElementQuerySelector,
|
|
2173
2562
|
rawElementQuerySelectorAll,
|
|
2563
|
+
rawInsertAdjacentElement,
|
|
2174
2564
|
rawInnerHTMLDesc,
|
|
2175
2565
|
rawParentNodeDesc,
|
|
2176
2566
|
rawCreateElement,
|
|
@@ -2185,594 +2575,243 @@ function initGlobalEnv() {
|
|
|
2185
2575
|
rawGetElementsByName,
|
|
2186
2576
|
ImageProxy,
|
|
2187
2577
|
// sandbox/effect
|
|
2188
|
-
rawWindowAddEventListener,
|
|
2189
|
-
rawWindowRemoveEventListener,
|
|
2190
2578
|
rawSetInterval,
|
|
2191
2579
|
rawSetTimeout,
|
|
2192
2580
|
rawClearInterval,
|
|
2193
2581
|
rawClearTimeout,
|
|
2194
|
-
rawDocumentAddEventListener,
|
|
2195
|
-
rawDocumentRemoveEventListener,
|
|
2196
2582
|
rawPushState,
|
|
2197
2583
|
rawReplaceState,
|
|
2198
2584
|
rawAddEventListener,
|
|
2199
2585
|
rawRemoveEventListener,
|
|
2200
|
-
});
|
|
2201
|
-
// global effect
|
|
2202
|
-
rejectMicroAppStyle();
|
|
2203
|
-
}
|
|
2204
|
-
}
|
|
2205
|
-
|
|
2206
|
-
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
2207
|
-
// whether use type='module' script
|
|
2208
|
-
function isTypeModule(app, scriptInfo) {
|
|
2209
|
-
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
|
|
2210
|
-
}
|
|
2211
|
-
// special script element
|
|
2212
|
-
function isSpecialScript(app, scriptInfo) {
|
|
2213
|
-
const attrs = scriptInfo.appSpace[app.name].attrs;
|
|
2214
|
-
return attrs.has('id');
|
|
2215
|
-
}
|
|
2216
|
-
/**
|
|
2217
|
-
* whether to run js in inline mode
|
|
2218
|
-
* scene:
|
|
2219
|
-
* 1. inline config for app
|
|
2220
|
-
* 2. inline attr in script element
|
|
2221
|
-
* 3. module script
|
|
2222
|
-
* 4. script with special attr
|
|
2223
|
-
*/
|
|
2224
|
-
function isInlineMode(app, scriptInfo) {
|
|
2225
|
-
return (app.inline ||
|
|
2226
|
-
scriptInfo.appSpace[app.name].inline ||
|
|
2227
|
-
isTypeModule(app, scriptInfo) ||
|
|
2228
|
-
isSpecialScript(app, scriptInfo) ||
|
|
2229
|
-
app.iframe);
|
|
2230
|
-
}
|
|
2231
|
-
// TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
|
|
2232
|
-
function getEffectWindow(app) {
|
|
2233
|
-
return app.iframe ? app.sandBox.microAppWindow : globalEnv.rawWindow;
|
|
2234
|
-
}
|
|
2235
|
-
// Convert string code to function
|
|
2236
|
-
function code2Function(app, code) {
|
|
2237
|
-
const targetWindow = getEffectWindow(app);
|
|
2238
|
-
return new targetWindow.Function(code);
|
|
2239
|
-
}
|
|
2240
|
-
/**
|
|
2241
|
-
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
2242
|
-
* @param appName app.name
|
|
2243
|
-
* @param scriptInfo scriptInfo of current address
|
|
2244
|
-
* @param currentCode pure code of current address
|
|
2245
|
-
*/
|
|
2246
|
-
function getExistParseResult(app, scriptInfo, currentCode) {
|
|
2247
|
-
const appSpace = scriptInfo.appSpace;
|
|
2248
|
-
for (const item in appSpace) {
|
|
2249
|
-
if (item !== app.name) {
|
|
2250
|
-
const appSpaceData = appSpace[item];
|
|
2251
|
-
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
2252
|
-
return appSpaceData.parsedFunction;
|
|
2253
|
-
}
|
|
2254
|
-
}
|
|
2255
|
-
}
|
|
2256
|
-
}
|
|
2257
|
-
/**
|
|
2258
|
-
* get parsedFunction from exist data or parsedCode
|
|
2259
|
-
* @returns parsedFunction
|
|
2260
|
-
*/
|
|
2261
|
-
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
2262
|
-
return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
|
|
2263
|
-
}
|
|
2264
|
-
// Prevent randomly created strings from repeating
|
|
2265
|
-
function getUniqueNonceSrc() {
|
|
2266
|
-
const nonceStr = createNonceSrc();
|
|
2267
|
-
if (sourceCenter.script.hasInfo(nonceStr)) {
|
|
2268
|
-
return getUniqueNonceSrc();
|
|
2269
|
-
}
|
|
2270
|
-
return nonceStr;
|
|
2271
|
-
}
|
|
2272
|
-
// transfer the attributes on the script to convertScript
|
|
2273
|
-
function setConvertScriptAttr(convertScript, attrs) {
|
|
2274
|
-
attrs.forEach((value, key) => {
|
|
2275
|
-
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
2276
|
-
return;
|
|
2277
|
-
if (key === 'src')
|
|
2278
|
-
key = 'data-origin-src';
|
|
2279
|
-
convertScript.setAttribute(key, value);
|
|
2280
|
-
});
|
|
2281
|
-
}
|
|
2282
|
-
// wrap code in sandbox
|
|
2283
|
-
function isWrapInSandBox(app, scriptInfo) {
|
|
2284
|
-
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
2285
|
-
}
|
|
2286
|
-
function getSandboxType(app, scriptInfo) {
|
|
2287
|
-
return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
|
|
2288
|
-
}
|
|
2289
|
-
/**
|
|
2290
|
-
* Extract script elements
|
|
2291
|
-
* @param script script element
|
|
2292
|
-
* @param parent parent element of script
|
|
2293
|
-
* @param app app
|
|
2294
|
-
* @param isDynamic dynamic insert
|
|
2295
|
-
*/
|
|
2296
|
-
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
2297
|
-
var _a;
|
|
2298
|
-
let replaceComment = null;
|
|
2299
|
-
let src = script.getAttribute('src');
|
|
2300
|
-
if (src)
|
|
2301
|
-
src = CompletionPath(src, app.url);
|
|
2302
|
-
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
2303
|
-
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
2304
|
-
}
|
|
2305
|
-
else if ((script.type &&
|
|
2306
|
-
!scriptTypes.includes(script.type)) ||
|
|
2307
|
-
script.hasAttribute('ignore') ||
|
|
2308
|
-
checkIgnoreUrl(src, app.name)) {
|
|
2309
|
-
// 配置为忽略的脚本,清空 rawDocument.currentScript,避免被忽略的脚本内获取 currentScript 出错
|
|
2310
|
-
if ((_a = globalEnv.rawDocument) === null || _a === void 0 ? void 0 : _a.currentScript) {
|
|
2311
|
-
delete globalEnv.rawDocument.currentScript;
|
|
2312
|
-
}
|
|
2313
|
-
return null;
|
|
2314
|
-
}
|
|
2315
|
-
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
2316
|
-
(!globalEnv.supportModuleScript && script.type === 'module')) {
|
|
2317
|
-
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
2318
|
-
}
|
|
2319
|
-
else if (src) { // remote script
|
|
2320
|
-
let scriptInfo = sourceCenter.script.getInfo(src);
|
|
2321
|
-
const appSpaceData = {
|
|
2322
|
-
async: script.hasAttribute('async'),
|
|
2323
|
-
defer: script.defer || script.type === 'module',
|
|
2324
|
-
module: script.type === 'module',
|
|
2325
|
-
inline: script.hasAttribute('inline'),
|
|
2326
|
-
pure: script.hasAttribute('pure'),
|
|
2327
|
-
attrs: getAttributes(script),
|
|
2328
|
-
};
|
|
2329
|
-
if (!scriptInfo) {
|
|
2330
|
-
scriptInfo = {
|
|
2331
|
-
code: '',
|
|
2332
|
-
isExternal: true,
|
|
2333
|
-
appSpace: {
|
|
2334
|
-
[app.name]: appSpaceData,
|
|
2335
|
-
}
|
|
2336
|
-
};
|
|
2337
|
-
}
|
|
2338
|
-
else {
|
|
2339
|
-
/**
|
|
2340
|
-
* Reuse when appSpace exists
|
|
2341
|
-
* NOTE:
|
|
2342
|
-
* 1. The same static script, appSpace must be the same (in fact, it may be different when url change)
|
|
2343
|
-
* 2. The same dynamic script, appSpace may be the same, but we still reuse appSpace, which should pay attention
|
|
2344
|
-
*/
|
|
2345
|
-
scriptInfo.appSpace[app.name] = scriptInfo.appSpace[app.name] || appSpaceData;
|
|
2346
|
-
}
|
|
2347
|
-
sourceCenter.script.setInfo(src, scriptInfo);
|
|
2348
|
-
if (!isDynamic) {
|
|
2349
|
-
app.source.scripts.add(src);
|
|
2350
|
-
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
2351
|
-
}
|
|
2352
|
-
else {
|
|
2353
|
-
return { address: src, scriptInfo };
|
|
2354
|
-
}
|
|
2355
|
-
}
|
|
2356
|
-
else if (script.textContent) { // inline script
|
|
2357
|
-
/**
|
|
2358
|
-
* NOTE:
|
|
2359
|
-
* 1. Each inline script is unique
|
|
2360
|
-
* 2. Every dynamic created inline script will be re-executed
|
|
2361
|
-
* ACTION:
|
|
2362
|
-
* 1. Delete dynamic inline script info after exec
|
|
2363
|
-
* 2. Delete static inline script info when destroy
|
|
2364
|
-
*/
|
|
2365
|
-
const nonceStr = getUniqueNonceSrc();
|
|
2366
|
-
const scriptInfo = {
|
|
2367
|
-
code: script.textContent,
|
|
2368
|
-
isExternal: false,
|
|
2369
|
-
appSpace: {
|
|
2370
|
-
[app.name]: {
|
|
2371
|
-
async: false,
|
|
2372
|
-
defer: script.type === 'module',
|
|
2373
|
-
module: script.type === 'module',
|
|
2374
|
-
inline: script.hasAttribute('inline'),
|
|
2375
|
-
pure: script.hasAttribute('pure'),
|
|
2376
|
-
attrs: getAttributes(script),
|
|
2377
|
-
}
|
|
2378
|
-
}
|
|
2379
|
-
};
|
|
2380
|
-
if (!isDynamic) {
|
|
2381
|
-
app.source.scripts.add(nonceStr);
|
|
2382
|
-
sourceCenter.script.setInfo(nonceStr, scriptInfo);
|
|
2383
|
-
replaceComment = document.createComment('inline script extract by micro-app');
|
|
2384
|
-
}
|
|
2385
|
-
else {
|
|
2386
|
-
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
2387
|
-
return { address: nonceStr, scriptInfo };
|
|
2388
|
-
}
|
|
2389
|
-
}
|
|
2390
|
-
else if (!isDynamic) {
|
|
2391
|
-
/**
|
|
2392
|
-
* script with empty src or empty script.textContent remove in static html
|
|
2393
|
-
* & not removed if it created by dynamic
|
|
2394
|
-
*/
|
|
2395
|
-
replaceComment = document.createComment('script element removed by micro-app');
|
|
2396
|
-
}
|
|
2397
|
-
if (isDynamic) {
|
|
2398
|
-
return { replaceComment };
|
|
2399
|
-
}
|
|
2400
|
-
else {
|
|
2401
|
-
return parent.replaceChild(replaceComment, script);
|
|
2402
|
-
}
|
|
2403
|
-
}
|
|
2404
|
-
/**
|
|
2405
|
-
* get assets plugins
|
|
2406
|
-
* @param appName app name
|
|
2407
|
-
*/
|
|
2408
|
-
function getAssetsPlugins(appName) {
|
|
2409
|
-
var _a, _b, _c;
|
|
2410
|
-
const globalPlugins = ((_a = microApp.options.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
2411
|
-
const modulePlugins = ((_c = (_b = microApp.options.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
2412
|
-
return [...globalPlugins, ...modulePlugins];
|
|
2413
|
-
}
|
|
2414
|
-
/**
|
|
2415
|
-
* whether the address needs to be excluded
|
|
2416
|
-
* @param address css or js link
|
|
2417
|
-
* @param plugins microApp plugins
|
|
2418
|
-
*/
|
|
2419
|
-
function checkExcludeUrl(address, appName) {
|
|
2420
|
-
if (!address)
|
|
2421
|
-
return false;
|
|
2422
|
-
const plugins = getAssetsPlugins(appName) || [];
|
|
2423
|
-
return plugins.some(plugin => {
|
|
2424
|
-
if (!plugin.excludeChecker)
|
|
2425
|
-
return false;
|
|
2426
|
-
return plugin.excludeChecker(address);
|
|
2427
|
-
});
|
|
2428
|
-
}
|
|
2429
|
-
/**
|
|
2430
|
-
* whether the address needs to be ignore
|
|
2431
|
-
* @param address css or js link
|
|
2432
|
-
* @param plugins microApp plugins
|
|
2433
|
-
*/
|
|
2434
|
-
function checkIgnoreUrl(address, appName) {
|
|
2435
|
-
if (!address)
|
|
2436
|
-
return false;
|
|
2437
|
-
const plugins = getAssetsPlugins(appName) || [];
|
|
2438
|
-
return plugins.some(plugin => {
|
|
2439
|
-
if (!plugin.ignoreChecker)
|
|
2440
|
-
return false;
|
|
2441
|
-
return plugin.ignoreChecker(address);
|
|
2442
|
-
});
|
|
2443
|
-
}
|
|
2444
|
-
/**
|
|
2445
|
-
* Get remote resources of script
|
|
2446
|
-
* @param wrapElement htmlDom
|
|
2447
|
-
* @param app app
|
|
2448
|
-
*/
|
|
2449
|
-
function fetchScriptsFromHtml(wrapElement, app) {
|
|
2450
|
-
const scriptList = Array.from(app.source.scripts);
|
|
2451
|
-
const fetchScriptPromise = [];
|
|
2452
|
-
const fetchScriptPromiseInfo = [];
|
|
2453
|
-
for (const address of scriptList) {
|
|
2454
|
-
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2455
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2456
|
-
if ((!appSpaceData.defer && !appSpaceData.async) || (app.isPrefetch && !app.isPrerender)) {
|
|
2457
|
-
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
2458
|
-
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
2459
|
-
}
|
|
2460
|
-
}
|
|
2461
|
-
const fiberScriptTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
2462
|
-
if (fetchScriptPromise.length) {
|
|
2463
|
-
promiseStream(fetchScriptPromise, (res) => {
|
|
2464
|
-
injectFiberTask(fiberScriptTasks, () => fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data, app));
|
|
2465
|
-
}, (err) => {
|
|
2466
|
-
logError(err, app.name);
|
|
2467
|
-
}, () => {
|
|
2468
|
-
if (fiberScriptTasks) {
|
|
2469
|
-
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2470
|
-
serialExecFiberTasks(fiberScriptTasks);
|
|
2471
|
-
}
|
|
2472
|
-
else {
|
|
2473
|
-
app.onLoad(wrapElement);
|
|
2474
|
-
}
|
|
2475
|
-
});
|
|
2476
|
-
}
|
|
2477
|
-
else {
|
|
2478
|
-
app.onLoad(wrapElement);
|
|
2586
|
+
});
|
|
2587
|
+
// global effect
|
|
2588
|
+
rejectMicroAppStyle();
|
|
2479
2589
|
}
|
|
2480
2590
|
}
|
|
2591
|
+
|
|
2481
2592
|
/**
|
|
2482
|
-
*
|
|
2483
|
-
* @param
|
|
2484
|
-
* @param
|
|
2485
|
-
* @param data code
|
|
2593
|
+
*
|
|
2594
|
+
* @param appName app.name
|
|
2595
|
+
* @param linkInfo linkInfo of current address
|
|
2486
2596
|
*/
|
|
2487
|
-
function
|
|
2488
|
-
|
|
2489
|
-
|
|
2490
|
-
|
|
2491
|
-
|
|
2492
|
-
|
|
2493
|
-
|
|
2494
|
-
* 2. if app is inline or script is esmodule, skip this step
|
|
2495
|
-
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
2496
|
-
*/
|
|
2497
|
-
if (app.isPrefetch && app.prefetchLevel === 2) {
|
|
2498
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2499
|
-
/**
|
|
2500
|
-
* When prefetch app is replaced by a new app in the processing phase, since the scriptInfo is common, when the scriptInfo of the prefetch app is processed, it may have already been processed.
|
|
2501
|
-
* This causes parsedCode to already exist when preloading ends
|
|
2502
|
-
* e.g.
|
|
2503
|
-
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
2504
|
-
* 2. prefetch param different from <micro-app></micro-app>
|
|
2505
|
-
*/
|
|
2506
|
-
if (!appSpaceData.parsedCode) {
|
|
2507
|
-
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
2508
|
-
appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
|
|
2509
|
-
if (!isInlineMode(app, scriptInfo)) {
|
|
2510
|
-
try {
|
|
2511
|
-
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2512
|
-
}
|
|
2513
|
-
catch (err) {
|
|
2514
|
-
logError('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
2515
|
-
}
|
|
2597
|
+
function getExistParseCode(appName, prefix, linkInfo) {
|
|
2598
|
+
const appSpace = linkInfo.appSpace;
|
|
2599
|
+
for (const item in appSpace) {
|
|
2600
|
+
if (item !== appName) {
|
|
2601
|
+
const appSpaceData = appSpace[item];
|
|
2602
|
+
if (appSpaceData.parsedCode) {
|
|
2603
|
+
return appSpaceData.parsedCode.replace(new RegExp(createPrefix(item, true), 'g'), prefix);
|
|
2516
2604
|
}
|
|
2517
2605
|
}
|
|
2518
2606
|
}
|
|
2519
2607
|
}
|
|
2608
|
+
// transfer the attributes on the link to convertStyle
|
|
2609
|
+
function setConvertStyleAttr(convertStyle, attrs) {
|
|
2610
|
+
attrs.forEach((value, key) => {
|
|
2611
|
+
if (key === 'rel')
|
|
2612
|
+
return;
|
|
2613
|
+
if (key === 'href')
|
|
2614
|
+
key = 'data-origin-href';
|
|
2615
|
+
globalEnv.rawSetAttribute.call(convertStyle, key, value);
|
|
2616
|
+
});
|
|
2617
|
+
}
|
|
2520
2618
|
/**
|
|
2521
|
-
*
|
|
2619
|
+
* Extract link elements
|
|
2620
|
+
* @param link link element
|
|
2621
|
+
* @param parent parent element of link
|
|
2522
2622
|
* @param app app
|
|
2523
|
-
* @param
|
|
2623
|
+
* @param microAppHead micro-app-head element
|
|
2624
|
+
* @param isDynamic dynamic insert
|
|
2524
2625
|
*/
|
|
2525
|
-
function
|
|
2526
|
-
const
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
|
|
2531
|
-
|
|
2532
|
-
const appSpaceData =
|
|
2533
|
-
|
|
2534
|
-
|
|
2535
|
-
|
|
2536
|
-
|
|
2537
|
-
|
|
2538
|
-
|
|
2539
|
-
|
|
2540
|
-
|
|
2541
|
-
}
|
|
2542
|
-
deferScriptInfo.push([address, scriptInfo]);
|
|
2543
|
-
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
2626
|
+
function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
2627
|
+
const rel = link.getAttribute('rel');
|
|
2628
|
+
let href = link.getAttribute('href');
|
|
2629
|
+
let replaceComment = null;
|
|
2630
|
+
if (rel === 'stylesheet' && href) {
|
|
2631
|
+
href = CompletionPath(href, app.url);
|
|
2632
|
+
let linkInfo = sourceCenter.link.getInfo(href);
|
|
2633
|
+
const appSpaceData = {
|
|
2634
|
+
attrs: getAttributes(link),
|
|
2635
|
+
};
|
|
2636
|
+
if (!linkInfo) {
|
|
2637
|
+
linkInfo = {
|
|
2638
|
+
code: '',
|
|
2639
|
+
appSpace: {
|
|
2640
|
+
[app.name]: appSpaceData,
|
|
2641
|
+
}
|
|
2642
|
+
};
|
|
2544
2643
|
}
|
|
2545
2644
|
else {
|
|
2546
|
-
|
|
2547
|
-
|
|
2548
|
-
|
|
2549
|
-
|
|
2645
|
+
linkInfo.appSpace[app.name] = linkInfo.appSpace[app.name] || appSpaceData;
|
|
2646
|
+
}
|
|
2647
|
+
sourceCenter.link.setInfo(href, linkInfo);
|
|
2648
|
+
if (!isDynamic) {
|
|
2649
|
+
app.source.links.add(href);
|
|
2650
|
+
replaceComment = document.createComment(`link element with href=${href} move to micro-app-head as style element`);
|
|
2651
|
+
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
2652
|
+
}
|
|
2653
|
+
else {
|
|
2654
|
+
return { address: href, linkInfo };
|
|
2550
2655
|
}
|
|
2551
2656
|
}
|
|
2552
|
-
if (
|
|
2553
|
-
|
|
2554
|
-
|
|
2555
|
-
|
|
2556
|
-
}, (err) => {
|
|
2557
|
-
initHook.errorCount = initHook.errorCount ? ++initHook.errorCount : 1;
|
|
2558
|
-
logError(err, app.name);
|
|
2559
|
-
}, () => {
|
|
2560
|
-
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
2561
|
-
if (isString(scriptInfo.code)) {
|
|
2562
|
-
injectFiberTask(fiberScriptTasks, () => {
|
|
2563
|
-
runScript(address, app, scriptInfo, initHook);
|
|
2564
|
-
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
2565
|
-
});
|
|
2566
|
-
}
|
|
2567
|
-
});
|
|
2568
|
-
/**
|
|
2569
|
-
* Fiber wraps js in requestIdleCallback and executes it in sequence
|
|
2570
|
-
* NOTE:
|
|
2571
|
-
* 1. In order to ensure the execution order, wait for all js loaded and then execute
|
|
2572
|
-
* 2. If js create a dynamic script, it may be errors in the execution order, because the subsequent js is wrapped in requestIdleCallback, even putting dynamic script in requestIdleCallback doesn't solve it
|
|
2573
|
-
*
|
|
2574
|
-
* BUG: NOTE.2 - execution order problem
|
|
2575
|
-
*/
|
|
2576
|
-
if (fiberScriptTasks) {
|
|
2577
|
-
fiberScriptTasks.push(() => Promise.resolve(initHook(isUndefined(initHook.moduleCount) ||
|
|
2578
|
-
initHook.errorCount === deferScriptPromise.length)));
|
|
2579
|
-
serialExecFiberTasks(fiberScriptTasks);
|
|
2580
|
-
}
|
|
2581
|
-
else {
|
|
2582
|
-
initHook(isUndefined(initHook.moduleCount) ||
|
|
2583
|
-
initHook.errorCount === deferScriptPromise.length);
|
|
2584
|
-
}
|
|
2585
|
-
});
|
|
2586
|
-
}
|
|
2587
|
-
else {
|
|
2588
|
-
if (fiberScriptTasks) {
|
|
2589
|
-
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
2590
|
-
serialExecFiberTasks(fiberScriptTasks);
|
|
2657
|
+
else if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
|
|
2658
|
+
// preload prefetch icon ....
|
|
2659
|
+
if (isDynamic) {
|
|
2660
|
+
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
2591
2661
|
}
|
|
2592
2662
|
else {
|
|
2593
|
-
|
|
2663
|
+
parent === null || parent === void 0 ? void 0 : parent.removeChild(link);
|
|
2594
2664
|
}
|
|
2595
2665
|
}
|
|
2666
|
+
else if (href) {
|
|
2667
|
+
// dns-prefetch preconnect modulepreload search ....
|
|
2668
|
+
globalEnv.rawSetAttribute.call(link, 'href', CompletionPath(href, app.url));
|
|
2669
|
+
}
|
|
2670
|
+
if (isDynamic) {
|
|
2671
|
+
return { replaceComment };
|
|
2672
|
+
}
|
|
2673
|
+
else if (replaceComment) {
|
|
2674
|
+
return parent === null || parent === void 0 ? void 0 : parent.replaceChild(replaceComment, link);
|
|
2675
|
+
}
|
|
2596
2676
|
}
|
|
2597
2677
|
/**
|
|
2598
|
-
*
|
|
2599
|
-
* @param
|
|
2678
|
+
* Get link remote resources
|
|
2679
|
+
* @param wrapElement htmlDom
|
|
2600
2680
|
* @param app app
|
|
2601
|
-
* @param
|
|
2602
|
-
* @param callback callback of module script
|
|
2681
|
+
* @param microAppHead micro-app-head
|
|
2603
2682
|
*/
|
|
2604
|
-
function
|
|
2605
|
-
|
|
2606
|
-
|
|
2607
|
-
const
|
|
2608
|
-
|
|
2683
|
+
function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
2684
|
+
const styleList = Array.from(app.source.links);
|
|
2685
|
+
const fetchLinkPromise = styleList.map((address) => {
|
|
2686
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
2687
|
+
return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
|
|
2688
|
+
});
|
|
2689
|
+
const fiberLinkTasks = fiberStyleResult ? [] : null;
|
|
2690
|
+
promiseStream(fetchLinkPromise, (res) => {
|
|
2691
|
+
injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
|
|
2692
|
+
}, (err) => {
|
|
2693
|
+
logError(err, app.name);
|
|
2694
|
+
}, () => {
|
|
2609
2695
|
/**
|
|
2610
|
-
*
|
|
2611
|
-
*
|
|
2612
|
-
*
|
|
2613
|
-
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
2696
|
+
* 1. If fiberStyleResult exist, fiberLinkTasks must exist
|
|
2697
|
+
* 2. Download link source while processing style
|
|
2698
|
+
* 3. Process style first, and then process link
|
|
2614
2699
|
*/
|
|
2615
|
-
if (
|
|
2616
|
-
|
|
2617
|
-
|
|
2618
|
-
|
|
2619
|
-
|
|
2620
|
-
if (isInlineMode(app, scriptInfo)) {
|
|
2621
|
-
const scriptElement = replaceElement || pureCreateElement('script');
|
|
2622
|
-
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
2623
|
-
if (!replaceElement) {
|
|
2624
|
-
// TEST IGNORE
|
|
2625
|
-
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
2626
|
-
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
2627
|
-
}
|
|
2700
|
+
if (fiberStyleResult) {
|
|
2701
|
+
fiberStyleResult.then(() => {
|
|
2702
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2703
|
+
serialExecFiberTasks(fiberLinkTasks);
|
|
2704
|
+
});
|
|
2628
2705
|
}
|
|
2629
2706
|
else {
|
|
2630
|
-
|
|
2707
|
+
app.onLoad(wrapElement);
|
|
2631
2708
|
}
|
|
2632
|
-
}
|
|
2633
|
-
catch (e) {
|
|
2634
|
-
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
2635
|
-
}
|
|
2709
|
+
});
|
|
2636
2710
|
}
|
|
2637
2711
|
/**
|
|
2638
|
-
*
|
|
2639
|
-
*
|
|
2712
|
+
* Fetch link succeeded, replace placeholder with style tag
|
|
2713
|
+
* NOTE:
|
|
2714
|
+
* 1. Only exec when init, no longer exec when remount
|
|
2715
|
+
* 2. Only handler html link element, not dynamic link or style
|
|
2716
|
+
* 3. The same prefix can reuse parsedCode
|
|
2717
|
+
* 4. Async exec with requestIdleCallback in prefetch or fiber
|
|
2718
|
+
* 5. appSpace[app.name].placeholder/attrs must exist
|
|
2719
|
+
* @param address resource address
|
|
2720
|
+
* @param code link source code
|
|
2721
|
+
* @param microAppHead micro-app-head
|
|
2640
2722
|
* @param app app instance
|
|
2641
|
-
* @param scriptInfo scriptInfo
|
|
2642
|
-
* @param originScript origin script element
|
|
2643
2723
|
*/
|
|
2644
|
-
function
|
|
2645
|
-
|
|
2646
|
-
|
|
2647
|
-
|
|
2648
|
-
|
|
2649
|
-
|
|
2650
|
-
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2724
|
+
function fetchLinkSuccess(address, code, microAppHead, app) {
|
|
2725
|
+
/**
|
|
2726
|
+
* linkInfo must exist, but linkInfo.code not
|
|
2727
|
+
* so we set code to linkInfo.code
|
|
2728
|
+
*/
|
|
2729
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
2730
|
+
linkInfo.code = code;
|
|
2731
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
2732
|
+
const placeholder = appSpaceData.placeholder;
|
|
2733
|
+
/**
|
|
2734
|
+
* When prefetch app is replaced by a new app in the processing phase, since the linkInfo is common, when the linkInfo of the prefetch app is processed, it may have already been processed.
|
|
2735
|
+
* This causes placeholder to be possibly null
|
|
2736
|
+
* e.g.
|
|
2737
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
2738
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
2739
|
+
*/
|
|
2740
|
+
if (placeholder) {
|
|
2741
|
+
const convertStyle = pureCreateElement('style');
|
|
2742
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, appSpaceData.attrs);
|
|
2743
|
+
if (placeholder.parentNode) {
|
|
2744
|
+
placeholder.parentNode.replaceChild(convertStyle, placeholder);
|
|
2654
2745
|
}
|
|
2655
|
-
|
|
2656
|
-
|
|
2657
|
-
|
|
2658
|
-
|
|
2659
|
-
|
|
2660
|
-
}
|
|
2661
|
-
else {
|
|
2662
|
-
fetchSource(address, app.name).then((code) => {
|
|
2663
|
-
scriptInfo.code = code;
|
|
2664
|
-
runDynamicScript();
|
|
2665
|
-
}).catch((err) => {
|
|
2666
|
-
logError(err, app.name);
|
|
2667
|
-
dispatchOnErrorEvent(originScript);
|
|
2668
|
-
});
|
|
2746
|
+
else {
|
|
2747
|
+
microAppHead.appendChild(convertStyle);
|
|
2748
|
+
}
|
|
2749
|
+
// clear placeholder
|
|
2750
|
+
appSpaceData.placeholder = null;
|
|
2669
2751
|
}
|
|
2670
|
-
return replaceElement;
|
|
2671
2752
|
}
|
|
2672
2753
|
/**
|
|
2673
|
-
* Get
|
|
2674
|
-
*
|
|
2754
|
+
* Get parsedCode, update convertStyle
|
|
2755
|
+
* Actions:
|
|
2756
|
+
* 1. get scope css (through scopedCSS or oldData)
|
|
2757
|
+
* 2. record parsedCode
|
|
2758
|
+
* 3. set parsedCode to convertStyle if need
|
|
2675
2759
|
* @param app app instance
|
|
2676
|
-
* @param
|
|
2677
|
-
|
|
2678
|
-
|
|
2679
|
-
|
|
2680
|
-
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
2681
|
-
return replaceElement;
|
|
2682
|
-
}
|
|
2683
|
-
/**
|
|
2684
|
-
* common handle for inline script
|
|
2685
|
-
* @param address script address
|
|
2686
|
-
* @param code bound code
|
|
2687
|
-
* @param module type='module' of script
|
|
2688
|
-
* @param scriptElement target script element
|
|
2689
|
-
* @param attrs attributes of script element
|
|
2690
|
-
* @param callback callback of module script
|
|
2760
|
+
* @param address resource address
|
|
2761
|
+
* @param convertStyle converted style
|
|
2762
|
+
* @param linkInfo linkInfo in sourceCenter
|
|
2763
|
+
* @param attrs attrs of link
|
|
2691
2764
|
*/
|
|
2692
|
-
function
|
|
2693
|
-
if (
|
|
2694
|
-
|
|
2695
|
-
|
|
2696
|
-
|
|
2697
|
-
|
|
2765
|
+
function handleConvertStyle(app, address, convertStyle, linkInfo, attrs) {
|
|
2766
|
+
if (app.scopecss) {
|
|
2767
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
2768
|
+
appSpaceData.prefix = appSpaceData.prefix || createPrefix(app.name);
|
|
2769
|
+
if (!appSpaceData.parsedCode) {
|
|
2770
|
+
const existParsedCode = getExistParseCode(app.name, appSpaceData.prefix, linkInfo);
|
|
2771
|
+
if (!existParsedCode) {
|
|
2772
|
+
convertStyle.textContent = linkInfo.code;
|
|
2773
|
+
scopedCSS(convertStyle, app, address);
|
|
2774
|
+
}
|
|
2775
|
+
else {
|
|
2776
|
+
convertStyle.textContent = existParsedCode;
|
|
2777
|
+
}
|
|
2778
|
+
appSpaceData.parsedCode = convertStyle.textContent;
|
|
2698
2779
|
}
|
|
2699
2780
|
else {
|
|
2700
|
-
|
|
2701
|
-
}
|
|
2702
|
-
scriptElement.setAttribute('type', 'module');
|
|
2703
|
-
if (callback) {
|
|
2704
|
-
callback.moduleCount && callback.moduleCount--;
|
|
2705
|
-
/**
|
|
2706
|
-
* module script will execute onload method only after it insert to document/iframe
|
|
2707
|
-
*/
|
|
2708
|
-
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
2781
|
+
convertStyle.textContent = appSpaceData.parsedCode;
|
|
2709
2782
|
}
|
|
2710
2783
|
}
|
|
2711
2784
|
else {
|
|
2712
|
-
|
|
2713
|
-
}
|
|
2714
|
-
setConvertScriptAttr(scriptElement, attrs);
|
|
2715
|
-
}
|
|
2716
|
-
// init & run code2Function
|
|
2717
|
-
function runParsedFunction(app, scriptInfo) {
|
|
2718
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2719
|
-
if (!appSpaceData.parsedFunction) {
|
|
2720
|
-
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2785
|
+
convertStyle.textContent = linkInfo.code;
|
|
2721
2786
|
}
|
|
2722
|
-
|
|
2787
|
+
setConvertStyleAttr(convertStyle, attrs);
|
|
2723
2788
|
}
|
|
2724
2789
|
/**
|
|
2725
|
-
*
|
|
2790
|
+
* Handle css of dynamic link
|
|
2791
|
+
* @param address link address
|
|
2726
2792
|
* @param app app
|
|
2727
|
-
* @param
|
|
2728
|
-
* @param
|
|
2729
|
-
*/
|
|
2730
|
-
function bindScope(address, app, code, scriptInfo) {
|
|
2731
|
-
// TODO: 1、cache 2、esm code is null
|
|
2732
|
-
if (isPlainObject(microApp.options.plugins)) {
|
|
2733
|
-
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
2734
|
-
}
|
|
2735
|
-
if (isWrapInSandBox(app, scriptInfo)) {
|
|
2736
|
-
return app.iframe ? `(function(window,self,global,location){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyWindow,window.__MICRO_APP_SANDBOX__.proxyLocation);` : `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n${isInlineScript(address) ? '' : `//# sourceURL=${address}\n`}}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
|
|
2737
|
-
}
|
|
2738
|
-
return code;
|
|
2739
|
-
}
|
|
2740
|
-
/**
|
|
2741
|
-
* actions before run script
|
|
2742
|
-
*/
|
|
2743
|
-
function actionsBeforeRunScript(app) {
|
|
2744
|
-
setActiveProxyWindow(app);
|
|
2745
|
-
}
|
|
2746
|
-
/**
|
|
2747
|
-
* set active sandBox.proxyWindow to window.__MICRO_APP_PROXY_WINDOW__
|
|
2793
|
+
* @param linkInfo linkInfo
|
|
2794
|
+
* @param originLink origin link element
|
|
2748
2795
|
*/
|
|
2749
|
-
function
|
|
2750
|
-
|
|
2751
|
-
|
|
2796
|
+
function formatDynamicLink(address, app, linkInfo, originLink) {
|
|
2797
|
+
const convertStyle = pureCreateElement('style');
|
|
2798
|
+
const handleDynamicLink = () => {
|
|
2799
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, linkInfo.appSpace[app.name].attrs);
|
|
2800
|
+
dispatchOnLoadEvent(originLink);
|
|
2801
|
+
};
|
|
2802
|
+
if (linkInfo.code) {
|
|
2803
|
+
defer(handleDynamicLink);
|
|
2752
2804
|
}
|
|
2753
|
-
|
|
2754
|
-
|
|
2755
|
-
|
|
2756
|
-
|
|
2757
|
-
|
|
2758
|
-
|
|
2759
|
-
|
|
2760
|
-
|
|
2761
|
-
function usePlugins(address, code, appName, plugins) {
|
|
2762
|
-
var _a;
|
|
2763
|
-
const newCode = processCode(plugins.global, code, address);
|
|
2764
|
-
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, address);
|
|
2765
|
-
}
|
|
2766
|
-
function processCode(configs, code, address) {
|
|
2767
|
-
if (!isArray(configs)) {
|
|
2768
|
-
return code;
|
|
2805
|
+
else {
|
|
2806
|
+
fetchSource(address, app.name).then((data) => {
|
|
2807
|
+
linkInfo.code = data;
|
|
2808
|
+
handleDynamicLink();
|
|
2809
|
+
}).catch((err) => {
|
|
2810
|
+
logError(err, app.name);
|
|
2811
|
+
dispatchOnErrorEvent(originLink);
|
|
2812
|
+
});
|
|
2769
2813
|
}
|
|
2770
|
-
return
|
|
2771
|
-
if (isPlainObject(config) && isFunction(config.loader)) {
|
|
2772
|
-
return config.loader(preCode, address);
|
|
2773
|
-
}
|
|
2774
|
-
return preCode;
|
|
2775
|
-
}, code);
|
|
2814
|
+
return convertStyle;
|
|
2776
2815
|
}
|
|
2777
2816
|
|
|
2778
2817
|
/**
|
|
@@ -2804,7 +2843,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2804
2843
|
extractLinkFromHtml(dom, parent, app);
|
|
2805
2844
|
}
|
|
2806
2845
|
else if (dom.hasAttribute('href')) {
|
|
2807
|
-
|
|
2846
|
+
globalEnv.rawSetAttribute.call(dom, 'href', CompletionPath(dom.getAttribute('href'), app.url));
|
|
2808
2847
|
}
|
|
2809
2848
|
}
|
|
2810
2849
|
else if (isStyleElement(dom)) {
|
|
@@ -2819,7 +2858,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2819
2858
|
extractScriptElement(dom, parent, app);
|
|
2820
2859
|
}
|
|
2821
2860
|
else if (isImageElement(dom) && dom.hasAttribute('src')) {
|
|
2822
|
-
|
|
2861
|
+
globalEnv.rawSetAttribute.call(dom, 'src', CompletionPath(dom.getAttribute('src'), app.url));
|
|
2823
2862
|
}
|
|
2824
2863
|
/**
|
|
2825
2864
|
* Don't remove meta and title, they have some special scenes
|
|
@@ -2871,6 +2910,40 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2871
2910
|
}
|
|
2872
2911
|
}
|
|
2873
2912
|
|
|
2913
|
+
/* eslint-disable no-return-assign */
|
|
2914
|
+
function isBoundedFunction(value) {
|
|
2915
|
+
if (isBoolean(value.__MICRO_APP_IS_BOUND_FUNCTION__))
|
|
2916
|
+
return value.__MICRO_APP_IS_BOUND_FUNCTION__;
|
|
2917
|
+
return value.__MICRO_APP_IS_BOUND_FUNCTION__ = isBoundFunction(value);
|
|
2918
|
+
}
|
|
2919
|
+
function isConstructorFunction(value) {
|
|
2920
|
+
if (isBoolean(value.__MICRO_APP_IS_CONSTRUCTOR__))
|
|
2921
|
+
return value.__MICRO_APP_IS_CONSTRUCTOR__;
|
|
2922
|
+
return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
|
|
2923
|
+
}
|
|
2924
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
2925
|
+
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
2926
|
+
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
|
|
2927
|
+
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
2928
|
+
if (value[cacheKey])
|
|
2929
|
+
return value[cacheKey];
|
|
2930
|
+
const bindRawObjectValue = value.bind(rawTarget);
|
|
2931
|
+
for (const key in value) {
|
|
2932
|
+
bindRawObjectValue[key] = value[key];
|
|
2933
|
+
}
|
|
2934
|
+
if (value.hasOwnProperty('prototype')) {
|
|
2935
|
+
rawDefineProperty(bindRawObjectValue, 'prototype', {
|
|
2936
|
+
value: value.prototype,
|
|
2937
|
+
configurable: true,
|
|
2938
|
+
enumerable: false,
|
|
2939
|
+
writable: true,
|
|
2940
|
+
});
|
|
2941
|
+
}
|
|
2942
|
+
return value[cacheKey] = bindRawObjectValue;
|
|
2943
|
+
}
|
|
2944
|
+
return value;
|
|
2945
|
+
}
|
|
2946
|
+
|
|
2874
2947
|
class EventCenter {
|
|
2875
2948
|
constructor() {
|
|
2876
2949
|
this.eventList = new Map();
|
|
@@ -3237,8 +3310,12 @@ class EventCenterForMicroApp extends EventCenterForGlobal {
|
|
|
3237
3310
|
* @param microAppEventCenter instance of EventCenterForMicroApp
|
|
3238
3311
|
*/
|
|
3239
3312
|
function recordDataCenterSnapshot(microAppEventCenter) {
|
|
3240
|
-
|
|
3241
|
-
|
|
3313
|
+
var _a, _b;
|
|
3314
|
+
if (microAppEventCenter) {
|
|
3315
|
+
microAppEventCenter.umdDataListeners = {
|
|
3316
|
+
global: new Set((_a = microAppEventCenter.umdDataListeners) === null || _a === void 0 ? void 0 : _a.global),
|
|
3317
|
+
normal: new Set((_b = microAppEventCenter.umdDataListeners) === null || _b === void 0 ? void 0 : _b.normal),
|
|
3318
|
+
};
|
|
3242
3319
|
const globalEventInfo = eventCenter.eventList.get('global');
|
|
3243
3320
|
if (globalEventInfo) {
|
|
3244
3321
|
for (const cb of globalEventInfo.callbacks) {
|
|
@@ -3249,7 +3326,9 @@ function recordDataCenterSnapshot(microAppEventCenter) {
|
|
|
3249
3326
|
}
|
|
3250
3327
|
const subAppEventInfo = eventCenter.eventList.get(createEventName(microAppEventCenter.appName, true));
|
|
3251
3328
|
if (subAppEventInfo) {
|
|
3252
|
-
|
|
3329
|
+
for (const cb of subAppEventInfo.callbacks) {
|
|
3330
|
+
microAppEventCenter.umdDataListeners.normal.add(cb);
|
|
3331
|
+
}
|
|
3253
3332
|
}
|
|
3254
3333
|
}
|
|
3255
3334
|
}
|
|
@@ -3274,7 +3353,7 @@ function rebuildDataCenterSnapshot(microAppEventCenter) {
|
|
|
3274
3353
|
* @param microAppEventCenter instance of EventCenterForMicroApp
|
|
3275
3354
|
*/
|
|
3276
3355
|
function resetDataCenterSnapshot(microAppEventCenter) {
|
|
3277
|
-
delete microAppEventCenter.umdDataListeners;
|
|
3356
|
+
microAppEventCenter === null || microAppEventCenter === void 0 ? true : delete microAppEventCenter.umdDataListeners;
|
|
3278
3357
|
}
|
|
3279
3358
|
|
|
3280
3359
|
// 管理 app 的单例
|
|
@@ -3303,171 +3382,224 @@ class AppManager {
|
|
|
3303
3382
|
}
|
|
3304
3383
|
}
|
|
3305
3384
|
|
|
3306
|
-
function unmountNestedApp() {
|
|
3307
|
-
releaseUnmountOfNestedApp();
|
|
3308
|
-
AppManager.getInstance().getAll().forEach(app => {
|
|
3309
|
-
// @ts-ignore
|
|
3310
|
-
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
3311
|
-
});
|
|
3312
|
-
!window.__MICRO_APP_UMD_MODE__ && AppManager.getInstance().clear();
|
|
3313
|
-
}
|
|
3314
|
-
// release listener
|
|
3315
|
-
function releaseUnmountOfNestedApp() {
|
|
3316
|
-
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
3317
|
-
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
3318
|
-
}
|
|
3319
|
-
}
|
|
3320
|
-
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
3321
|
-
// unmount event will auto release by sandbox
|
|
3322
|
-
function initEnvOfNestedApp() {
|
|
3323
|
-
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
3324
|
-
releaseUnmountOfNestedApp();
|
|
3325
|
-
window.addEventListener('unmount', unmountNestedApp, false);
|
|
3326
|
-
}
|
|
3327
|
-
}
|
|
3328
|
-
|
|
3329
|
-
/* eslint-disable no-return-assign */
|
|
3330
|
-
function isBoundedFunction(value) {
|
|
3331
|
-
if (isBoolean(value.__MICRO_APP_IS_BOUND_FUNCTION__))
|
|
3332
|
-
return value.__MICRO_APP_IS_BOUND_FUNCTION__;
|
|
3333
|
-
return value.__MICRO_APP_IS_BOUND_FUNCTION__ = isBoundFunction(value);
|
|
3334
|
-
}
|
|
3335
|
-
function isConstructorFunction(value) {
|
|
3336
|
-
if (isBoolean(value.__MICRO_APP_IS_CONSTRUCTOR__))
|
|
3337
|
-
return value.__MICRO_APP_IS_CONSTRUCTOR__;
|
|
3338
|
-
return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
|
|
3339
|
-
}
|
|
3340
|
-
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
3341
|
-
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
3342
|
-
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
|
|
3343
|
-
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
3344
|
-
if (value[cacheKey])
|
|
3345
|
-
return value[cacheKey];
|
|
3346
|
-
const bindRawObjectValue = value.bind(rawTarget);
|
|
3347
|
-
for (const key in value) {
|
|
3348
|
-
bindRawObjectValue[key] = value[key];
|
|
3349
|
-
}
|
|
3350
|
-
if (value.hasOwnProperty('prototype')) {
|
|
3351
|
-
rawDefineProperty(bindRawObjectValue, 'prototype', {
|
|
3352
|
-
value: value.prototype,
|
|
3353
|
-
configurable: true,
|
|
3354
|
-
enumerable: false,
|
|
3355
|
-
writable: true,
|
|
3356
|
-
});
|
|
3357
|
-
}
|
|
3358
|
-
return value[cacheKey] = bindRawObjectValue;
|
|
3359
|
-
}
|
|
3360
|
-
return value;
|
|
3361
|
-
}
|
|
3362
|
-
|
|
3363
|
-
// document.onclick binding list, the binding function of each application is unique
|
|
3364
|
-
const documentClickListMap = new Map();
|
|
3365
|
-
let hasRewriteDocumentOnClick = false;
|
|
3366
|
-
/**
|
|
3367
|
-
* Rewrite document.onclick and execute it only once
|
|
3368
|
-
*/
|
|
3369
|
-
function overwriteDocumentOnClick() {
|
|
3370
|
-
hasRewriteDocumentOnClick = true;
|
|
3371
|
-
if (Object.getOwnPropertyDescriptor(document, 'onclick')) {
|
|
3372
|
-
return logWarn('Cannot redefine document property onclick');
|
|
3373
|
-
}
|
|
3374
|
-
const rawOnClick = document.onclick;
|
|
3375
|
-
document.onclick = null;
|
|
3376
|
-
let hasDocumentClickInited = false;
|
|
3377
|
-
function onClickHandler(e) {
|
|
3378
|
-
documentClickListMap.forEach((f) => {
|
|
3379
|
-
isFunction(f) && f.call(document, e);
|
|
3380
|
-
});
|
|
3385
|
+
function unmountNestedApp() {
|
|
3386
|
+
releaseUnmountOfNestedApp();
|
|
3387
|
+
AppManager.getInstance().getAll().forEach(app => {
|
|
3388
|
+
// @ts-ignore
|
|
3389
|
+
app.container && getRootContainer(app.container).disconnectedCallback();
|
|
3390
|
+
});
|
|
3391
|
+
!window.__MICRO_APP_UMD_MODE__ && AppManager.getInstance().clear();
|
|
3392
|
+
}
|
|
3393
|
+
// release listener
|
|
3394
|
+
function releaseUnmountOfNestedApp() {
|
|
3395
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
3396
|
+
window.removeEventListener('unmount', unmountNestedApp, false);
|
|
3381
3397
|
}
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3388
|
-
|
|
3389
|
-
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
|
|
3393
|
-
|
|
3394
|
-
|
|
3395
|
-
|
|
3396
|
-
|
|
3397
|
-
|
|
3398
|
-
|
|
3399
|
-
|
|
3398
|
+
}
|
|
3399
|
+
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
3400
|
+
// unmount event will auto release by sandbox
|
|
3401
|
+
function initEnvOfNestedApp() {
|
|
3402
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
3403
|
+
releaseUnmountOfNestedApp();
|
|
3404
|
+
window.addEventListener('unmount', unmountNestedApp, false);
|
|
3405
|
+
}
|
|
3406
|
+
}
|
|
3407
|
+
|
|
3408
|
+
function createMicroDocument(appName, proxyDocument) {
|
|
3409
|
+
const { rawDocument, rawRootDocument } = globalEnv;
|
|
3410
|
+
class MicroDocument {
|
|
3411
|
+
static [Symbol.hasInstance](target) {
|
|
3412
|
+
let proto = target;
|
|
3413
|
+
while (proto = Object.getPrototypeOf(proto)) {
|
|
3414
|
+
if (proto === MicroDocument.prototype) {
|
|
3415
|
+
return true;
|
|
3416
|
+
}
|
|
3400
3417
|
}
|
|
3418
|
+
return (target === proxyDocument ||
|
|
3419
|
+
target instanceof rawRootDocument);
|
|
3401
3420
|
}
|
|
3402
|
-
}
|
|
3403
|
-
|
|
3421
|
+
}
|
|
3422
|
+
/**
|
|
3423
|
+
* TIP:
|
|
3424
|
+
* 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
|
|
3425
|
+
* 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
|
|
3426
|
+
* e.g.
|
|
3427
|
+
* class B extends A {}
|
|
3428
|
+
* B.__proto__ === A // true
|
|
3429
|
+
* B.prototype.__proto__ === A.prototype // true
|
|
3430
|
+
*/
|
|
3431
|
+
Object.setPrototypeOf(MicroDocument, rawRootDocument);
|
|
3432
|
+
// Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
|
|
3433
|
+
Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
|
|
3434
|
+
get(target, key) {
|
|
3435
|
+
throttleDeferForSetAppName(appName);
|
|
3436
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
3437
|
+
},
|
|
3438
|
+
set(target, key, value) {
|
|
3439
|
+
Reflect.set(target, key, value);
|
|
3440
|
+
return true;
|
|
3441
|
+
}
|
|
3442
|
+
}));
|
|
3443
|
+
return MicroDocument;
|
|
3404
3444
|
}
|
|
3405
3445
|
/**
|
|
3406
|
-
*
|
|
3446
|
+
* Create new document and Document
|
|
3407
3447
|
*/
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
const
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3448
|
+
function createProxyDocument(appName, sandbox) {
|
|
3449
|
+
const eventListenerMap = new Map();
|
|
3450
|
+
const sstEventListenerMap = new Map();
|
|
3451
|
+
let onClickHandler = null;
|
|
3452
|
+
let sstOnClickHandler = null;
|
|
3453
|
+
const { rawDocument, rawCreateElement, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
3454
|
+
function createElement(tagName, options) {
|
|
3455
|
+
const element = rawCreateElement.call(rawDocument, tagName, options);
|
|
3456
|
+
element.__MICRO_APP_NAME__ = appName;
|
|
3457
|
+
return element;
|
|
3458
|
+
}
|
|
3459
|
+
/**
|
|
3460
|
+
* TODO:
|
|
3461
|
+
* 1. listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
3462
|
+
* 2. 相似代码提取为公共方法(with, iframe)
|
|
3463
|
+
*/
|
|
3464
|
+
function addEventListener(type, listener, options) {
|
|
3465
|
+
const listenerList = eventListenerMap.get(type);
|
|
3466
|
+
if (listenerList) {
|
|
3467
|
+
listenerList.add(listener);
|
|
3468
|
+
}
|
|
3469
|
+
else {
|
|
3470
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
3471
|
+
}
|
|
3472
|
+
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
3473
|
+
rawAddEventListener.call(rawDocument, type, listener, options);
|
|
3474
|
+
}
|
|
3475
|
+
function removeEventListener(type, listener, options) {
|
|
3476
|
+
const listenerList = eventListenerMap.get(type);
|
|
3477
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3478
|
+
listenerList.delete(listener);
|
|
3479
|
+
}
|
|
3480
|
+
rawRemoveEventListener.call(rawDocument, type, listener, options);
|
|
3481
|
+
}
|
|
3482
|
+
// reset snapshot data
|
|
3483
|
+
const reset = () => {
|
|
3484
|
+
sstEventListenerMap.clear();
|
|
3485
|
+
sstOnClickHandler = null;
|
|
3486
|
+
};
|
|
3487
|
+
/**
|
|
3488
|
+
* NOTE:
|
|
3489
|
+
* 1. about timer(events & properties should record & rebuild at all modes, exclude default mode)
|
|
3490
|
+
* 2. record maybe call twice when unmount prerender, keep-alive app manually with umd mode
|
|
3491
|
+
* 4 modes: default-mode、umd-mode、prerender、keep-alive
|
|
3492
|
+
* Solution:
|
|
3493
|
+
* 1. default-mode(normal): clear events & timers, not record & rebuild anything
|
|
3494
|
+
* 2. umd-mode(normal): not clear timers, record & rebuild events
|
|
3495
|
+
* 3. prerender/keep-alive(default, umd): not clear timers, record & rebuild events
|
|
3496
|
+
*/
|
|
3497
|
+
const record = () => {
|
|
3414
3498
|
/**
|
|
3415
|
-
*
|
|
3416
|
-
*
|
|
3417
|
-
* boundFunction is no longer exclude, because events in UMD mode will not cleared from v1.0.0-alpha.4
|
|
3418
|
-
* if (appName && !(appInstanceMap.get(appName)?.umdMode && isBoundFunction(listener))) {
|
|
3499
|
+
* record onclick handler
|
|
3500
|
+
* onClickHandler maybe set again after prerender/keep-alive app hidden
|
|
3419
3501
|
*/
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
}
|
|
3427
|
-
else {
|
|
3428
|
-
appListenersMap.set(type, new Set([listener]));
|
|
3429
|
-
}
|
|
3502
|
+
sstOnClickHandler = onClickHandler || sstOnClickHandler;
|
|
3503
|
+
// record document event
|
|
3504
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
3505
|
+
if (listenerList.size) {
|
|
3506
|
+
const cacheList = sstEventListenerMap.get(type) || [];
|
|
3507
|
+
sstEventListenerMap.set(type, new Set([...cacheList, ...listenerList]));
|
|
3430
3508
|
}
|
|
3431
|
-
|
|
3432
|
-
|
|
3509
|
+
});
|
|
3510
|
+
};
|
|
3511
|
+
// rebuild event and timer before remount app
|
|
3512
|
+
const rebuild = () => {
|
|
3513
|
+
// rebuild onclick event
|
|
3514
|
+
if (sstOnClickHandler && !onClickHandler)
|
|
3515
|
+
proxyDocument.onclick = sstOnClickHandler;
|
|
3516
|
+
// rebuild document event
|
|
3517
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
3518
|
+
for (const listener of listenerList) {
|
|
3519
|
+
proxyDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3433
3520
|
}
|
|
3434
|
-
|
|
3521
|
+
});
|
|
3522
|
+
reset();
|
|
3523
|
+
};
|
|
3524
|
+
// release all event listener & interval & timeout when unmount app
|
|
3525
|
+
const release = () => {
|
|
3526
|
+
// Clear the function bound by micro app through document.onclick
|
|
3527
|
+
if (isFunction(onClickHandler)) {
|
|
3528
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
|
|
3529
|
+
}
|
|
3530
|
+
onClickHandler = null;
|
|
3531
|
+
// Clear document binding event
|
|
3532
|
+
if (eventListenerMap.size) {
|
|
3533
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
3534
|
+
for (const listener of listenerList) {
|
|
3535
|
+
rawRemoveEventListener.call(rawDocument, type, listener);
|
|
3536
|
+
}
|
|
3537
|
+
});
|
|
3538
|
+
eventListenerMap.clear();
|
|
3435
3539
|
}
|
|
3436
|
-
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
3437
3540
|
};
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3541
|
+
const proxyDocument = new Proxy(rawDocument, {
|
|
3542
|
+
get: (target, key) => {
|
|
3543
|
+
throttleDeferForSetAppName(appName);
|
|
3544
|
+
throttleDeferForParentNode(proxyDocument);
|
|
3545
|
+
if (key === 'createElement')
|
|
3546
|
+
return createElement;
|
|
3547
|
+
if (key === Symbol.toStringTag)
|
|
3548
|
+
return 'ProxyDocument';
|
|
3549
|
+
if (key === 'defaultView')
|
|
3550
|
+
return sandbox.proxyWindow;
|
|
3551
|
+
if (key === 'onclick')
|
|
3552
|
+
return onClickHandler;
|
|
3553
|
+
if (key === 'addEventListener')
|
|
3554
|
+
return addEventListener;
|
|
3555
|
+
if (key === 'removeEventListener')
|
|
3556
|
+
return removeEventListener;
|
|
3557
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
3558
|
+
},
|
|
3559
|
+
set: (target, key, value) => {
|
|
3560
|
+
if (key === 'onclick') {
|
|
3561
|
+
if (isFunction(onClickHandler)) {
|
|
3562
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
|
|
3451
3563
|
}
|
|
3564
|
+
// TODO: listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
3565
|
+
if (isFunction(value)) {
|
|
3566
|
+
rawAddEventListener.call(rawDocument, 'click', value, false);
|
|
3567
|
+
}
|
|
3568
|
+
onClickHandler = value;
|
|
3569
|
+
}
|
|
3570
|
+
else {
|
|
3571
|
+
/**
|
|
3572
|
+
* 1. Fix TypeError: Illegal invocation when set document.title
|
|
3573
|
+
* 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
3574
|
+
*/
|
|
3575
|
+
Reflect.set(target, key, value);
|
|
3452
3576
|
}
|
|
3577
|
+
return true;
|
|
3578
|
+
}
|
|
3579
|
+
});
|
|
3580
|
+
return {
|
|
3581
|
+
proxyDocument,
|
|
3582
|
+
MicroDocument: createMicroDocument(appName, proxyDocument),
|
|
3583
|
+
documentEffect: {
|
|
3584
|
+
reset,
|
|
3585
|
+
record,
|
|
3586
|
+
rebuild,
|
|
3587
|
+
release,
|
|
3453
3588
|
}
|
|
3454
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
3455
3589
|
};
|
|
3456
3590
|
}
|
|
3457
|
-
|
|
3458
|
-
function releaseEffectDocumentEvent() {
|
|
3459
|
-
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
3460
|
-
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
3461
|
-
}
|
|
3591
|
+
|
|
3462
3592
|
/**
|
|
3463
3593
|
* Rewrite side-effect events
|
|
3464
3594
|
* @param microAppWindow micro window
|
|
3465
3595
|
*/
|
|
3466
|
-
function
|
|
3596
|
+
function patchWindowEffect(appName, microAppWindow) {
|
|
3467
3597
|
const eventListenerMap = new Map();
|
|
3598
|
+
const sstEventListenerMap = new Map();
|
|
3468
3599
|
const intervalIdMap = new Map();
|
|
3469
3600
|
const timeoutIdMap = new Map();
|
|
3470
|
-
const { rawWindow,
|
|
3601
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, } = globalEnv;
|
|
3602
|
+
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
3471
3603
|
// listener may be null, e.g test-passive
|
|
3472
3604
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3473
3605
|
type = formatEventName(type, appName);
|
|
@@ -3479,7 +3611,7 @@ function effect(appName, microAppWindow) {
|
|
|
3479
3611
|
eventListenerMap.set(type, new Set([listener]));
|
|
3480
3612
|
}
|
|
3481
3613
|
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
3482
|
-
|
|
3614
|
+
rawAddEventListener.call(rawWindow, type, listener, options);
|
|
3483
3615
|
};
|
|
3484
3616
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3485
3617
|
type = formatEventName(type, appName);
|
|
@@ -3487,7 +3619,7 @@ function effect(appName, microAppWindow) {
|
|
|
3487
3619
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3488
3620
|
listenerList.delete(listener);
|
|
3489
3621
|
}
|
|
3490
|
-
|
|
3622
|
+
rawRemoveEventListener.call(rawWindow, type, listener, options);
|
|
3491
3623
|
};
|
|
3492
3624
|
microAppWindow.setInterval = function (handler, timeout, ...args) {
|
|
3493
3625
|
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
@@ -3507,14 +3639,9 @@ function effect(appName, microAppWindow) {
|
|
|
3507
3639
|
timeoutIdMap.delete(timeoutId);
|
|
3508
3640
|
rawClearTimeout.call(rawWindow, timeoutId);
|
|
3509
3641
|
};
|
|
3510
|
-
const sstWindowListenerMap = new Map();
|
|
3511
|
-
const sstDocumentListenerMap = new Map();
|
|
3512
|
-
let sstOnClickHandler;
|
|
3513
3642
|
// reset snapshot data
|
|
3514
3643
|
const reset = () => {
|
|
3515
|
-
|
|
3516
|
-
sstDocumentListenerMap.clear();
|
|
3517
|
-
sstOnClickHandler = null;
|
|
3644
|
+
sstEventListenerMap.clear();
|
|
3518
3645
|
};
|
|
3519
3646
|
/**
|
|
3520
3647
|
* NOTE:
|
|
@@ -3530,57 +3657,34 @@ function effect(appName, microAppWindow) {
|
|
|
3530
3657
|
// record window event
|
|
3531
3658
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3532
3659
|
if (listenerList.size) {
|
|
3533
|
-
|
|
3660
|
+
const cacheList = sstEventListenerMap.get(type) || [];
|
|
3661
|
+
sstEventListenerMap.set(type, new Set([...cacheList, ...listenerList]));
|
|
3534
3662
|
}
|
|
3535
3663
|
});
|
|
3536
|
-
// record onclick handler
|
|
3537
|
-
sstOnClickHandler = sstOnClickHandler || documentClickListMap.get(appName);
|
|
3538
|
-
// record document event
|
|
3539
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
3540
|
-
if (documentAppListenersMap) {
|
|
3541
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
3542
|
-
if (listenerList.size) {
|
|
3543
|
-
sstDocumentListenerMap.set(type, new Set(listenerList));
|
|
3544
|
-
}
|
|
3545
|
-
});
|
|
3546
|
-
}
|
|
3547
3664
|
};
|
|
3548
3665
|
// rebuild event and timer before remount app
|
|
3549
3666
|
const rebuild = () => {
|
|
3550
3667
|
// rebuild window event
|
|
3551
|
-
|
|
3668
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
3552
3669
|
for (const listener of listenerList) {
|
|
3553
3670
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3554
3671
|
}
|
|
3555
3672
|
});
|
|
3556
|
-
// rebuild onclick event
|
|
3557
|
-
sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
|
|
3558
|
-
/**
|
|
3559
|
-
* rebuild document event
|
|
3560
|
-
* WARNING!!: do not delete setCurrentAppName & removeDomScope
|
|
3561
|
-
*/
|
|
3562
|
-
setCurrentAppName(appName);
|
|
3563
|
-
sstDocumentListenerMap.forEach((listenerList, type) => {
|
|
3564
|
-
for (const listener of listenerList) {
|
|
3565
|
-
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3566
|
-
}
|
|
3567
|
-
});
|
|
3568
|
-
removeDomScope();
|
|
3569
3673
|
reset();
|
|
3570
3674
|
};
|
|
3571
3675
|
// release all event listener & interval & timeout when unmount app
|
|
3572
|
-
const release = (
|
|
3676
|
+
const release = (clearTimer) => {
|
|
3573
3677
|
// Clear window binding events
|
|
3574
3678
|
if (eventListenerMap.size) {
|
|
3575
3679
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3576
3680
|
for (const listener of listenerList) {
|
|
3577
|
-
|
|
3681
|
+
rawRemoveEventListener.call(rawWindow, type, listener);
|
|
3578
3682
|
}
|
|
3579
3683
|
});
|
|
3580
3684
|
eventListenerMap.clear();
|
|
3581
3685
|
}
|
|
3582
3686
|
// default mode(not keep-alive or isPrerender)
|
|
3583
|
-
if (
|
|
3687
|
+
if (clearTimer) {
|
|
3584
3688
|
intervalIdMap.forEach((_, intervalId) => {
|
|
3585
3689
|
rawClearInterval.call(rawWindow, intervalId);
|
|
3586
3690
|
});
|
|
@@ -3590,18 +3694,6 @@ function effect(appName, microAppWindow) {
|
|
|
3590
3694
|
intervalIdMap.clear();
|
|
3591
3695
|
timeoutIdMap.clear();
|
|
3592
3696
|
}
|
|
3593
|
-
// Clear the function bound by micro application through document.onclick
|
|
3594
|
-
documentClickListMap.delete(appName);
|
|
3595
|
-
// Clear document binding event
|
|
3596
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
3597
|
-
if (documentAppListenersMap) {
|
|
3598
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
3599
|
-
for (const listener of listenerList) {
|
|
3600
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
3601
|
-
}
|
|
3602
|
-
});
|
|
3603
|
-
documentAppListenersMap.clear();
|
|
3604
|
-
}
|
|
3605
3697
|
};
|
|
3606
3698
|
return {
|
|
3607
3699
|
reset,
|
|
@@ -3784,7 +3876,7 @@ function getNoHashMicroPathFromURL(appName, baseUrl) {
|
|
|
3784
3876
|
*/
|
|
3785
3877
|
function isEffectiveApp(appName) {
|
|
3786
3878
|
const app = appInstanceMap.get(appName);
|
|
3787
|
-
return !!(app && !app.isPrefetch);
|
|
3879
|
+
return !!(app && !app.isPrefetch && !app.isHidden());
|
|
3788
3880
|
}
|
|
3789
3881
|
|
|
3790
3882
|
/**
|
|
@@ -4814,6 +4906,7 @@ const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
|
4814
4906
|
const globalPropertyList$1 = ['window', 'self', 'globalThis'];
|
|
4815
4907
|
class WithSandBox {
|
|
4816
4908
|
constructor(appName, url) {
|
|
4909
|
+
this.active = false;
|
|
4817
4910
|
/**
|
|
4818
4911
|
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
4819
4912
|
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
@@ -4821,24 +4914,20 @@ class WithSandBox {
|
|
|
4821
4914
|
this.scopeProperties = [];
|
|
4822
4915
|
// Properties that can be escape to rawWindow
|
|
4823
4916
|
this.escapeProperties = [];
|
|
4824
|
-
// Properties newly added to microAppWindow
|
|
4825
|
-
this.injectedKeys = new Set();
|
|
4826
4917
|
// Properties escape to rawWindow, cleared when unmount
|
|
4827
4918
|
this.escapeKeys = new Set();
|
|
4828
|
-
//
|
|
4829
|
-
|
|
4830
|
-
// sandbox state
|
|
4831
|
-
this.active = false;
|
|
4919
|
+
// Properties newly added to microAppWindow
|
|
4920
|
+
this.injectedKeys = new Set();
|
|
4832
4921
|
this.microAppWindow = {}; // Proxy target
|
|
4833
4922
|
this.adapter = new Adapter();
|
|
4834
4923
|
// get scopeProperties and escapeProperties from plugins
|
|
4835
4924
|
this.getSpecialProperties(appName);
|
|
4836
|
-
//
|
|
4837
|
-
this.
|
|
4838
|
-
//
|
|
4839
|
-
this.
|
|
4925
|
+
// rewrite window of child app
|
|
4926
|
+
this.windowEffect = this.patchWithWindow(appName, this.microAppWindow);
|
|
4927
|
+
// rewrite document of child app
|
|
4928
|
+
this.documentEffect = this.patchWithDocument(appName, this.microAppWindow);
|
|
4840
4929
|
// inject global properties
|
|
4841
|
-
this.initStaticGlobalKeys(
|
|
4930
|
+
this.initStaticGlobalKeys(appName, url, this.microAppWindow);
|
|
4842
4931
|
}
|
|
4843
4932
|
/**
|
|
4844
4933
|
* open sandbox and perform some initial actions
|
|
@@ -4849,38 +4938,38 @@ class WithSandBox {
|
|
|
4849
4938
|
* @param disablePatchRequest prevent patchRequestApi
|
|
4850
4939
|
*/
|
|
4851
4940
|
start({ umdMode, baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
4852
|
-
if (
|
|
4853
|
-
|
|
4854
|
-
|
|
4855
|
-
|
|
4856
|
-
|
|
4857
|
-
|
|
4858
|
-
this.initRouteState(defaultPage);
|
|
4859
|
-
// unique listener of popstate event for sub app
|
|
4860
|
-
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4861
|
-
}
|
|
4862
|
-
else {
|
|
4863
|
-
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
4864
|
-
}
|
|
4865
|
-
/**
|
|
4866
|
-
* Target: Ensure default mode action exactly same to first time when render again
|
|
4867
|
-
* 1. The following globalKey maybe modified when render, reset them when render again in default mode
|
|
4868
|
-
* 2. Umd mode will not delete any keys during sandBox.stop, ignore umd mode
|
|
4869
|
-
* 3. When sandbox.start called for the first time, it must be the default mode
|
|
4870
|
-
*/
|
|
4871
|
-
if (!umdMode) {
|
|
4872
|
-
this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
|
|
4873
|
-
}
|
|
4874
|
-
if (++globalEnv.activeSandbox === 1) {
|
|
4875
|
-
patchElementAndDocument();
|
|
4876
|
-
patchHistory();
|
|
4877
|
-
}
|
|
4878
|
-
if (++WithSandBox.activeCount === 1) {
|
|
4879
|
-
effectDocumentEvent();
|
|
4880
|
-
initEnvOfNestedApp();
|
|
4941
|
+
if (this.active)
|
|
4942
|
+
return;
|
|
4943
|
+
this.active = true;
|
|
4944
|
+
if (useMemoryRouter) {
|
|
4945
|
+
if (isUndefined(this.microAppWindow.location)) {
|
|
4946
|
+
this.setMicroAppRouter(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow);
|
|
4881
4947
|
}
|
|
4882
|
-
|
|
4948
|
+
this.initRouteState(defaultPage);
|
|
4949
|
+
// unique listener of popstate event for sub app
|
|
4950
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4951
|
+
}
|
|
4952
|
+
else {
|
|
4953
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
4954
|
+
}
|
|
4955
|
+
/**
|
|
4956
|
+
* Target: Ensure default mode action exactly same to first time when render again
|
|
4957
|
+
* 1. The following globalKey maybe modified when render, reset them when render again in default mode
|
|
4958
|
+
* 2. Umd mode will not delete any keys during sandBox.stop, ignore umd mode
|
|
4959
|
+
* 3. When sandbox.start called for the first time, it must be the default mode
|
|
4960
|
+
*/
|
|
4961
|
+
if (!umdMode) {
|
|
4962
|
+
this.initGlobalKeysWhenStart(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow, disablePatchRequest);
|
|
4963
|
+
}
|
|
4964
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
4965
|
+
patchElementAndDocument();
|
|
4966
|
+
patchHistory();
|
|
4967
|
+
}
|
|
4968
|
+
if (++WithSandBox.activeCount === 1) {
|
|
4969
|
+
// effectDocumentEvent()
|
|
4970
|
+
initEnvOfNestedApp();
|
|
4883
4971
|
}
|
|
4972
|
+
fixBabelPolyfill6();
|
|
4884
4973
|
}
|
|
4885
4974
|
/**
|
|
4886
4975
|
* close sandbox and perform some clean up actions
|
|
@@ -4890,39 +4979,61 @@ class WithSandBox {
|
|
|
4890
4979
|
* @param clearData clear data from base app
|
|
4891
4980
|
*/
|
|
4892
4981
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
4893
|
-
if (this.active)
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
4903
|
-
|
|
4904
|
-
|
|
4905
|
-
|
|
4906
|
-
|
|
4907
|
-
|
|
4908
|
-
|
|
4909
|
-
|
|
4910
|
-
|
|
4911
|
-
|
|
4912
|
-
|
|
4913
|
-
|
|
4914
|
-
|
|
4915
|
-
|
|
4916
|
-
|
|
4917
|
-
if (--globalEnv.activeSandbox === 0) {
|
|
4918
|
-
releasePatchElementAndDocument();
|
|
4919
|
-
releasePatchHistory();
|
|
4920
|
-
}
|
|
4921
|
-
if (--WithSandBox.activeCount === 0) {
|
|
4922
|
-
releaseEffectDocumentEvent();
|
|
4923
|
-
}
|
|
4924
|
-
this.active = false;
|
|
4982
|
+
if (!this.active)
|
|
4983
|
+
return;
|
|
4984
|
+
this.recordAndReleaseEffect({ umdMode, clearData, destroy }, !umdMode || destroy);
|
|
4985
|
+
if (this.removeHistoryListener) {
|
|
4986
|
+
this.clearRouteState(keepRouteState);
|
|
4987
|
+
// release listener of popstate
|
|
4988
|
+
this.removeHistoryListener();
|
|
4989
|
+
}
|
|
4990
|
+
/**
|
|
4991
|
+
* NOTE:
|
|
4992
|
+
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
4993
|
+
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
4994
|
+
* 3. umd mode will not delete global keys
|
|
4995
|
+
*/
|
|
4996
|
+
if (!umdMode || destroy) {
|
|
4997
|
+
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4998
|
+
this.injectedKeys.forEach((key) => {
|
|
4999
|
+
Reflect.deleteProperty(this.microAppWindow, key);
|
|
5000
|
+
});
|
|
5001
|
+
this.injectedKeys.clear();
|
|
5002
|
+
this.escapeKeys.forEach((key) => {
|
|
5003
|
+
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
5004
|
+
});
|
|
5005
|
+
this.escapeKeys.clear();
|
|
4925
5006
|
}
|
|
5007
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
5008
|
+
releasePatchElementAndDocument();
|
|
5009
|
+
releasePatchHistory();
|
|
5010
|
+
}
|
|
5011
|
+
if (--WithSandBox.activeCount === 0) ;
|
|
5012
|
+
this.active = false;
|
|
5013
|
+
}
|
|
5014
|
+
/**
|
|
5015
|
+
* inject global properties to microAppWindow
|
|
5016
|
+
* @param appName app name
|
|
5017
|
+
* @param url app url
|
|
5018
|
+
* @param microAppWindow micro window
|
|
5019
|
+
*/
|
|
5020
|
+
initStaticGlobalKeys(appName, url, microAppWindow) {
|
|
5021
|
+
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
5022
|
+
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
5023
|
+
microAppWindow.__MICRO_APP_URL__ = url;
|
|
5024
|
+
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
5025
|
+
microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
5026
|
+
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
5027
|
+
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
5028
|
+
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
5029
|
+
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
5030
|
+
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
5031
|
+
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
5032
|
+
removeDomScope,
|
|
5033
|
+
pureCreateElement,
|
|
5034
|
+
router,
|
|
5035
|
+
});
|
|
5036
|
+
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
4926
5037
|
}
|
|
4927
5038
|
/**
|
|
4928
5039
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -4953,7 +5064,8 @@ class WithSandBox {
|
|
|
4953
5064
|
* 2. unmount prerender app manually
|
|
4954
5065
|
*/
|
|
4955
5066
|
resetEffectSnapshot() {
|
|
4956
|
-
this.
|
|
5067
|
+
this.windowEffect.reset();
|
|
5068
|
+
this.documentEffect.reset();
|
|
4957
5069
|
resetDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4958
5070
|
}
|
|
4959
5071
|
/**
|
|
@@ -4964,20 +5076,14 @@ class WithSandBox {
|
|
|
4964
5076
|
* 3. after init prerender app
|
|
4965
5077
|
*/
|
|
4966
5078
|
recordEffectSnapshot() {
|
|
4967
|
-
|
|
4968
|
-
this.
|
|
5079
|
+
this.windowEffect.record();
|
|
5080
|
+
this.documentEffect.record();
|
|
4969
5081
|
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4970
|
-
// this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
|
|
4971
|
-
// this.injectedKeys.forEach((key: PropertyKey) => {
|
|
4972
|
-
// this.recordUmdInjectedValues!.set(key, Reflect.get(this.microAppWindow, key))
|
|
4973
|
-
// })
|
|
4974
5082
|
}
|
|
4975
5083
|
// rebuild umd snapshot before remount umd app
|
|
4976
5084
|
rebuildEffectSnapshot() {
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
// })
|
|
4980
|
-
this.effectController.rebuild();
|
|
5085
|
+
this.windowEffect.rebuild();
|
|
5086
|
+
this.documentEffect.rebuild();
|
|
4981
5087
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4982
5088
|
}
|
|
4983
5089
|
/**
|
|
@@ -4986,19 +5092,17 @@ class WithSandBox {
|
|
|
4986
5092
|
* 1. unmount of default/umd app
|
|
4987
5093
|
* 2. hidden keep-alive app
|
|
4988
5094
|
* 3. after init prerender app
|
|
5095
|
+
* @param umdMode is umd mode
|
|
4989
5096
|
* @param clearData clear data from base app
|
|
4990
5097
|
* @param isPrerender is prerender app
|
|
4991
5098
|
* @param keepAlive is keep-alive app
|
|
4992
5099
|
* @param destroy completely destroy
|
|
4993
5100
|
*/
|
|
4994
|
-
releaseGlobalEffect({ clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
5101
|
+
releaseGlobalEffect({ umdMode = false, clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
4995
5102
|
var _a, _b, _c;
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
keepAlive,
|
|
5000
|
-
destroy,
|
|
5001
|
-
});
|
|
5103
|
+
// default mode(not keep-alive or isPrerender)
|
|
5104
|
+
this.windowEffect.release((!umdMode && !keepAlive && !isPrerender) || destroy);
|
|
5105
|
+
this.documentEffect.release();
|
|
5002
5106
|
(_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
|
|
5003
5107
|
(_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
|
|
5004
5108
|
if (clearData) {
|
|
@@ -5034,10 +5138,10 @@ class WithSandBox {
|
|
|
5034
5138
|
}
|
|
5035
5139
|
}
|
|
5036
5140
|
// create proxyWindow with Proxy(microAppWindow)
|
|
5037
|
-
createProxyWindow(appName) {
|
|
5141
|
+
createProxyWindow(appName, microAppWindow) {
|
|
5038
5142
|
const rawWindow = globalEnv.rawWindow;
|
|
5039
5143
|
const descriptorTargetMap = new Map();
|
|
5040
|
-
return new Proxy(
|
|
5144
|
+
return new Proxy(microAppWindow, {
|
|
5041
5145
|
get: (target, key) => {
|
|
5042
5146
|
throttleDeferForSetAppName(appName);
|
|
5043
5147
|
if (Reflect.has(target, key) ||
|
|
@@ -5047,41 +5151,39 @@ class WithSandBox {
|
|
|
5047
5151
|
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
5048
5152
|
},
|
|
5049
5153
|
set: (target, key, value) => {
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
|
|
5058
|
-
|
|
5059
|
-
|
|
5060
|
-
|
|
5061
|
-
|
|
5062
|
-
|
|
5063
|
-
|
|
5064
|
-
|
|
5065
|
-
|
|
5066
|
-
|
|
5067
|
-
|
|
5068
|
-
|
|
5069
|
-
|
|
5070
|
-
|
|
5071
|
-
|
|
5072
|
-
|
|
5073
|
-
|
|
5074
|
-
|
|
5075
|
-
|
|
5076
|
-
|
|
5077
|
-
|
|
5078
|
-
|
|
5079
|
-
|
|
5080
|
-
|
|
5081
|
-
|
|
5082
|
-
|
|
5083
|
-
Reflect.set(rawWindow, key, value);
|
|
5084
|
-
}
|
|
5154
|
+
/**
|
|
5155
|
+
* TODO:
|
|
5156
|
+
* 1、location域名相同,子应用内部跳转时的处理
|
|
5157
|
+
*/
|
|
5158
|
+
if (this.adapter.escapeSetterKeyList.includes(key)) {
|
|
5159
|
+
Reflect.set(rawWindow, key, value);
|
|
5160
|
+
}
|
|
5161
|
+
else if (
|
|
5162
|
+
// target.hasOwnProperty has been rewritten
|
|
5163
|
+
!rawHasOwnProperty.call(target, key) &&
|
|
5164
|
+
rawHasOwnProperty.call(rawWindow, key) &&
|
|
5165
|
+
!this.scopeProperties.includes(key)) {
|
|
5166
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
5167
|
+
const { configurable, enumerable, writable, set } = descriptor;
|
|
5168
|
+
// set value because it can be set
|
|
5169
|
+
rawDefineProperty(target, key, {
|
|
5170
|
+
value,
|
|
5171
|
+
configurable,
|
|
5172
|
+
enumerable,
|
|
5173
|
+
writable: writable !== null && writable !== void 0 ? writable : !!set,
|
|
5174
|
+
});
|
|
5175
|
+
this.injectedKeys.add(key);
|
|
5176
|
+
}
|
|
5177
|
+
else {
|
|
5178
|
+
!Reflect.has(target, key) && this.injectedKeys.add(key);
|
|
5179
|
+
Reflect.set(target, key, value);
|
|
5180
|
+
}
|
|
5181
|
+
if ((this.escapeProperties.includes(key) ||
|
|
5182
|
+
(this.adapter.staticEscapeProperties.includes(key) &&
|
|
5183
|
+
!Reflect.has(rawWindow, key))) &&
|
|
5184
|
+
!this.scopeProperties.includes(key)) {
|
|
5185
|
+
!Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
|
|
5186
|
+
Reflect.set(rawWindow, key, value);
|
|
5085
5187
|
}
|
|
5086
5188
|
return true;
|
|
5087
5189
|
},
|
|
@@ -5123,46 +5225,29 @@ class WithSandBox {
|
|
|
5123
5225
|
this.injectedKeys.has(key) && this.injectedKeys.delete(key);
|
|
5124
5226
|
this.escapeKeys.has(key) && Reflect.deleteProperty(rawWindow, key);
|
|
5125
5227
|
return Reflect.deleteProperty(target, key);
|
|
5126
|
-
}
|
|
5127
|
-
return true;
|
|
5128
|
-
},
|
|
5129
|
-
});
|
|
5130
|
-
}
|
|
5131
|
-
// set __MICRO_APP_PRE_RENDER__ state
|
|
5132
|
-
setPreRenderState(state) {
|
|
5133
|
-
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
5134
|
-
}
|
|
5135
|
-
markUmdMode(state) {
|
|
5136
|
-
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
5228
|
+
}
|
|
5229
|
+
return true;
|
|
5230
|
+
},
|
|
5231
|
+
});
|
|
5137
5232
|
}
|
|
5138
5233
|
/**
|
|
5139
|
-
*
|
|
5140
|
-
* @param microAppWindow micro window
|
|
5234
|
+
* create proxyWindow, rewrite window event & timer of child app
|
|
5141
5235
|
* @param appName app name
|
|
5142
|
-
* @param
|
|
5143
|
-
* @param useMemoryRouter whether use memory router
|
|
5236
|
+
* @param microAppWindow Proxy target
|
|
5144
5237
|
*/
|
|
5145
|
-
|
|
5146
|
-
|
|
5147
|
-
|
|
5148
|
-
|
|
5149
|
-
|
|
5150
|
-
microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
5151
|
-
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
5152
|
-
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
5153
|
-
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
5154
|
-
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
5155
|
-
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
5156
|
-
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
5157
|
-
removeDomScope,
|
|
5158
|
-
pureCreateElement,
|
|
5159
|
-
router,
|
|
5160
|
-
});
|
|
5161
|
-
this.setProxyDocument(microAppWindow, appName);
|
|
5162
|
-
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
5238
|
+
patchWithWindow(appName, microAppWindow) {
|
|
5239
|
+
// create proxyWindow with Proxy(microAppWindow)
|
|
5240
|
+
this.proxyWindow = this.createProxyWindow(appName, microAppWindow);
|
|
5241
|
+
// rewrite global event & timeout of window
|
|
5242
|
+
return patchWindowEffect(appName, microAppWindow);
|
|
5163
5243
|
}
|
|
5164
|
-
|
|
5165
|
-
|
|
5244
|
+
/**
|
|
5245
|
+
* create proxyDocument and MicroDocument, rewrite document of child app
|
|
5246
|
+
* @param appName app name
|
|
5247
|
+
* @param microAppWindow Proxy target
|
|
5248
|
+
*/
|
|
5249
|
+
patchWithDocument(appName, microAppWindow) {
|
|
5250
|
+
const { proxyDocument, MicroDocument, documentEffect } = createProxyDocument(appName, this);
|
|
5166
5251
|
rawDefineProperties(microAppWindow, {
|
|
5167
5252
|
document: {
|
|
5168
5253
|
configurable: false,
|
|
@@ -5181,6 +5266,14 @@ class WithSandBox {
|
|
|
5181
5266
|
},
|
|
5182
5267
|
}
|
|
5183
5268
|
});
|
|
5269
|
+
return documentEffect;
|
|
5270
|
+
}
|
|
5271
|
+
// set __MICRO_APP_PRE_RENDER__ state
|
|
5272
|
+
setPreRenderState(state) {
|
|
5273
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
5274
|
+
}
|
|
5275
|
+
markUmdMode(state) {
|
|
5276
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
5184
5277
|
}
|
|
5185
5278
|
// properties associated with the native window
|
|
5186
5279
|
setMappingPropertiesWithRawDescriptor(microAppWindow) {
|
|
@@ -5193,6 +5286,7 @@ class WithSandBox {
|
|
|
5193
5286
|
topValue = rawWindow.top;
|
|
5194
5287
|
parentValue = rawWindow.parent;
|
|
5195
5288
|
}
|
|
5289
|
+
// TODO: 用rawDefineProperties
|
|
5196
5290
|
rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
|
|
5197
5291
|
rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
|
|
5198
5292
|
globalPropertyList$1.forEach((key) => {
|
|
@@ -5216,15 +5310,15 @@ class WithSandBox {
|
|
|
5216
5310
|
* @param url app url
|
|
5217
5311
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
5218
5312
|
*/
|
|
5219
|
-
initGlobalKeysWhenStart(
|
|
5313
|
+
initGlobalKeysWhenStart(appName, url, microAppWindow, disablePatchRequest) {
|
|
5220
5314
|
microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
|
|
5221
|
-
this.setHijackProperty(
|
|
5315
|
+
this.setHijackProperty(appName, microAppWindow);
|
|
5222
5316
|
if (!disablePatchRequest)
|
|
5223
|
-
this.patchRequestApi(
|
|
5317
|
+
this.patchRequestApi(appName, url, microAppWindow);
|
|
5224
5318
|
this.setScopeProperties(microAppWindow);
|
|
5225
5319
|
}
|
|
5226
5320
|
// set hijack Properties to microAppWindow
|
|
5227
|
-
setHijackProperty(
|
|
5321
|
+
setHijackProperty(appName, microAppWindow) {
|
|
5228
5322
|
let modifiedEval, modifiedImage;
|
|
5229
5323
|
rawDefineProperties(microAppWindow, {
|
|
5230
5324
|
eval: {
|
|
@@ -5252,7 +5346,7 @@ class WithSandBox {
|
|
|
5252
5346
|
});
|
|
5253
5347
|
}
|
|
5254
5348
|
// rewrite fetch, XMLHttpRequest, EventSource
|
|
5255
|
-
patchRequestApi(
|
|
5349
|
+
patchRequestApi(appName, url, microAppWindow) {
|
|
5256
5350
|
let microFetch = createMicroFetch(url);
|
|
5257
5351
|
let microXMLHttpRequest = createMicroXMLHttpRequest(url);
|
|
5258
5352
|
let microEventSource = createMicroEventSource(appName, url);
|
|
@@ -5302,7 +5396,7 @@ class WithSandBox {
|
|
|
5302
5396
|
});
|
|
5303
5397
|
}
|
|
5304
5398
|
// set location & history for memory router
|
|
5305
|
-
setMicroAppRouter(
|
|
5399
|
+
setMicroAppRouter(appName, url, microAppWindow) {
|
|
5306
5400
|
const { microLocation, microHistory } = createMicroRouter(appName, url);
|
|
5307
5401
|
rawDefineProperties(microAppWindow, {
|
|
5308
5402
|
location: {
|
|
@@ -5352,85 +5446,26 @@ class WithSandBox {
|
|
|
5352
5446
|
actionBeforeExecScripts(container) {
|
|
5353
5447
|
this.patchStaticElement(container);
|
|
5354
5448
|
}
|
|
5355
|
-
/**
|
|
5356
|
-
* Create new document and Document
|
|
5357
|
-
*/
|
|
5358
|
-
createProxyDocument(appName) {
|
|
5359
|
-
const rawDocument = globalEnv.rawDocument;
|
|
5360
|
-
const rawRootDocument = globalEnv.rawRootDocument;
|
|
5361
|
-
const createElement = function (tagName, options) {
|
|
5362
|
-
const element = globalEnv.rawCreateElement.call(rawDocument, tagName, options);
|
|
5363
|
-
element.__MICRO_APP_NAME__ = appName;
|
|
5364
|
-
return element;
|
|
5365
|
-
};
|
|
5366
|
-
const proxyDocument = new Proxy(rawDocument, {
|
|
5367
|
-
get: (target, key) => {
|
|
5368
|
-
throttleDeferForSetAppName(appName);
|
|
5369
|
-
throttleDeferForParentNode(proxyDocument);
|
|
5370
|
-
if (key === 'createElement')
|
|
5371
|
-
return createElement;
|
|
5372
|
-
if (key === Symbol.toStringTag)
|
|
5373
|
-
return 'ProxyDocument';
|
|
5374
|
-
if (key === 'defaultView')
|
|
5375
|
-
return this.proxyWindow;
|
|
5376
|
-
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
5377
|
-
},
|
|
5378
|
-
set: (target, key, value) => {
|
|
5379
|
-
/**
|
|
5380
|
-
* 1. Fix TypeError: Illegal invocation when set document.title
|
|
5381
|
-
* 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
5382
|
-
*/
|
|
5383
|
-
Reflect.set(target, key, value);
|
|
5384
|
-
return true;
|
|
5385
|
-
}
|
|
5386
|
-
});
|
|
5387
|
-
class MicroDocument {
|
|
5388
|
-
static [Symbol.hasInstance](target) {
|
|
5389
|
-
let proto = target;
|
|
5390
|
-
while (proto = Object.getPrototypeOf(proto)) {
|
|
5391
|
-
if (proto === MicroDocument.prototype) {
|
|
5392
|
-
return true;
|
|
5393
|
-
}
|
|
5394
|
-
}
|
|
5395
|
-
return (target === proxyDocument ||
|
|
5396
|
-
target instanceof rawRootDocument);
|
|
5397
|
-
}
|
|
5398
|
-
}
|
|
5399
|
-
/**
|
|
5400
|
-
* TIP:
|
|
5401
|
-
* 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
|
|
5402
|
-
* 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
|
|
5403
|
-
* e.g.
|
|
5404
|
-
* class B extends A {}
|
|
5405
|
-
* B.__proto__ === A // true
|
|
5406
|
-
* B.prototype.__proto__ === A.prototype // true
|
|
5407
|
-
*/
|
|
5408
|
-
Object.setPrototypeOf(MicroDocument, rawRootDocument);
|
|
5409
|
-
// Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
|
|
5410
|
-
Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
|
|
5411
|
-
get(target, key) {
|
|
5412
|
-
throttleDeferForSetAppName(appName);
|
|
5413
|
-
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
5414
|
-
},
|
|
5415
|
-
set(target, key, value) {
|
|
5416
|
-
Reflect.set(target, key, value);
|
|
5417
|
-
return true;
|
|
5418
|
-
}
|
|
5419
|
-
}));
|
|
5420
|
-
return {
|
|
5421
|
-
proxyDocument,
|
|
5422
|
-
MicroDocument,
|
|
5423
|
-
};
|
|
5424
|
-
}
|
|
5425
5449
|
}
|
|
5426
5450
|
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5427
5451
|
|
|
5428
|
-
function patchIframeRoute(appName, microAppWindow,
|
|
5452
|
+
function patchIframeRoute(appName, url, microAppWindow, browserHost) {
|
|
5453
|
+
const childStaticLocation = new URL(url);
|
|
5454
|
+
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
5455
|
+
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
5456
|
+
// rewrite microAppWindow.history
|
|
5429
5457
|
const microHistory = microAppWindow.history;
|
|
5430
5458
|
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5431
5459
|
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5432
|
-
|
|
5460
|
+
/**
|
|
5461
|
+
* Init microLocation before exec sandbox.start (sandbox.start will sync microLocation info to browser url)
|
|
5462
|
+
* NOTE:
|
|
5463
|
+
* 1. exec updateMicroLocation after patch microHistory
|
|
5464
|
+
* 2.
|
|
5465
|
+
*/
|
|
5433
5466
|
updateMicroLocation(appName, childFullPath, microAppWindow.location, 'prevent');
|
|
5467
|
+
// create proxyLocation
|
|
5468
|
+
return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
5434
5469
|
}
|
|
5435
5470
|
|
|
5436
5471
|
function patchIframeWindow(appName, microAppWindow) {
|
|
@@ -5496,15 +5531,16 @@ function patchIframeWindow(appName, microAppWindow) {
|
|
|
5496
5531
|
logWarn(e, appName);
|
|
5497
5532
|
}
|
|
5498
5533
|
});
|
|
5499
|
-
return
|
|
5534
|
+
return patchWindowEffect$1(microAppWindow);
|
|
5500
5535
|
}
|
|
5501
|
-
function
|
|
5502
|
-
const { rawWindow, rawAddEventListener, rawRemoveEventListener
|
|
5536
|
+
function patchWindowEffect$1(microAppWindow) {
|
|
5537
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5503
5538
|
const eventListenerMap = new Map();
|
|
5504
|
-
const
|
|
5539
|
+
const sstEventListenerMap = new Map();
|
|
5505
5540
|
function getEventTarget(type) {
|
|
5506
5541
|
return scopeIframeWindowEvent.includes(type) ? microAppWindow : rawWindow;
|
|
5507
5542
|
}
|
|
5543
|
+
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
5508
5544
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
5509
5545
|
const listenerList = eventListenerMap.get(type);
|
|
5510
5546
|
if (listenerList) {
|
|
@@ -5524,7 +5560,7 @@ function windowEffect(microAppWindow) {
|
|
|
5524
5560
|
rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
|
|
5525
5561
|
};
|
|
5526
5562
|
const reset = () => {
|
|
5527
|
-
|
|
5563
|
+
sstEventListenerMap.clear();
|
|
5528
5564
|
};
|
|
5529
5565
|
/**
|
|
5530
5566
|
* NOTE:
|
|
@@ -5542,14 +5578,15 @@ function windowEffect(microAppWindow) {
|
|
|
5542
5578
|
// record window event
|
|
5543
5579
|
eventListenerMap.forEach((listenerList, type) => {
|
|
5544
5580
|
if (listenerList.size) {
|
|
5545
|
-
|
|
5581
|
+
const cacheList = sstEventListenerMap.get(type) || [];
|
|
5582
|
+
sstEventListenerMap.set(type, new Set([...cacheList, ...listenerList]));
|
|
5546
5583
|
}
|
|
5547
5584
|
});
|
|
5548
5585
|
};
|
|
5549
5586
|
// rebuild event and timer before remount app
|
|
5550
5587
|
const rebuild = () => {
|
|
5551
5588
|
// rebuild window event
|
|
5552
|
-
|
|
5589
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
5553
5590
|
for (const listener of listenerList) {
|
|
5554
5591
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5555
5592
|
}
|
|
@@ -5583,18 +5620,26 @@ function windowEffect(microAppWindow) {
|
|
|
5583
5620
|
function patchIframeDocument(appName, microAppWindow, proxyLocation) {
|
|
5584
5621
|
patchDocumentPrototype(appName, microAppWindow);
|
|
5585
5622
|
patchDocumentProperties(appName, microAppWindow, proxyLocation);
|
|
5586
|
-
return
|
|
5623
|
+
return patchDocumentEffect(appName, microAppWindow);
|
|
5587
5624
|
}
|
|
5588
5625
|
function patchDocumentPrototype(appName, microAppWindow) {
|
|
5589
5626
|
const rawDocument = globalEnv.rawDocument;
|
|
5590
5627
|
const microRootDocument = microAppWindow.Document;
|
|
5591
5628
|
const microDocument = microAppWindow.document;
|
|
5629
|
+
const rawMicroCreateElement = microRootDocument.prototype.createElement;
|
|
5630
|
+
const rawMicroCreateTextNode = microRootDocument.prototype.createTextNode;
|
|
5631
|
+
const rawMicroQuerySelector = microRootDocument.prototype.querySelector;
|
|
5632
|
+
const rawMicroQuerySelectorAll = microRootDocument.prototype.querySelectorAll;
|
|
5633
|
+
const rawMicroGetElementById = microRootDocument.prototype.getElementById;
|
|
5634
|
+
const rawMicroGetElementsByClassName = microRootDocument.prototype.getElementsByClassName;
|
|
5635
|
+
const rawMicroGetElementsByTagName = microRootDocument.prototype.getElementsByTagName;
|
|
5636
|
+
const rawMicroGetElementsByName = microRootDocument.prototype.getElementsByName;
|
|
5592
5637
|
microRootDocument.prototype.createElement = function createElement(tagName, options) {
|
|
5593
|
-
const element =
|
|
5638
|
+
const element = rawMicroCreateElement.call(this, tagName, options);
|
|
5594
5639
|
return updateElementInfo(element, appName);
|
|
5595
5640
|
};
|
|
5596
5641
|
microRootDocument.prototype.createTextNode = function createTextNode(data) {
|
|
5597
|
-
const element =
|
|
5642
|
+
const element = rawMicroCreateTextNode.call(this, data);
|
|
5598
5643
|
return updateElementInfo(element, appName);
|
|
5599
5644
|
};
|
|
5600
5645
|
function getDefaultRawTarget(target) {
|
|
@@ -5603,19 +5648,21 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5603
5648
|
// query element👇
|
|
5604
5649
|
function querySelector(selectors) {
|
|
5605
5650
|
var _a, _b;
|
|
5606
|
-
if (
|
|
5651
|
+
if (!selectors ||
|
|
5652
|
+
isUniqueElement(selectors) ||
|
|
5607
5653
|
microDocument !== this) {
|
|
5608
5654
|
const _this = getDefaultRawTarget(this);
|
|
5609
|
-
return
|
|
5655
|
+
return rawMicroQuerySelector.call(_this, selectors);
|
|
5610
5656
|
}
|
|
5611
5657
|
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
5612
5658
|
}
|
|
5613
5659
|
function querySelectorAll(selectors) {
|
|
5614
5660
|
var _a, _b;
|
|
5615
|
-
if (
|
|
5661
|
+
if (!selectors ||
|
|
5662
|
+
isUniqueElement(selectors) ||
|
|
5616
5663
|
microDocument !== this) {
|
|
5617
5664
|
const _this = getDefaultRawTarget(this);
|
|
5618
|
-
return
|
|
5665
|
+
return rawMicroQuerySelectorAll.call(_this, selectors);
|
|
5619
5666
|
}
|
|
5620
5667
|
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
5621
5668
|
}
|
|
@@ -5624,25 +5671,25 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5624
5671
|
microRootDocument.prototype.getElementById = function getElementById(key) {
|
|
5625
5672
|
const _this = getDefaultRawTarget(this);
|
|
5626
5673
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5627
|
-
return
|
|
5674
|
+
return rawMicroGetElementById.call(_this, key);
|
|
5628
5675
|
}
|
|
5629
5676
|
try {
|
|
5630
5677
|
return querySelector.call(this, `#${key}`);
|
|
5631
5678
|
}
|
|
5632
5679
|
catch (_a) {
|
|
5633
|
-
return
|
|
5680
|
+
return rawMicroGetElementById.call(_this, key);
|
|
5634
5681
|
}
|
|
5635
5682
|
};
|
|
5636
5683
|
microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
5637
5684
|
const _this = getDefaultRawTarget(this);
|
|
5638
5685
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5639
|
-
return
|
|
5686
|
+
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5640
5687
|
}
|
|
5641
5688
|
try {
|
|
5642
5689
|
return querySelectorAll.call(this, `.${key}`);
|
|
5643
5690
|
}
|
|
5644
5691
|
catch (_a) {
|
|
5645
|
-
return
|
|
5692
|
+
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5646
5693
|
}
|
|
5647
5694
|
};
|
|
5648
5695
|
microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
@@ -5651,25 +5698,25 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5651
5698
|
if (isUniqueElement(key) ||
|
|
5652
5699
|
isInvalidQuerySelectorKey(key) ||
|
|
5653
5700
|
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
5654
|
-
return
|
|
5701
|
+
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5655
5702
|
}
|
|
5656
5703
|
try {
|
|
5657
5704
|
return querySelectorAll.call(this, key);
|
|
5658
5705
|
}
|
|
5659
5706
|
catch (_b) {
|
|
5660
|
-
return
|
|
5707
|
+
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5661
5708
|
}
|
|
5662
5709
|
};
|
|
5663
5710
|
microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
|
|
5664
5711
|
const _this = getDefaultRawTarget(this);
|
|
5665
5712
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5666
|
-
return
|
|
5713
|
+
return rawMicroGetElementsByName.call(_this, key);
|
|
5667
5714
|
}
|
|
5668
5715
|
try {
|
|
5669
5716
|
return querySelectorAll.call(this, `[name=${key}]`);
|
|
5670
5717
|
}
|
|
5671
5718
|
catch (_a) {
|
|
5672
|
-
return
|
|
5719
|
+
return rawMicroGetElementsByName.call(_this, key);
|
|
5673
5720
|
}
|
|
5674
5721
|
};
|
|
5675
5722
|
}
|
|
@@ -5725,46 +5772,37 @@ function patchDocumentProperties(appName, microAppWindow, proxyLocation) {
|
|
|
5725
5772
|
enumerable: true,
|
|
5726
5773
|
configurable: true,
|
|
5727
5774
|
get: () => rawDocument[tagName],
|
|
5728
|
-
set:
|
|
5775
|
+
set: (value) => { rawDocument[tagName] = value; },
|
|
5729
5776
|
});
|
|
5730
5777
|
});
|
|
5731
5778
|
}
|
|
5732
|
-
function
|
|
5733
|
-
const
|
|
5734
|
-
const
|
|
5779
|
+
function patchDocumentEffect(appName, microAppWindow) {
|
|
5780
|
+
const { rawDocument, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5781
|
+
const eventListenerMap = new Map();
|
|
5782
|
+
const sstEventListenerMap = new Map();
|
|
5735
5783
|
let onClickHandler = null;
|
|
5736
5784
|
let sstOnClickHandler = null;
|
|
5737
5785
|
const microRootDocument = microAppWindow.Document;
|
|
5738
5786
|
const microDocument = microAppWindow.document;
|
|
5739
|
-
const { rawDocument, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
5740
5787
|
function getEventTarget(type, bindTarget) {
|
|
5741
5788
|
return scopeIframeDocumentEvent.includes(type) ? bindTarget : rawDocument;
|
|
5742
5789
|
}
|
|
5743
5790
|
microRootDocument.prototype.addEventListener = function (type, listener, options) {
|
|
5744
5791
|
const handler = isFunction(listener) ? (listener.__MICRO_APP_BOUND_FUNCTION__ = listener.__MICRO_APP_BOUND_FUNCTION__ || listener.bind(this)) : listener;
|
|
5745
|
-
const
|
|
5746
|
-
if (
|
|
5747
|
-
|
|
5748
|
-
if (appListenerList) {
|
|
5749
|
-
appListenerList.add(listener);
|
|
5750
|
-
}
|
|
5751
|
-
else {
|
|
5752
|
-
appListenersMap.set(type, new Set([listener]));
|
|
5753
|
-
}
|
|
5792
|
+
const listenerList = eventListenerMap.get(type);
|
|
5793
|
+
if (listenerList) {
|
|
5794
|
+
listenerList.add(listener);
|
|
5754
5795
|
}
|
|
5755
5796
|
else {
|
|
5756
|
-
|
|
5797
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
5757
5798
|
}
|
|
5758
5799
|
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
5759
5800
|
rawAddEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5760
5801
|
};
|
|
5761
5802
|
microRootDocument.prototype.removeEventListener = function (type, listener, options) {
|
|
5762
|
-
const
|
|
5763
|
-
if (
|
|
5764
|
-
|
|
5765
|
-
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
5766
|
-
appListenerList.delete(listener);
|
|
5767
|
-
}
|
|
5803
|
+
const listenerList = eventListenerMap.get(type);
|
|
5804
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
5805
|
+
listenerList.delete(listener);
|
|
5768
5806
|
}
|
|
5769
5807
|
const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
|
|
5770
5808
|
rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
@@ -5816,7 +5854,7 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5816
5854
|
}
|
|
5817
5855
|
});
|
|
5818
5856
|
const reset = () => {
|
|
5819
|
-
|
|
5857
|
+
sstEventListenerMap.clear();
|
|
5820
5858
|
sstOnClickHandler = null;
|
|
5821
5859
|
};
|
|
5822
5860
|
/**
|
|
@@ -5829,24 +5867,25 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5829
5867
|
* 3. after init prerender app
|
|
5830
5868
|
*/
|
|
5831
5869
|
const record = () => {
|
|
5832
|
-
|
|
5833
|
-
|
|
5870
|
+
/**
|
|
5871
|
+
* record onclick handler
|
|
5872
|
+
* onClickHandler maybe set again after prerender/keep-alive app hidden
|
|
5873
|
+
*/
|
|
5874
|
+
sstOnClickHandler = onClickHandler || sstOnClickHandler;
|
|
5834
5875
|
// record document event
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
|
|
5841
|
-
});
|
|
5842
|
-
}
|
|
5876
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5877
|
+
if (listenerList.size) {
|
|
5878
|
+
const cacheList = sstEventListenerMap.get(type) || [];
|
|
5879
|
+
sstEventListenerMap.set(type, new Set([...cacheList, ...listenerList]));
|
|
5880
|
+
}
|
|
5881
|
+
});
|
|
5843
5882
|
};
|
|
5844
5883
|
// rebuild event and timer before remount app
|
|
5845
5884
|
const rebuild = () => {
|
|
5846
5885
|
// rebuild onclick event
|
|
5847
|
-
if (sstOnClickHandler)
|
|
5886
|
+
if (sstOnClickHandler && !onClickHandler)
|
|
5848
5887
|
microDocument.onclick = sstOnClickHandler;
|
|
5849
|
-
|
|
5888
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
5850
5889
|
for (const listener of listenerList) {
|
|
5851
5890
|
microDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5852
5891
|
}
|
|
@@ -5854,20 +5893,19 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5854
5893
|
reset();
|
|
5855
5894
|
};
|
|
5856
5895
|
const release = () => {
|
|
5857
|
-
// Clear the function bound by micro
|
|
5896
|
+
// Clear the function bound by micro app through document.onclick
|
|
5858
5897
|
if (isFunction(onClickHandler)) {
|
|
5859
5898
|
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
|
|
5860
|
-
onClickHandler = null;
|
|
5861
5899
|
}
|
|
5900
|
+
onClickHandler = null;
|
|
5862
5901
|
// Clear document binding event
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
5902
|
+
if (eventListenerMap.size) {
|
|
5903
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5866
5904
|
for (const listener of listenerList) {
|
|
5867
5905
|
rawRemoveEventListener.call(getEventTarget(type, microDocument), type, (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener);
|
|
5868
5906
|
}
|
|
5869
5907
|
});
|
|
5870
|
-
|
|
5908
|
+
eventListenerMap.clear();
|
|
5871
5909
|
}
|
|
5872
5910
|
};
|
|
5873
5911
|
return {
|
|
@@ -5878,33 +5916,38 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5878
5916
|
};
|
|
5879
5917
|
}
|
|
5880
5918
|
|
|
5881
|
-
function patchIframeElement(appName, url, microAppWindow,
|
|
5882
|
-
patchIframeNode(appName, microAppWindow,
|
|
5919
|
+
function patchIframeElement(appName, url, microAppWindow, sandbox) {
|
|
5920
|
+
patchIframeNode(appName, microAppWindow, sandbox);
|
|
5883
5921
|
patchIframeAttribute(appName, url, microAppWindow);
|
|
5884
5922
|
}
|
|
5885
|
-
function patchIframeNode(appName, microAppWindow,
|
|
5886
|
-
const
|
|
5923
|
+
function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
5924
|
+
const rawRootElement = globalEnv.rawRootElement; // native root Element
|
|
5887
5925
|
const rawDocument = globalEnv.rawDocument;
|
|
5926
|
+
const microDocument = microAppWindow.document;
|
|
5888
5927
|
const microRootNode = microAppWindow.Node;
|
|
5889
5928
|
const microRootElement = microAppWindow.Element;
|
|
5890
5929
|
// const rawMicroGetRootNode = microRootNode.prototype.getRootNode
|
|
5891
5930
|
const rawMicroAppendChild = microRootNode.prototype.appendChild;
|
|
5892
5931
|
const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
|
|
5893
5932
|
const rawMicroReplaceChild = microRootNode.prototype.replaceChild;
|
|
5933
|
+
const rawMicroRemoveChild = microRootNode.prototype.removeChild;
|
|
5934
|
+
const rawMicroAppend = microRootElement.prototype.append;
|
|
5935
|
+
const rawMicroPrepend = microRootElement.prototype.prepend;
|
|
5936
|
+
const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
|
|
5894
5937
|
const rawMicroCloneNode = microRootNode.prototype.cloneNode;
|
|
5895
5938
|
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
|
|
5896
5939
|
const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
|
|
5897
5940
|
const isPureNode = (target) => {
|
|
5898
5941
|
return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
|
|
5899
5942
|
};
|
|
5900
|
-
const getRawTarget = (
|
|
5901
|
-
if (
|
|
5943
|
+
const getRawTarget = (parent) => {
|
|
5944
|
+
if (parent === sandbox.microHead) {
|
|
5902
5945
|
return rawDocument.head;
|
|
5903
5946
|
}
|
|
5904
|
-
else if (
|
|
5947
|
+
else if (parent === sandbox.microBody) {
|
|
5905
5948
|
return rawDocument.body;
|
|
5906
5949
|
}
|
|
5907
|
-
return
|
|
5950
|
+
return parent;
|
|
5908
5951
|
};
|
|
5909
5952
|
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
5910
5953
|
return microDocument;
|
|
@@ -5915,46 +5958,70 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5915
5958
|
};
|
|
5916
5959
|
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5917
5960
|
updateElementInfo(node, appName);
|
|
5918
|
-
// TODO:只有script才可以这样拦截,link、style不应该拦截
|
|
5919
5961
|
if (isPureNode(node)) {
|
|
5920
5962
|
return rawMicroAppendChild.call(this, node);
|
|
5921
5963
|
}
|
|
5922
|
-
|
|
5923
|
-
if (_this !== this) {
|
|
5924
|
-
return _this.appendChild(node);
|
|
5925
|
-
}
|
|
5926
|
-
return rawMicroAppendChild.call(_this, node);
|
|
5964
|
+
return rawRootElement.prototype.appendChild.call(getRawTarget(this), node);
|
|
5927
5965
|
};
|
|
5928
|
-
// TODO: 更多场景适配
|
|
5929
5966
|
microRootNode.prototype.insertBefore = function insertBefore(node, child) {
|
|
5930
5967
|
updateElementInfo(node, appName);
|
|
5931
5968
|
if (isPureNode(node)) {
|
|
5932
5969
|
return rawMicroInsertBefore.call(this, node, child);
|
|
5933
5970
|
}
|
|
5934
|
-
|
|
5935
|
-
if (_this !== this) {
|
|
5936
|
-
if (child && !_this.contains(child)) {
|
|
5937
|
-
return _this.appendChild(node);
|
|
5938
|
-
}
|
|
5939
|
-
return _this.insertBefore(node, child);
|
|
5940
|
-
}
|
|
5941
|
-
return rawMicroInsertBefore.call(_this, node, child);
|
|
5971
|
+
return rawRootElement.prototype.insertBefore.call(getRawTarget(this), node, child);
|
|
5942
5972
|
};
|
|
5943
|
-
// TODO: 更多场景适配
|
|
5944
5973
|
microRootNode.prototype.replaceChild = function replaceChild(node, child) {
|
|
5945
5974
|
updateElementInfo(node, appName);
|
|
5946
5975
|
if (isPureNode(node)) {
|
|
5947
5976
|
return rawMicroReplaceChild.call(this, node, child);
|
|
5948
5977
|
}
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5978
|
+
return rawRootElement.prototype.replaceChild.call(getRawTarget(this), node, child);
|
|
5979
|
+
};
|
|
5980
|
+
microRootNode.prototype.removeChild = function removeChild(oldChild) {
|
|
5981
|
+
if (isPureNode(oldChild) || this.contains(oldChild)) {
|
|
5982
|
+
return rawMicroRemoveChild.call(this, oldChild);
|
|
5983
|
+
}
|
|
5984
|
+
return rawRootElement.prototype.removeChild.call(getRawTarget(this), oldChild);
|
|
5985
|
+
};
|
|
5986
|
+
microRootElement.prototype.append = function append(...nodes) {
|
|
5987
|
+
let i = 0;
|
|
5988
|
+
let hasPureNode = false;
|
|
5989
|
+
while (i < nodes.length) {
|
|
5990
|
+
nodes[i] = isNode(nodes[i]) ? nodes[i] : microDocument.createTextNode(nodes[i]);
|
|
5991
|
+
if (isPureNode(nodes[i]))
|
|
5992
|
+
hasPureNode = true;
|
|
5993
|
+
i++;
|
|
5994
|
+
}
|
|
5995
|
+
if (hasPureNode) {
|
|
5996
|
+
return rawMicroAppend.call(this, ...nodes);
|
|
5997
|
+
}
|
|
5998
|
+
return rawRootElement.prototype.append.call(getRawTarget(this), ...nodes);
|
|
5999
|
+
};
|
|
6000
|
+
microRootElement.prototype.prepend = function prepend(...nodes) {
|
|
6001
|
+
let i = 0;
|
|
6002
|
+
let hasPureNode = false;
|
|
6003
|
+
while (i < nodes.length) {
|
|
6004
|
+
nodes[i] = isNode(nodes[i]) ? nodes[i] : microDocument.createTextNode(nodes[i]);
|
|
6005
|
+
if (isPureNode(nodes[i]))
|
|
6006
|
+
hasPureNode = true;
|
|
6007
|
+
i++;
|
|
6008
|
+
}
|
|
6009
|
+
if (hasPureNode) {
|
|
6010
|
+
return rawMicroPrepend.call(this, ...nodes);
|
|
6011
|
+
}
|
|
6012
|
+
return rawRootElement.prototype.prepend.call(getRawTarget(this), ...nodes);
|
|
6013
|
+
};
|
|
6014
|
+
/**
|
|
6015
|
+
* The insertAdjacentElement method of the Element interface inserts a given element node at a given position relative to the element it is invoked upon.
|
|
6016
|
+
* Scenes:
|
|
6017
|
+
* 1. vite4 development env for style
|
|
6018
|
+
*/
|
|
6019
|
+
microRootElement.prototype.insertAdjacentElement = function insertAdjacentElement(where, element) {
|
|
6020
|
+
updateElementInfo(element, appName);
|
|
6021
|
+
if (isPureNode(element)) {
|
|
6022
|
+
return rawMicroInsertAdjacentElement.call(this, where, element);
|
|
5956
6023
|
}
|
|
5957
|
-
return
|
|
6024
|
+
return rawRootElement.prototype.insertAdjacentElement.call(getRawTarget(this), where, element);
|
|
5958
6025
|
};
|
|
5959
6026
|
// patch cloneNode
|
|
5960
6027
|
microRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
@@ -5999,7 +6066,6 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5999
6066
|
}
|
|
6000
6067
|
return result;
|
|
6001
6068
|
},
|
|
6002
|
-
set: undefined,
|
|
6003
6069
|
});
|
|
6004
6070
|
// Adapt to new image(...) scene
|
|
6005
6071
|
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
@@ -6039,6 +6105,12 @@ function patchIframeAttribute(appName, url, microAppWindow) {
|
|
|
6039
6105
|
[microAppWindow.HTMLScriptElement.prototype, 'src'],
|
|
6040
6106
|
[microAppWindow.HTMLLinkElement.prototype, 'href'],
|
|
6041
6107
|
];
|
|
6108
|
+
/**
|
|
6109
|
+
* element.setAttribute does not trigger this actions:
|
|
6110
|
+
* 1. img.src = xxx
|
|
6111
|
+
* 2. script.src = xxx
|
|
6112
|
+
* 3. link.href = xxx
|
|
6113
|
+
*/
|
|
6042
6114
|
protoAttrList.forEach(([target, attr]) => {
|
|
6043
6115
|
const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
|
|
6044
6116
|
enumerable: true,
|
|
@@ -6071,23 +6143,30 @@ class IframeSandbox {
|
|
|
6071
6143
|
};
|
|
6072
6144
|
const rawLocation = globalEnv.rawWindow.location;
|
|
6073
6145
|
const browserHost = rawLocation.protocol + '//' + rawLocation.host;
|
|
6074
|
-
const childStaticLocation = new URL(url);
|
|
6075
|
-
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
6076
|
-
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
6077
6146
|
this.deleteIframeElement = this.createIframeElement(appName, browserHost);
|
|
6078
6147
|
this.microAppWindow = this.iframe.contentWindow;
|
|
6079
6148
|
this.patchIframe(this.microAppWindow, (resolve) => {
|
|
6080
6149
|
// TODO: 优化代码
|
|
6081
|
-
//
|
|
6082
|
-
this.
|
|
6083
|
-
this.createProxyWindow(this.microAppWindow);
|
|
6084
|
-
this.initStaticGlobalKeys(appName, url);
|
|
6150
|
+
// create new html to iframe
|
|
6151
|
+
this.createIframeTemplate(this.microAppWindow);
|
|
6085
6152
|
// get escapeProperties from plugins
|
|
6086
6153
|
this.getSpecialProperties(appName);
|
|
6087
|
-
|
|
6088
|
-
patchIframeRoute(appName, this.microAppWindow,
|
|
6154
|
+
// rewrite location & history of child app
|
|
6155
|
+
this.proxyLocation = patchIframeRoute(appName, url, this.microAppWindow, browserHost);
|
|
6156
|
+
// create proxy window
|
|
6157
|
+
this.proxyWindow = this.createProxyWindow(this.microAppWindow);
|
|
6158
|
+
/**
|
|
6159
|
+
* create static properties
|
|
6160
|
+
* NOTE:
|
|
6161
|
+
* 1. execute as early as possible
|
|
6162
|
+
* 2. run after patchIframeRoute & createProxyWindow
|
|
6163
|
+
*/
|
|
6164
|
+
this.initStaticGlobalKeys(appName, url);
|
|
6165
|
+
// rewrite window of child app
|
|
6089
6166
|
this.windowEffect = patchIframeWindow(appName, this.microAppWindow);
|
|
6167
|
+
// rewrite document of child app
|
|
6090
6168
|
this.documentEffect = patchIframeDocument(appName, this.microAppWindow, this.proxyLocation);
|
|
6169
|
+
// rewrite Node & Element of child app
|
|
6091
6170
|
patchIframeElement(appName, url, this.microAppWindow, this);
|
|
6092
6171
|
resolve();
|
|
6093
6172
|
});
|
|
@@ -6124,53 +6203,78 @@ class IframeSandbox {
|
|
|
6124
6203
|
});
|
|
6125
6204
|
}
|
|
6126
6205
|
start({ baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
6127
|
-
if (
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
}
|
|
6145
|
-
if (++globalEnv.activeSandbox === 1) {
|
|
6146
|
-
patchElementAndDocument();
|
|
6147
|
-
patchHistory();
|
|
6148
|
-
}
|
|
6149
|
-
if (++IframeSandbox.activeCount === 1) ;
|
|
6206
|
+
if (this.active)
|
|
6207
|
+
return;
|
|
6208
|
+
this.active = true;
|
|
6209
|
+
if (useMemoryRouter) {
|
|
6210
|
+
this.initRouteState(defaultPage);
|
|
6211
|
+
// unique listener of popstate event for sub app
|
|
6212
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
6213
|
+
}
|
|
6214
|
+
else {
|
|
6215
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
6216
|
+
}
|
|
6217
|
+
/**
|
|
6218
|
+
* create base element to iframe
|
|
6219
|
+
* WARNING: This will also affect a, image, link and script
|
|
6220
|
+
*/
|
|
6221
|
+
if (!disablePatchRequest) {
|
|
6222
|
+
this.createIframeBase();
|
|
6150
6223
|
}
|
|
6224
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
6225
|
+
patchElementAndDocument();
|
|
6226
|
+
patchHistory();
|
|
6227
|
+
}
|
|
6228
|
+
if (++IframeSandbox.activeCount === 1) ;
|
|
6151
6229
|
}
|
|
6152
6230
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
6153
|
-
if (this.active)
|
|
6154
|
-
|
|
6155
|
-
|
|
6156
|
-
|
|
6157
|
-
|
|
6158
|
-
|
|
6159
|
-
|
|
6160
|
-
|
|
6161
|
-
|
|
6162
|
-
|
|
6163
|
-
|
|
6164
|
-
|
|
6165
|
-
|
|
6166
|
-
|
|
6167
|
-
if (--globalEnv.activeSandbox === 0) {
|
|
6168
|
-
releasePatchElementAndDocument();
|
|
6169
|
-
releasePatchHistory();
|
|
6170
|
-
}
|
|
6171
|
-
if (--IframeSandbox.activeCount === 0) ;
|
|
6172
|
-
this.active = false;
|
|
6231
|
+
if (!this.active)
|
|
6232
|
+
return;
|
|
6233
|
+
this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
|
|
6234
|
+
if (this.removeHistoryListener) {
|
|
6235
|
+
this.clearRouteState(keepRouteState);
|
|
6236
|
+
// release listener of popstate
|
|
6237
|
+
this.removeHistoryListener();
|
|
6238
|
+
}
|
|
6239
|
+
if (!umdMode || destroy) {
|
|
6240
|
+
this.deleteIframeElement();
|
|
6241
|
+
this.escapeKeys.forEach((key) => {
|
|
6242
|
+
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
6243
|
+
});
|
|
6244
|
+
this.escapeKeys.clear();
|
|
6173
6245
|
}
|
|
6246
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
6247
|
+
releasePatchElementAndDocument();
|
|
6248
|
+
releasePatchHistory();
|
|
6249
|
+
}
|
|
6250
|
+
if (--IframeSandbox.activeCount === 0) ;
|
|
6251
|
+
this.active = false;
|
|
6252
|
+
}
|
|
6253
|
+
/**
|
|
6254
|
+
* create static properties
|
|
6255
|
+
* NOTE:
|
|
6256
|
+
* 1. execute as early as possible
|
|
6257
|
+
* 2. run after patchIframeRoute & createProxyWindow
|
|
6258
|
+
*/
|
|
6259
|
+
initStaticGlobalKeys(appName, url) {
|
|
6260
|
+
this.microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
6261
|
+
this.microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
6262
|
+
this.microAppWindow.__MICRO_APP_URL__ = url;
|
|
6263
|
+
this.microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
6264
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
6265
|
+
this.microAppWindow.__MICRO_APP_WINDOW__ = this.microAppWindow;
|
|
6266
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
6267
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
6268
|
+
this.microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
6269
|
+
this.microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
6270
|
+
this.microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
6271
|
+
this.microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
6272
|
+
this.microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
6273
|
+
removeDomScope,
|
|
6274
|
+
pureCreateElement,
|
|
6275
|
+
location: this.proxyLocation,
|
|
6276
|
+
router,
|
|
6277
|
+
});
|
|
6174
6278
|
}
|
|
6175
6279
|
/**
|
|
6176
6280
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -6201,8 +6305,9 @@ class IframeSandbox {
|
|
|
6201
6305
|
* 2. unmount prerender app manually
|
|
6202
6306
|
*/
|
|
6203
6307
|
resetEffectSnapshot() {
|
|
6204
|
-
|
|
6205
|
-
this.
|
|
6308
|
+
var _a, _b;
|
|
6309
|
+
(_a = this.windowEffect) === null || _a === void 0 ? void 0 : _a.reset();
|
|
6310
|
+
(_b = this.documentEffect) === null || _b === void 0 ? void 0 : _b.reset();
|
|
6206
6311
|
resetDataCenterSnapshot(this.microAppWindow.microApp);
|
|
6207
6312
|
}
|
|
6208
6313
|
/**
|
|
@@ -6213,14 +6318,16 @@ class IframeSandbox {
|
|
|
6213
6318
|
* 3. after init prerender app
|
|
6214
6319
|
*/
|
|
6215
6320
|
recordEffectSnapshot() {
|
|
6216
|
-
|
|
6217
|
-
this.
|
|
6321
|
+
var _a, _b;
|
|
6322
|
+
(_a = this.windowEffect) === null || _a === void 0 ? void 0 : _a.record();
|
|
6323
|
+
(_b = this.documentEffect) === null || _b === void 0 ? void 0 : _b.record();
|
|
6218
6324
|
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
6219
6325
|
}
|
|
6220
6326
|
// rebuild umd snapshot before remount umd app
|
|
6221
6327
|
rebuildEffectSnapshot() {
|
|
6222
|
-
|
|
6223
|
-
this.
|
|
6328
|
+
var _a, _b;
|
|
6329
|
+
(_a = this.windowEffect) === null || _a === void 0 ? void 0 : _a.rebuild();
|
|
6330
|
+
(_b = this.documentEffect) === null || _b === void 0 ? void 0 : _b.rebuild();
|
|
6224
6331
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
6225
6332
|
}
|
|
6226
6333
|
/**
|
|
@@ -6234,43 +6341,24 @@ class IframeSandbox {
|
|
|
6234
6341
|
* @param keepAlive is keep-alive app
|
|
6235
6342
|
*/
|
|
6236
6343
|
releaseGlobalEffect({ clearData = false }) {
|
|
6237
|
-
var _a, _b, _c;
|
|
6238
|
-
this.windowEffect.release();
|
|
6239
|
-
this.documentEffect.release();
|
|
6240
|
-
(
|
|
6241
|
-
(
|
|
6344
|
+
var _a, _b, _c, _d, _e;
|
|
6345
|
+
(_a = this.windowEffect) === null || _a === void 0 ? void 0 : _a.release();
|
|
6346
|
+
(_b = this.documentEffect) === null || _b === void 0 ? void 0 : _b.release();
|
|
6347
|
+
(_c = this.microAppWindow.microApp) === null || _c === void 0 ? void 0 : _c.clearDataListener();
|
|
6348
|
+
(_d = this.microAppWindow.microApp) === null || _d === void 0 ? void 0 : _d.clearGlobalDataListener();
|
|
6242
6349
|
if (clearData) {
|
|
6243
6350
|
microApp.clearData(this.microAppWindow.__MICRO_APP_NAME__);
|
|
6244
|
-
(
|
|
6351
|
+
(_e = this.microAppWindow.microApp) === null || _e === void 0 ? void 0 : _e.clearData();
|
|
6245
6352
|
}
|
|
6246
6353
|
}
|
|
6247
6354
|
// set __MICRO_APP_PRE_RENDER__ state
|
|
6248
6355
|
setPreRenderState(state) {
|
|
6249
6356
|
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
6250
6357
|
}
|
|
6358
|
+
// record umdMode
|
|
6251
6359
|
markUmdMode(state) {
|
|
6252
6360
|
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
6253
6361
|
}
|
|
6254
|
-
initStaticGlobalKeys(appName, url) {
|
|
6255
|
-
this.microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
6256
|
-
this.microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
6257
|
-
this.microAppWindow.__MICRO_APP_URL__ = url;
|
|
6258
|
-
this.microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
6259
|
-
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
6260
|
-
this.microAppWindow.__MICRO_APP_WINDOW__ = this.microAppWindow;
|
|
6261
|
-
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
6262
|
-
this.microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
6263
|
-
this.microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
6264
|
-
this.microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
6265
|
-
this.microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
6266
|
-
this.microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
6267
|
-
this.microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
6268
|
-
removeDomScope,
|
|
6269
|
-
pureCreateElement,
|
|
6270
|
-
location: this.proxyLocation,
|
|
6271
|
-
router,
|
|
6272
|
-
});
|
|
6273
|
-
}
|
|
6274
6362
|
// TODO: RESTRUCTURE
|
|
6275
6363
|
patchIframe(microAppWindow, cb) {
|
|
6276
6364
|
const oldMicroDocument = microAppWindow.document;
|
|
@@ -6319,12 +6407,9 @@ class IframeSandbox {
|
|
|
6319
6407
|
this.updateIframeBase();
|
|
6320
6408
|
this.microHead.appendChild(this.baseElement);
|
|
6321
6409
|
}
|
|
6322
|
-
createProxyLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
|
|
6323
|
-
this.proxyLocation = createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
6324
|
-
}
|
|
6325
6410
|
createProxyWindow(microAppWindow) {
|
|
6326
6411
|
const rawWindow = globalEnv.rawWindow;
|
|
6327
|
-
|
|
6412
|
+
return new Proxy(microAppWindow, {
|
|
6328
6413
|
get: (target, key) => {
|
|
6329
6414
|
if (key === 'location') {
|
|
6330
6415
|
return this.proxyLocation;
|
|
@@ -6335,20 +6420,18 @@ class IframeSandbox {
|
|
|
6335
6420
|
return bindFunctionToRawTarget(Reflect.get(target, key), target);
|
|
6336
6421
|
},
|
|
6337
6422
|
set: (target, key, value) => {
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
Reflect.set(rawWindow, key, value);
|
|
6351
|
-
}
|
|
6423
|
+
/**
|
|
6424
|
+
* TODO:
|
|
6425
|
+
* 1、location域名相同,子应用内部跳转时的处理
|
|
6426
|
+
* 2、和with沙箱的变量相同,提取成公共数组
|
|
6427
|
+
*/
|
|
6428
|
+
if (key === 'location') {
|
|
6429
|
+
return Reflect.set(rawWindow, key, value);
|
|
6430
|
+
}
|
|
6431
|
+
Reflect.set(target, key, value);
|
|
6432
|
+
if (this.escapeProperties.includes(key)) {
|
|
6433
|
+
!Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
|
|
6434
|
+
Reflect.set(rawWindow, key, value);
|
|
6352
6435
|
}
|
|
6353
6436
|
return true;
|
|
6354
6437
|
},
|
|
@@ -6520,9 +6603,14 @@ class CreateApp {
|
|
|
6520
6603
|
var _a;
|
|
6521
6604
|
if (++this.loadSourceLevel === 2) {
|
|
6522
6605
|
this.source.html = html;
|
|
6523
|
-
this.
|
|
6524
|
-
if (!this.isPrefetch && appStates.UNMOUNT !== this.state) {
|
|
6606
|
+
if (!this.isPrefetch && !this.isUnmounted()) {
|
|
6525
6607
|
getRootContainer(this.container).mount(this);
|
|
6608
|
+
// Abandonment plan
|
|
6609
|
+
// if (this.isHidden()) {
|
|
6610
|
+
// getRootContainer(this.container!).unmount()
|
|
6611
|
+
// } else if (!this.isUnmounted()) {
|
|
6612
|
+
// getRootContainer(this.container!).mount(this)
|
|
6613
|
+
// }
|
|
6526
6614
|
}
|
|
6527
6615
|
else if (this.isPrerender) {
|
|
6528
6616
|
/**
|
|
@@ -6563,7 +6651,7 @@ class CreateApp {
|
|
|
6563
6651
|
*/
|
|
6564
6652
|
onLoadError(e) {
|
|
6565
6653
|
this.loadSourceLevel = -1;
|
|
6566
|
-
if (
|
|
6654
|
+
if (!this.isUnmounted()) {
|
|
6567
6655
|
this.onerror(e);
|
|
6568
6656
|
this.setAppState(appStates.LOAD_FAILED);
|
|
6569
6657
|
}
|
|
@@ -6617,7 +6705,7 @@ class CreateApp {
|
|
|
6617
6705
|
*/
|
|
6618
6706
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.rebuildEffectSnapshot();
|
|
6619
6707
|
// current this.container is <div prerender='true'></div>
|
|
6620
|
-
cloneContainer(
|
|
6708
|
+
cloneContainer(container, this.container, false);
|
|
6621
6709
|
/**
|
|
6622
6710
|
* set this.container to <micro-app></micro-app>
|
|
6623
6711
|
* NOTE:
|
|
@@ -6648,7 +6736,7 @@ class CreateApp {
|
|
|
6648
6736
|
}
|
|
6649
6737
|
this.setAppState(appStates.MOUNTING);
|
|
6650
6738
|
// TODO: 将所有cloneContainer中的'as Element'去掉,兼容shadowRoot的场景
|
|
6651
|
-
cloneContainer(this.
|
|
6739
|
+
cloneContainer(this.container, this.source.html, !this.umdMode);
|
|
6652
6740
|
(_e = this.sandBox) === null || _e === void 0 ? void 0 : _e.start({
|
|
6653
6741
|
umdMode: this.umdMode,
|
|
6654
6742
|
baseroute,
|
|
@@ -6677,7 +6765,7 @@ class CreateApp {
|
|
|
6677
6765
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6678
6766
|
}
|
|
6679
6767
|
catch (e) {
|
|
6680
|
-
logError('An error occurred in
|
|
6768
|
+
logError('An error occurred in window.mount \n', this.name, e);
|
|
6681
6769
|
}
|
|
6682
6770
|
}
|
|
6683
6771
|
else if (isFinished === true) {
|
|
@@ -6692,7 +6780,7 @@ class CreateApp {
|
|
|
6692
6780
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6693
6781
|
}
|
|
6694
6782
|
catch (e) {
|
|
6695
|
-
logError('An error occurred in
|
|
6783
|
+
logError('An error occurred in window.mount \n', this.name, e);
|
|
6696
6784
|
}
|
|
6697
6785
|
}
|
|
6698
6786
|
}
|
|
@@ -6710,7 +6798,7 @@ class CreateApp {
|
|
|
6710
6798
|
if (isPromise(umdHookMountResult)) {
|
|
6711
6799
|
umdHookMountResult
|
|
6712
6800
|
.then(() => this.dispatchMountedEvent())
|
|
6713
|
-
.catch((
|
|
6801
|
+
.catch(() => this.dispatchMountedEvent());
|
|
6714
6802
|
}
|
|
6715
6803
|
else {
|
|
6716
6804
|
this.dispatchMountedEvent();
|
|
@@ -6728,17 +6816,27 @@ class CreateApp {
|
|
|
6728
6816
|
* dispatch mounted event when app run finished
|
|
6729
6817
|
*/
|
|
6730
6818
|
dispatchMountedEvent() {
|
|
6731
|
-
|
|
6819
|
+
var _a;
|
|
6820
|
+
if (!this.isUnmounted()) {
|
|
6732
6821
|
this.setAppState(appStates.MOUNTED);
|
|
6733
6822
|
// call window.onmount of child app
|
|
6734
6823
|
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONMOUNT), this.name, microGlobalEvent.ONMOUNT, microApp.getData(this.name, true));
|
|
6735
6824
|
// dispatch event mounted to parent
|
|
6736
6825
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.MOUNTED);
|
|
6826
|
+
/**
|
|
6827
|
+
* Hidden Keep-alive app during resource loading, render normally to ensure their liveliness (running in the background) characteristics.
|
|
6828
|
+
* Actions:
|
|
6829
|
+
* 1. Record & release all global events after mount
|
|
6830
|
+
*/
|
|
6831
|
+
if (this.isHidden()) {
|
|
6832
|
+
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.recordAndReleaseEffect({ keepAlive: true });
|
|
6833
|
+
}
|
|
6737
6834
|
}
|
|
6738
6835
|
}
|
|
6739
6836
|
/**
|
|
6740
6837
|
* unmount app
|
|
6741
|
-
* NOTE:
|
|
6838
|
+
* NOTE:
|
|
6839
|
+
* 1. do not add any params on account of unmountApp
|
|
6742
6840
|
* @param destroy completely destroy, delete cache resources
|
|
6743
6841
|
* @param clearData clear data of dateCenter
|
|
6744
6842
|
* @param keepRouteState keep route state when unmount, default is false
|
|
@@ -6748,33 +6846,35 @@ class CreateApp {
|
|
|
6748
6846
|
var _a;
|
|
6749
6847
|
destroy = destroy || this.state === appStates.LOAD_FAILED;
|
|
6750
6848
|
this.setAppState(appStates.UNMOUNT);
|
|
6751
|
-
// result of unmount function
|
|
6752
6849
|
let umdHookUnmountResult = null;
|
|
6753
|
-
/**
|
|
6754
|
-
* send an unmount event to the micro app or call umd unmount hook
|
|
6755
|
-
* before the sandbox is cleared
|
|
6756
|
-
*/
|
|
6757
6850
|
try {
|
|
6851
|
+
// call umd unmount hook before the sandbox is cleared
|
|
6758
6852
|
umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
|
|
6759
6853
|
}
|
|
6760
6854
|
catch (e) {
|
|
6761
|
-
logError('An error occurred in
|
|
6855
|
+
logError('An error occurred in window.unmount \n', this.name, e);
|
|
6762
6856
|
}
|
|
6763
6857
|
// dispatch unmount event to micro app
|
|
6764
6858
|
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
6765
6859
|
// call window.onunmount of child app
|
|
6766
6860
|
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
6767
|
-
this.handleUnmounted(
|
|
6861
|
+
this.handleUnmounted({
|
|
6862
|
+
destroy,
|
|
6863
|
+
clearData,
|
|
6864
|
+
keepRouteState,
|
|
6865
|
+
unmountcb,
|
|
6866
|
+
umdHookUnmountResult,
|
|
6867
|
+
});
|
|
6768
6868
|
}
|
|
6769
6869
|
/**
|
|
6770
6870
|
* handle for promise umdHookUnmount
|
|
6771
6871
|
* @param destroy completely destroy, delete cache resources
|
|
6772
6872
|
* @param clearData clear data of dateCenter
|
|
6773
6873
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6774
|
-
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6775
6874
|
* @param unmountcb callback of unmount
|
|
6875
|
+
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6776
6876
|
*/
|
|
6777
|
-
handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult,
|
|
6877
|
+
handleUnmounted({ destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult, }) {
|
|
6778
6878
|
const nextAction = () => this.actionsForUnmount({
|
|
6779
6879
|
destroy,
|
|
6780
6880
|
clearData,
|
|
@@ -6782,6 +6882,8 @@ class CreateApp {
|
|
|
6782
6882
|
unmountcb,
|
|
6783
6883
|
});
|
|
6784
6884
|
if (isPromise(umdHookUnmountResult)) {
|
|
6885
|
+
// async window.unmount will cause appName bind error in nest app
|
|
6886
|
+
removeDomScope();
|
|
6785
6887
|
umdHookUnmountResult.then(nextAction).catch(nextAction);
|
|
6786
6888
|
}
|
|
6787
6889
|
else {
|
|
@@ -6795,10 +6897,10 @@ class CreateApp {
|
|
|
6795
6897
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6796
6898
|
* @param unmountcb callback of unmount
|
|
6797
6899
|
*/
|
|
6798
|
-
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
|
|
6900
|
+
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
6799
6901
|
var _a;
|
|
6800
6902
|
if (this.umdMode && this.container && !destroy) {
|
|
6801
|
-
cloneContainer(this.
|
|
6903
|
+
cloneContainer(this.source.html, this.container, false);
|
|
6802
6904
|
}
|
|
6803
6905
|
/**
|
|
6804
6906
|
* this.container maybe contains micro-app element, stop sandbox should exec after cloneContainer
|
|
@@ -6812,9 +6914,6 @@ class CreateApp {
|
|
|
6812
6914
|
destroy,
|
|
6813
6915
|
clearData: clearData || destroy,
|
|
6814
6916
|
});
|
|
6815
|
-
if (!getActiveApps().length) {
|
|
6816
|
-
releasePatchSetAttribute();
|
|
6817
|
-
}
|
|
6818
6917
|
// dispatch unmount event to base app
|
|
6819
6918
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
6820
6919
|
this.clearOptions(destroy);
|
|
@@ -6831,6 +6930,7 @@ class CreateApp {
|
|
|
6831
6930
|
this.sandBox = null;
|
|
6832
6931
|
if (destroy)
|
|
6833
6932
|
this.actionsForCompletelyDestroy();
|
|
6933
|
+
removeDomScope();
|
|
6834
6934
|
}
|
|
6835
6935
|
// actions for completely destroy
|
|
6836
6936
|
actionsForCompletelyDestroy() {
|
|
@@ -6856,7 +6956,6 @@ class CreateApp {
|
|
|
6856
6956
|
// called after lifeCyclesEvent
|
|
6857
6957
|
(_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.removeRouteInfoForKeepAliveApp();
|
|
6858
6958
|
}
|
|
6859
|
-
this.container = cloneContainer(this.container, pureCreateElement('div'), false);
|
|
6860
6959
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.recordAndReleaseEffect({ keepAlive: true });
|
|
6861
6960
|
callback === null || callback === void 0 ? void 0 : callback();
|
|
6862
6961
|
}
|
|
@@ -6871,7 +6970,7 @@ class CreateApp {
|
|
|
6871
6970
|
// dispatch beforeShow event to base app
|
|
6872
6971
|
dispatchLifecyclesEvent(container, this.name, lifeCycles.BEFORESHOW);
|
|
6873
6972
|
this.setKeepAliveState(keepAliveStates.KEEP_ALIVE_SHOW);
|
|
6874
|
-
this.container = cloneContainer(
|
|
6973
|
+
this.container = cloneContainer(container, this.container, false);
|
|
6875
6974
|
if (this.useMemoryRouter) {
|
|
6876
6975
|
// called before lifeCyclesEvent
|
|
6877
6976
|
(_b = this.sandBox) === null || _b === void 0 ? void 0 : _b.setRouteInfoForKeepAliveApp();
|
|
@@ -6922,10 +7021,18 @@ class CreateApp {
|
|
|
6922
7021
|
getKeepAliveState() {
|
|
6923
7022
|
return this.keepAliveState;
|
|
6924
7023
|
}
|
|
7024
|
+
// is app unmounted
|
|
7025
|
+
isUnmounted() {
|
|
7026
|
+
return appStates.UNMOUNT === this.state;
|
|
7027
|
+
}
|
|
7028
|
+
// is app already hidden
|
|
7029
|
+
isHidden() {
|
|
7030
|
+
return keepAliveStates.KEEP_ALIVE_HIDDEN === this.keepAliveState;
|
|
7031
|
+
}
|
|
6925
7032
|
// get umd library, if it not exist, return empty object
|
|
6926
7033
|
getUmdLibraryHooks() {
|
|
6927
7034
|
// after execScripts, the app maybe unmounted
|
|
6928
|
-
if (
|
|
7035
|
+
if (!this.isUnmounted() && this.sandBox) {
|
|
6929
7036
|
const libraryName = getRootContainer(this.container).getAttribute('library') || `micro-app-${this.name}`;
|
|
6930
7037
|
const proxyWindow = this.sandBox.proxyWindow;
|
|
6931
7038
|
// compatible with pre versions
|
|
@@ -6964,7 +7071,7 @@ function isIframeSandbox(appName) {
|
|
|
6964
7071
|
function defineElement(tagName) {
|
|
6965
7072
|
class MicroAppElement extends HTMLElement {
|
|
6966
7073
|
constructor() {
|
|
6967
|
-
super();
|
|
7074
|
+
super(...arguments);
|
|
6968
7075
|
this.isWaiting = false;
|
|
6969
7076
|
this.cacheData = null;
|
|
6970
7077
|
this.connectedCount = 0;
|
|
@@ -6988,16 +7095,14 @@ function defineElement(tagName) {
|
|
|
6988
7095
|
* If oldApp exist & appName is different, determine whether oldApp is running
|
|
6989
7096
|
*/
|
|
6990
7097
|
if (formatAttrName !== this.appName && oldApp) {
|
|
6991
|
-
if (oldApp.
|
|
6992
|
-
oldApp.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN &&
|
|
6993
|
-
!oldApp.isPrefetch) {
|
|
7098
|
+
if (!oldApp.isUnmounted() && !oldApp.isHidden() && !oldApp.isPrefetch) {
|
|
6994
7099
|
this.setAttribute('name', this.appName);
|
|
6995
7100
|
return logError(`app name conflict, an app named ${formatAttrName} is running`);
|
|
6996
7101
|
}
|
|
6997
7102
|
}
|
|
6998
7103
|
if (formatAttrName !== this.appName || formatAttrUrl !== this.appUrl) {
|
|
6999
7104
|
if (formatAttrName === this.appName) {
|
|
7000
|
-
this.
|
|
7105
|
+
this.unmount(true, () => {
|
|
7001
7106
|
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
|
|
7002
7107
|
});
|
|
7003
7108
|
}
|
|
@@ -7006,7 +7111,7 @@ function defineElement(tagName) {
|
|
|
7006
7111
|
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
|
|
7007
7112
|
}
|
|
7008
7113
|
else {
|
|
7009
|
-
this.
|
|
7114
|
+
this.unmount(false, () => {
|
|
7010
7115
|
this.actionsForAttributeChange(formatAttrName, formatAttrUrl, oldApp);
|
|
7011
7116
|
});
|
|
7012
7117
|
}
|
|
@@ -7016,8 +7121,6 @@ function defineElement(tagName) {
|
|
|
7016
7121
|
this.setAttribute('name', this.appName);
|
|
7017
7122
|
}
|
|
7018
7123
|
};
|
|
7019
|
-
// patchSetAttribute hijiack data attribute, it needs exec first
|
|
7020
|
-
patchSetAttribute();
|
|
7021
7124
|
}
|
|
7022
7125
|
static get observedAttributes() {
|
|
7023
7126
|
return ['name', 'url'];
|
|
@@ -7080,15 +7183,13 @@ function defineElement(tagName) {
|
|
|
7080
7183
|
*/
|
|
7081
7184
|
handleDisconnected(destroy = false, callback) {
|
|
7082
7185
|
const app = appInstanceMap.get(this.appName);
|
|
7083
|
-
if (app &&
|
|
7084
|
-
app.getAppState() !== appStates.UNMOUNT &&
|
|
7085
|
-
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
7186
|
+
if (app && !app.isUnmounted() && !app.isHidden()) {
|
|
7086
7187
|
// keep-alive
|
|
7087
7188
|
if (this.getKeepAliveModeResult() && !destroy) {
|
|
7088
7189
|
this.handleHiddenKeepAliveApp(callback);
|
|
7089
7190
|
}
|
|
7090
7191
|
else {
|
|
7091
|
-
this.
|
|
7192
|
+
this.unmount(destroy, callback);
|
|
7092
7193
|
}
|
|
7093
7194
|
}
|
|
7094
7195
|
}
|
|
@@ -7148,16 +7249,16 @@ function defineElement(tagName) {
|
|
|
7148
7249
|
* 2. 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
|
|
7149
7250
|
* 3. When scopecss, useSandbox of prefetch app different from target app, delete prefetch app and create new one
|
|
7150
7251
|
*/
|
|
7151
|
-
if (oldApp.
|
|
7252
|
+
if (oldApp.isHidden() &&
|
|
7152
7253
|
oldApp.url === this.appUrl) {
|
|
7153
7254
|
this.handleShowKeepAliveApp(oldApp);
|
|
7154
7255
|
}
|
|
7155
|
-
else if (oldAppUrl === targetUrl && (oldApp.
|
|
7256
|
+
else if (oldAppUrl === targetUrl && (oldApp.isUnmounted() ||
|
|
7156
7257
|
(oldApp.isPrefetch &&
|
|
7157
7258
|
this.sameCoreOptions(oldApp)))) {
|
|
7158
|
-
this.
|
|
7259
|
+
this.handleMount(oldApp);
|
|
7159
7260
|
}
|
|
7160
|
-
else if (oldApp.isPrefetch || oldApp.
|
|
7261
|
+
else if (oldApp.isPrefetch || oldApp.isUnmounted()) {
|
|
7161
7262
|
if ((process.env.NODE_ENV !== 'production') && this.sameCoreOptions(oldApp)) {
|
|
7162
7263
|
/**
|
|
7163
7264
|
* url is different & old app is unmounted or prefetch, create new app to replace old one
|
|
@@ -7196,7 +7297,7 @@ function defineElement(tagName) {
|
|
|
7196
7297
|
* scene5: if oldApp is KEEP_ALIVE_HIDDEN, name must different
|
|
7197
7298
|
*/
|
|
7198
7299
|
if (oldApp) {
|
|
7199
|
-
if (oldApp.
|
|
7300
|
+
if (oldApp.isHidden()) {
|
|
7200
7301
|
if (oldApp.url === this.appUrl) {
|
|
7201
7302
|
this.handleShowKeepAliveApp(oldApp);
|
|
7202
7303
|
}
|
|
@@ -7211,7 +7312,7 @@ function defineElement(tagName) {
|
|
|
7211
7312
|
* 推荐:if (
|
|
7212
7313
|
* oldApp.url === this.appUrl &&
|
|
7213
7314
|
* oldApp.ssrUrl === this.ssrUrl && (
|
|
7214
|
-
* oldApp.
|
|
7315
|
+
* oldApp.isUnmounted() ||
|
|
7215
7316
|
* (oldApp.isPrefetch && this.sameCoreOptions(oldApp))
|
|
7216
7317
|
* )
|
|
7217
7318
|
* )
|
|
@@ -7219,7 +7320,7 @@ function defineElement(tagName) {
|
|
|
7219
7320
|
}
|
|
7220
7321
|
else if (oldApp.url === this.appUrl && oldApp.ssrUrl === this.ssrUrl) {
|
|
7221
7322
|
// mount app
|
|
7222
|
-
this.
|
|
7323
|
+
this.handleMount(oldApp);
|
|
7223
7324
|
}
|
|
7224
7325
|
else {
|
|
7225
7326
|
this.handleCreateApp();
|
|
@@ -7266,7 +7367,7 @@ function defineElement(tagName) {
|
|
|
7266
7367
|
const oldApp = appInstanceMap.get(this.appName);
|
|
7267
7368
|
if (oldApp) {
|
|
7268
7369
|
if (oldApp.isPrerender) {
|
|
7269
|
-
this.
|
|
7370
|
+
this.unmount(true, createAppInstance);
|
|
7270
7371
|
}
|
|
7271
7372
|
else {
|
|
7272
7373
|
oldApp.actionsForCompletelyDestroy();
|
|
@@ -7284,8 +7385,9 @@ function defineElement(tagName) {
|
|
|
7284
7385
|
* 2. is remount in another container ?
|
|
7285
7386
|
* 3. is remount with change properties of the container ?
|
|
7286
7387
|
*/
|
|
7287
|
-
|
|
7388
|
+
handleMount(app) {
|
|
7288
7389
|
app.isPrefetch = false;
|
|
7390
|
+
// TODO: Can defer be removed?
|
|
7289
7391
|
defer(() => this.mount(app));
|
|
7290
7392
|
}
|
|
7291
7393
|
/**
|
|
@@ -7306,13 +7408,13 @@ function defineElement(tagName) {
|
|
|
7306
7408
|
/**
|
|
7307
7409
|
* unmount app
|
|
7308
7410
|
* @param destroy delete cache resources when unmount
|
|
7411
|
+
* @param unmountcb callback
|
|
7309
7412
|
*/
|
|
7310
|
-
|
|
7413
|
+
unmount(destroy, unmountcb) {
|
|
7311
7414
|
const app = appInstanceMap.get(this.appName);
|
|
7312
|
-
if (app &&
|
|
7313
|
-
app.getAppState() !== appStates.UNMOUNT) {
|
|
7415
|
+
if (app && !app.isUnmounted()) {
|
|
7314
7416
|
app.unmount({
|
|
7315
|
-
destroy,
|
|
7417
|
+
destroy: destroy || this.getDestroyCompatibleResult(),
|
|
7316
7418
|
clearData: this.getDisposeResult('clear-data'),
|
|
7317
7419
|
keepRouteState: this.getDisposeResult('keep-router-state'),
|
|
7318
7420
|
unmountcb,
|
|
@@ -7322,9 +7424,7 @@ function defineElement(tagName) {
|
|
|
7322
7424
|
// hidden app when disconnectedCallback called with keep-alive
|
|
7323
7425
|
handleHiddenKeepAliveApp(callback) {
|
|
7324
7426
|
const app = appInstanceMap.get(this.appName);
|
|
7325
|
-
if (app &&
|
|
7326
|
-
app.getAppState() !== appStates.UNMOUNT &&
|
|
7327
|
-
app.getKeepAliveState() !== keepAliveStates.KEEP_ALIVE_HIDDEN) {
|
|
7427
|
+
if (app && !app.isUnmounted() && !app.isHidden()) {
|
|
7328
7428
|
app.hiddenKeepAliveApp(callback);
|
|
7329
7429
|
}
|
|
7330
7430
|
}
|
|
@@ -7427,6 +7527,30 @@ function defineElement(tagName) {
|
|
|
7427
7527
|
this.getAttribute('defaultPage') ||
|
|
7428
7528
|
'');
|
|
7429
7529
|
}
|
|
7530
|
+
/**
|
|
7531
|
+
* Rewrite micro-app.setAttribute, process attr data
|
|
7532
|
+
* @param key attr name
|
|
7533
|
+
* @param value attr value
|
|
7534
|
+
*/
|
|
7535
|
+
setAttribute(key, value) {
|
|
7536
|
+
if (key === 'data') {
|
|
7537
|
+
if (isPlainObject(value)) {
|
|
7538
|
+
const cloneValue = {};
|
|
7539
|
+
Object.getOwnPropertyNames(value).forEach((ownKey) => {
|
|
7540
|
+
if (!(isString(ownKey) && ownKey.indexOf('__') === 0)) {
|
|
7541
|
+
cloneValue[ownKey] = value[ownKey];
|
|
7542
|
+
}
|
|
7543
|
+
});
|
|
7544
|
+
this.data = cloneValue;
|
|
7545
|
+
}
|
|
7546
|
+
else if (value !== '[object Object]') {
|
|
7547
|
+
logWarn('property data must be an object', this.appName);
|
|
7548
|
+
}
|
|
7549
|
+
}
|
|
7550
|
+
else {
|
|
7551
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7552
|
+
}
|
|
7553
|
+
}
|
|
7430
7554
|
/**
|
|
7431
7555
|
* Data from the base application
|
|
7432
7556
|
*/
|
|
@@ -7598,10 +7722,10 @@ function fetchGlobalResources(resources, suffix, sourceHandler) {
|
|
|
7598
7722
|
function getActiveApps({ excludeHiddenApp = false, excludePreRender = false, } = {}) {
|
|
7599
7723
|
const activeApps = [];
|
|
7600
7724
|
appInstanceMap.forEach((app, appName) => {
|
|
7601
|
-
if (
|
|
7725
|
+
if (!app.isUnmounted() &&
|
|
7602
7726
|
(!app.isPrefetch || (app.isPrerender && !excludePreRender)) &&
|
|
7603
7727
|
(!excludeHiddenApp ||
|
|
7604
|
-
|
|
7728
|
+
!app.isHidden())) {
|
|
7605
7729
|
activeApps.push(appName);
|
|
7606
7730
|
}
|
|
7607
7731
|
});
|
|
@@ -7621,7 +7745,7 @@ function unmountApp(appName, options) {
|
|
|
7621
7745
|
const app = appInstanceMap.get(formatAppName(appName));
|
|
7622
7746
|
return new Promise((resolve) => {
|
|
7623
7747
|
if (app) {
|
|
7624
|
-
if (app.
|
|
7748
|
+
if (app.isUnmounted() || app.isPrefetch) {
|
|
7625
7749
|
if (app.isPrerender) {
|
|
7626
7750
|
app.unmount({
|
|
7627
7751
|
destroy: !!(options === null || options === void 0 ? void 0 : options.destroy),
|
|
@@ -7636,7 +7760,7 @@ function unmountApp(appName, options) {
|
|
|
7636
7760
|
resolve(true);
|
|
7637
7761
|
}
|
|
7638
7762
|
}
|
|
7639
|
-
else if (app.
|
|
7763
|
+
else if (app.isHidden()) {
|
|
7640
7764
|
if (options === null || options === void 0 ? void 0 : options.destroy) {
|
|
7641
7765
|
app.unmount({
|
|
7642
7766
|
destroy: true,
|