@micro-zoe/micro-app 1.0.0-beta.1 → 1.0.0-beta.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.esm.js +1529 -1453
- 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 +3 -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.2';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -1171,237 +1171,584 @@ function createSourceCenter() {
|
|
|
1171
1171
|
}
|
|
1172
1172
|
var sourceCenter = createSourceCenter();
|
|
1173
1173
|
|
|
1174
|
+
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
1175
|
+
// whether use type='module' script
|
|
1176
|
+
function isTypeModule(app, scriptInfo) {
|
|
1177
|
+
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
|
|
1178
|
+
}
|
|
1179
|
+
// special script element
|
|
1180
|
+
function isSpecialScript(app, scriptInfo) {
|
|
1181
|
+
const attrs = scriptInfo.appSpace[app.name].attrs;
|
|
1182
|
+
return attrs.has('id');
|
|
1183
|
+
}
|
|
1174
1184
|
/**
|
|
1175
|
-
*
|
|
1185
|
+
* whether to run js in inline mode
|
|
1186
|
+
* scene:
|
|
1187
|
+
* 1. inline config for app
|
|
1188
|
+
* 2. inline attr in script element
|
|
1189
|
+
* 3. module script
|
|
1190
|
+
* 4. script with special attr
|
|
1191
|
+
*/
|
|
1192
|
+
function isInlineMode(app, scriptInfo) {
|
|
1193
|
+
return (app.inline ||
|
|
1194
|
+
scriptInfo.appSpace[app.name].inline ||
|
|
1195
|
+
isTypeModule(app, scriptInfo) ||
|
|
1196
|
+
isSpecialScript(app, scriptInfo) ||
|
|
1197
|
+
app.iframe);
|
|
1198
|
+
}
|
|
1199
|
+
// TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
|
|
1200
|
+
function getEffectWindow(app) {
|
|
1201
|
+
return app.iframe ? app.sandBox.microAppWindow : globalEnv.rawWindow;
|
|
1202
|
+
}
|
|
1203
|
+
// Convert string code to function
|
|
1204
|
+
function code2Function(app, code) {
|
|
1205
|
+
const targetWindow = getEffectWindow(app);
|
|
1206
|
+
return new targetWindow.Function(code);
|
|
1207
|
+
}
|
|
1208
|
+
/**
|
|
1209
|
+
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
1176
1210
|
* @param appName app.name
|
|
1177
|
-
* @param
|
|
1211
|
+
* @param scriptInfo scriptInfo of current address
|
|
1212
|
+
* @param currentCode pure code of current address
|
|
1178
1213
|
*/
|
|
1179
|
-
function
|
|
1180
|
-
const appSpace =
|
|
1214
|
+
function getExistParseResult(app, scriptInfo, currentCode) {
|
|
1215
|
+
const appSpace = scriptInfo.appSpace;
|
|
1181
1216
|
for (const item in appSpace) {
|
|
1182
|
-
if (item !==
|
|
1217
|
+
if (item !== app.name) {
|
|
1183
1218
|
const appSpaceData = appSpace[item];
|
|
1184
|
-
if (appSpaceData.parsedCode) {
|
|
1185
|
-
return appSpaceData.
|
|
1219
|
+
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
1220
|
+
return appSpaceData.parsedFunction;
|
|
1186
1221
|
}
|
|
1187
1222
|
}
|
|
1188
1223
|
}
|
|
1189
1224
|
}
|
|
1190
|
-
|
|
1191
|
-
|
|
1225
|
+
/**
|
|
1226
|
+
* get parsedFunction from exist data or parsedCode
|
|
1227
|
+
* @returns parsedFunction
|
|
1228
|
+
*/
|
|
1229
|
+
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
1230
|
+
return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
|
|
1231
|
+
}
|
|
1232
|
+
// Prevent randomly created strings from repeating
|
|
1233
|
+
function getUniqueNonceSrc() {
|
|
1234
|
+
const nonceStr = createNonceSrc();
|
|
1235
|
+
if (sourceCenter.script.hasInfo(nonceStr)) {
|
|
1236
|
+
return getUniqueNonceSrc();
|
|
1237
|
+
}
|
|
1238
|
+
return nonceStr;
|
|
1239
|
+
}
|
|
1240
|
+
// transfer the attributes on the script to convertScript
|
|
1241
|
+
function setConvertScriptAttr(convertScript, attrs) {
|
|
1192
1242
|
attrs.forEach((value, key) => {
|
|
1193
|
-
if (key === '
|
|
1243
|
+
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
1194
1244
|
return;
|
|
1195
|
-
if (key === '
|
|
1196
|
-
key = 'data-origin-
|
|
1197
|
-
|
|
1245
|
+
if (key === 'src')
|
|
1246
|
+
key = 'data-origin-src';
|
|
1247
|
+
globalEnv.rawSetAttribute.call(convertScript, key, value);
|
|
1198
1248
|
});
|
|
1199
1249
|
}
|
|
1250
|
+
// wrap code in sandbox
|
|
1251
|
+
function isWrapInSandBox(app, scriptInfo) {
|
|
1252
|
+
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
1253
|
+
}
|
|
1254
|
+
function getSandboxType(app, scriptInfo) {
|
|
1255
|
+
return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
|
|
1256
|
+
}
|
|
1200
1257
|
/**
|
|
1201
|
-
* Extract
|
|
1202
|
-
* @param
|
|
1203
|
-
* @param parent parent element of
|
|
1258
|
+
* Extract script elements
|
|
1259
|
+
* @param script script element
|
|
1260
|
+
* @param parent parent element of script
|
|
1204
1261
|
* @param app app
|
|
1205
|
-
* @param microAppHead micro-app-head element
|
|
1206
1262
|
* @param isDynamic dynamic insert
|
|
1207
1263
|
*/
|
|
1208
|
-
function
|
|
1209
|
-
|
|
1210
|
-
let href = link.getAttribute('href');
|
|
1264
|
+
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
1265
|
+
var _a;
|
|
1211
1266
|
let replaceComment = null;
|
|
1212
|
-
|
|
1213
|
-
|
|
1214
|
-
|
|
1267
|
+
let src = script.getAttribute('src');
|
|
1268
|
+
if (src)
|
|
1269
|
+
src = CompletionPath(src, app.url);
|
|
1270
|
+
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
1271
|
+
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
1272
|
+
}
|
|
1273
|
+
else if ((script.type &&
|
|
1274
|
+
!scriptTypes.includes(script.type)) ||
|
|
1275
|
+
script.hasAttribute('ignore') ||
|
|
1276
|
+
checkIgnoreUrl(src, app.name)) {
|
|
1277
|
+
// 配置为忽略的脚本,清空 rawDocument.currentScript,避免被忽略的脚本内获取 currentScript 出错
|
|
1278
|
+
if ((_a = globalEnv.rawDocument) === null || _a === void 0 ? void 0 : _a.currentScript) {
|
|
1279
|
+
delete globalEnv.rawDocument.currentScript;
|
|
1280
|
+
}
|
|
1281
|
+
return null;
|
|
1282
|
+
}
|
|
1283
|
+
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
1284
|
+
(!globalEnv.supportModuleScript && script.type === 'module')) {
|
|
1285
|
+
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
1286
|
+
}
|
|
1287
|
+
else if (src) { // remote script
|
|
1288
|
+
let scriptInfo = sourceCenter.script.getInfo(src);
|
|
1215
1289
|
const appSpaceData = {
|
|
1216
|
-
|
|
1290
|
+
async: script.hasAttribute('async'),
|
|
1291
|
+
defer: script.defer || script.type === 'module',
|
|
1292
|
+
module: script.type === 'module',
|
|
1293
|
+
inline: script.hasAttribute('inline'),
|
|
1294
|
+
pure: script.hasAttribute('pure'),
|
|
1295
|
+
attrs: getAttributes(script),
|
|
1217
1296
|
};
|
|
1218
|
-
if (!
|
|
1219
|
-
|
|
1297
|
+
if (!scriptInfo) {
|
|
1298
|
+
scriptInfo = {
|
|
1220
1299
|
code: '',
|
|
1300
|
+
isExternal: true,
|
|
1221
1301
|
appSpace: {
|
|
1222
1302
|
[app.name]: appSpaceData,
|
|
1223
1303
|
}
|
|
1224
1304
|
};
|
|
1225
1305
|
}
|
|
1226
1306
|
else {
|
|
1227
|
-
|
|
1307
|
+
/**
|
|
1308
|
+
* Reuse when appSpace exists
|
|
1309
|
+
* NOTE:
|
|
1310
|
+
* 1. The same static script, appSpace must be the same (in fact, it may be different when url change)
|
|
1311
|
+
* 2. The same dynamic script, appSpace may be the same, but we still reuse appSpace, which should pay attention
|
|
1312
|
+
*/
|
|
1313
|
+
scriptInfo.appSpace[app.name] = scriptInfo.appSpace[app.name] || appSpaceData;
|
|
1228
1314
|
}
|
|
1229
|
-
sourceCenter.
|
|
1315
|
+
sourceCenter.script.setInfo(src, scriptInfo);
|
|
1230
1316
|
if (!isDynamic) {
|
|
1231
|
-
app.source.
|
|
1232
|
-
replaceComment = document.createComment(`
|
|
1233
|
-
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
1317
|
+
app.source.scripts.add(src);
|
|
1318
|
+
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
1234
1319
|
}
|
|
1235
1320
|
else {
|
|
1236
|
-
return { address:
|
|
1321
|
+
return { address: src, scriptInfo };
|
|
1237
1322
|
}
|
|
1238
1323
|
}
|
|
1239
|
-
else if (
|
|
1240
|
-
|
|
1241
|
-
|
|
1242
|
-
|
|
1324
|
+
else if (script.textContent) { // inline script
|
|
1325
|
+
/**
|
|
1326
|
+
* NOTE:
|
|
1327
|
+
* 1. Each inline script is unique
|
|
1328
|
+
* 2. Every dynamic created inline script will be re-executed
|
|
1329
|
+
* ACTION:
|
|
1330
|
+
* 1. Delete dynamic inline script info after exec
|
|
1331
|
+
* 2. Delete static inline script info when destroy
|
|
1332
|
+
*/
|
|
1333
|
+
const nonceStr = getUniqueNonceSrc();
|
|
1334
|
+
const scriptInfo = {
|
|
1335
|
+
code: script.textContent,
|
|
1336
|
+
isExternal: false,
|
|
1337
|
+
appSpace: {
|
|
1338
|
+
[app.name]: {
|
|
1339
|
+
async: false,
|
|
1340
|
+
defer: script.type === 'module',
|
|
1341
|
+
module: script.type === 'module',
|
|
1342
|
+
inline: script.hasAttribute('inline'),
|
|
1343
|
+
pure: script.hasAttribute('pure'),
|
|
1344
|
+
attrs: getAttributes(script),
|
|
1345
|
+
}
|
|
1346
|
+
}
|
|
1347
|
+
};
|
|
1348
|
+
if (!isDynamic) {
|
|
1349
|
+
app.source.scripts.add(nonceStr);
|
|
1350
|
+
sourceCenter.script.setInfo(nonceStr, scriptInfo);
|
|
1351
|
+
replaceComment = document.createComment('inline script extract by micro-app');
|
|
1243
1352
|
}
|
|
1244
1353
|
else {
|
|
1245
|
-
|
|
1354
|
+
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
1355
|
+
return { address: nonceStr, scriptInfo };
|
|
1246
1356
|
}
|
|
1247
1357
|
}
|
|
1248
|
-
else if (
|
|
1249
|
-
|
|
1250
|
-
|
|
1358
|
+
else if (!isDynamic) {
|
|
1359
|
+
/**
|
|
1360
|
+
* script with empty src or empty script.textContent remove in static html
|
|
1361
|
+
* & not removed if it created by dynamic
|
|
1362
|
+
*/
|
|
1363
|
+
replaceComment = document.createComment('script element removed by micro-app');
|
|
1251
1364
|
}
|
|
1252
1365
|
if (isDynamic) {
|
|
1253
1366
|
return { replaceComment };
|
|
1254
1367
|
}
|
|
1255
|
-
else
|
|
1256
|
-
return parent.replaceChild(replaceComment,
|
|
1368
|
+
else {
|
|
1369
|
+
return parent === null || parent === void 0 ? void 0 : parent.replaceChild(replaceComment, script);
|
|
1257
1370
|
}
|
|
1258
1371
|
}
|
|
1259
1372
|
/**
|
|
1260
|
-
*
|
|
1261
|
-
* @param
|
|
1262
|
-
* @param app app
|
|
1263
|
-
* @param microAppHead micro-app-head
|
|
1373
|
+
* get assets plugins
|
|
1374
|
+
* @param appName app name
|
|
1264
1375
|
*/
|
|
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
|
-
}
|
|
1376
|
+
function getAssetsPlugins(appName) {
|
|
1377
|
+
var _a, _b, _c;
|
|
1378
|
+
const globalPlugins = ((_a = microApp.options.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
1379
|
+
const modulePlugins = ((_c = (_b = microApp.options.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
1380
|
+
return [...globalPlugins, ...modulePlugins];
|
|
1381
|
+
}
|
|
1382
|
+
/**
|
|
1383
|
+
* whether the address needs to be excluded
|
|
1384
|
+
* @param address css or js link
|
|
1385
|
+
* @param plugins microApp plugins
|
|
1386
|
+
*/
|
|
1387
|
+
function checkExcludeUrl(address, appName) {
|
|
1388
|
+
if (!address)
|
|
1389
|
+
return false;
|
|
1390
|
+
const plugins = getAssetsPlugins(appName) || [];
|
|
1391
|
+
return plugins.some(plugin => {
|
|
1392
|
+
if (!plugin.excludeChecker)
|
|
1393
|
+
return false;
|
|
1394
|
+
return plugin.excludeChecker(address);
|
|
1291
1395
|
});
|
|
1292
1396
|
}
|
|
1293
1397
|
/**
|
|
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
|
|
1398
|
+
* whether the address needs to be ignore
|
|
1399
|
+
* @param address css or js link
|
|
1400
|
+
* @param plugins microApp plugins
|
|
1305
1401
|
*/
|
|
1306
|
-
function
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1402
|
+
function checkIgnoreUrl(address, appName) {
|
|
1403
|
+
if (!address)
|
|
1404
|
+
return false;
|
|
1405
|
+
const plugins = getAssetsPlugins(appName) || [];
|
|
1406
|
+
return plugins.some(plugin => {
|
|
1407
|
+
if (!plugin.ignoreChecker)
|
|
1408
|
+
return false;
|
|
1409
|
+
return plugin.ignoreChecker(address);
|
|
1410
|
+
});
|
|
1411
|
+
}
|
|
1412
|
+
/**
|
|
1413
|
+
* Get remote resources of script
|
|
1414
|
+
* @param wrapElement htmlDom
|
|
1415
|
+
* @param app app
|
|
1416
|
+
*/
|
|
1417
|
+
function fetchScriptsFromHtml(wrapElement, app) {
|
|
1418
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1419
|
+
const fetchScriptPromise = [];
|
|
1420
|
+
const fetchScriptPromiseInfo = [];
|
|
1421
|
+
for (const address of scriptList) {
|
|
1422
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
1423
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1424
|
+
if ((!appSpaceData.defer && !appSpaceData.async) || (app.isPrefetch && !app.isPrerender)) {
|
|
1425
|
+
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
1426
|
+
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
1427
|
+
}
|
|
1428
|
+
}
|
|
1429
|
+
const fiberScriptTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
1430
|
+
if (fetchScriptPromise.length) {
|
|
1431
|
+
promiseStream(fetchScriptPromise, (res) => {
|
|
1432
|
+
injectFiberTask(fiberScriptTasks, () => fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data, app));
|
|
1433
|
+
}, (err) => {
|
|
1434
|
+
logError(err, app.name);
|
|
1435
|
+
}, () => {
|
|
1436
|
+
if (fiberScriptTasks) {
|
|
1437
|
+
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1438
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1439
|
+
}
|
|
1440
|
+
else {
|
|
1441
|
+
app.onLoad(wrapElement);
|
|
1442
|
+
}
|
|
1443
|
+
});
|
|
1444
|
+
}
|
|
1445
|
+
else {
|
|
1446
|
+
app.onLoad(wrapElement);
|
|
1447
|
+
}
|
|
1448
|
+
}
|
|
1449
|
+
/**
|
|
1450
|
+
* fetch js succeeded, record the code value
|
|
1451
|
+
* @param address script address
|
|
1452
|
+
* @param scriptInfo resource script info
|
|
1453
|
+
* @param data code
|
|
1454
|
+
*/
|
|
1455
|
+
function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
1456
|
+
// reset scriptInfo.code
|
|
1457
|
+
scriptInfo.code = code;
|
|
1315
1458
|
/**
|
|
1316
|
-
*
|
|
1317
|
-
*
|
|
1318
|
-
*
|
|
1319
|
-
*
|
|
1320
|
-
*
|
|
1459
|
+
* Pre parse script for prefetch, improve rendering performance
|
|
1460
|
+
* NOTE:
|
|
1461
|
+
* 1. if global parseResult exist, skip this step
|
|
1462
|
+
* 2. if app is inline or script is esmodule, skip this step
|
|
1463
|
+
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
1321
1464
|
*/
|
|
1322
|
-
if (
|
|
1323
|
-
const
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1327
|
-
|
|
1328
|
-
|
|
1329
|
-
|
|
1465
|
+
if (app.isPrefetch && app.prefetchLevel === 2) {
|
|
1466
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1467
|
+
/**
|
|
1468
|
+
* 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.
|
|
1469
|
+
* This causes parsedCode to already exist when preloading ends
|
|
1470
|
+
* e.g.
|
|
1471
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
1472
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
1473
|
+
*/
|
|
1474
|
+
if (!appSpaceData.parsedCode) {
|
|
1475
|
+
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
1476
|
+
appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
|
|
1477
|
+
if (!isInlineMode(app, scriptInfo)) {
|
|
1478
|
+
try {
|
|
1479
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
1480
|
+
}
|
|
1481
|
+
catch (err) {
|
|
1482
|
+
logError('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
1483
|
+
}
|
|
1484
|
+
}
|
|
1330
1485
|
}
|
|
1331
|
-
// clear placeholder
|
|
1332
|
-
appSpaceData.placeholder = null;
|
|
1333
1486
|
}
|
|
1334
1487
|
}
|
|
1335
1488
|
/**
|
|
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
|
|
1489
|
+
* Execute js in the mount lifecycle
|
|
1490
|
+
* @param app app
|
|
1491
|
+
* @param initHook callback for umd mode
|
|
1346
1492
|
*/
|
|
1347
|
-
function
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
1352
|
-
|
|
1353
|
-
|
|
1354
|
-
|
|
1355
|
-
|
|
1493
|
+
function execScripts(app, initHook) {
|
|
1494
|
+
const fiberScriptTasks = app.fiber ? [] : null;
|
|
1495
|
+
const scriptList = Array.from(app.source.scripts);
|
|
1496
|
+
const deferScriptPromise = [];
|
|
1497
|
+
const deferScriptInfo = [];
|
|
1498
|
+
for (const address of scriptList) {
|
|
1499
|
+
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
1500
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1501
|
+
// Notice the second render
|
|
1502
|
+
if (appSpaceData.defer || appSpaceData.async) {
|
|
1503
|
+
// TODO: defer和module彻底分开,不要混在一起
|
|
1504
|
+
if (scriptInfo.isExternal && !scriptInfo.code && !(app.iframe && appSpaceData.module)) {
|
|
1505
|
+
deferScriptPromise.push(fetchSource(address, app.name));
|
|
1356
1506
|
}
|
|
1357
1507
|
else {
|
|
1358
|
-
|
|
1508
|
+
deferScriptPromise.push(scriptInfo.code);
|
|
1359
1509
|
}
|
|
1360
|
-
|
|
1510
|
+
deferScriptInfo.push([address, scriptInfo]);
|
|
1511
|
+
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
1361
1512
|
}
|
|
1362
1513
|
else {
|
|
1363
|
-
|
|
1514
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
1515
|
+
runScript(address, app, scriptInfo);
|
|
1516
|
+
initHook(false);
|
|
1517
|
+
});
|
|
1364
1518
|
}
|
|
1365
1519
|
}
|
|
1520
|
+
if (deferScriptPromise.length) {
|
|
1521
|
+
promiseStream(deferScriptPromise, (res) => {
|
|
1522
|
+
const scriptInfo = deferScriptInfo[res.index][1];
|
|
1523
|
+
scriptInfo.code = scriptInfo.code || res.data;
|
|
1524
|
+
}, (err) => {
|
|
1525
|
+
initHook.errorCount = initHook.errorCount ? ++initHook.errorCount : 1;
|
|
1526
|
+
logError(err, app.name);
|
|
1527
|
+
}, () => {
|
|
1528
|
+
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
1529
|
+
if (isString(scriptInfo.code)) {
|
|
1530
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
1531
|
+
runScript(address, app, scriptInfo, initHook);
|
|
1532
|
+
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
1533
|
+
});
|
|
1534
|
+
}
|
|
1535
|
+
});
|
|
1536
|
+
/**
|
|
1537
|
+
* Fiber wraps js in requestIdleCallback and executes it in sequence
|
|
1538
|
+
* NOTE:
|
|
1539
|
+
* 1. In order to ensure the execution order, wait for all js loaded and then execute
|
|
1540
|
+
* 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
|
|
1541
|
+
*
|
|
1542
|
+
* BUG: NOTE.2 - execution order problem
|
|
1543
|
+
*/
|
|
1544
|
+
if (fiberScriptTasks) {
|
|
1545
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(isUndefined(initHook.moduleCount) ||
|
|
1546
|
+
initHook.errorCount === deferScriptPromise.length)));
|
|
1547
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1548
|
+
}
|
|
1549
|
+
else {
|
|
1550
|
+
initHook(isUndefined(initHook.moduleCount) ||
|
|
1551
|
+
initHook.errorCount === deferScriptPromise.length);
|
|
1552
|
+
}
|
|
1553
|
+
});
|
|
1554
|
+
}
|
|
1366
1555
|
else {
|
|
1367
|
-
|
|
1556
|
+
if (fiberScriptTasks) {
|
|
1557
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
1558
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1559
|
+
}
|
|
1560
|
+
else {
|
|
1561
|
+
initHook(true);
|
|
1562
|
+
}
|
|
1368
1563
|
}
|
|
1369
|
-
setConvertStyleAttr(convertStyle, attrs);
|
|
1370
1564
|
}
|
|
1371
1565
|
/**
|
|
1372
|
-
*
|
|
1373
|
-
* @param address
|
|
1566
|
+
* run code
|
|
1567
|
+
* @param address script address
|
|
1374
1568
|
* @param app app
|
|
1375
|
-
* @param
|
|
1376
|
-
* @param
|
|
1569
|
+
* @param scriptInfo script info
|
|
1570
|
+
* @param callback callback of module script
|
|
1377
1571
|
*/
|
|
1378
|
-
function
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
|
|
1572
|
+
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
1573
|
+
try {
|
|
1574
|
+
actionsBeforeRunScript(app);
|
|
1575
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1576
|
+
const sandboxType = getSandboxType(app, scriptInfo);
|
|
1577
|
+
/**
|
|
1578
|
+
* NOTE:
|
|
1579
|
+
* 1. plugins and wrapCode will only be executed once
|
|
1580
|
+
* 2. if parsedCode not exist, parsedFunction is not exist
|
|
1581
|
+
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
1582
|
+
*/
|
|
1583
|
+
if (!appSpaceData.parsedCode || appSpaceData.sandboxType !== sandboxType) {
|
|
1584
|
+
appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
|
|
1585
|
+
appSpaceData.sandboxType = sandboxType;
|
|
1586
|
+
appSpaceData.parsedFunction = null;
|
|
1587
|
+
}
|
|
1588
|
+
if (isInlineMode(app, scriptInfo)) {
|
|
1589
|
+
const scriptElement = replaceElement || pureCreateElement('script');
|
|
1590
|
+
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
1591
|
+
if (!replaceElement) {
|
|
1592
|
+
// TEST IGNORE
|
|
1593
|
+
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
1594
|
+
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
1595
|
+
}
|
|
1596
|
+
}
|
|
1597
|
+
else {
|
|
1598
|
+
runParsedFunction(app, scriptInfo);
|
|
1599
|
+
}
|
|
1386
1600
|
}
|
|
1387
|
-
|
|
1388
|
-
|
|
1389
|
-
linkInfo.code = data;
|
|
1390
|
-
handleDynamicLink();
|
|
1391
|
-
}).catch((err) => {
|
|
1392
|
-
logError(err, app.name);
|
|
1393
|
-
dispatchOnErrorEvent(originLink);
|
|
1394
|
-
});
|
|
1601
|
+
catch (e) {
|
|
1602
|
+
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
1395
1603
|
}
|
|
1396
|
-
return convertStyle;
|
|
1397
1604
|
}
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1605
|
+
/**
|
|
1606
|
+
* Get dynamically created remote script
|
|
1607
|
+
* @param address script address
|
|
1608
|
+
* @param app app instance
|
|
1609
|
+
* @param scriptInfo scriptInfo
|
|
1610
|
+
* @param originScript origin script element
|
|
1611
|
+
*/
|
|
1612
|
+
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
1613
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
1614
|
+
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
1615
|
+
const runDynamicScript = () => {
|
|
1616
|
+
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
1617
|
+
if (!descriptor || descriptor.configurable) {
|
|
1618
|
+
Object.defineProperty(globalEnv.rawDocument, 'currentScript', {
|
|
1619
|
+
value: originScript,
|
|
1620
|
+
configurable: true,
|
|
1621
|
+
});
|
|
1622
|
+
}
|
|
1623
|
+
runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
|
|
1624
|
+
!isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
|
|
1625
|
+
};
|
|
1626
|
+
if (scriptInfo.code || (app.iframe && scriptInfo.appSpace[app.name].module)) {
|
|
1627
|
+
defer(runDynamicScript);
|
|
1628
|
+
}
|
|
1629
|
+
else {
|
|
1630
|
+
fetchSource(address, app.name).then((code) => {
|
|
1631
|
+
scriptInfo.code = code;
|
|
1632
|
+
runDynamicScript();
|
|
1633
|
+
}).catch((err) => {
|
|
1634
|
+
logError(err, app.name);
|
|
1635
|
+
dispatchOnErrorEvent(originScript);
|
|
1636
|
+
});
|
|
1637
|
+
}
|
|
1638
|
+
return replaceElement;
|
|
1639
|
+
}
|
|
1640
|
+
/**
|
|
1641
|
+
* Get dynamically created inline script
|
|
1642
|
+
* @param address script address
|
|
1643
|
+
* @param app app instance
|
|
1644
|
+
* @param scriptInfo scriptInfo
|
|
1645
|
+
*/
|
|
1646
|
+
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
1647
|
+
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
1648
|
+
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
1649
|
+
return replaceElement;
|
|
1650
|
+
}
|
|
1651
|
+
/**
|
|
1652
|
+
* common handle for inline script
|
|
1653
|
+
* @param address script address
|
|
1654
|
+
* @param code bound code
|
|
1655
|
+
* @param module type='module' of script
|
|
1656
|
+
* @param scriptElement target script element
|
|
1657
|
+
* @param attrs attributes of script element
|
|
1658
|
+
* @param callback callback of module script
|
|
1659
|
+
*/
|
|
1660
|
+
function runCode2InlineScript(address, code, module, scriptElement, attrs, callback) {
|
|
1661
|
+
if (module) {
|
|
1662
|
+
// module script is async, transform it to a blob for subsequent operations
|
|
1663
|
+
if (isInlineScript(address)) {
|
|
1664
|
+
const blob = new Blob([code], { type: 'text/javascript' });
|
|
1665
|
+
scriptElement.src = URL.createObjectURL(blob);
|
|
1666
|
+
}
|
|
1667
|
+
else {
|
|
1668
|
+
scriptElement.src = address;
|
|
1669
|
+
}
|
|
1670
|
+
globalEnv.rawSetAttribute.call(scriptElement, 'type', 'module');
|
|
1671
|
+
if (callback) {
|
|
1672
|
+
callback.moduleCount && callback.moduleCount--;
|
|
1673
|
+
/**
|
|
1674
|
+
* module script will execute onload method only after it insert to document/iframe
|
|
1675
|
+
*/
|
|
1676
|
+
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
1677
|
+
}
|
|
1678
|
+
}
|
|
1679
|
+
else {
|
|
1680
|
+
scriptElement.textContent = code;
|
|
1681
|
+
}
|
|
1682
|
+
setConvertScriptAttr(scriptElement, attrs);
|
|
1683
|
+
}
|
|
1684
|
+
// init & run code2Function
|
|
1685
|
+
function runParsedFunction(app, scriptInfo) {
|
|
1686
|
+
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
1687
|
+
if (!appSpaceData.parsedFunction) {
|
|
1688
|
+
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
1689
|
+
}
|
|
1690
|
+
appSpaceData.parsedFunction.call(getEffectWindow(app));
|
|
1691
|
+
}
|
|
1692
|
+
/**
|
|
1693
|
+
* bind js scope
|
|
1694
|
+
* @param app app
|
|
1695
|
+
* @param code code
|
|
1696
|
+
* @param scriptInfo source script info
|
|
1697
|
+
*/
|
|
1698
|
+
function bindScope(address, app, code, scriptInfo) {
|
|
1699
|
+
// TODO: 1、cache 2、esm code is null
|
|
1700
|
+
if (isPlainObject(microApp.options.plugins)) {
|
|
1701
|
+
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
1702
|
+
}
|
|
1703
|
+
if (isWrapInSandBox(app, scriptInfo)) {
|
|
1704
|
+
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__);`;
|
|
1705
|
+
}
|
|
1706
|
+
return code;
|
|
1707
|
+
}
|
|
1708
|
+
/**
|
|
1709
|
+
* actions before run script
|
|
1710
|
+
*/
|
|
1711
|
+
function actionsBeforeRunScript(app) {
|
|
1712
|
+
setActiveProxyWindow(app);
|
|
1713
|
+
}
|
|
1714
|
+
/**
|
|
1715
|
+
* set active sandBox.proxyWindow to window.__MICRO_APP_PROXY_WINDOW__
|
|
1716
|
+
*/
|
|
1717
|
+
function setActiveProxyWindow(app) {
|
|
1718
|
+
if (app.sandBox) {
|
|
1719
|
+
globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
|
|
1720
|
+
}
|
|
1721
|
+
}
|
|
1722
|
+
/**
|
|
1723
|
+
* Call the plugin to process the file
|
|
1724
|
+
* @param address script address
|
|
1725
|
+
* @param code code
|
|
1726
|
+
* @param appName app name
|
|
1727
|
+
* @param plugins plugin list
|
|
1728
|
+
*/
|
|
1729
|
+
function usePlugins(address, code, appName, plugins) {
|
|
1730
|
+
var _a;
|
|
1731
|
+
const newCode = processCode(plugins.global, code, address);
|
|
1732
|
+
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, address);
|
|
1733
|
+
}
|
|
1734
|
+
function processCode(configs, code, address) {
|
|
1735
|
+
if (!isArray(configs)) {
|
|
1736
|
+
return code;
|
|
1737
|
+
}
|
|
1738
|
+
return configs.reduce((preCode, config) => {
|
|
1739
|
+
if (isPlainObject(config) && isFunction(config.loader)) {
|
|
1740
|
+
return config.loader(preCode, address);
|
|
1741
|
+
}
|
|
1742
|
+
return preCode;
|
|
1743
|
+
}, code);
|
|
1744
|
+
}
|
|
1745
|
+
|
|
1746
|
+
class Adapter {
|
|
1747
|
+
constructor() {
|
|
1748
|
+
// keys that can only assigned to rawWindow
|
|
1749
|
+
this.escapeSetterKeyList = [
|
|
1750
|
+
'location',
|
|
1751
|
+
];
|
|
1405
1752
|
// keys that can escape to rawWindow
|
|
1406
1753
|
this.staticEscapeProperties = [
|
|
1407
1754
|
'System',
|
|
@@ -1521,7 +1868,10 @@ function patchElementTree(container, appName) {
|
|
|
1521
1868
|
function updateElementInfo(node, appName) {
|
|
1522
1869
|
var _a, _b;
|
|
1523
1870
|
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 (
|
|
1871
|
+
if (isNode(node) &&
|
|
1872
|
+
!node.__MICRO_APP_NAME__ &&
|
|
1873
|
+
!node.__PURE_ELEMENT__ &&
|
|
1874
|
+
proxyWindow) {
|
|
1525
1875
|
/**
|
|
1526
1876
|
* TODO:
|
|
1527
1877
|
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
@@ -1552,14 +1902,21 @@ function updateElementInfo(node, appName) {
|
|
|
1552
1902
|
|
|
1553
1903
|
// Record element and map element
|
|
1554
1904
|
const dynamicElementInMicroAppMap = new WeakMap();
|
|
1905
|
+
// Get the map element
|
|
1906
|
+
function getMappingNode(node) {
|
|
1907
|
+
var _a;
|
|
1908
|
+
return (_a = dynamicElementInMicroAppMap.get(node)) !== null && _a !== void 0 ? _a : node;
|
|
1909
|
+
}
|
|
1555
1910
|
/**
|
|
1556
1911
|
* Process the new node and format the style, link and script element
|
|
1557
|
-
* @param parent parent node
|
|
1558
1912
|
* @param child new node
|
|
1559
1913
|
* @param app app
|
|
1560
1914
|
*/
|
|
1561
|
-
function handleNewNode(
|
|
1562
|
-
if (
|
|
1915
|
+
function handleNewNode(child, app) {
|
|
1916
|
+
if (dynamicElementInMicroAppMap.has(child)) {
|
|
1917
|
+
return dynamicElementInMicroAppMap.get(child);
|
|
1918
|
+
}
|
|
1919
|
+
else if (isStyleElement(child)) {
|
|
1563
1920
|
if (child.hasAttribute('exclude')) {
|
|
1564
1921
|
const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
|
|
1565
1922
|
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
@@ -1583,7 +1940,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1583
1940
|
microApp.options.excludeAssetFilter(child.href))) {
|
|
1584
1941
|
return child;
|
|
1585
1942
|
}
|
|
1586
|
-
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child,
|
|
1943
|
+
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child, null, app, true);
|
|
1587
1944
|
if (address && linkInfo) {
|
|
1588
1945
|
const replaceStyle = formatDynamicLink(address, app, linkInfo, child);
|
|
1589
1946
|
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
@@ -1601,7 +1958,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1601
1958
|
microApp.options.excludeAssetFilter(child.src)) {
|
|
1602
1959
|
return child;
|
|
1603
1960
|
}
|
|
1604
|
-
const { replaceComment, address, scriptInfo } = extractScriptElement(child,
|
|
1961
|
+
const { replaceComment, address, scriptInfo } = extractScriptElement(child, null, app, true) || {};
|
|
1605
1962
|
if (address && scriptInfo) {
|
|
1606
1963
|
// remote script or inline script
|
|
1607
1964
|
const replaceElement = scriptInfo.isExternal ? runDynamicRemoteScript(address, app, scriptInfo, child) : runDynamicInlineScript(address, app, scriptInfo);
|
|
@@ -1705,6 +2062,9 @@ function getHijackParent(parent, targetChild, app) {
|
|
|
1705
2062
|
}
|
|
1706
2063
|
return app.querySelector('micro-app-body');
|
|
1707
2064
|
}
|
|
2065
|
+
if (app.iframe && isScriptElement(targetChild)) {
|
|
2066
|
+
return app.sandBox.microBody;
|
|
2067
|
+
}
|
|
1708
2068
|
}
|
|
1709
2069
|
return null;
|
|
1710
2070
|
}
|
|
@@ -1717,10 +2077,25 @@ function invokeRawMethod(rawMethod, parent, targetChild, passiveChild) {
|
|
|
1717
2077
|
function isPendMethod(method) {
|
|
1718
2078
|
return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
|
|
1719
2079
|
}
|
|
1720
|
-
|
|
1721
|
-
|
|
1722
|
-
|
|
1723
|
-
|
|
2080
|
+
/**
|
|
2081
|
+
* Attempt to complete the static resource address again before insert the node
|
|
2082
|
+
* @param app app instance
|
|
2083
|
+
* @param newChild target node
|
|
2084
|
+
*/
|
|
2085
|
+
function completePathDynamic(app, newChild) {
|
|
2086
|
+
if (isElement(newChild)) {
|
|
2087
|
+
if (/^(img|script)$/i.test(newChild.tagName)) {
|
|
2088
|
+
if (newChild.hasAttribute('src')) {
|
|
2089
|
+
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
2090
|
+
}
|
|
2091
|
+
if (newChild.hasAttribute('srcset')) {
|
|
2092
|
+
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
2093
|
+
}
|
|
2094
|
+
}
|
|
2095
|
+
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
2096
|
+
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
2097
|
+
}
|
|
2098
|
+
}
|
|
1724
2099
|
}
|
|
1725
2100
|
/**
|
|
1726
2101
|
* method of handle new node
|
|
@@ -1738,37 +2113,11 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1738
2113
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1739
2114
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1740
2115
|
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);
|
|
2116
|
+
completePathDynamic(app, newChild);
|
|
2117
|
+
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
1758
2118
|
}
|
|
1759
2119
|
}
|
|
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
|
-
}
|
|
2120
|
+
if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1772
2121
|
return rawMethod.call(parent, newChild);
|
|
1773
2122
|
}
|
|
1774
2123
|
return rawMethod.call(parent, newChild, passiveChild);
|
|
@@ -1778,33 +2127,37 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1778
2127
|
*/
|
|
1779
2128
|
function patchElementAndDocument() {
|
|
1780
2129
|
patchDocument();
|
|
2130
|
+
const rawRootElement = globalEnv.rawRootElement;
|
|
1781
2131
|
// prototype methods of add element👇
|
|
1782
|
-
|
|
2132
|
+
rawRootElement.prototype.appendChild = function appendChild(newChild) {
|
|
1783
2133
|
return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
|
|
1784
2134
|
};
|
|
1785
|
-
|
|
2135
|
+
rawRootElement.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
1786
2136
|
return commonElementHandler(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
1787
2137
|
};
|
|
1788
|
-
|
|
2138
|
+
rawRootElement.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
1789
2139
|
return commonElementHandler(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
1790
2140
|
};
|
|
1791
|
-
|
|
2141
|
+
rawRootElement.prototype.append = function append(...nodes) {
|
|
1792
2142
|
let i = 0;
|
|
1793
|
-
|
|
1794
|
-
|
|
1795
|
-
|
|
2143
|
+
while (i < nodes.length) {
|
|
2144
|
+
let node = nodes[i];
|
|
2145
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
2146
|
+
commonElementHandler(this, markElement(node), null, globalEnv.rawAppend);
|
|
1796
2147
|
i++;
|
|
1797
2148
|
}
|
|
1798
2149
|
};
|
|
1799
|
-
|
|
2150
|
+
rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
1800
2151
|
let i = nodes.length;
|
|
1801
2152
|
while (i > 0) {
|
|
1802
|
-
|
|
2153
|
+
let node = nodes[i - 1];
|
|
2154
|
+
node = isNode(node) ? node : globalEnv.rawCreateTextNode.call(globalEnv.rawDocument, node);
|
|
2155
|
+
commonElementHandler(this, markElement(node), null, globalEnv.rawPrepend);
|
|
1803
2156
|
i--;
|
|
1804
2157
|
}
|
|
1805
2158
|
};
|
|
1806
2159
|
// prototype methods of delete element👇
|
|
1807
|
-
|
|
2160
|
+
rawRootElement.prototype.removeChild = function removeChild(oldChild) {
|
|
1808
2161
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1809
2162
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1810
2163
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -1819,8 +2172,20 @@ function patchElementAndDocument() {
|
|
|
1819
2172
|
}
|
|
1820
2173
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1821
2174
|
};
|
|
2175
|
+
rawRootElement.prototype.insertAdjacentElement = function (where, element) {
|
|
2176
|
+
var _a;
|
|
2177
|
+
if (element === null || element === void 0 ? void 0 : element.__MICRO_APP_NAME__) {
|
|
2178
|
+
const app = appInstanceMap.get(element.__MICRO_APP_NAME__);
|
|
2179
|
+
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
2180
|
+
element = handleNewNode(element, app);
|
|
2181
|
+
const realParent = (_a = getHijackParent(this, element, app)) !== null && _a !== void 0 ? _a : this;
|
|
2182
|
+
return globalEnv.rawInsertAdjacentElement.call(realParent, where, element);
|
|
2183
|
+
}
|
|
2184
|
+
}
|
|
2185
|
+
return globalEnv.rawInsertAdjacentElement.call(this, where, element);
|
|
2186
|
+
};
|
|
1822
2187
|
// patch cloneNode
|
|
1823
|
-
|
|
2188
|
+
rawRootElement.prototype.cloneNode = function cloneNode(deep) {
|
|
1824
2189
|
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
1825
2190
|
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
1826
2191
|
return clonedNode;
|
|
@@ -1840,17 +2205,63 @@ function patchElementAndDocument() {
|
|
|
1840
2205
|
}
|
|
1841
2206
|
return null;
|
|
1842
2207
|
}
|
|
1843
|
-
|
|
2208
|
+
rawRootElement.prototype.querySelector = function querySelector(selectors) {
|
|
1844
2209
|
var _a;
|
|
1845
2210
|
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1846
2211
|
return globalEnv.rawElementQuerySelector.call(target, selectors);
|
|
1847
2212
|
};
|
|
1848
|
-
|
|
2213
|
+
rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
1849
2214
|
var _a;
|
|
1850
2215
|
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1851
2216
|
return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
|
|
1852
2217
|
};
|
|
1853
|
-
|
|
2218
|
+
// rewrite setAttribute, complete resource address
|
|
2219
|
+
rawRootElement.prototype.setAttribute = function setAttribute(key, value) {
|
|
2220
|
+
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
2221
|
+
if (appName &&
|
|
2222
|
+
appInstanceMap.has(appName) &&
|
|
2223
|
+
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
2224
|
+
(key === 'href' && /^link$/i.test(this.tagName)))) {
|
|
2225
|
+
const app = appInstanceMap.get(appName);
|
|
2226
|
+
value = CompletionPath(value, app.url);
|
|
2227
|
+
}
|
|
2228
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
2229
|
+
};
|
|
2230
|
+
/**
|
|
2231
|
+
* TODO: 兼容直接通过img.src等操作设置的资源
|
|
2232
|
+
* NOTE:
|
|
2233
|
+
* 1. 卸载时恢复原始值
|
|
2234
|
+
* 2. 循环嵌套的情况
|
|
2235
|
+
* 3. 放在global_env中统一处理
|
|
2236
|
+
* 4. 是否和completePathDynamic的作用重复?
|
|
2237
|
+
*/
|
|
2238
|
+
// const protoAttrList: Array<[HTMLElement, string]> = [
|
|
2239
|
+
// [HTMLImageElement.prototype, 'src'],
|
|
2240
|
+
// [HTMLScriptElement.prototype, 'src'],
|
|
2241
|
+
// [HTMLLinkElement.prototype, 'href'],
|
|
2242
|
+
// ]
|
|
2243
|
+
// protoAttrList.forEach(([target, attr]) => {
|
|
2244
|
+
// const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
|
|
2245
|
+
// enumerable: true,
|
|
2246
|
+
// configurable: true,
|
|
2247
|
+
// }
|
|
2248
|
+
// rawDefineProperty(target, attr, {
|
|
2249
|
+
// enumerable,
|
|
2250
|
+
// configurable,
|
|
2251
|
+
// get: function () {
|
|
2252
|
+
// return get?.call(this)
|
|
2253
|
+
// },
|
|
2254
|
+
// set: function (value) {
|
|
2255
|
+
// const currentAppName = getCurrentAppName()
|
|
2256
|
+
// if (currentAppName && appInstanceMap.has(currentAppName)) {
|
|
2257
|
+
// const app = appInstanceMap.get(currentAppName)
|
|
2258
|
+
// value = CompletionPath(value, app!.url)
|
|
2259
|
+
// }
|
|
2260
|
+
// set?.call(this, value)
|
|
2261
|
+
// },
|
|
2262
|
+
// })
|
|
2263
|
+
// })
|
|
2264
|
+
rawDefineProperty(rawRootElement.prototype, 'innerHTML', {
|
|
1854
2265
|
configurable: true,
|
|
1855
2266
|
enumerable: true,
|
|
1856
2267
|
get() {
|
|
@@ -1866,7 +2277,9 @@ function patchElementAndDocument() {
|
|
|
1866
2277
|
});
|
|
1867
2278
|
}
|
|
1868
2279
|
});
|
|
1869
|
-
|
|
2280
|
+
/**
|
|
2281
|
+
* NOTE:Abandon this way at 2023.2.28 before v1.0.0-beta.0, it will cause vue2 throw error when render again
|
|
2282
|
+
*/
|
|
1870
2283
|
// rawDefineProperty(Node.prototype, 'parentNode', {
|
|
1871
2284
|
// configurable: true,
|
|
1872
2285
|
// enumerable: true,
|
|
@@ -1921,33 +2334,35 @@ function patchDocument() {
|
|
|
1921
2334
|
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
1922
2335
|
return markElement(element);
|
|
1923
2336
|
};
|
|
2337
|
+
// rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
|
|
2338
|
+
// const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
|
|
2339
|
+
// return markElement(element)
|
|
2340
|
+
// }
|
|
1924
2341
|
// query element👇
|
|
1925
2342
|
function querySelector(selectors) {
|
|
1926
|
-
var _a, _b
|
|
2343
|
+
var _a, _b;
|
|
1927
2344
|
const _this = getBindTarget(this);
|
|
1928
2345
|
const currentAppName = getCurrentAppName();
|
|
1929
2346
|
if (!currentAppName ||
|
|
1930
|
-
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1931
2347
|
!selectors ||
|
|
1932
2348
|
isUniqueElement(selectors) ||
|
|
1933
2349
|
// see https://github.com/micro-zoe/micro-app/issues/56
|
|
1934
2350
|
rawDocument !== _this) {
|
|
1935
2351
|
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
1936
2352
|
}
|
|
1937
|
-
return (
|
|
2353
|
+
return (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
1938
2354
|
}
|
|
1939
2355
|
function querySelectorAll(selectors) {
|
|
1940
|
-
var _a, _b
|
|
2356
|
+
var _a, _b;
|
|
1941
2357
|
const _this = getBindTarget(this);
|
|
1942
2358
|
const currentAppName = getCurrentAppName();
|
|
1943
2359
|
if (!currentAppName ||
|
|
1944
|
-
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1945
2360
|
!selectors ||
|
|
1946
2361
|
isUniqueElement(selectors) ||
|
|
1947
2362
|
rawDocument !== _this) {
|
|
1948
2363
|
return globalEnv.rawQuerySelectorAll.call(_this, selectors);
|
|
1949
2364
|
}
|
|
1950
|
-
return (
|
|
2365
|
+
return (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
1951
2366
|
}
|
|
1952
2367
|
rawRootDocument.prototype.querySelector = querySelector;
|
|
1953
2368
|
rawRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
@@ -2005,45 +2420,6 @@ function patchDocument() {
|
|
|
2005
2420
|
}
|
|
2006
2421
|
};
|
|
2007
2422
|
}
|
|
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
2423
|
function releasePatchDocument() {
|
|
2048
2424
|
const rawRootDocument = globalEnv.rawRootDocument;
|
|
2049
2425
|
rawRootDocument.prototype.createElement = globalEnv.rawCreateElement;
|
|
@@ -2060,21 +2436,18 @@ function releasePatchDocument() {
|
|
|
2060
2436
|
function releasePatchElementAndDocument() {
|
|
2061
2437
|
removeDomScope();
|
|
2062
2438
|
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;
|
|
2439
|
+
const rawRootElement = globalEnv.rawRootElement;
|
|
2440
|
+
rawRootElement.prototype.appendChild = globalEnv.rawAppendChild;
|
|
2441
|
+
rawRootElement.prototype.insertBefore = globalEnv.rawInsertBefore;
|
|
2442
|
+
rawRootElement.prototype.replaceChild = globalEnv.rawReplaceChild;
|
|
2443
|
+
rawRootElement.prototype.removeChild = globalEnv.rawRemoveChild;
|
|
2444
|
+
rawRootElement.prototype.append = globalEnv.rawAppend;
|
|
2445
|
+
rawRootElement.prototype.prepend = globalEnv.rawPrepend;
|
|
2446
|
+
rawRootElement.prototype.cloneNode = globalEnv.rawCloneNode;
|
|
2447
|
+
rawRootElement.prototype.querySelector = globalEnv.rawElementQuerySelector;
|
|
2448
|
+
rawRootElement.prototype.querySelectorAll = globalEnv.rawElementQuerySelectorAll;
|
|
2449
|
+
rawRootElement.prototype.setAttribute = globalEnv.rawSetAttribute;
|
|
2450
|
+
rawDefineProperty(rawRootElement.prototype, 'innerHTML', globalEnv.rawInnerHTMLDesc);
|
|
2078
2451
|
}
|
|
2079
2452
|
// Set the style of micro-app-head and micro-app-body
|
|
2080
2453
|
let hasRejectMicroAppStyle = false;
|
|
@@ -2103,23 +2476,24 @@ function initGlobalEnv() {
|
|
|
2103
2476
|
const rawWindow = window.rawWindow || Function('return window')();
|
|
2104
2477
|
const rawDocument = window.rawDocument || Function('return document')();
|
|
2105
2478
|
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(
|
|
2479
|
+
const rawRootElement = rawWindow.Element;
|
|
2480
|
+
const rawRootNode = rawWindow.Node;
|
|
2481
|
+
const rawRootEventTarget = rawWindow.EventTarget;
|
|
2482
|
+
// save patch raw methods, pay attention to this binding
|
|
2483
|
+
const rawSetAttribute = rawRootElement.prototype.setAttribute;
|
|
2484
|
+
const rawAppendChild = rawRootElement.prototype.appendChild;
|
|
2485
|
+
const rawInsertBefore = rawRootElement.prototype.insertBefore;
|
|
2486
|
+
const rawReplaceChild = rawRootElement.prototype.replaceChild;
|
|
2487
|
+
const rawRemoveChild = rawRootElement.prototype.removeChild;
|
|
2488
|
+
const rawAppend = rawRootElement.prototype.append;
|
|
2489
|
+
const rawPrepend = rawRootElement.prototype.prepend;
|
|
2490
|
+
const rawCloneNode = rawRootElement.prototype.cloneNode;
|
|
2491
|
+
const rawElementQuerySelector = rawRootElement.prototype.querySelector;
|
|
2492
|
+
const rawElementQuerySelectorAll = rawRootElement.prototype.querySelectorAll;
|
|
2493
|
+
const rawInsertAdjacentElement = rawRootElement.prototype.insertAdjacentElement;
|
|
2494
|
+
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(rawRootElement.prototype, 'innerHTML');
|
|
2495
|
+
const rawParentNodeDesc = Object.getOwnPropertyDescriptor(rawRootNode.prototype, 'parentNode');
|
|
2496
|
+
// Document proto methods
|
|
2123
2497
|
const rawCreateElement = rawRootDocument.prototype.createElement;
|
|
2124
2498
|
const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
|
|
2125
2499
|
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
@@ -2133,7 +2507,9 @@ function initGlobalEnv() {
|
|
|
2133
2507
|
const ImageProxy = new Proxy(Image, {
|
|
2134
2508
|
construct(Target, args) {
|
|
2135
2509
|
const elementImage = new Target(...args);
|
|
2136
|
-
|
|
2510
|
+
const currentAppName = getCurrentAppName();
|
|
2511
|
+
if (currentAppName)
|
|
2512
|
+
elementImage.__MICRO_APP_NAME__ = currentAppName;
|
|
2137
2513
|
return elementImage;
|
|
2138
2514
|
},
|
|
2139
2515
|
});
|
|
@@ -2147,19 +2523,16 @@ function initGlobalEnv() {
|
|
|
2147
2523
|
const rawClearTimeout = rawWindow.clearTimeout;
|
|
2148
2524
|
const rawPushState = rawWindow.history.pushState;
|
|
2149
2525
|
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;
|
|
2526
|
+
const rawAddEventListener = rawRootEventTarget.prototype.addEventListener;
|
|
2527
|
+
const rawRemoveEventListener = rawRootEventTarget.prototype.removeEventListener;
|
|
2157
2528
|
assign(globalEnv, {
|
|
2529
|
+
supportModuleScript: isSupportModuleScript(),
|
|
2158
2530
|
// common global vars
|
|
2159
2531
|
rawWindow,
|
|
2160
2532
|
rawDocument,
|
|
2161
2533
|
rawRootDocument,
|
|
2162
|
-
|
|
2534
|
+
rawRootElement,
|
|
2535
|
+
rawRootNode,
|
|
2163
2536
|
// source/patch
|
|
2164
2537
|
rawSetAttribute,
|
|
2165
2538
|
rawAppendChild,
|
|
@@ -2171,6 +2544,7 @@ function initGlobalEnv() {
|
|
|
2171
2544
|
rawCloneNode,
|
|
2172
2545
|
rawElementQuerySelector,
|
|
2173
2546
|
rawElementQuerySelectorAll,
|
|
2547
|
+
rawInsertAdjacentElement,
|
|
2174
2548
|
rawInnerHTMLDesc,
|
|
2175
2549
|
rawParentNodeDesc,
|
|
2176
2550
|
rawCreateElement,
|
|
@@ -2185,14 +2559,10 @@ function initGlobalEnv() {
|
|
|
2185
2559
|
rawGetElementsByName,
|
|
2186
2560
|
ImageProxy,
|
|
2187
2561
|
// sandbox/effect
|
|
2188
|
-
rawWindowAddEventListener,
|
|
2189
|
-
rawWindowRemoveEventListener,
|
|
2190
2562
|
rawSetInterval,
|
|
2191
2563
|
rawSetTimeout,
|
|
2192
2564
|
rawClearInterval,
|
|
2193
2565
|
rawClearTimeout,
|
|
2194
|
-
rawDocumentAddEventListener,
|
|
2195
|
-
rawDocumentRemoveEventListener,
|
|
2196
2566
|
rawPushState,
|
|
2197
2567
|
rawReplaceState,
|
|
2198
2568
|
rawAddEventListener,
|
|
@@ -2203,576 +2573,229 @@ function initGlobalEnv() {
|
|
|
2203
2573
|
}
|
|
2204
2574
|
}
|
|
2205
2575
|
|
|
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
2576
|
/**
|
|
2217
|
-
*
|
|
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
|
|
2577
|
+
*
|
|
2242
2578
|
* @param appName app.name
|
|
2243
|
-
* @param
|
|
2244
|
-
* @param currentCode pure code of current address
|
|
2579
|
+
* @param linkInfo linkInfo of current address
|
|
2245
2580
|
*/
|
|
2246
|
-
function
|
|
2247
|
-
const appSpace =
|
|
2248
|
-
for (const item in appSpace) {
|
|
2249
|
-
if (item !==
|
|
2581
|
+
function getExistParseCode(appName, prefix, linkInfo) {
|
|
2582
|
+
const appSpace = linkInfo.appSpace;
|
|
2583
|
+
for (const item in appSpace) {
|
|
2584
|
+
if (item !== appName) {
|
|
2250
2585
|
const appSpaceData = appSpace[item];
|
|
2251
|
-
if (appSpaceData.parsedCode
|
|
2252
|
-
return appSpaceData.
|
|
2586
|
+
if (appSpaceData.parsedCode) {
|
|
2587
|
+
return appSpaceData.parsedCode.replace(new RegExp(createPrefix(item, true), 'g'), prefix);
|
|
2253
2588
|
}
|
|
2254
2589
|
}
|
|
2255
2590
|
}
|
|
2256
2591
|
}
|
|
2257
|
-
|
|
2258
|
-
|
|
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) {
|
|
2592
|
+
// transfer the attributes on the link to convertStyle
|
|
2593
|
+
function setConvertStyleAttr(convertStyle, attrs) {
|
|
2274
2594
|
attrs.forEach((value, key) => {
|
|
2275
|
-
if (
|
|
2595
|
+
if (key === 'rel')
|
|
2276
2596
|
return;
|
|
2277
|
-
if (key === '
|
|
2278
|
-
key = 'data-origin-
|
|
2279
|
-
|
|
2597
|
+
if (key === 'href')
|
|
2598
|
+
key = 'data-origin-href';
|
|
2599
|
+
globalEnv.rawSetAttribute.call(convertStyle, key, value);
|
|
2280
2600
|
});
|
|
2281
2601
|
}
|
|
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
2602
|
/**
|
|
2290
|
-
* Extract
|
|
2291
|
-
* @param
|
|
2292
|
-
* @param parent parent element of
|
|
2603
|
+
* Extract link elements
|
|
2604
|
+
* @param link link element
|
|
2605
|
+
* @param parent parent element of link
|
|
2293
2606
|
* @param app app
|
|
2607
|
+
* @param microAppHead micro-app-head element
|
|
2294
2608
|
* @param isDynamic dynamic insert
|
|
2295
2609
|
*/
|
|
2296
|
-
function
|
|
2297
|
-
|
|
2610
|
+
function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
2611
|
+
const rel = link.getAttribute('rel');
|
|
2612
|
+
let href = link.getAttribute('href');
|
|
2298
2613
|
let replaceComment = null;
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
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);
|
|
2614
|
+
if (rel === 'stylesheet' && href) {
|
|
2615
|
+
href = CompletionPath(href, app.url);
|
|
2616
|
+
let linkInfo = sourceCenter.link.getInfo(href);
|
|
2321
2617
|
const appSpaceData = {
|
|
2322
|
-
|
|
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),
|
|
2618
|
+
attrs: getAttributes(link),
|
|
2328
2619
|
};
|
|
2329
|
-
if (!
|
|
2330
|
-
|
|
2620
|
+
if (!linkInfo) {
|
|
2621
|
+
linkInfo = {
|
|
2331
2622
|
code: '',
|
|
2332
|
-
isExternal: true,
|
|
2333
2623
|
appSpace: {
|
|
2334
2624
|
[app.name]: appSpaceData,
|
|
2335
2625
|
}
|
|
2336
2626
|
};
|
|
2337
2627
|
}
|
|
2338
|
-
else {
|
|
2339
|
-
|
|
2340
|
-
|
|
2341
|
-
|
|
2342
|
-
|
|
2343
|
-
|
|
2344
|
-
|
|
2345
|
-
|
|
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);
|
|
2479
|
-
}
|
|
2480
|
-
}
|
|
2481
|
-
/**
|
|
2482
|
-
* fetch js succeeded, record the code value
|
|
2483
|
-
* @param address script address
|
|
2484
|
-
* @param scriptInfo resource script info
|
|
2485
|
-
* @param data code
|
|
2486
|
-
*/
|
|
2487
|
-
function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
2488
|
-
// reset scriptInfo.code
|
|
2489
|
-
scriptInfo.code = code;
|
|
2490
|
-
/**
|
|
2491
|
-
* Pre parse script for prefetch, improve rendering performance
|
|
2492
|
-
* NOTE:
|
|
2493
|
-
* 1. if global parseResult exist, skip this step
|
|
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
|
-
}
|
|
2516
|
-
}
|
|
2517
|
-
}
|
|
2518
|
-
}
|
|
2519
|
-
}
|
|
2520
|
-
/**
|
|
2521
|
-
* Execute js in the mount lifecycle
|
|
2522
|
-
* @param app app
|
|
2523
|
-
* @param initHook callback for umd mode
|
|
2524
|
-
*/
|
|
2525
|
-
function execScripts(app, initHook) {
|
|
2526
|
-
const fiberScriptTasks = app.fiber ? [] : null;
|
|
2527
|
-
const scriptList = Array.from(app.source.scripts);
|
|
2528
|
-
const deferScriptPromise = [];
|
|
2529
|
-
const deferScriptInfo = [];
|
|
2530
|
-
for (const address of scriptList) {
|
|
2531
|
-
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2532
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2533
|
-
// Notice the second render
|
|
2534
|
-
if (appSpaceData.defer || appSpaceData.async) {
|
|
2535
|
-
// TODO: defer和module彻底分开,不要混在一起
|
|
2536
|
-
if (scriptInfo.isExternal && !scriptInfo.code && !(app.iframe && appSpaceData.module)) {
|
|
2537
|
-
deferScriptPromise.push(fetchSource(address, app.name));
|
|
2538
|
-
}
|
|
2539
|
-
else {
|
|
2540
|
-
deferScriptPromise.push(scriptInfo.code);
|
|
2541
|
-
}
|
|
2542
|
-
deferScriptInfo.push([address, scriptInfo]);
|
|
2543
|
-
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
2544
|
-
}
|
|
2545
|
-
else {
|
|
2546
|
-
injectFiberTask(fiberScriptTasks, () => {
|
|
2547
|
-
runScript(address, app, scriptInfo);
|
|
2548
|
-
initHook(false);
|
|
2549
|
-
});
|
|
2550
|
-
}
|
|
2551
|
-
}
|
|
2552
|
-
if (deferScriptPromise.length) {
|
|
2553
|
-
promiseStream(deferScriptPromise, (res) => {
|
|
2554
|
-
const scriptInfo = deferScriptInfo[res.index][1];
|
|
2555
|
-
scriptInfo.code = scriptInfo.code || res.data;
|
|
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);
|
|
2591
|
-
}
|
|
2592
|
-
else {
|
|
2593
|
-
initHook(true);
|
|
2594
|
-
}
|
|
2595
|
-
}
|
|
2596
|
-
}
|
|
2597
|
-
/**
|
|
2598
|
-
* run code
|
|
2599
|
-
* @param address script address
|
|
2600
|
-
* @param app app
|
|
2601
|
-
* @param scriptInfo script info
|
|
2602
|
-
* @param callback callback of module script
|
|
2603
|
-
*/
|
|
2604
|
-
function runScript(address, app, scriptInfo, callback, replaceElement) {
|
|
2605
|
-
try {
|
|
2606
|
-
actionsBeforeRunScript(app);
|
|
2607
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2608
|
-
const sandboxType = getSandboxType(app, scriptInfo);
|
|
2609
|
-
/**
|
|
2610
|
-
* NOTE:
|
|
2611
|
-
* 1. plugins and wrapCode will only be executed once
|
|
2612
|
-
* 2. if parsedCode not exist, parsedFunction is not exist
|
|
2613
|
-
* 3. if parsedCode exist, parsedFunction does not necessarily exist
|
|
2614
|
-
*/
|
|
2615
|
-
if (!appSpaceData.parsedCode || appSpaceData.sandboxType !== sandboxType) {
|
|
2616
|
-
appSpaceData.parsedCode = bindScope(address, app, scriptInfo.code, scriptInfo);
|
|
2617
|
-
appSpaceData.sandboxType = sandboxType;
|
|
2618
|
-
appSpaceData.parsedFunction = null;
|
|
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
|
-
}
|
|
2628
|
-
}
|
|
2629
|
-
else {
|
|
2630
|
-
runParsedFunction(app, scriptInfo);
|
|
2631
|
-
}
|
|
2632
|
-
}
|
|
2633
|
-
catch (e) {
|
|
2634
|
-
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
2635
|
-
}
|
|
2636
|
-
}
|
|
2637
|
-
/**
|
|
2638
|
-
* Get dynamically created remote script
|
|
2639
|
-
* @param address script address
|
|
2640
|
-
* @param app app instance
|
|
2641
|
-
* @param scriptInfo scriptInfo
|
|
2642
|
-
* @param originScript origin script element
|
|
2643
|
-
*/
|
|
2644
|
-
function runDynamicRemoteScript(address, app, scriptInfo, originScript) {
|
|
2645
|
-
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
2646
|
-
const dispatchScriptOnLoadEvent = () => dispatchOnLoadEvent(originScript);
|
|
2647
|
-
const runDynamicScript = () => {
|
|
2648
|
-
const descriptor = Object.getOwnPropertyDescriptor(globalEnv.rawDocument, 'currentScript');
|
|
2649
|
-
if (!descriptor || descriptor.configurable) {
|
|
2650
|
-
Object.defineProperty(globalEnv.rawDocument, 'currentScript', {
|
|
2651
|
-
value: originScript,
|
|
2652
|
-
configurable: true,
|
|
2653
|
-
});
|
|
2654
|
-
}
|
|
2655
|
-
runScript(address, app, scriptInfo, dispatchScriptOnLoadEvent, replaceElement);
|
|
2656
|
-
!isTypeModule(app, scriptInfo) && dispatchScriptOnLoadEvent();
|
|
2657
|
-
};
|
|
2658
|
-
if (scriptInfo.code || (app.iframe && scriptInfo.appSpace[app.name].module)) {
|
|
2659
|
-
defer(runDynamicScript);
|
|
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
|
-
});
|
|
2669
|
-
}
|
|
2670
|
-
return replaceElement;
|
|
2671
|
-
}
|
|
2672
|
-
/**
|
|
2673
|
-
* Get dynamically created inline script
|
|
2674
|
-
* @param address script address
|
|
2675
|
-
* @param app app instance
|
|
2676
|
-
* @param scriptInfo scriptInfo
|
|
2677
|
-
*/
|
|
2678
|
-
function runDynamicInlineScript(address, app, scriptInfo) {
|
|
2679
|
-
const replaceElement = isInlineMode(app, scriptInfo) ? pureCreateElement('script') : document.createComment('dynamic script extract by micro-app');
|
|
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
|
|
2691
|
-
*/
|
|
2692
|
-
function runCode2InlineScript(address, code, module, scriptElement, attrs, callback) {
|
|
2693
|
-
if (module) {
|
|
2694
|
-
// module script is async, transform it to a blob for subsequent operations
|
|
2695
|
-
if (isInlineScript(address)) {
|
|
2696
|
-
const blob = new Blob([code], { type: 'text/javascript' });
|
|
2697
|
-
scriptElement.src = URL.createObjectURL(blob);
|
|
2628
|
+
else {
|
|
2629
|
+
linkInfo.appSpace[app.name] = linkInfo.appSpace[app.name] || appSpaceData;
|
|
2630
|
+
}
|
|
2631
|
+
sourceCenter.link.setInfo(href, linkInfo);
|
|
2632
|
+
if (!isDynamic) {
|
|
2633
|
+
app.source.links.add(href);
|
|
2634
|
+
replaceComment = document.createComment(`link element with href=${href} move to micro-app-head as style element`);
|
|
2635
|
+
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
2698
2636
|
}
|
|
2699
2637
|
else {
|
|
2700
|
-
|
|
2638
|
+
return { address: href, linkInfo };
|
|
2701
2639
|
}
|
|
2702
|
-
|
|
2703
|
-
|
|
2704
|
-
|
|
2705
|
-
|
|
2706
|
-
|
|
2707
|
-
|
|
2708
|
-
|
|
2640
|
+
}
|
|
2641
|
+
else if (rel && ['prefetch', 'preload', 'prerender', 'icon', 'apple-touch-icon'].includes(rel)) {
|
|
2642
|
+
// preload prefetch icon ....
|
|
2643
|
+
if (isDynamic) {
|
|
2644
|
+
replaceComment = document.createComment(`link element with rel=${rel}${href ? ' & href=' + href : ''} removed by micro-app`);
|
|
2645
|
+
}
|
|
2646
|
+
else {
|
|
2647
|
+
parent === null || parent === void 0 ? void 0 : parent.removeChild(link);
|
|
2709
2648
|
}
|
|
2710
2649
|
}
|
|
2711
|
-
else {
|
|
2712
|
-
|
|
2650
|
+
else if (href) {
|
|
2651
|
+
// dns-prefetch preconnect modulepreload search ....
|
|
2652
|
+
globalEnv.rawSetAttribute.call(link, 'href', CompletionPath(href, app.url));
|
|
2713
2653
|
}
|
|
2714
|
-
|
|
2715
|
-
}
|
|
2716
|
-
|
|
2717
|
-
|
|
2718
|
-
|
|
2719
|
-
if (!appSpaceData.parsedFunction) {
|
|
2720
|
-
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2654
|
+
if (isDynamic) {
|
|
2655
|
+
return { replaceComment };
|
|
2656
|
+
}
|
|
2657
|
+
else if (replaceComment) {
|
|
2658
|
+
return parent === null || parent === void 0 ? void 0 : parent.replaceChild(replaceComment, link);
|
|
2721
2659
|
}
|
|
2722
|
-
appSpaceData.parsedFunction.call(getEffectWindow(app));
|
|
2723
2660
|
}
|
|
2724
2661
|
/**
|
|
2725
|
-
*
|
|
2662
|
+
* Get link remote resources
|
|
2663
|
+
* @param wrapElement htmlDom
|
|
2726
2664
|
* @param app app
|
|
2727
|
-
* @param
|
|
2728
|
-
* @param scriptInfo source script info
|
|
2665
|
+
* @param microAppHead micro-app-head
|
|
2729
2666
|
*/
|
|
2730
|
-
function
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
|
|
2736
|
-
|
|
2737
|
-
|
|
2738
|
-
|
|
2667
|
+
function fetchLinksFromHtml(wrapElement, app, microAppHead, fiberStyleResult) {
|
|
2668
|
+
const styleList = Array.from(app.source.links);
|
|
2669
|
+
const fetchLinkPromise = styleList.map((address) => {
|
|
2670
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
2671
|
+
return linkInfo.code ? linkInfo.code : fetchSource(address, app.name);
|
|
2672
|
+
});
|
|
2673
|
+
const fiberLinkTasks = fiberStyleResult ? [] : null;
|
|
2674
|
+
promiseStream(fetchLinkPromise, (res) => {
|
|
2675
|
+
injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
|
|
2676
|
+
}, (err) => {
|
|
2677
|
+
logError(err, app.name);
|
|
2678
|
+
}, () => {
|
|
2679
|
+
/**
|
|
2680
|
+
* 1. If fiberStyleResult exist, fiberLinkTasks must exist
|
|
2681
|
+
* 2. Download link source while processing style
|
|
2682
|
+
* 3. Process style first, and then process link
|
|
2683
|
+
*/
|
|
2684
|
+
if (fiberStyleResult) {
|
|
2685
|
+
fiberStyleResult.then(() => {
|
|
2686
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2687
|
+
serialExecFiberTasks(fiberLinkTasks);
|
|
2688
|
+
});
|
|
2689
|
+
}
|
|
2690
|
+
else {
|
|
2691
|
+
app.onLoad(wrapElement);
|
|
2692
|
+
}
|
|
2693
|
+
});
|
|
2739
2694
|
}
|
|
2740
2695
|
/**
|
|
2741
|
-
*
|
|
2696
|
+
* Fetch link succeeded, replace placeholder with style tag
|
|
2697
|
+
* NOTE:
|
|
2698
|
+
* 1. Only exec when init, no longer exec when remount
|
|
2699
|
+
* 2. Only handler html link element, not dynamic link or style
|
|
2700
|
+
* 3. The same prefix can reuse parsedCode
|
|
2701
|
+
* 4. Async exec with requestIdleCallback in prefetch or fiber
|
|
2702
|
+
* 5. appSpace[app.name].placeholder/attrs must exist
|
|
2703
|
+
* @param address resource address
|
|
2704
|
+
* @param code link source code
|
|
2705
|
+
* @param microAppHead micro-app-head
|
|
2706
|
+
* @param app app instance
|
|
2742
2707
|
*/
|
|
2743
|
-
function
|
|
2744
|
-
|
|
2708
|
+
function fetchLinkSuccess(address, code, microAppHead, app) {
|
|
2709
|
+
/**
|
|
2710
|
+
* linkInfo must exist, but linkInfo.code not
|
|
2711
|
+
* so we set code to linkInfo.code
|
|
2712
|
+
*/
|
|
2713
|
+
const linkInfo = sourceCenter.link.getInfo(address);
|
|
2714
|
+
linkInfo.code = code;
|
|
2715
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
2716
|
+
const placeholder = appSpaceData.placeholder;
|
|
2717
|
+
/**
|
|
2718
|
+
* 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.
|
|
2719
|
+
* This causes placeholder to be possibly null
|
|
2720
|
+
* e.g.
|
|
2721
|
+
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
2722
|
+
* 2. prefetch param different from <micro-app></micro-app>
|
|
2723
|
+
*/
|
|
2724
|
+
if (placeholder) {
|
|
2725
|
+
const convertStyle = pureCreateElement('style');
|
|
2726
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, appSpaceData.attrs);
|
|
2727
|
+
if (placeholder.parentNode) {
|
|
2728
|
+
placeholder.parentNode.replaceChild(convertStyle, placeholder);
|
|
2729
|
+
}
|
|
2730
|
+
else {
|
|
2731
|
+
microAppHead.appendChild(convertStyle);
|
|
2732
|
+
}
|
|
2733
|
+
// clear placeholder
|
|
2734
|
+
appSpaceData.placeholder = null;
|
|
2735
|
+
}
|
|
2745
2736
|
}
|
|
2746
2737
|
/**
|
|
2747
|
-
*
|
|
2738
|
+
* Get parsedCode, update convertStyle
|
|
2739
|
+
* Actions:
|
|
2740
|
+
* 1. get scope css (through scopedCSS or oldData)
|
|
2741
|
+
* 2. record parsedCode
|
|
2742
|
+
* 3. set parsedCode to convertStyle if need
|
|
2743
|
+
* @param app app instance
|
|
2744
|
+
* @param address resource address
|
|
2745
|
+
* @param convertStyle converted style
|
|
2746
|
+
* @param linkInfo linkInfo in sourceCenter
|
|
2747
|
+
* @param attrs attrs of link
|
|
2748
2748
|
*/
|
|
2749
|
-
function
|
|
2750
|
-
if (app.
|
|
2751
|
-
|
|
2749
|
+
function handleConvertStyle(app, address, convertStyle, linkInfo, attrs) {
|
|
2750
|
+
if (app.scopecss) {
|
|
2751
|
+
const appSpaceData = linkInfo.appSpace[app.name];
|
|
2752
|
+
appSpaceData.prefix = appSpaceData.prefix || createPrefix(app.name);
|
|
2753
|
+
if (!appSpaceData.parsedCode) {
|
|
2754
|
+
const existParsedCode = getExistParseCode(app.name, appSpaceData.prefix, linkInfo);
|
|
2755
|
+
if (!existParsedCode) {
|
|
2756
|
+
convertStyle.textContent = linkInfo.code;
|
|
2757
|
+
scopedCSS(convertStyle, app, address);
|
|
2758
|
+
}
|
|
2759
|
+
else {
|
|
2760
|
+
convertStyle.textContent = existParsedCode;
|
|
2761
|
+
}
|
|
2762
|
+
appSpaceData.parsedCode = convertStyle.textContent;
|
|
2763
|
+
}
|
|
2764
|
+
else {
|
|
2765
|
+
convertStyle.textContent = appSpaceData.parsedCode;
|
|
2766
|
+
}
|
|
2767
|
+
}
|
|
2768
|
+
else {
|
|
2769
|
+
convertStyle.textContent = linkInfo.code;
|
|
2752
2770
|
}
|
|
2771
|
+
setConvertStyleAttr(convertStyle, attrs);
|
|
2753
2772
|
}
|
|
2754
2773
|
/**
|
|
2755
|
-
*
|
|
2756
|
-
* @param address
|
|
2757
|
-
* @param
|
|
2758
|
-
* @param
|
|
2759
|
-
* @param
|
|
2774
|
+
* Handle css of dynamic link
|
|
2775
|
+
* @param address link address
|
|
2776
|
+
* @param app app
|
|
2777
|
+
* @param linkInfo linkInfo
|
|
2778
|
+
* @param originLink origin link element
|
|
2760
2779
|
*/
|
|
2761
|
-
function
|
|
2762
|
-
|
|
2763
|
-
const
|
|
2764
|
-
|
|
2765
|
-
|
|
2766
|
-
|
|
2767
|
-
if (
|
|
2768
|
-
|
|
2780
|
+
function formatDynamicLink(address, app, linkInfo, originLink) {
|
|
2781
|
+
const convertStyle = pureCreateElement('style');
|
|
2782
|
+
const handleDynamicLink = () => {
|
|
2783
|
+
handleConvertStyle(app, address, convertStyle, linkInfo, linkInfo.appSpace[app.name].attrs);
|
|
2784
|
+
dispatchOnLoadEvent(originLink);
|
|
2785
|
+
};
|
|
2786
|
+
if (linkInfo.code) {
|
|
2787
|
+
defer(handleDynamicLink);
|
|
2769
2788
|
}
|
|
2770
|
-
|
|
2771
|
-
|
|
2772
|
-
|
|
2773
|
-
|
|
2774
|
-
|
|
2775
|
-
|
|
2789
|
+
else {
|
|
2790
|
+
fetchSource(address, app.name).then((data) => {
|
|
2791
|
+
linkInfo.code = data;
|
|
2792
|
+
handleDynamicLink();
|
|
2793
|
+
}).catch((err) => {
|
|
2794
|
+
logError(err, app.name);
|
|
2795
|
+
dispatchOnErrorEvent(originLink);
|
|
2796
|
+
});
|
|
2797
|
+
}
|
|
2798
|
+
return convertStyle;
|
|
2776
2799
|
}
|
|
2777
2800
|
|
|
2778
2801
|
/**
|
|
@@ -2804,7 +2827,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2804
2827
|
extractLinkFromHtml(dom, parent, app);
|
|
2805
2828
|
}
|
|
2806
2829
|
else if (dom.hasAttribute('href')) {
|
|
2807
|
-
|
|
2830
|
+
globalEnv.rawSetAttribute.call(dom, 'href', CompletionPath(dom.getAttribute('href'), app.url));
|
|
2808
2831
|
}
|
|
2809
2832
|
}
|
|
2810
2833
|
else if (isStyleElement(dom)) {
|
|
@@ -2819,7 +2842,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2819
2842
|
extractScriptElement(dom, parent, app);
|
|
2820
2843
|
}
|
|
2821
2844
|
else if (isImageElement(dom) && dom.hasAttribute('src')) {
|
|
2822
|
-
|
|
2845
|
+
globalEnv.rawSetAttribute.call(dom, 'src', CompletionPath(dom.getAttribute('src'), app.url));
|
|
2823
2846
|
}
|
|
2824
2847
|
/**
|
|
2825
2848
|
* Don't remove meta and title, they have some special scenes
|
|
@@ -2871,6 +2894,40 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2871
2894
|
}
|
|
2872
2895
|
}
|
|
2873
2896
|
|
|
2897
|
+
/* eslint-disable no-return-assign */
|
|
2898
|
+
function isBoundedFunction(value) {
|
|
2899
|
+
if (isBoolean(value.__MICRO_APP_IS_BOUND_FUNCTION__))
|
|
2900
|
+
return value.__MICRO_APP_IS_BOUND_FUNCTION__;
|
|
2901
|
+
return value.__MICRO_APP_IS_BOUND_FUNCTION__ = isBoundFunction(value);
|
|
2902
|
+
}
|
|
2903
|
+
function isConstructorFunction(value) {
|
|
2904
|
+
if (isBoolean(value.__MICRO_APP_IS_CONSTRUCTOR__))
|
|
2905
|
+
return value.__MICRO_APP_IS_CONSTRUCTOR__;
|
|
2906
|
+
return value.__MICRO_APP_IS_CONSTRUCTOR__ = isConstructor(value);
|
|
2907
|
+
}
|
|
2908
|
+
// eslint-disable-next-line @typescript-eslint/explicit-module-boundary-types
|
|
2909
|
+
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
2910
|
+
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
|
|
2911
|
+
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
2912
|
+
if (value[cacheKey])
|
|
2913
|
+
return value[cacheKey];
|
|
2914
|
+
const bindRawObjectValue = value.bind(rawTarget);
|
|
2915
|
+
for (const key in value) {
|
|
2916
|
+
bindRawObjectValue[key] = value[key];
|
|
2917
|
+
}
|
|
2918
|
+
if (value.hasOwnProperty('prototype')) {
|
|
2919
|
+
rawDefineProperty(bindRawObjectValue, 'prototype', {
|
|
2920
|
+
value: value.prototype,
|
|
2921
|
+
configurable: true,
|
|
2922
|
+
enumerable: false,
|
|
2923
|
+
writable: true,
|
|
2924
|
+
});
|
|
2925
|
+
}
|
|
2926
|
+
return value[cacheKey] = bindRawObjectValue;
|
|
2927
|
+
}
|
|
2928
|
+
return value;
|
|
2929
|
+
}
|
|
2930
|
+
|
|
2874
2931
|
class EventCenter {
|
|
2875
2932
|
constructor() {
|
|
2876
2933
|
this.eventList = new Map();
|
|
@@ -3315,159 +3372,208 @@ function unmountNestedApp() {
|
|
|
3315
3372
|
function releaseUnmountOfNestedApp() {
|
|
3316
3373
|
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
3317
3374
|
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);
|
|
3375
|
+
}
|
|
3339
3376
|
}
|
|
3340
|
-
//
|
|
3341
|
-
|
|
3342
|
-
|
|
3343
|
-
|
|
3344
|
-
|
|
3345
|
-
|
|
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;
|
|
3377
|
+
// if micro-app run in micro application, delete all next generation application when unmount event received
|
|
3378
|
+
// unmount event will auto release by sandbox
|
|
3379
|
+
function initEnvOfNestedApp() {
|
|
3380
|
+
if (window.__MICRO_APP_ENVIRONMENT__) {
|
|
3381
|
+
releaseUnmountOfNestedApp();
|
|
3382
|
+
window.addEventListener('unmount', unmountNestedApp, false);
|
|
3359
3383
|
}
|
|
3360
|
-
return value;
|
|
3361
3384
|
}
|
|
3362
3385
|
|
|
3363
|
-
|
|
3364
|
-
const
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
3374
|
-
|
|
3375
|
-
|
|
3376
|
-
let hasDocumentClickInited = false;
|
|
3377
|
-
function onClickHandler(e) {
|
|
3378
|
-
documentClickListMap.forEach((f) => {
|
|
3379
|
-
isFunction(f) && f.call(document, e);
|
|
3380
|
-
});
|
|
3386
|
+
function createMicroDocument(appName, proxyDocument) {
|
|
3387
|
+
const { rawDocument, rawRootDocument } = globalEnv;
|
|
3388
|
+
class MicroDocument {
|
|
3389
|
+
static [Symbol.hasInstance](target) {
|
|
3390
|
+
let proto = target;
|
|
3391
|
+
while (proto = Object.getPrototypeOf(proto)) {
|
|
3392
|
+
if (proto === MicroDocument.prototype) {
|
|
3393
|
+
return true;
|
|
3394
|
+
}
|
|
3395
|
+
}
|
|
3396
|
+
return (target === proxyDocument ||
|
|
3397
|
+
target instanceof rawRootDocument);
|
|
3398
|
+
}
|
|
3381
3399
|
}
|
|
3382
|
-
|
|
3383
|
-
|
|
3384
|
-
|
|
3385
|
-
|
|
3386
|
-
|
|
3387
|
-
|
|
3400
|
+
/**
|
|
3401
|
+
* TIP:
|
|
3402
|
+
* 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
|
|
3403
|
+
* 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
|
|
3404
|
+
* e.g.
|
|
3405
|
+
* class B extends A {}
|
|
3406
|
+
* B.__proto__ === A // true
|
|
3407
|
+
* B.prototype.__proto__ === A.prototype // true
|
|
3408
|
+
*/
|
|
3409
|
+
Object.setPrototypeOf(MicroDocument, rawRootDocument);
|
|
3410
|
+
// Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
|
|
3411
|
+
Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
|
|
3412
|
+
get(target, key) {
|
|
3413
|
+
throttleDeferForSetAppName(appName);
|
|
3414
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
3388
3415
|
},
|
|
3389
|
-
set(
|
|
3390
|
-
|
|
3391
|
-
|
|
3392
|
-
documentClickListMap.set(appName, f);
|
|
3393
|
-
}
|
|
3394
|
-
else {
|
|
3395
|
-
documentClickListMap.set('base', f);
|
|
3396
|
-
}
|
|
3397
|
-
if (!hasDocumentClickInited && isFunction(f)) {
|
|
3398
|
-
hasDocumentClickInited = true;
|
|
3399
|
-
globalEnv.rawDocumentAddEventListener.call(globalEnv.rawDocument, 'click', onClickHandler, false);
|
|
3400
|
-
}
|
|
3416
|
+
set(target, key, value) {
|
|
3417
|
+
Reflect.set(target, key, value);
|
|
3418
|
+
return true;
|
|
3401
3419
|
}
|
|
3402
|
-
});
|
|
3403
|
-
|
|
3420
|
+
}));
|
|
3421
|
+
return MicroDocument;
|
|
3404
3422
|
}
|
|
3405
3423
|
/**
|
|
3406
|
-
*
|
|
3424
|
+
* Create new document and Document
|
|
3407
3425
|
*/
|
|
3408
|
-
|
|
3409
|
-
|
|
3410
|
-
const
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
|
|
3420
|
-
|
|
3421
|
-
|
|
3422
|
-
|
|
3423
|
-
|
|
3424
|
-
|
|
3425
|
-
|
|
3426
|
-
|
|
3427
|
-
|
|
3428
|
-
|
|
3429
|
-
|
|
3426
|
+
function createProxyDocument(appName, sandbox) {
|
|
3427
|
+
const eventListenerMap = new Map();
|
|
3428
|
+
const sstEventListenerMap = new Map();
|
|
3429
|
+
let onClickHandler = null;
|
|
3430
|
+
let sstOnClickHandler = null;
|
|
3431
|
+
const { rawDocument, rawCreateElement, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
3432
|
+
function createElement(tagName, options) {
|
|
3433
|
+
const element = rawCreateElement.call(rawDocument, tagName, options);
|
|
3434
|
+
element.__MICRO_APP_NAME__ = appName;
|
|
3435
|
+
return element;
|
|
3436
|
+
}
|
|
3437
|
+
/**
|
|
3438
|
+
* TODO:
|
|
3439
|
+
* 1. listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
3440
|
+
* 2. 相似代码提取为公共方法(with, iframe)
|
|
3441
|
+
*/
|
|
3442
|
+
function addEventListener(type, listener, options) {
|
|
3443
|
+
const listenerList = eventListenerMap.get(type);
|
|
3444
|
+
if (listenerList) {
|
|
3445
|
+
listenerList.add(listener);
|
|
3446
|
+
}
|
|
3447
|
+
else {
|
|
3448
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
3449
|
+
}
|
|
3450
|
+
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
3451
|
+
rawAddEventListener.call(rawDocument, type, listener, options);
|
|
3452
|
+
}
|
|
3453
|
+
function removeEventListener(type, listener, options) {
|
|
3454
|
+
const listenerList = eventListenerMap.get(type);
|
|
3455
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3456
|
+
listenerList.delete(listener);
|
|
3457
|
+
}
|
|
3458
|
+
rawRemoveEventListener.call(rawDocument, type, listener, options);
|
|
3459
|
+
}
|
|
3460
|
+
// reset snapshot data
|
|
3461
|
+
const reset = () => {
|
|
3462
|
+
sstEventListenerMap.clear();
|
|
3463
|
+
sstOnClickHandler = null;
|
|
3464
|
+
};
|
|
3465
|
+
/**
|
|
3466
|
+
* NOTE:
|
|
3467
|
+
* 1. about timer(events & properties should record & rebuild at all modes, exclude default mode)
|
|
3468
|
+
* 2. record maybe call twice when unmount prerender, keep-alive app manually with umd mode
|
|
3469
|
+
* 4 modes: default-mode、umd-mode、prerender、keep-alive
|
|
3470
|
+
* Solution:
|
|
3471
|
+
* 1. default-mode(normal): clear events & timers, not record & rebuild anything
|
|
3472
|
+
* 2. umd-mode(normal): not clear timers, record & rebuild events
|
|
3473
|
+
* 3. prerender/keep-alive(default, umd): not clear timers, record & rebuild events
|
|
3474
|
+
*/
|
|
3475
|
+
const record = () => {
|
|
3476
|
+
// record onclick handler
|
|
3477
|
+
sstOnClickHandler = sstOnClickHandler || onClickHandler;
|
|
3478
|
+
// record document event
|
|
3479
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
3480
|
+
if (listenerList.size) {
|
|
3481
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
3430
3482
|
}
|
|
3431
|
-
|
|
3432
|
-
|
|
3483
|
+
});
|
|
3484
|
+
};
|
|
3485
|
+
// rebuild event and timer before remount app
|
|
3486
|
+
const rebuild = () => {
|
|
3487
|
+
// rebuild onclick event
|
|
3488
|
+
if (sstOnClickHandler)
|
|
3489
|
+
proxyDocument.onclick = sstOnClickHandler;
|
|
3490
|
+
// rebuild document event
|
|
3491
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
3492
|
+
for (const listener of listenerList) {
|
|
3493
|
+
proxyDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3433
3494
|
}
|
|
3434
|
-
|
|
3495
|
+
});
|
|
3496
|
+
reset();
|
|
3497
|
+
};
|
|
3498
|
+
// release all event listener & interval & timeout when unmount app
|
|
3499
|
+
const release = () => {
|
|
3500
|
+
// Clear the function bound by micro app through document.onclick
|
|
3501
|
+
if (isFunction(onClickHandler)) {
|
|
3502
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
|
|
3503
|
+
onClickHandler = null;
|
|
3504
|
+
}
|
|
3505
|
+
// Clear document binding event
|
|
3506
|
+
if (eventListenerMap.size) {
|
|
3507
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
3508
|
+
for (const listener of listenerList) {
|
|
3509
|
+
rawRemoveEventListener.call(rawDocument, type, listener);
|
|
3510
|
+
}
|
|
3511
|
+
});
|
|
3512
|
+
eventListenerMap.clear();
|
|
3435
3513
|
}
|
|
3436
|
-
rawDocumentAddEventListener.call(rawDocument, type, listener, options);
|
|
3437
3514
|
};
|
|
3438
|
-
|
|
3439
|
-
|
|
3440
|
-
|
|
3441
|
-
|
|
3442
|
-
|
|
3443
|
-
|
|
3444
|
-
|
|
3445
|
-
|
|
3446
|
-
|
|
3447
|
-
|
|
3448
|
-
|
|
3449
|
-
|
|
3450
|
-
|
|
3515
|
+
const proxyDocument = new Proxy(rawDocument, {
|
|
3516
|
+
get: (target, key) => {
|
|
3517
|
+
throttleDeferForSetAppName(appName);
|
|
3518
|
+
throttleDeferForParentNode(proxyDocument);
|
|
3519
|
+
if (key === 'createElement')
|
|
3520
|
+
return createElement;
|
|
3521
|
+
if (key === Symbol.toStringTag)
|
|
3522
|
+
return 'ProxyDocument';
|
|
3523
|
+
if (key === 'defaultView')
|
|
3524
|
+
return sandbox.proxyWindow;
|
|
3525
|
+
if (key === 'onclick')
|
|
3526
|
+
return onClickHandler;
|
|
3527
|
+
if (key === 'addEventListener')
|
|
3528
|
+
return addEventListener;
|
|
3529
|
+
if (key === 'removeEventListener')
|
|
3530
|
+
return removeEventListener;
|
|
3531
|
+
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
3532
|
+
},
|
|
3533
|
+
set: (target, key, value) => {
|
|
3534
|
+
if (key === 'onclick') {
|
|
3535
|
+
if (isFunction(onClickHandler)) {
|
|
3536
|
+
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler, false);
|
|
3537
|
+
}
|
|
3538
|
+
// TODO: listener 是否需要绑定proxyDocument,否则函数中的this指向原生window
|
|
3539
|
+
if (isFunction(value)) {
|
|
3540
|
+
rawAddEventListener.call(rawDocument, 'click', value, false);
|
|
3451
3541
|
}
|
|
3542
|
+
onClickHandler = value;
|
|
3543
|
+
}
|
|
3544
|
+
else {
|
|
3545
|
+
/**
|
|
3546
|
+
* 1. Fix TypeError: Illegal invocation when set document.title
|
|
3547
|
+
* 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
3548
|
+
*/
|
|
3549
|
+
Reflect.set(target, key, value);
|
|
3452
3550
|
}
|
|
3551
|
+
return true;
|
|
3552
|
+
}
|
|
3553
|
+
});
|
|
3554
|
+
return {
|
|
3555
|
+
proxyDocument,
|
|
3556
|
+
MicroDocument: createMicroDocument(appName, proxyDocument),
|
|
3557
|
+
documentEffect: {
|
|
3558
|
+
reset,
|
|
3559
|
+
record,
|
|
3560
|
+
rebuild,
|
|
3561
|
+
release,
|
|
3453
3562
|
}
|
|
3454
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
3455
3563
|
};
|
|
3456
3564
|
}
|
|
3457
|
-
|
|
3458
|
-
function releaseEffectDocumentEvent() {
|
|
3459
|
-
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
3460
|
-
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
3461
|
-
}
|
|
3565
|
+
|
|
3462
3566
|
/**
|
|
3463
3567
|
* Rewrite side-effect events
|
|
3464
3568
|
* @param microAppWindow micro window
|
|
3465
3569
|
*/
|
|
3466
|
-
function
|
|
3570
|
+
function patchWindowEffect(appName, microAppWindow) {
|
|
3467
3571
|
const eventListenerMap = new Map();
|
|
3572
|
+
const sstEventListenerMap = new Map();
|
|
3468
3573
|
const intervalIdMap = new Map();
|
|
3469
3574
|
const timeoutIdMap = new Map();
|
|
3470
|
-
const { rawWindow,
|
|
3575
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, } = globalEnv;
|
|
3576
|
+
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
3471
3577
|
// listener may be null, e.g test-passive
|
|
3472
3578
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3473
3579
|
type = formatEventName(type, appName);
|
|
@@ -3479,7 +3585,7 @@ function effect(appName, microAppWindow) {
|
|
|
3479
3585
|
eventListenerMap.set(type, new Set([listener]));
|
|
3480
3586
|
}
|
|
3481
3587
|
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
3482
|
-
|
|
3588
|
+
rawAddEventListener.call(rawWindow, type, listener, options);
|
|
3483
3589
|
};
|
|
3484
3590
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3485
3591
|
type = formatEventName(type, appName);
|
|
@@ -3487,7 +3593,7 @@ function effect(appName, microAppWindow) {
|
|
|
3487
3593
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3488
3594
|
listenerList.delete(listener);
|
|
3489
3595
|
}
|
|
3490
|
-
|
|
3596
|
+
rawRemoveEventListener.call(rawWindow, type, listener, options);
|
|
3491
3597
|
};
|
|
3492
3598
|
microAppWindow.setInterval = function (handler, timeout, ...args) {
|
|
3493
3599
|
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
@@ -3507,14 +3613,9 @@ function effect(appName, microAppWindow) {
|
|
|
3507
3613
|
timeoutIdMap.delete(timeoutId);
|
|
3508
3614
|
rawClearTimeout.call(rawWindow, timeoutId);
|
|
3509
3615
|
};
|
|
3510
|
-
const sstWindowListenerMap = new Map();
|
|
3511
|
-
const sstDocumentListenerMap = new Map();
|
|
3512
|
-
let sstOnClickHandler;
|
|
3513
3616
|
// reset snapshot data
|
|
3514
3617
|
const reset = () => {
|
|
3515
|
-
|
|
3516
|
-
sstDocumentListenerMap.clear();
|
|
3517
|
-
sstOnClickHandler = null;
|
|
3618
|
+
sstEventListenerMap.clear();
|
|
3518
3619
|
};
|
|
3519
3620
|
/**
|
|
3520
3621
|
* NOTE:
|
|
@@ -3530,57 +3631,33 @@ function effect(appName, microAppWindow) {
|
|
|
3530
3631
|
// record window event
|
|
3531
3632
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3532
3633
|
if (listenerList.size) {
|
|
3533
|
-
|
|
3634
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
3534
3635
|
}
|
|
3535
3636
|
});
|
|
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
3637
|
};
|
|
3548
3638
|
// rebuild event and timer before remount app
|
|
3549
3639
|
const rebuild = () => {
|
|
3550
3640
|
// rebuild window event
|
|
3551
|
-
|
|
3641
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
3552
3642
|
for (const listener of listenerList) {
|
|
3553
3643
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3554
3644
|
}
|
|
3555
3645
|
});
|
|
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
3646
|
reset();
|
|
3570
3647
|
};
|
|
3571
3648
|
// release all event listener & interval & timeout when unmount app
|
|
3572
|
-
const release = (
|
|
3649
|
+
const release = (clearTimer) => {
|
|
3573
3650
|
// Clear window binding events
|
|
3574
3651
|
if (eventListenerMap.size) {
|
|
3575
3652
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3576
3653
|
for (const listener of listenerList) {
|
|
3577
|
-
|
|
3654
|
+
rawRemoveEventListener.call(rawWindow, type, listener);
|
|
3578
3655
|
}
|
|
3579
3656
|
});
|
|
3580
3657
|
eventListenerMap.clear();
|
|
3581
3658
|
}
|
|
3582
3659
|
// default mode(not keep-alive or isPrerender)
|
|
3583
|
-
if (
|
|
3660
|
+
if (clearTimer) {
|
|
3584
3661
|
intervalIdMap.forEach((_, intervalId) => {
|
|
3585
3662
|
rawClearInterval.call(rawWindow, intervalId);
|
|
3586
3663
|
});
|
|
@@ -3590,18 +3667,6 @@ function effect(appName, microAppWindow) {
|
|
|
3590
3667
|
intervalIdMap.clear();
|
|
3591
3668
|
timeoutIdMap.clear();
|
|
3592
3669
|
}
|
|
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
3670
|
};
|
|
3606
3671
|
return {
|
|
3607
3672
|
reset,
|
|
@@ -4814,6 +4879,7 @@ const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
|
4814
4879
|
const globalPropertyList$1 = ['window', 'self', 'globalThis'];
|
|
4815
4880
|
class WithSandBox {
|
|
4816
4881
|
constructor(appName, url) {
|
|
4882
|
+
this.active = false;
|
|
4817
4883
|
/**
|
|
4818
4884
|
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
4819
4885
|
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
@@ -4821,24 +4887,20 @@ class WithSandBox {
|
|
|
4821
4887
|
this.scopeProperties = [];
|
|
4822
4888
|
// Properties that can be escape to rawWindow
|
|
4823
4889
|
this.escapeProperties = [];
|
|
4824
|
-
// Properties newly added to microAppWindow
|
|
4825
|
-
this.injectedKeys = new Set();
|
|
4826
4890
|
// Properties escape to rawWindow, cleared when unmount
|
|
4827
4891
|
this.escapeKeys = new Set();
|
|
4828
|
-
//
|
|
4829
|
-
|
|
4830
|
-
// sandbox state
|
|
4831
|
-
this.active = false;
|
|
4892
|
+
// Properties newly added to microAppWindow
|
|
4893
|
+
this.injectedKeys = new Set();
|
|
4832
4894
|
this.microAppWindow = {}; // Proxy target
|
|
4833
4895
|
this.adapter = new Adapter();
|
|
4834
4896
|
// get scopeProperties and escapeProperties from plugins
|
|
4835
4897
|
this.getSpecialProperties(appName);
|
|
4836
|
-
//
|
|
4837
|
-
this.
|
|
4838
|
-
//
|
|
4839
|
-
this.
|
|
4898
|
+
// rewrite window of child app
|
|
4899
|
+
this.windowEffect = this.patchWithWindow(appName, this.microAppWindow);
|
|
4900
|
+
// rewrite document of child app
|
|
4901
|
+
this.documentEffect = this.patchWithDocument(appName, this.microAppWindow);
|
|
4840
4902
|
// inject global properties
|
|
4841
|
-
this.initStaticGlobalKeys(
|
|
4903
|
+
this.initStaticGlobalKeys(appName, url, this.microAppWindow);
|
|
4842
4904
|
}
|
|
4843
4905
|
/**
|
|
4844
4906
|
* open sandbox and perform some initial actions
|
|
@@ -4849,38 +4911,38 @@ class WithSandBox {
|
|
|
4849
4911
|
* @param disablePatchRequest prevent patchRequestApi
|
|
4850
4912
|
*/
|
|
4851
4913
|
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();
|
|
4914
|
+
if (this.active)
|
|
4915
|
+
return;
|
|
4916
|
+
this.active = true;
|
|
4917
|
+
if (useMemoryRouter) {
|
|
4918
|
+
if (isUndefined(this.microAppWindow.location)) {
|
|
4919
|
+
this.setMicroAppRouter(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow);
|
|
4881
4920
|
}
|
|
4882
|
-
|
|
4921
|
+
this.initRouteState(defaultPage);
|
|
4922
|
+
// unique listener of popstate event for sub app
|
|
4923
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4924
|
+
}
|
|
4925
|
+
else {
|
|
4926
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
4927
|
+
}
|
|
4928
|
+
/**
|
|
4929
|
+
* Target: Ensure default mode action exactly same to first time when render again
|
|
4930
|
+
* 1. The following globalKey maybe modified when render, reset them when render again in default mode
|
|
4931
|
+
* 2. Umd mode will not delete any keys during sandBox.stop, ignore umd mode
|
|
4932
|
+
* 3. When sandbox.start called for the first time, it must be the default mode
|
|
4933
|
+
*/
|
|
4934
|
+
if (!umdMode) {
|
|
4935
|
+
this.initGlobalKeysWhenStart(this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, this.microAppWindow, disablePatchRequest);
|
|
4883
4936
|
}
|
|
4937
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
4938
|
+
patchElementAndDocument();
|
|
4939
|
+
patchHistory();
|
|
4940
|
+
}
|
|
4941
|
+
if (++WithSandBox.activeCount === 1) {
|
|
4942
|
+
// effectDocumentEvent()
|
|
4943
|
+
initEnvOfNestedApp();
|
|
4944
|
+
}
|
|
4945
|
+
fixBabelPolyfill6();
|
|
4884
4946
|
}
|
|
4885
4947
|
/**
|
|
4886
4948
|
* close sandbox and perform some clean up actions
|
|
@@ -4890,39 +4952,61 @@ class WithSandBox {
|
|
|
4890
4952
|
* @param clearData clear data from base app
|
|
4891
4953
|
*/
|
|
4892
4954
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
4893
|
-
if (this.active)
|
|
4894
|
-
|
|
4895
|
-
|
|
4896
|
-
|
|
4897
|
-
|
|
4898
|
-
|
|
4899
|
-
|
|
4900
|
-
/**
|
|
4901
|
-
* NOTE:
|
|
4902
|
-
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
4903
|
-
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
4904
|
-
* 3. umd mode will not delete global keys
|
|
4905
|
-
*/
|
|
4906
|
-
if (!umdMode || destroy) {
|
|
4907
|
-
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4908
|
-
this.injectedKeys.forEach((key) => {
|
|
4909
|
-
Reflect.deleteProperty(this.microAppWindow, key);
|
|
4910
|
-
});
|
|
4911
|
-
this.injectedKeys.clear();
|
|
4912
|
-
this.escapeKeys.forEach((key) => {
|
|
4913
|
-
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
4914
|
-
});
|
|
4915
|
-
this.escapeKeys.clear();
|
|
4916
|
-
}
|
|
4917
|
-
if (--globalEnv.activeSandbox === 0) {
|
|
4918
|
-
releasePatchElementAndDocument();
|
|
4919
|
-
releasePatchHistory();
|
|
4920
|
-
}
|
|
4921
|
-
if (--WithSandBox.activeCount === 0) {
|
|
4922
|
-
releaseEffectDocumentEvent();
|
|
4923
|
-
}
|
|
4924
|
-
this.active = false;
|
|
4955
|
+
if (!this.active)
|
|
4956
|
+
return;
|
|
4957
|
+
this.recordAndReleaseEffect({ umdMode, clearData, destroy }, !umdMode || destroy);
|
|
4958
|
+
if (this.removeHistoryListener) {
|
|
4959
|
+
this.clearRouteState(keepRouteState);
|
|
4960
|
+
// release listener of popstate
|
|
4961
|
+
this.removeHistoryListener();
|
|
4925
4962
|
}
|
|
4963
|
+
/**
|
|
4964
|
+
* NOTE:
|
|
4965
|
+
* 1. injectedKeys and escapeKeys must be placed at the back
|
|
4966
|
+
* 2. if key in initial microAppWindow, and then rewrite, this key will be delete from microAppWindow when stop, and lost when restart
|
|
4967
|
+
* 3. umd mode will not delete global keys
|
|
4968
|
+
*/
|
|
4969
|
+
if (!umdMode || destroy) {
|
|
4970
|
+
clearMicroEventSource(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4971
|
+
this.injectedKeys.forEach((key) => {
|
|
4972
|
+
Reflect.deleteProperty(this.microAppWindow, key);
|
|
4973
|
+
});
|
|
4974
|
+
this.injectedKeys.clear();
|
|
4975
|
+
this.escapeKeys.forEach((key) => {
|
|
4976
|
+
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
4977
|
+
});
|
|
4978
|
+
this.escapeKeys.clear();
|
|
4979
|
+
}
|
|
4980
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
4981
|
+
releasePatchElementAndDocument();
|
|
4982
|
+
releasePatchHistory();
|
|
4983
|
+
}
|
|
4984
|
+
if (--WithSandBox.activeCount === 0) ;
|
|
4985
|
+
this.active = false;
|
|
4986
|
+
}
|
|
4987
|
+
/**
|
|
4988
|
+
* inject global properties to microAppWindow
|
|
4989
|
+
* @param appName app name
|
|
4990
|
+
* @param url app url
|
|
4991
|
+
* @param microAppWindow micro window
|
|
4992
|
+
*/
|
|
4993
|
+
initStaticGlobalKeys(appName, url, microAppWindow) {
|
|
4994
|
+
microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
4995
|
+
microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
4996
|
+
microAppWindow.__MICRO_APP_URL__ = url;
|
|
4997
|
+
microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
4998
|
+
microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
4999
|
+
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
5000
|
+
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
5001
|
+
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
5002
|
+
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
5003
|
+
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
5004
|
+
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
5005
|
+
removeDomScope,
|
|
5006
|
+
pureCreateElement,
|
|
5007
|
+
router,
|
|
5008
|
+
});
|
|
5009
|
+
this.setMappingPropertiesWithRawDescriptor(microAppWindow);
|
|
4926
5010
|
}
|
|
4927
5011
|
/**
|
|
4928
5012
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -4953,7 +5037,8 @@ class WithSandBox {
|
|
|
4953
5037
|
* 2. unmount prerender app manually
|
|
4954
5038
|
*/
|
|
4955
5039
|
resetEffectSnapshot() {
|
|
4956
|
-
this.
|
|
5040
|
+
this.windowEffect.reset();
|
|
5041
|
+
this.documentEffect.reset();
|
|
4957
5042
|
resetDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4958
5043
|
}
|
|
4959
5044
|
/**
|
|
@@ -4964,20 +5049,14 @@ class WithSandBox {
|
|
|
4964
5049
|
* 3. after init prerender app
|
|
4965
5050
|
*/
|
|
4966
5051
|
recordEffectSnapshot() {
|
|
4967
|
-
|
|
4968
|
-
this.
|
|
5052
|
+
this.windowEffect.record();
|
|
5053
|
+
this.documentEffect.record();
|
|
4969
5054
|
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
5055
|
}
|
|
4975
5056
|
// rebuild umd snapshot before remount umd app
|
|
4976
5057
|
rebuildEffectSnapshot() {
|
|
4977
|
-
|
|
4978
|
-
|
|
4979
|
-
// })
|
|
4980
|
-
this.effectController.rebuild();
|
|
5058
|
+
this.windowEffect.rebuild();
|
|
5059
|
+
this.documentEffect.rebuild();
|
|
4981
5060
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4982
5061
|
}
|
|
4983
5062
|
/**
|
|
@@ -4986,19 +5065,17 @@ class WithSandBox {
|
|
|
4986
5065
|
* 1. unmount of default/umd app
|
|
4987
5066
|
* 2. hidden keep-alive app
|
|
4988
5067
|
* 3. after init prerender app
|
|
5068
|
+
* @param umdMode is umd mode
|
|
4989
5069
|
* @param clearData clear data from base app
|
|
4990
5070
|
* @param isPrerender is prerender app
|
|
4991
5071
|
* @param keepAlive is keep-alive app
|
|
4992
5072
|
* @param destroy completely destroy
|
|
4993
5073
|
*/
|
|
4994
|
-
releaseGlobalEffect({ clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
5074
|
+
releaseGlobalEffect({ umdMode = false, clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
4995
5075
|
var _a, _b, _c;
|
|
4996
|
-
|
|
4997
|
-
|
|
4998
|
-
|
|
4999
|
-
keepAlive,
|
|
5000
|
-
destroy,
|
|
5001
|
-
});
|
|
5076
|
+
// default mode(not keep-alive or isPrerender)
|
|
5077
|
+
this.windowEffect.release((!umdMode && !keepAlive && !isPrerender) || destroy);
|
|
5078
|
+
this.documentEffect.release();
|
|
5002
5079
|
(_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
|
|
5003
5080
|
(_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
|
|
5004
5081
|
if (clearData) {
|
|
@@ -5034,54 +5111,52 @@ class WithSandBox {
|
|
|
5034
5111
|
}
|
|
5035
5112
|
}
|
|
5036
5113
|
// create proxyWindow with Proxy(microAppWindow)
|
|
5037
|
-
createProxyWindow(appName) {
|
|
5114
|
+
createProxyWindow(appName, microAppWindow) {
|
|
5038
5115
|
const rawWindow = globalEnv.rawWindow;
|
|
5039
|
-
const descriptorTargetMap = new Map();
|
|
5040
|
-
return new Proxy(
|
|
5041
|
-
get: (target, key) => {
|
|
5042
|
-
throttleDeferForSetAppName(appName);
|
|
5043
|
-
if (Reflect.has(target, key) ||
|
|
5044
|
-
(isString(key) && /^__MICRO_APP_/.test(key)) ||
|
|
5045
|
-
this.scopeProperties.includes(key))
|
|
5046
|
-
return Reflect.get(target, key);
|
|
5047
|
-
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
5048
|
-
},
|
|
5049
|
-
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
|
-
}
|
|
5116
|
+
const descriptorTargetMap = new Map();
|
|
5117
|
+
return new Proxy(microAppWindow, {
|
|
5118
|
+
get: (target, key) => {
|
|
5119
|
+
throttleDeferForSetAppName(appName);
|
|
5120
|
+
if (Reflect.has(target, key) ||
|
|
5121
|
+
(isString(key) && /^__MICRO_APP_/.test(key)) ||
|
|
5122
|
+
this.scopeProperties.includes(key))
|
|
5123
|
+
return Reflect.get(target, key);
|
|
5124
|
+
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
5125
|
+
},
|
|
5126
|
+
set: (target, key, value) => {
|
|
5127
|
+
/**
|
|
5128
|
+
* TODO:
|
|
5129
|
+
* 1、location域名相同,子应用内部跳转时的处理
|
|
5130
|
+
*/
|
|
5131
|
+
if (this.adapter.escapeSetterKeyList.includes(key)) {
|
|
5132
|
+
Reflect.set(rawWindow, key, value);
|
|
5133
|
+
}
|
|
5134
|
+
else if (
|
|
5135
|
+
// target.hasOwnProperty has been rewritten
|
|
5136
|
+
!rawHasOwnProperty.call(target, key) &&
|
|
5137
|
+
rawHasOwnProperty.call(rawWindow, key) &&
|
|
5138
|
+
!this.scopeProperties.includes(key)) {
|
|
5139
|
+
const descriptor = Object.getOwnPropertyDescriptor(rawWindow, key);
|
|
5140
|
+
const { configurable, enumerable, writable, set } = descriptor;
|
|
5141
|
+
// set value because it can be set
|
|
5142
|
+
rawDefineProperty(target, key, {
|
|
5143
|
+
value,
|
|
5144
|
+
configurable,
|
|
5145
|
+
enumerable,
|
|
5146
|
+
writable: writable !== null && writable !== void 0 ? writable : !!set,
|
|
5147
|
+
});
|
|
5148
|
+
this.injectedKeys.add(key);
|
|
5149
|
+
}
|
|
5150
|
+
else {
|
|
5151
|
+
!Reflect.has(target, key) && this.injectedKeys.add(key);
|
|
5152
|
+
Reflect.set(target, key, value);
|
|
5153
|
+
}
|
|
5154
|
+
if ((this.escapeProperties.includes(key) ||
|
|
5155
|
+
(this.adapter.staticEscapeProperties.includes(key) &&
|
|
5156
|
+
!Reflect.has(rawWindow, key))) &&
|
|
5157
|
+
!this.scopeProperties.includes(key)) {
|
|
5158
|
+
!Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
|
|
5159
|
+
Reflect.set(rawWindow, key, value);
|
|
5085
5160
|
}
|
|
5086
5161
|
return true;
|
|
5087
5162
|
},
|
|
@@ -5128,41 +5203,24 @@ class WithSandBox {
|
|
|
5128
5203
|
},
|
|
5129
5204
|
});
|
|
5130
5205
|
}
|
|
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;
|
|
5137
|
-
}
|
|
5138
5206
|
/**
|
|
5139
|
-
*
|
|
5140
|
-
* @param microAppWindow micro window
|
|
5207
|
+
* create proxyWindow, rewrite window event & timer of child app
|
|
5141
5208
|
* @param appName app name
|
|
5142
|
-
* @param
|
|
5143
|
-
* @param useMemoryRouter whether use memory router
|
|
5209
|
+
* @param microAppWindow Proxy target
|
|
5144
5210
|
*/
|
|
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);
|
|
5211
|
+
patchWithWindow(appName, microAppWindow) {
|
|
5212
|
+
// create proxyWindow with Proxy(microAppWindow)
|
|
5213
|
+
this.proxyWindow = this.createProxyWindow(appName, microAppWindow);
|
|
5214
|
+
// rewrite global event & timeout of window
|
|
5215
|
+
return patchWindowEffect(appName, microAppWindow);
|
|
5163
5216
|
}
|
|
5164
|
-
|
|
5165
|
-
|
|
5217
|
+
/**
|
|
5218
|
+
* create proxyDocument and MicroDocument, rewrite document of child app
|
|
5219
|
+
* @param appName app name
|
|
5220
|
+
* @param microAppWindow Proxy target
|
|
5221
|
+
*/
|
|
5222
|
+
patchWithDocument(appName, microAppWindow) {
|
|
5223
|
+
const { proxyDocument, MicroDocument, documentEffect } = createProxyDocument(appName, this);
|
|
5166
5224
|
rawDefineProperties(microAppWindow, {
|
|
5167
5225
|
document: {
|
|
5168
5226
|
configurable: false,
|
|
@@ -5181,6 +5239,14 @@ class WithSandBox {
|
|
|
5181
5239
|
},
|
|
5182
5240
|
}
|
|
5183
5241
|
});
|
|
5242
|
+
return documentEffect;
|
|
5243
|
+
}
|
|
5244
|
+
// set __MICRO_APP_PRE_RENDER__ state
|
|
5245
|
+
setPreRenderState(state) {
|
|
5246
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
5247
|
+
}
|
|
5248
|
+
markUmdMode(state) {
|
|
5249
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
5184
5250
|
}
|
|
5185
5251
|
// properties associated with the native window
|
|
5186
5252
|
setMappingPropertiesWithRawDescriptor(microAppWindow) {
|
|
@@ -5193,6 +5259,7 @@ class WithSandBox {
|
|
|
5193
5259
|
topValue = rawWindow.top;
|
|
5194
5260
|
parentValue = rawWindow.parent;
|
|
5195
5261
|
}
|
|
5262
|
+
// TODO: 用rawDefineProperties
|
|
5196
5263
|
rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
|
|
5197
5264
|
rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
|
|
5198
5265
|
globalPropertyList$1.forEach((key) => {
|
|
@@ -5216,15 +5283,15 @@ class WithSandBox {
|
|
|
5216
5283
|
* @param url app url
|
|
5217
5284
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
5218
5285
|
*/
|
|
5219
|
-
initGlobalKeysWhenStart(
|
|
5286
|
+
initGlobalKeysWhenStart(appName, url, microAppWindow, disablePatchRequest) {
|
|
5220
5287
|
microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
|
|
5221
|
-
this.setHijackProperty(
|
|
5288
|
+
this.setHijackProperty(appName, microAppWindow);
|
|
5222
5289
|
if (!disablePatchRequest)
|
|
5223
|
-
this.patchRequestApi(
|
|
5290
|
+
this.patchRequestApi(appName, url, microAppWindow);
|
|
5224
5291
|
this.setScopeProperties(microAppWindow);
|
|
5225
5292
|
}
|
|
5226
5293
|
// set hijack Properties to microAppWindow
|
|
5227
|
-
setHijackProperty(
|
|
5294
|
+
setHijackProperty(appName, microAppWindow) {
|
|
5228
5295
|
let modifiedEval, modifiedImage;
|
|
5229
5296
|
rawDefineProperties(microAppWindow, {
|
|
5230
5297
|
eval: {
|
|
@@ -5252,7 +5319,7 @@ class WithSandBox {
|
|
|
5252
5319
|
});
|
|
5253
5320
|
}
|
|
5254
5321
|
// rewrite fetch, XMLHttpRequest, EventSource
|
|
5255
|
-
patchRequestApi(
|
|
5322
|
+
patchRequestApi(appName, url, microAppWindow) {
|
|
5256
5323
|
let microFetch = createMicroFetch(url);
|
|
5257
5324
|
let microXMLHttpRequest = createMicroXMLHttpRequest(url);
|
|
5258
5325
|
let microEventSource = createMicroEventSource(appName, url);
|
|
@@ -5302,7 +5369,7 @@ class WithSandBox {
|
|
|
5302
5369
|
});
|
|
5303
5370
|
}
|
|
5304
5371
|
// set location & history for memory router
|
|
5305
|
-
setMicroAppRouter(
|
|
5372
|
+
setMicroAppRouter(appName, url, microAppWindow) {
|
|
5306
5373
|
const { microLocation, microHistory } = createMicroRouter(appName, url);
|
|
5307
5374
|
rawDefineProperties(microAppWindow, {
|
|
5308
5375
|
location: {
|
|
@@ -5352,85 +5419,26 @@ class WithSandBox {
|
|
|
5352
5419
|
actionBeforeExecScripts(container) {
|
|
5353
5420
|
this.patchStaticElement(container);
|
|
5354
5421
|
}
|
|
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
5422
|
}
|
|
5426
5423
|
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5427
5424
|
|
|
5428
|
-
function patchIframeRoute(appName, microAppWindow,
|
|
5425
|
+
function patchIframeRoute(appName, url, microAppWindow, browserHost) {
|
|
5426
|
+
const childStaticLocation = new URL(url);
|
|
5427
|
+
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
5428
|
+
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
5429
|
+
// rewrite microAppWindow.history
|
|
5429
5430
|
const microHistory = microAppWindow.history;
|
|
5430
5431
|
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5431
5432
|
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5432
|
-
|
|
5433
|
+
/**
|
|
5434
|
+
* Init microLocation before exec sandbox.start (sandbox.start will sync microLocation info to browser url)
|
|
5435
|
+
* NOTE:
|
|
5436
|
+
* 1. exec updateMicroLocation after patch microHistory
|
|
5437
|
+
* 2.
|
|
5438
|
+
*/
|
|
5433
5439
|
updateMicroLocation(appName, childFullPath, microAppWindow.location, 'prevent');
|
|
5440
|
+
// create proxyLocation
|
|
5441
|
+
return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
5434
5442
|
}
|
|
5435
5443
|
|
|
5436
5444
|
function patchIframeWindow(appName, microAppWindow) {
|
|
@@ -5496,15 +5504,16 @@ function patchIframeWindow(appName, microAppWindow) {
|
|
|
5496
5504
|
logWarn(e, appName);
|
|
5497
5505
|
}
|
|
5498
5506
|
});
|
|
5499
|
-
return
|
|
5507
|
+
return patchWindowEffect$1(microAppWindow);
|
|
5500
5508
|
}
|
|
5501
|
-
function
|
|
5502
|
-
const { rawWindow, rawAddEventListener, rawRemoveEventListener
|
|
5509
|
+
function patchWindowEffect$1(microAppWindow) {
|
|
5510
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5503
5511
|
const eventListenerMap = new Map();
|
|
5504
|
-
const
|
|
5512
|
+
const sstEventListenerMap = new Map();
|
|
5505
5513
|
function getEventTarget(type) {
|
|
5506
5514
|
return scopeIframeWindowEvent.includes(type) ? microAppWindow : rawWindow;
|
|
5507
5515
|
}
|
|
5516
|
+
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
5508
5517
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
5509
5518
|
const listenerList = eventListenerMap.get(type);
|
|
5510
5519
|
if (listenerList) {
|
|
@@ -5524,7 +5533,7 @@ function windowEffect(microAppWindow) {
|
|
|
5524
5533
|
rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
|
|
5525
5534
|
};
|
|
5526
5535
|
const reset = () => {
|
|
5527
|
-
|
|
5536
|
+
sstEventListenerMap.clear();
|
|
5528
5537
|
};
|
|
5529
5538
|
/**
|
|
5530
5539
|
* NOTE:
|
|
@@ -5542,14 +5551,14 @@ function windowEffect(microAppWindow) {
|
|
|
5542
5551
|
// record window event
|
|
5543
5552
|
eventListenerMap.forEach((listenerList, type) => {
|
|
5544
5553
|
if (listenerList.size) {
|
|
5545
|
-
|
|
5554
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
5546
5555
|
}
|
|
5547
5556
|
});
|
|
5548
5557
|
};
|
|
5549
5558
|
// rebuild event and timer before remount app
|
|
5550
5559
|
const rebuild = () => {
|
|
5551
5560
|
// rebuild window event
|
|
5552
|
-
|
|
5561
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
5553
5562
|
for (const listener of listenerList) {
|
|
5554
5563
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5555
5564
|
}
|
|
@@ -5583,18 +5592,26 @@ function windowEffect(microAppWindow) {
|
|
|
5583
5592
|
function patchIframeDocument(appName, microAppWindow, proxyLocation) {
|
|
5584
5593
|
patchDocumentPrototype(appName, microAppWindow);
|
|
5585
5594
|
patchDocumentProperties(appName, microAppWindow, proxyLocation);
|
|
5586
|
-
return
|
|
5595
|
+
return patchDocumentEffect(appName, microAppWindow);
|
|
5587
5596
|
}
|
|
5588
5597
|
function patchDocumentPrototype(appName, microAppWindow) {
|
|
5589
5598
|
const rawDocument = globalEnv.rawDocument;
|
|
5590
5599
|
const microRootDocument = microAppWindow.Document;
|
|
5591
5600
|
const microDocument = microAppWindow.document;
|
|
5601
|
+
const rawMicroCreateElement = microRootDocument.prototype.createElement;
|
|
5602
|
+
const rawMicroCreateTextNode = microRootDocument.prototype.createTextNode;
|
|
5603
|
+
const rawMicroQuerySelector = microRootDocument.prototype.querySelector;
|
|
5604
|
+
const rawMicroQuerySelectorAll = microRootDocument.prototype.querySelectorAll;
|
|
5605
|
+
const rawMicroGetElementById = microRootDocument.prototype.getElementById;
|
|
5606
|
+
const rawMicroGetElementsByClassName = microRootDocument.prototype.getElementsByClassName;
|
|
5607
|
+
const rawMicroGetElementsByTagName = microRootDocument.prototype.getElementsByTagName;
|
|
5608
|
+
const rawMicroGetElementsByName = microRootDocument.prototype.getElementsByName;
|
|
5592
5609
|
microRootDocument.prototype.createElement = function createElement(tagName, options) {
|
|
5593
|
-
const element =
|
|
5610
|
+
const element = rawMicroCreateElement.call(this, tagName, options);
|
|
5594
5611
|
return updateElementInfo(element, appName);
|
|
5595
5612
|
};
|
|
5596
5613
|
microRootDocument.prototype.createTextNode = function createTextNode(data) {
|
|
5597
|
-
const element =
|
|
5614
|
+
const element = rawMicroCreateTextNode.call(this, data);
|
|
5598
5615
|
return updateElementInfo(element, appName);
|
|
5599
5616
|
};
|
|
5600
5617
|
function getDefaultRawTarget(target) {
|
|
@@ -5603,19 +5620,21 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5603
5620
|
// query element👇
|
|
5604
5621
|
function querySelector(selectors) {
|
|
5605
5622
|
var _a, _b;
|
|
5606
|
-
if (
|
|
5623
|
+
if (!selectors ||
|
|
5624
|
+
isUniqueElement(selectors) ||
|
|
5607
5625
|
microDocument !== this) {
|
|
5608
5626
|
const _this = getDefaultRawTarget(this);
|
|
5609
|
-
return
|
|
5627
|
+
return rawMicroQuerySelector.call(_this, selectors);
|
|
5610
5628
|
}
|
|
5611
5629
|
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
5612
5630
|
}
|
|
5613
5631
|
function querySelectorAll(selectors) {
|
|
5614
5632
|
var _a, _b;
|
|
5615
|
-
if (
|
|
5633
|
+
if (!selectors ||
|
|
5634
|
+
isUniqueElement(selectors) ||
|
|
5616
5635
|
microDocument !== this) {
|
|
5617
5636
|
const _this = getDefaultRawTarget(this);
|
|
5618
|
-
return
|
|
5637
|
+
return rawMicroQuerySelectorAll.call(_this, selectors);
|
|
5619
5638
|
}
|
|
5620
5639
|
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
5621
5640
|
}
|
|
@@ -5624,25 +5643,25 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5624
5643
|
microRootDocument.prototype.getElementById = function getElementById(key) {
|
|
5625
5644
|
const _this = getDefaultRawTarget(this);
|
|
5626
5645
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5627
|
-
return
|
|
5646
|
+
return rawMicroGetElementById.call(_this, key);
|
|
5628
5647
|
}
|
|
5629
5648
|
try {
|
|
5630
5649
|
return querySelector.call(this, `#${key}`);
|
|
5631
5650
|
}
|
|
5632
5651
|
catch (_a) {
|
|
5633
|
-
return
|
|
5652
|
+
return rawMicroGetElementById.call(_this, key);
|
|
5634
5653
|
}
|
|
5635
5654
|
};
|
|
5636
5655
|
microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
5637
5656
|
const _this = getDefaultRawTarget(this);
|
|
5638
5657
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5639
|
-
return
|
|
5658
|
+
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5640
5659
|
}
|
|
5641
5660
|
try {
|
|
5642
5661
|
return querySelectorAll.call(this, `.${key}`);
|
|
5643
5662
|
}
|
|
5644
5663
|
catch (_a) {
|
|
5645
|
-
return
|
|
5664
|
+
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5646
5665
|
}
|
|
5647
5666
|
};
|
|
5648
5667
|
microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
@@ -5651,25 +5670,25 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5651
5670
|
if (isUniqueElement(key) ||
|
|
5652
5671
|
isInvalidQuerySelectorKey(key) ||
|
|
5653
5672
|
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
5654
|
-
return
|
|
5673
|
+
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5655
5674
|
}
|
|
5656
5675
|
try {
|
|
5657
5676
|
return querySelectorAll.call(this, key);
|
|
5658
5677
|
}
|
|
5659
5678
|
catch (_b) {
|
|
5660
|
-
return
|
|
5679
|
+
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5661
5680
|
}
|
|
5662
5681
|
};
|
|
5663
5682
|
microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
|
|
5664
5683
|
const _this = getDefaultRawTarget(this);
|
|
5665
5684
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5666
|
-
return
|
|
5685
|
+
return rawMicroGetElementsByName.call(_this, key);
|
|
5667
5686
|
}
|
|
5668
5687
|
try {
|
|
5669
5688
|
return querySelectorAll.call(this, `[name=${key}]`);
|
|
5670
5689
|
}
|
|
5671
5690
|
catch (_a) {
|
|
5672
|
-
return
|
|
5691
|
+
return rawMicroGetElementsByName.call(_this, key);
|
|
5673
5692
|
}
|
|
5674
5693
|
};
|
|
5675
5694
|
}
|
|
@@ -5725,46 +5744,37 @@ function patchDocumentProperties(appName, microAppWindow, proxyLocation) {
|
|
|
5725
5744
|
enumerable: true,
|
|
5726
5745
|
configurable: true,
|
|
5727
5746
|
get: () => rawDocument[tagName],
|
|
5728
|
-
set:
|
|
5747
|
+
set: (value) => { rawDocument[tagName] = value; },
|
|
5729
5748
|
});
|
|
5730
5749
|
});
|
|
5731
5750
|
}
|
|
5732
|
-
function
|
|
5733
|
-
const
|
|
5734
|
-
const
|
|
5751
|
+
function patchDocumentEffect(appName, microAppWindow) {
|
|
5752
|
+
const { rawDocument, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5753
|
+
const eventListenerMap = new Map();
|
|
5754
|
+
const sstEventListenerMap = new Map();
|
|
5735
5755
|
let onClickHandler = null;
|
|
5736
5756
|
let sstOnClickHandler = null;
|
|
5737
5757
|
const microRootDocument = microAppWindow.Document;
|
|
5738
5758
|
const microDocument = microAppWindow.document;
|
|
5739
|
-
const { rawDocument, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
5740
5759
|
function getEventTarget(type, bindTarget) {
|
|
5741
5760
|
return scopeIframeDocumentEvent.includes(type) ? bindTarget : rawDocument;
|
|
5742
5761
|
}
|
|
5743
5762
|
microRootDocument.prototype.addEventListener = function (type, listener, options) {
|
|
5744
5763
|
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
|
-
}
|
|
5764
|
+
const listenerList = eventListenerMap.get(type);
|
|
5765
|
+
if (listenerList) {
|
|
5766
|
+
listenerList.add(listener);
|
|
5754
5767
|
}
|
|
5755
5768
|
else {
|
|
5756
|
-
|
|
5769
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
5757
5770
|
}
|
|
5758
5771
|
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
5759
5772
|
rawAddEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5760
5773
|
};
|
|
5761
5774
|
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
|
-
}
|
|
5775
|
+
const listenerList = eventListenerMap.get(type);
|
|
5776
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
5777
|
+
listenerList.delete(listener);
|
|
5768
5778
|
}
|
|
5769
5779
|
const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
|
|
5770
5780
|
rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
@@ -5816,7 +5826,7 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5816
5826
|
}
|
|
5817
5827
|
});
|
|
5818
5828
|
const reset = () => {
|
|
5819
|
-
|
|
5829
|
+
sstEventListenerMap.clear();
|
|
5820
5830
|
sstOnClickHandler = null;
|
|
5821
5831
|
};
|
|
5822
5832
|
/**
|
|
@@ -5832,21 +5842,18 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5832
5842
|
// record onclick handler
|
|
5833
5843
|
sstOnClickHandler = sstOnClickHandler || onClickHandler;
|
|
5834
5844
|
// record document event
|
|
5835
|
-
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
|
|
5839
|
-
|
|
5840
|
-
}
|
|
5841
|
-
});
|
|
5842
|
-
}
|
|
5845
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5846
|
+
if (listenerList.size) {
|
|
5847
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
5848
|
+
}
|
|
5849
|
+
});
|
|
5843
5850
|
};
|
|
5844
5851
|
// rebuild event and timer before remount app
|
|
5845
5852
|
const rebuild = () => {
|
|
5846
5853
|
// rebuild onclick event
|
|
5847
5854
|
if (sstOnClickHandler)
|
|
5848
5855
|
microDocument.onclick = sstOnClickHandler;
|
|
5849
|
-
|
|
5856
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
5850
5857
|
for (const listener of listenerList) {
|
|
5851
5858
|
microDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5852
5859
|
}
|
|
@@ -5854,20 +5861,19 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5854
5861
|
reset();
|
|
5855
5862
|
};
|
|
5856
5863
|
const release = () => {
|
|
5857
|
-
// Clear the function bound by micro
|
|
5864
|
+
// Clear the function bound by micro app through document.onclick
|
|
5858
5865
|
if (isFunction(onClickHandler)) {
|
|
5859
5866
|
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
|
|
5860
5867
|
onClickHandler = null;
|
|
5861
5868
|
}
|
|
5862
5869
|
// Clear document binding event
|
|
5863
|
-
|
|
5864
|
-
|
|
5865
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
5870
|
+
if (eventListenerMap.size) {
|
|
5871
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5866
5872
|
for (const listener of listenerList) {
|
|
5867
5873
|
rawRemoveEventListener.call(getEventTarget(type, microDocument), type, (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener);
|
|
5868
5874
|
}
|
|
5869
5875
|
});
|
|
5870
|
-
|
|
5876
|
+
eventListenerMap.clear();
|
|
5871
5877
|
}
|
|
5872
5878
|
};
|
|
5873
5879
|
return {
|
|
@@ -5878,33 +5884,38 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5878
5884
|
};
|
|
5879
5885
|
}
|
|
5880
5886
|
|
|
5881
|
-
function patchIframeElement(appName, url, microAppWindow,
|
|
5882
|
-
patchIframeNode(appName, microAppWindow,
|
|
5887
|
+
function patchIframeElement(appName, url, microAppWindow, sandbox) {
|
|
5888
|
+
patchIframeNode(appName, microAppWindow, sandbox);
|
|
5883
5889
|
patchIframeAttribute(appName, url, microAppWindow);
|
|
5884
5890
|
}
|
|
5885
|
-
function patchIframeNode(appName, microAppWindow,
|
|
5886
|
-
const
|
|
5891
|
+
function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
5892
|
+
const rawRootElement = globalEnv.rawRootElement; // native root Element
|
|
5887
5893
|
const rawDocument = globalEnv.rawDocument;
|
|
5894
|
+
const microDocument = microAppWindow.document;
|
|
5888
5895
|
const microRootNode = microAppWindow.Node;
|
|
5889
5896
|
const microRootElement = microAppWindow.Element;
|
|
5890
5897
|
// const rawMicroGetRootNode = microRootNode.prototype.getRootNode
|
|
5891
5898
|
const rawMicroAppendChild = microRootNode.prototype.appendChild;
|
|
5892
5899
|
const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
|
|
5893
5900
|
const rawMicroReplaceChild = microRootNode.prototype.replaceChild;
|
|
5901
|
+
const rawMicroRemoveChild = microRootNode.prototype.removeChild;
|
|
5902
|
+
const rawMicroAppend = microRootElement.prototype.append;
|
|
5903
|
+
const rawMicroPrepend = microRootElement.prototype.prepend;
|
|
5904
|
+
const rawMicroInsertAdjacentElement = microRootElement.prototype.insertAdjacentElement;
|
|
5894
5905
|
const rawMicroCloneNode = microRootNode.prototype.cloneNode;
|
|
5895
5906
|
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
|
|
5896
5907
|
const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
|
|
5897
5908
|
const isPureNode = (target) => {
|
|
5898
5909
|
return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
|
|
5899
5910
|
};
|
|
5900
|
-
const getRawTarget = (
|
|
5901
|
-
if (
|
|
5911
|
+
const getRawTarget = (parent) => {
|
|
5912
|
+
if (parent === sandbox.microHead) {
|
|
5902
5913
|
return rawDocument.head;
|
|
5903
5914
|
}
|
|
5904
|
-
else if (
|
|
5915
|
+
else if (parent === sandbox.microBody) {
|
|
5905
5916
|
return rawDocument.body;
|
|
5906
5917
|
}
|
|
5907
|
-
return
|
|
5918
|
+
return parent;
|
|
5908
5919
|
};
|
|
5909
5920
|
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
5910
5921
|
return microDocument;
|
|
@@ -5915,46 +5926,70 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5915
5926
|
};
|
|
5916
5927
|
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5917
5928
|
updateElementInfo(node, appName);
|
|
5918
|
-
// TODO:只有script才可以这样拦截,link、style不应该拦截
|
|
5919
5929
|
if (isPureNode(node)) {
|
|
5920
5930
|
return rawMicroAppendChild.call(this, node);
|
|
5921
5931
|
}
|
|
5922
|
-
|
|
5923
|
-
if (_this !== this) {
|
|
5924
|
-
return _this.appendChild(node);
|
|
5925
|
-
}
|
|
5926
|
-
return rawMicroAppendChild.call(_this, node);
|
|
5932
|
+
return rawRootElement.prototype.appendChild.call(getRawTarget(this), node);
|
|
5927
5933
|
};
|
|
5928
|
-
// TODO: 更多场景适配
|
|
5929
5934
|
microRootNode.prototype.insertBefore = function insertBefore(node, child) {
|
|
5930
5935
|
updateElementInfo(node, appName);
|
|
5931
5936
|
if (isPureNode(node)) {
|
|
5932
5937
|
return rawMicroInsertBefore.call(this, node, child);
|
|
5933
5938
|
}
|
|
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);
|
|
5939
|
+
return rawRootElement.prototype.insertBefore.call(getRawTarget(this), node, child);
|
|
5942
5940
|
};
|
|
5943
|
-
// TODO: 更多场景适配
|
|
5944
5941
|
microRootNode.prototype.replaceChild = function replaceChild(node, child) {
|
|
5945
5942
|
updateElementInfo(node, appName);
|
|
5946
5943
|
if (isPureNode(node)) {
|
|
5947
5944
|
return rawMicroReplaceChild.call(this, node, child);
|
|
5948
5945
|
}
|
|
5949
|
-
|
|
5950
|
-
|
|
5951
|
-
|
|
5952
|
-
|
|
5953
|
-
|
|
5954
|
-
|
|
5955
|
-
|
|
5946
|
+
return rawRootElement.prototype.replaceChild.call(getRawTarget(this), node, child);
|
|
5947
|
+
};
|
|
5948
|
+
microRootNode.prototype.removeChild = function removeChild(oldChild) {
|
|
5949
|
+
if (isPureNode(oldChild) || this.contains(oldChild)) {
|
|
5950
|
+
return rawMicroRemoveChild.call(this, oldChild);
|
|
5951
|
+
}
|
|
5952
|
+
return rawRootElement.prototype.removeChild.call(getRawTarget(this), oldChild);
|
|
5953
|
+
};
|
|
5954
|
+
microRootElement.prototype.append = function append(...nodes) {
|
|
5955
|
+
let i = 0;
|
|
5956
|
+
let hasPureNode = false;
|
|
5957
|
+
while (i < nodes.length) {
|
|
5958
|
+
nodes[i] = isNode(nodes[i]) ? nodes[i] : microDocument.createTextNode(nodes[i]);
|
|
5959
|
+
if (isPureNode(nodes[i]))
|
|
5960
|
+
hasPureNode = true;
|
|
5961
|
+
i++;
|
|
5962
|
+
}
|
|
5963
|
+
if (hasPureNode) {
|
|
5964
|
+
return rawMicroAppend.call(this, ...nodes);
|
|
5965
|
+
}
|
|
5966
|
+
return rawRootElement.prototype.append.call(getRawTarget(this), ...nodes);
|
|
5967
|
+
};
|
|
5968
|
+
microRootElement.prototype.prepend = function prepend(...nodes) {
|
|
5969
|
+
let i = 0;
|
|
5970
|
+
let hasPureNode = false;
|
|
5971
|
+
while (i < nodes.length) {
|
|
5972
|
+
nodes[i] = isNode(nodes[i]) ? nodes[i] : microDocument.createTextNode(nodes[i]);
|
|
5973
|
+
if (isPureNode(nodes[i]))
|
|
5974
|
+
hasPureNode = true;
|
|
5975
|
+
i++;
|
|
5976
|
+
}
|
|
5977
|
+
if (hasPureNode) {
|
|
5978
|
+
return rawMicroPrepend.call(this, ...nodes);
|
|
5979
|
+
}
|
|
5980
|
+
return rawRootElement.prototype.prepend.call(getRawTarget(this), ...nodes);
|
|
5981
|
+
};
|
|
5982
|
+
/**
|
|
5983
|
+
* The insertAdjacentElement method of the Element interface inserts a given element node at a given position relative to the element it is invoked upon.
|
|
5984
|
+
* Scenes:
|
|
5985
|
+
* 1. vite4 development env for style
|
|
5986
|
+
*/
|
|
5987
|
+
microRootElement.prototype.insertAdjacentElement = function insertAdjacentElement(where, element) {
|
|
5988
|
+
updateElementInfo(element, appName);
|
|
5989
|
+
if (isPureNode(element)) {
|
|
5990
|
+
return rawMicroInsertAdjacentElement.call(this, where, element);
|
|
5956
5991
|
}
|
|
5957
|
-
return
|
|
5992
|
+
return rawRootElement.prototype.insertAdjacentElement.call(getRawTarget(this), where, element);
|
|
5958
5993
|
};
|
|
5959
5994
|
// patch cloneNode
|
|
5960
5995
|
microRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
@@ -5999,7 +6034,6 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5999
6034
|
}
|
|
6000
6035
|
return result;
|
|
6001
6036
|
},
|
|
6002
|
-
set: undefined,
|
|
6003
6037
|
});
|
|
6004
6038
|
// Adapt to new image(...) scene
|
|
6005
6039
|
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
@@ -6039,6 +6073,12 @@ function patchIframeAttribute(appName, url, microAppWindow) {
|
|
|
6039
6073
|
[microAppWindow.HTMLScriptElement.prototype, 'src'],
|
|
6040
6074
|
[microAppWindow.HTMLLinkElement.prototype, 'href'],
|
|
6041
6075
|
];
|
|
6076
|
+
/**
|
|
6077
|
+
* element.setAttribute does not trigger this actions:
|
|
6078
|
+
* 1. img.src = xxx
|
|
6079
|
+
* 2. script.src = xxx
|
|
6080
|
+
* 3. link.href = xxx
|
|
6081
|
+
*/
|
|
6042
6082
|
protoAttrList.forEach(([target, attr]) => {
|
|
6043
6083
|
const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
|
|
6044
6084
|
enumerable: true,
|
|
@@ -6071,23 +6111,30 @@ class IframeSandbox {
|
|
|
6071
6111
|
};
|
|
6072
6112
|
const rawLocation = globalEnv.rawWindow.location;
|
|
6073
6113
|
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
6114
|
this.deleteIframeElement = this.createIframeElement(appName, browserHost);
|
|
6078
6115
|
this.microAppWindow = this.iframe.contentWindow;
|
|
6079
6116
|
this.patchIframe(this.microAppWindow, (resolve) => {
|
|
6080
6117
|
// TODO: 优化代码
|
|
6081
|
-
//
|
|
6082
|
-
this.
|
|
6083
|
-
this.createProxyWindow(this.microAppWindow);
|
|
6084
|
-
this.initStaticGlobalKeys(appName, url);
|
|
6118
|
+
// create new html to iframe
|
|
6119
|
+
this.createIframeTemplate(this.microAppWindow);
|
|
6085
6120
|
// get escapeProperties from plugins
|
|
6086
6121
|
this.getSpecialProperties(appName);
|
|
6087
|
-
|
|
6088
|
-
patchIframeRoute(appName, this.microAppWindow,
|
|
6122
|
+
// rewrite location & history of child app
|
|
6123
|
+
this.proxyLocation = patchIframeRoute(appName, url, this.microAppWindow, browserHost);
|
|
6124
|
+
// create proxy window
|
|
6125
|
+
this.proxyWindow = this.createProxyWindow(this.microAppWindow);
|
|
6126
|
+
/**
|
|
6127
|
+
* create static properties
|
|
6128
|
+
* NOTE:
|
|
6129
|
+
* 1. execute as early as possible
|
|
6130
|
+
* 2. run after patchIframeRoute & createProxyWindow
|
|
6131
|
+
*/
|
|
6132
|
+
this.initStaticGlobalKeys(appName, url);
|
|
6133
|
+
// rewrite window of child app
|
|
6089
6134
|
this.windowEffect = patchIframeWindow(appName, this.microAppWindow);
|
|
6135
|
+
// rewrite document of child app
|
|
6090
6136
|
this.documentEffect = patchIframeDocument(appName, this.microAppWindow, this.proxyLocation);
|
|
6137
|
+
// rewrite Node & Element of child app
|
|
6091
6138
|
patchIframeElement(appName, url, this.microAppWindow, this);
|
|
6092
6139
|
resolve();
|
|
6093
6140
|
});
|
|
@@ -6124,53 +6171,80 @@ class IframeSandbox {
|
|
|
6124
6171
|
});
|
|
6125
6172
|
}
|
|
6126
6173
|
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
|
-
|
|
6146
|
-
patchElementAndDocument();
|
|
6147
|
-
patchHistory();
|
|
6148
|
-
}
|
|
6149
|
-
if (++IframeSandbox.activeCount === 1) ;
|
|
6174
|
+
if (this.active)
|
|
6175
|
+
return;
|
|
6176
|
+
this.active = true;
|
|
6177
|
+
// TODO: 虚拟路由升级
|
|
6178
|
+
// eslint-disable-next-line
|
|
6179
|
+
if (useMemoryRouter || true) {
|
|
6180
|
+
this.initRouteState(defaultPage);
|
|
6181
|
+
// unique listener of popstate event for sub app
|
|
6182
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
6183
|
+
}
|
|
6184
|
+
else {
|
|
6185
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
6186
|
+
}
|
|
6187
|
+
/**
|
|
6188
|
+
* create base element to iframe
|
|
6189
|
+
* WARNING: This will also affect a, image, link and script
|
|
6190
|
+
*/
|
|
6191
|
+
if (!disablePatchRequest) {
|
|
6192
|
+
this.createIframeBase();
|
|
6150
6193
|
}
|
|
6194
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
6195
|
+
patchElementAndDocument();
|
|
6196
|
+
patchHistory();
|
|
6197
|
+
}
|
|
6198
|
+
if (++IframeSandbox.activeCount === 1) ;
|
|
6151
6199
|
}
|
|
6152
6200
|
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;
|
|
6201
|
+
if (!this.active)
|
|
6202
|
+
return;
|
|
6203
|
+
this.recordAndReleaseEffect({ clearData }, !umdMode || destroy);
|
|
6204
|
+
if (this.removeHistoryListener) {
|
|
6205
|
+
this.clearRouteState(keepRouteState);
|
|
6206
|
+
// release listener of popstate
|
|
6207
|
+
this.removeHistoryListener();
|
|
6208
|
+
}
|
|
6209
|
+
if (!umdMode || destroy) {
|
|
6210
|
+
this.deleteIframeElement();
|
|
6211
|
+
this.escapeKeys.forEach((key) => {
|
|
6212
|
+
Reflect.deleteProperty(globalEnv.rawWindow, key);
|
|
6213
|
+
});
|
|
6214
|
+
this.escapeKeys.clear();
|
|
6173
6215
|
}
|
|
6216
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
6217
|
+
releasePatchElementAndDocument();
|
|
6218
|
+
releasePatchHistory();
|
|
6219
|
+
}
|
|
6220
|
+
if (--IframeSandbox.activeCount === 0) ;
|
|
6221
|
+
this.active = false;
|
|
6222
|
+
}
|
|
6223
|
+
/**
|
|
6224
|
+
* create static properties
|
|
6225
|
+
* NOTE:
|
|
6226
|
+
* 1. execute as early as possible
|
|
6227
|
+
* 2. run after patchIframeRoute & createProxyWindow
|
|
6228
|
+
*/
|
|
6229
|
+
initStaticGlobalKeys(appName, url) {
|
|
6230
|
+
this.microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
6231
|
+
this.microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
6232
|
+
this.microAppWindow.__MICRO_APP_URL__ = url;
|
|
6233
|
+
this.microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
6234
|
+
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = '';
|
|
6235
|
+
this.microAppWindow.__MICRO_APP_WINDOW__ = this.microAppWindow;
|
|
6236
|
+
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
6237
|
+
this.microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
6238
|
+
this.microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
6239
|
+
this.microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
6240
|
+
this.microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
6241
|
+
this.microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
6242
|
+
this.microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
6243
|
+
removeDomScope,
|
|
6244
|
+
pureCreateElement,
|
|
6245
|
+
location: this.proxyLocation,
|
|
6246
|
+
router,
|
|
6247
|
+
});
|
|
6174
6248
|
}
|
|
6175
6249
|
/**
|
|
6176
6250
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -6248,29 +6322,10 @@ class IframeSandbox {
|
|
|
6248
6322
|
setPreRenderState(state) {
|
|
6249
6323
|
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
6250
6324
|
}
|
|
6325
|
+
// record umdMode
|
|
6251
6326
|
markUmdMode(state) {
|
|
6252
6327
|
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
6253
6328
|
}
|
|
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
6329
|
// TODO: RESTRUCTURE
|
|
6275
6330
|
patchIframe(microAppWindow, cb) {
|
|
6276
6331
|
const oldMicroDocument = microAppWindow.document;
|
|
@@ -6319,12 +6374,9 @@ class IframeSandbox {
|
|
|
6319
6374
|
this.updateIframeBase();
|
|
6320
6375
|
this.microHead.appendChild(this.baseElement);
|
|
6321
6376
|
}
|
|
6322
|
-
createProxyLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost) {
|
|
6323
|
-
this.proxyLocation = createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
6324
|
-
}
|
|
6325
6377
|
createProxyWindow(microAppWindow) {
|
|
6326
6378
|
const rawWindow = globalEnv.rawWindow;
|
|
6327
|
-
|
|
6379
|
+
return new Proxy(microAppWindow, {
|
|
6328
6380
|
get: (target, key) => {
|
|
6329
6381
|
if (key === 'location') {
|
|
6330
6382
|
return this.proxyLocation;
|
|
@@ -6335,20 +6387,18 @@ class IframeSandbox {
|
|
|
6335
6387
|
return bindFunctionToRawTarget(Reflect.get(target, key), target);
|
|
6336
6388
|
},
|
|
6337
6389
|
set: (target, key, value) => {
|
|
6338
|
-
|
|
6339
|
-
|
|
6340
|
-
|
|
6341
|
-
|
|
6342
|
-
|
|
6343
|
-
|
|
6344
|
-
|
|
6345
|
-
|
|
6346
|
-
|
|
6347
|
-
|
|
6348
|
-
|
|
6349
|
-
|
|
6350
|
-
Reflect.set(rawWindow, key, value);
|
|
6351
|
-
}
|
|
6390
|
+
/**
|
|
6391
|
+
* TODO:
|
|
6392
|
+
* 1、location域名相同,子应用内部跳转时的处理
|
|
6393
|
+
* 2、和with沙箱的变量相同,提取成公共数组
|
|
6394
|
+
*/
|
|
6395
|
+
if (key === 'location') {
|
|
6396
|
+
return Reflect.set(rawWindow, key, value);
|
|
6397
|
+
}
|
|
6398
|
+
Reflect.set(target, key, value);
|
|
6399
|
+
if (this.escapeProperties.includes(key)) {
|
|
6400
|
+
!Reflect.has(rawWindow, key) && this.escapeKeys.add(key);
|
|
6401
|
+
Reflect.set(rawWindow, key, value);
|
|
6352
6402
|
}
|
|
6353
6403
|
return true;
|
|
6354
6404
|
},
|
|
@@ -6677,7 +6727,7 @@ class CreateApp {
|
|
|
6677
6727
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6678
6728
|
}
|
|
6679
6729
|
catch (e) {
|
|
6680
|
-
logError('An error occurred in
|
|
6730
|
+
logError('An error occurred in window.mount \n', this.name, e);
|
|
6681
6731
|
}
|
|
6682
6732
|
}
|
|
6683
6733
|
else if (isFinished === true) {
|
|
@@ -6692,7 +6742,7 @@ class CreateApp {
|
|
|
6692
6742
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6693
6743
|
}
|
|
6694
6744
|
catch (e) {
|
|
6695
|
-
logError('An error occurred in
|
|
6745
|
+
logError('An error occurred in window.mount \n', this.name, e);
|
|
6696
6746
|
}
|
|
6697
6747
|
}
|
|
6698
6748
|
}
|
|
@@ -6710,7 +6760,7 @@ class CreateApp {
|
|
|
6710
6760
|
if (isPromise(umdHookMountResult)) {
|
|
6711
6761
|
umdHookMountResult
|
|
6712
6762
|
.then(() => this.dispatchMountedEvent())
|
|
6713
|
-
.catch((
|
|
6763
|
+
.catch(() => this.dispatchMountedEvent());
|
|
6714
6764
|
}
|
|
6715
6765
|
else {
|
|
6716
6766
|
this.dispatchMountedEvent();
|
|
@@ -6738,7 +6788,8 @@ class CreateApp {
|
|
|
6738
6788
|
}
|
|
6739
6789
|
/**
|
|
6740
6790
|
* unmount app
|
|
6741
|
-
* NOTE:
|
|
6791
|
+
* NOTE:
|
|
6792
|
+
* 1. do not add any params on account of unmountApp
|
|
6742
6793
|
* @param destroy completely destroy, delete cache resources
|
|
6743
6794
|
* @param clearData clear data of dateCenter
|
|
6744
6795
|
* @param keepRouteState keep route state when unmount, default is false
|
|
@@ -6748,33 +6799,35 @@ class CreateApp {
|
|
|
6748
6799
|
var _a;
|
|
6749
6800
|
destroy = destroy || this.state === appStates.LOAD_FAILED;
|
|
6750
6801
|
this.setAppState(appStates.UNMOUNT);
|
|
6751
|
-
// result of unmount function
|
|
6752
6802
|
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
6803
|
try {
|
|
6804
|
+
// call umd unmount hook before the sandbox is cleared
|
|
6758
6805
|
umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
|
|
6759
6806
|
}
|
|
6760
6807
|
catch (e) {
|
|
6761
|
-
logError('An error occurred in
|
|
6808
|
+
logError('An error occurred in window.unmount \n', this.name, e);
|
|
6762
6809
|
}
|
|
6763
6810
|
// dispatch unmount event to micro app
|
|
6764
6811
|
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
6765
6812
|
// call window.onunmount of child app
|
|
6766
6813
|
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
6767
|
-
this.handleUnmounted(
|
|
6814
|
+
this.handleUnmounted({
|
|
6815
|
+
destroy,
|
|
6816
|
+
clearData,
|
|
6817
|
+
keepRouteState,
|
|
6818
|
+
unmountcb,
|
|
6819
|
+
umdHookUnmountResult,
|
|
6820
|
+
});
|
|
6768
6821
|
}
|
|
6769
6822
|
/**
|
|
6770
6823
|
* handle for promise umdHookUnmount
|
|
6771
6824
|
* @param destroy completely destroy, delete cache resources
|
|
6772
6825
|
* @param clearData clear data of dateCenter
|
|
6773
6826
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6774
|
-
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6775
6827
|
* @param unmountcb callback of unmount
|
|
6828
|
+
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6776
6829
|
*/
|
|
6777
|
-
handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult,
|
|
6830
|
+
handleUnmounted({ destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult, }) {
|
|
6778
6831
|
const nextAction = () => this.actionsForUnmount({
|
|
6779
6832
|
destroy,
|
|
6780
6833
|
clearData,
|
|
@@ -6782,6 +6835,8 @@ class CreateApp {
|
|
|
6782
6835
|
unmountcb,
|
|
6783
6836
|
});
|
|
6784
6837
|
if (isPromise(umdHookUnmountResult)) {
|
|
6838
|
+
// async window.unmount will cause appName bind error in nest app
|
|
6839
|
+
removeDomScope();
|
|
6785
6840
|
umdHookUnmountResult.then(nextAction).catch(nextAction);
|
|
6786
6841
|
}
|
|
6787
6842
|
else {
|
|
@@ -6795,7 +6850,7 @@ class CreateApp {
|
|
|
6795
6850
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6796
6851
|
* @param unmountcb callback of unmount
|
|
6797
6852
|
*/
|
|
6798
|
-
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
|
|
6853
|
+
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
6799
6854
|
var _a;
|
|
6800
6855
|
if (this.umdMode && this.container && !destroy) {
|
|
6801
6856
|
cloneContainer(this.container, this.source.html, false);
|
|
@@ -6812,9 +6867,6 @@ class CreateApp {
|
|
|
6812
6867
|
destroy,
|
|
6813
6868
|
clearData: clearData || destroy,
|
|
6814
6869
|
});
|
|
6815
|
-
if (!getActiveApps().length) {
|
|
6816
|
-
releasePatchSetAttribute();
|
|
6817
|
-
}
|
|
6818
6870
|
// dispatch unmount event to base app
|
|
6819
6871
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
6820
6872
|
this.clearOptions(destroy);
|
|
@@ -6831,6 +6883,7 @@ class CreateApp {
|
|
|
6831
6883
|
this.sandBox = null;
|
|
6832
6884
|
if (destroy)
|
|
6833
6885
|
this.actionsForCompletelyDestroy();
|
|
6886
|
+
removeDomScope();
|
|
6834
6887
|
}
|
|
6835
6888
|
// actions for completely destroy
|
|
6836
6889
|
actionsForCompletelyDestroy() {
|
|
@@ -6964,7 +7017,7 @@ function isIframeSandbox(appName) {
|
|
|
6964
7017
|
function defineElement(tagName) {
|
|
6965
7018
|
class MicroAppElement extends HTMLElement {
|
|
6966
7019
|
constructor() {
|
|
6967
|
-
super();
|
|
7020
|
+
super(...arguments);
|
|
6968
7021
|
this.isWaiting = false;
|
|
6969
7022
|
this.cacheData = null;
|
|
6970
7023
|
this.connectedCount = 0;
|
|
@@ -7016,8 +7069,6 @@ function defineElement(tagName) {
|
|
|
7016
7069
|
this.setAttribute('name', this.appName);
|
|
7017
7070
|
}
|
|
7018
7071
|
};
|
|
7019
|
-
// patchSetAttribute hijiack data attribute, it needs exec first
|
|
7020
|
-
patchSetAttribute();
|
|
7021
7072
|
}
|
|
7022
7073
|
static get observedAttributes() {
|
|
7023
7074
|
return ['name', 'url'];
|
|
@@ -7286,6 +7337,7 @@ function defineElement(tagName) {
|
|
|
7286
7337
|
*/
|
|
7287
7338
|
handleAppMount(app) {
|
|
7288
7339
|
app.isPrefetch = false;
|
|
7340
|
+
// TODO: Can defer be removed?
|
|
7289
7341
|
defer(() => this.mount(app));
|
|
7290
7342
|
}
|
|
7291
7343
|
/**
|
|
@@ -7427,6 +7479,30 @@ function defineElement(tagName) {
|
|
|
7427
7479
|
this.getAttribute('defaultPage') ||
|
|
7428
7480
|
'');
|
|
7429
7481
|
}
|
|
7482
|
+
/**
|
|
7483
|
+
* Rewrite micro-app.setAttribute, process attr data
|
|
7484
|
+
* @param key attr name
|
|
7485
|
+
* @param value attr value
|
|
7486
|
+
*/
|
|
7487
|
+
setAttribute(key, value) {
|
|
7488
|
+
if (key === 'data') {
|
|
7489
|
+
if (isPlainObject(value)) {
|
|
7490
|
+
const cloneValue = {};
|
|
7491
|
+
Object.getOwnPropertyNames(value).forEach((ownKey) => {
|
|
7492
|
+
if (!(isString(ownKey) && ownKey.indexOf('__') === 0)) {
|
|
7493
|
+
cloneValue[ownKey] = value[ownKey];
|
|
7494
|
+
}
|
|
7495
|
+
});
|
|
7496
|
+
this.data = cloneValue;
|
|
7497
|
+
}
|
|
7498
|
+
else if (value !== '[object Object]') {
|
|
7499
|
+
logWarn('property data must be an object', this.appName);
|
|
7500
|
+
}
|
|
7501
|
+
}
|
|
7502
|
+
else {
|
|
7503
|
+
globalEnv.rawSetAttribute.call(this, key, value);
|
|
7504
|
+
}
|
|
7505
|
+
}
|
|
7430
7506
|
/**
|
|
7431
7507
|
* Data from the base application
|
|
7432
7508
|
*/
|