@micro-zoe/micro-app 1.0.0-beta.0 → 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.d.ts +1 -0
- package/lib/index.esm.js +1640 -1527
- 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 +4 -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
|
|
@@ -114,6 +114,10 @@ function isBaseElement(target) {
|
|
|
114
114
|
var _a, _b;
|
|
115
115
|
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'BASE';
|
|
116
116
|
}
|
|
117
|
+
function isMicroAppBody(target) {
|
|
118
|
+
var _a, _b;
|
|
119
|
+
return ((_b = (_a = target) === null || _a === void 0 ? void 0 : _a.tagName) === null || _b === void 0 ? void 0 : _b.toUpperCase()) === 'MICRO-APP-BODY';
|
|
120
|
+
}
|
|
117
121
|
// is ProxyDocument
|
|
118
122
|
function isProxyDocument(target) {
|
|
119
123
|
return toString.call(target) === '[object ProxyDocument]';
|
|
@@ -1167,231 +1171,578 @@ function createSourceCenter() {
|
|
|
1167
1171
|
}
|
|
1168
1172
|
var sourceCenter = createSourceCenter();
|
|
1169
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
|
+
}
|
|
1170
1184
|
/**
|
|
1171
|
-
*
|
|
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
|
|
1172
1210
|
* @param appName app.name
|
|
1173
|
-
* @param
|
|
1211
|
+
* @param scriptInfo scriptInfo of current address
|
|
1212
|
+
* @param currentCode pure code of current address
|
|
1174
1213
|
*/
|
|
1175
|
-
function
|
|
1176
|
-
const appSpace =
|
|
1214
|
+
function getExistParseResult(app, scriptInfo, currentCode) {
|
|
1215
|
+
const appSpace = scriptInfo.appSpace;
|
|
1177
1216
|
for (const item in appSpace) {
|
|
1178
|
-
if (item !==
|
|
1217
|
+
if (item !== app.name) {
|
|
1179
1218
|
const appSpaceData = appSpace[item];
|
|
1180
|
-
if (appSpaceData.parsedCode) {
|
|
1181
|
-
return appSpaceData.
|
|
1219
|
+
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
1220
|
+
return appSpaceData.parsedFunction;
|
|
1182
1221
|
}
|
|
1183
1222
|
}
|
|
1184
1223
|
}
|
|
1185
1224
|
}
|
|
1186
|
-
|
|
1187
|
-
|
|
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) {
|
|
1188
1242
|
attrs.forEach((value, key) => {
|
|
1189
|
-
if (key === '
|
|
1243
|
+
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
1190
1244
|
return;
|
|
1191
|
-
if (key === '
|
|
1192
|
-
key = 'data-origin-
|
|
1193
|
-
|
|
1245
|
+
if (key === 'src')
|
|
1246
|
+
key = 'data-origin-src';
|
|
1247
|
+
globalEnv.rawSetAttribute.call(convertScript, key, value);
|
|
1194
1248
|
});
|
|
1195
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
|
+
}
|
|
1196
1257
|
/**
|
|
1197
|
-
* Extract
|
|
1198
|
-
* @param
|
|
1199
|
-
* @param parent parent element of
|
|
1258
|
+
* Extract script elements
|
|
1259
|
+
* @param script script element
|
|
1260
|
+
* @param parent parent element of script
|
|
1200
1261
|
* @param app app
|
|
1201
|
-
* @param microAppHead micro-app-head element
|
|
1202
1262
|
* @param isDynamic dynamic insert
|
|
1203
1263
|
*/
|
|
1204
|
-
function
|
|
1205
|
-
|
|
1206
|
-
let href = link.getAttribute('href');
|
|
1264
|
+
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
1265
|
+
var _a;
|
|
1207
1266
|
let replaceComment = null;
|
|
1208
|
-
|
|
1209
|
-
|
|
1210
|
-
|
|
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);
|
|
1211
1289
|
const appSpaceData = {
|
|
1212
|
-
|
|
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),
|
|
1213
1296
|
};
|
|
1214
|
-
if (!
|
|
1215
|
-
|
|
1297
|
+
if (!scriptInfo) {
|
|
1298
|
+
scriptInfo = {
|
|
1216
1299
|
code: '',
|
|
1300
|
+
isExternal: true,
|
|
1217
1301
|
appSpace: {
|
|
1218
1302
|
[app.name]: appSpaceData,
|
|
1219
1303
|
}
|
|
1220
1304
|
};
|
|
1221
1305
|
}
|
|
1222
1306
|
else {
|
|
1223
|
-
|
|
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;
|
|
1224
1314
|
}
|
|
1225
|
-
sourceCenter.
|
|
1315
|
+
sourceCenter.script.setInfo(src, scriptInfo);
|
|
1226
1316
|
if (!isDynamic) {
|
|
1227
|
-
app.source.
|
|
1228
|
-
replaceComment = document.createComment(`
|
|
1229
|
-
linkInfo.appSpace[app.name].placeholder = replaceComment;
|
|
1317
|
+
app.source.scripts.add(src);
|
|
1318
|
+
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
1230
1319
|
}
|
|
1231
1320
|
else {
|
|
1232
|
-
return { address:
|
|
1321
|
+
return { address: src, scriptInfo };
|
|
1233
1322
|
}
|
|
1234
1323
|
}
|
|
1235
|
-
else if (
|
|
1236
|
-
|
|
1237
|
-
|
|
1238
|
-
|
|
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');
|
|
1239
1352
|
}
|
|
1240
1353
|
else {
|
|
1241
|
-
|
|
1354
|
+
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
1355
|
+
return { address: nonceStr, scriptInfo };
|
|
1242
1356
|
}
|
|
1243
1357
|
}
|
|
1244
|
-
else if (
|
|
1245
|
-
|
|
1246
|
-
|
|
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');
|
|
1247
1364
|
}
|
|
1248
1365
|
if (isDynamic) {
|
|
1249
1366
|
return { replaceComment };
|
|
1250
1367
|
}
|
|
1251
|
-
else
|
|
1252
|
-
return parent.replaceChild(replaceComment,
|
|
1368
|
+
else {
|
|
1369
|
+
return parent === null || parent === void 0 ? void 0 : parent.replaceChild(replaceComment, script);
|
|
1253
1370
|
}
|
|
1254
1371
|
}
|
|
1255
1372
|
/**
|
|
1256
|
-
*
|
|
1257
|
-
* @param
|
|
1258
|
-
* @param app app
|
|
1259
|
-
* @param microAppHead micro-app-head
|
|
1373
|
+
* get assets plugins
|
|
1374
|
+
* @param appName app name
|
|
1260
1375
|
*/
|
|
1261
|
-
function
|
|
1262
|
-
|
|
1263
|
-
const
|
|
1264
|
-
|
|
1265
|
-
|
|
1266
|
-
});
|
|
1267
|
-
const fiberLinkTasks = fiberStyleResult ? [] : null;
|
|
1268
|
-
promiseStream(fetchLinkPromise, (res) => {
|
|
1269
|
-
injectFiberTask(fiberLinkTasks, () => fetchLinkSuccess(styleList[res.index], res.data, microAppHead, app));
|
|
1270
|
-
}, (err) => {
|
|
1271
|
-
logError(err, app.name);
|
|
1272
|
-
}, () => {
|
|
1273
|
-
/**
|
|
1274
|
-
* 1. If fiberStyleResult exist, fiberLinkTasks must exist
|
|
1275
|
-
* 2. Download link source while processing style
|
|
1276
|
-
* 3. Process style first, and then process link
|
|
1277
|
-
*/
|
|
1278
|
-
if (fiberStyleResult) {
|
|
1279
|
-
fiberStyleResult.then(() => {
|
|
1280
|
-
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
1281
|
-
serialExecFiberTasks(fiberLinkTasks);
|
|
1282
|
-
});
|
|
1283
|
-
}
|
|
1284
|
-
else {
|
|
1285
|
-
app.onLoad(wrapElement);
|
|
1286
|
-
}
|
|
1287
|
-
});
|
|
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];
|
|
1288
1381
|
}
|
|
1289
1382
|
/**
|
|
1290
|
-
*
|
|
1291
|
-
*
|
|
1292
|
-
*
|
|
1293
|
-
* 2. Only handler html link element, not dynamic link or style
|
|
1294
|
-
* 3. The same prefix can reuse parsedCode
|
|
1295
|
-
* 4. Async exec with requestIdleCallback in prefetch or fiber
|
|
1296
|
-
* 5. appSpace[app.name].placeholder/attrs must exist
|
|
1297
|
-
* @param address resource address
|
|
1298
|
-
* @param code link source code
|
|
1299
|
-
* @param microAppHead micro-app-head
|
|
1300
|
-
* @param app app instance
|
|
1383
|
+
* whether the address needs to be excluded
|
|
1384
|
+
* @param address css or js link
|
|
1385
|
+
* @param plugins microApp plugins
|
|
1301
1386
|
*/
|
|
1302
|
-
function
|
|
1303
|
-
|
|
1304
|
-
|
|
1305
|
-
|
|
1306
|
-
|
|
1307
|
-
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1311
|
-
|
|
1312
|
-
|
|
1313
|
-
|
|
1314
|
-
|
|
1315
|
-
|
|
1316
|
-
|
|
1317
|
-
|
|
1318
|
-
if (
|
|
1319
|
-
|
|
1320
|
-
|
|
1321
|
-
|
|
1322
|
-
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
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);
|
|
1395
|
+
});
|
|
1396
|
+
}
|
|
1397
|
+
/**
|
|
1398
|
+
* whether the address needs to be ignore
|
|
1399
|
+
* @param address css or js link
|
|
1400
|
+
* @param plugins microApp plugins
|
|
1401
|
+
*/
|
|
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]);
|
|
1326
1427
|
}
|
|
1327
|
-
|
|
1328
|
-
|
|
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);
|
|
1329
1447
|
}
|
|
1330
1448
|
}
|
|
1331
1449
|
/**
|
|
1332
|
-
*
|
|
1333
|
-
*
|
|
1334
|
-
*
|
|
1335
|
-
*
|
|
1336
|
-
* 3. set parsedCode to convertStyle if need
|
|
1337
|
-
* @param app app instance
|
|
1338
|
-
* @param address resource address
|
|
1339
|
-
* @param convertStyle converted style
|
|
1340
|
-
* @param linkInfo linkInfo in sourceCenter
|
|
1341
|
-
* @param attrs attrs of link
|
|
1450
|
+
* fetch js succeeded, record the code value
|
|
1451
|
+
* @param address script address
|
|
1452
|
+
* @param scriptInfo resource script info
|
|
1453
|
+
* @param data code
|
|
1342
1454
|
*/
|
|
1343
|
-
function
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1455
|
+
function fetchScriptSuccess(address, scriptInfo, code, app) {
|
|
1456
|
+
// reset scriptInfo.code
|
|
1457
|
+
scriptInfo.code = code;
|
|
1458
|
+
/**
|
|
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
|
|
1464
|
+
*/
|
|
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
|
+
*/
|
|
1347
1474
|
if (!appSpaceData.parsedCode) {
|
|
1348
|
-
|
|
1349
|
-
|
|
1350
|
-
|
|
1351
|
-
|
|
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
|
+
}
|
|
1485
|
+
}
|
|
1486
|
+
}
|
|
1487
|
+
}
|
|
1488
|
+
/**
|
|
1489
|
+
* Execute js in the mount lifecycle
|
|
1490
|
+
* @param app app
|
|
1491
|
+
* @param initHook callback for umd mode
|
|
1492
|
+
*/
|
|
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));
|
|
1352
1506
|
}
|
|
1353
1507
|
else {
|
|
1354
|
-
|
|
1508
|
+
deferScriptPromise.push(scriptInfo.code);
|
|
1355
1509
|
}
|
|
1356
|
-
|
|
1510
|
+
deferScriptInfo.push([address, scriptInfo]);
|
|
1511
|
+
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
1357
1512
|
}
|
|
1358
1513
|
else {
|
|
1359
|
-
|
|
1514
|
+
injectFiberTask(fiberScriptTasks, () => {
|
|
1515
|
+
runScript(address, app, scriptInfo);
|
|
1516
|
+
initHook(false);
|
|
1517
|
+
});
|
|
1360
1518
|
}
|
|
1361
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
|
+
}
|
|
1362
1555
|
else {
|
|
1363
|
-
|
|
1556
|
+
if (fiberScriptTasks) {
|
|
1557
|
+
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
1558
|
+
serialExecFiberTasks(fiberScriptTasks);
|
|
1559
|
+
}
|
|
1560
|
+
else {
|
|
1561
|
+
initHook(true);
|
|
1562
|
+
}
|
|
1364
1563
|
}
|
|
1365
|
-
setConvertStyleAttr(convertStyle, attrs);
|
|
1366
1564
|
}
|
|
1367
1565
|
/**
|
|
1368
|
-
*
|
|
1369
|
-
* @param address
|
|
1566
|
+
* run code
|
|
1567
|
+
* @param address script address
|
|
1370
1568
|
* @param app app
|
|
1371
|
-
* @param
|
|
1372
|
-
* @param
|
|
1569
|
+
* @param scriptInfo script info
|
|
1570
|
+
* @param callback callback of module script
|
|
1373
1571
|
*/
|
|
1374
|
-
function
|
|
1375
|
-
|
|
1376
|
-
|
|
1377
|
-
|
|
1378
|
-
|
|
1379
|
-
|
|
1380
|
-
|
|
1381
|
-
|
|
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
|
+
}
|
|
1382
1600
|
}
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
linkInfo.code = data;
|
|
1386
|
-
handleDynamicLink();
|
|
1387
|
-
}).catch((err) => {
|
|
1388
|
-
logError(err, app.name);
|
|
1389
|
-
dispatchOnErrorEvent(originLink);
|
|
1390
|
-
});
|
|
1601
|
+
catch (e) {
|
|
1602
|
+
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
1391
1603
|
}
|
|
1392
|
-
return convertStyle;
|
|
1393
1604
|
}
|
|
1394
|
-
|
|
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
|
+
|
|
1395
1746
|
class Adapter {
|
|
1396
1747
|
constructor() {
|
|
1397
1748
|
// keys that can only assigned to rawWindow
|
|
@@ -1517,37 +1868,55 @@ function patchElementTree(container, appName) {
|
|
|
1517
1868
|
function updateElementInfo(node, appName) {
|
|
1518
1869
|
var _a, _b;
|
|
1519
1870
|
const proxyWindow = (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.sandBox) === null || _b === void 0 ? void 0 : _b.proxyWindow;
|
|
1520
|
-
if (
|
|
1521
|
-
|
|
1871
|
+
if (isNode(node) &&
|
|
1872
|
+
!node.__MICRO_APP_NAME__ &&
|
|
1873
|
+
!node.__PURE_ELEMENT__ &&
|
|
1874
|
+
proxyWindow) {
|
|
1875
|
+
/**
|
|
1876
|
+
* TODO:
|
|
1877
|
+
* 1. 测试baseURI和ownerDocument在with沙箱中是否正确
|
|
1878
|
+
* 经过验证with沙箱不能重写ownerDocument,否则react点击事件会触发两次
|
|
1879
|
+
* 2. with沙箱所有node设置__MICRO_APP_NAME__都使用updateElementInfo
|
|
1880
|
+
* 3. 性能: defineProperty的性能肯定不如直接设置
|
|
1881
|
+
*/
|
|
1522
1882
|
rawDefineProperties(node, {
|
|
1523
1883
|
baseURI: {
|
|
1524
1884
|
configurable: true,
|
|
1525
1885
|
get: () => proxyWindow.location.href,
|
|
1526
1886
|
},
|
|
1527
|
-
ownerDocument: {
|
|
1528
|
-
configurable: true,
|
|
1529
|
-
get: () => proxyWindow.document,
|
|
1530
|
-
},
|
|
1531
1887
|
__MICRO_APP_NAME__: {
|
|
1532
1888
|
configurable: true,
|
|
1533
1889
|
writable: true,
|
|
1534
1890
|
value: appName,
|
|
1535
1891
|
},
|
|
1536
1892
|
});
|
|
1893
|
+
if (isIframeSandbox(appName)) {
|
|
1894
|
+
rawDefineProperty(node, 'ownerDocument', {
|
|
1895
|
+
configurable: true,
|
|
1896
|
+
get: () => proxyWindow.document,
|
|
1897
|
+
});
|
|
1898
|
+
}
|
|
1537
1899
|
}
|
|
1538
1900
|
return node;
|
|
1539
1901
|
}
|
|
1540
1902
|
|
|
1541
1903
|
// Record element and map element
|
|
1542
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
|
+
}
|
|
1543
1910
|
/**
|
|
1544
1911
|
* Process the new node and format the style, link and script element
|
|
1545
|
-
* @param parent parent node
|
|
1546
1912
|
* @param child new node
|
|
1547
1913
|
* @param app app
|
|
1548
1914
|
*/
|
|
1549
|
-
function handleNewNode(
|
|
1550
|
-
if (
|
|
1915
|
+
function handleNewNode(child, app) {
|
|
1916
|
+
if (dynamicElementInMicroAppMap.has(child)) {
|
|
1917
|
+
return dynamicElementInMicroAppMap.get(child);
|
|
1918
|
+
}
|
|
1919
|
+
else if (isStyleElement(child)) {
|
|
1551
1920
|
if (child.hasAttribute('exclude')) {
|
|
1552
1921
|
const replaceComment = document.createComment('style element with exclude attribute ignored by micro-app');
|
|
1553
1922
|
dynamicElementInMicroAppMap.set(child, replaceComment);
|
|
@@ -1571,7 +1940,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1571
1940
|
microApp.options.excludeAssetFilter(child.href))) {
|
|
1572
1941
|
return child;
|
|
1573
1942
|
}
|
|
1574
|
-
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child,
|
|
1943
|
+
const { address, linkInfo, replaceComment } = extractLinkFromHtml(child, null, app, true);
|
|
1575
1944
|
if (address && linkInfo) {
|
|
1576
1945
|
const replaceStyle = formatDynamicLink(address, app, linkInfo, child);
|
|
1577
1946
|
dynamicElementInMicroAppMap.set(child, replaceStyle);
|
|
@@ -1589,7 +1958,7 @@ function handleNewNode(parent, child, app) {
|
|
|
1589
1958
|
microApp.options.excludeAssetFilter(child.src)) {
|
|
1590
1959
|
return child;
|
|
1591
1960
|
}
|
|
1592
|
-
const { replaceComment, address, scriptInfo } = extractScriptElement(child,
|
|
1961
|
+
const { replaceComment, address, scriptInfo } = extractScriptElement(child, null, app, true) || {};
|
|
1593
1962
|
if (address && scriptInfo) {
|
|
1594
1963
|
// remote script or inline script
|
|
1595
1964
|
const replaceElement = scriptInfo.isExternal ? runDynamicRemoteScript(address, app, scriptInfo, child) : runDynamicInlineScript(address, app, scriptInfo);
|
|
@@ -1620,25 +1989,39 @@ function invokePrototypeMethod(app, rawMethod, parent, targetChild, passiveChild
|
|
|
1620
1989
|
*/
|
|
1621
1990
|
if (hijackParent) {
|
|
1622
1991
|
/**
|
|
1623
|
-
*
|
|
1992
|
+
* If parentNode is <micro-app-body>, return rawDocument.body
|
|
1993
|
+
* Scenes:
|
|
1994
|
+
* 1. element-ui@2/lib/utils/vue-popper.js
|
|
1995
|
+
* if (this.popperElm.parentNode === document.body) ...
|
|
1624
1996
|
* WARNING:
|
|
1625
|
-
*
|
|
1997
|
+
* 1. When operate child from parentNode async, may have been unmount
|
|
1998
|
+
* e.g. target.parentNode.remove(target)
|
|
1999
|
+
* ISSUE:
|
|
2000
|
+
* 1. https://github.com/micro-zoe/micro-app/issues/739
|
|
2001
|
+
* Solution: Return the true value when node not in document
|
|
1626
2002
|
*/
|
|
1627
2003
|
if (!isIframeSandbox(app.name) &&
|
|
1628
|
-
hijackParent
|
|
2004
|
+
isMicroAppBody(hijackParent) &&
|
|
1629
2005
|
rawMethod !== globalEnv.rawRemoveChild) {
|
|
1630
2006
|
const descriptor = Object.getOwnPropertyDescriptor(targetChild, 'parentNode');
|
|
1631
|
-
if (!descriptor || descriptor.configurable) {
|
|
1632
|
-
|
|
1633
|
-
|
|
1634
|
-
|
|
1635
|
-
|
|
1636
|
-
|
|
1637
|
-
|
|
1638
|
-
|
|
1639
|
-
|
|
1640
|
-
|
|
2007
|
+
if ((!descriptor || descriptor.configurable) && !targetChild.__MICRO_APP_HAS_DPN__) {
|
|
2008
|
+
rawDefineProperties(targetChild, {
|
|
2009
|
+
parentNode: {
|
|
2010
|
+
configurable: true,
|
|
2011
|
+
get() {
|
|
2012
|
+
var _a, _b;
|
|
2013
|
+
const result = globalEnv.rawParentNodeDesc.get.call(this);
|
|
2014
|
+
if (isMicroAppBody(result) && app.container) {
|
|
2015
|
+
// TODO: remove getRootElementParentNode
|
|
2016
|
+
return ((_b = (_a = microApp.options).getRootElementParentNode) === null || _b === void 0 ? void 0 : _b.call(_a, this, app.name)) || document.body;
|
|
2017
|
+
}
|
|
2018
|
+
return result;
|
|
2019
|
+
},
|
|
1641
2020
|
},
|
|
2021
|
+
__MICRO_APP_HAS_DPN__: {
|
|
2022
|
+
configurable: true,
|
|
2023
|
+
get: () => true,
|
|
2024
|
+
}
|
|
1642
2025
|
});
|
|
1643
2026
|
}
|
|
1644
2027
|
}
|
|
@@ -1679,6 +2062,9 @@ function getHijackParent(parent, targetChild, app) {
|
|
|
1679
2062
|
}
|
|
1680
2063
|
return app.querySelector('micro-app-body');
|
|
1681
2064
|
}
|
|
2065
|
+
if (app.iframe && isScriptElement(targetChild)) {
|
|
2066
|
+
return app.sandBox.microBody;
|
|
2067
|
+
}
|
|
1682
2068
|
}
|
|
1683
2069
|
return null;
|
|
1684
2070
|
}
|
|
@@ -1691,10 +2077,25 @@ function invokeRawMethod(rawMethod, parent, targetChild, passiveChild) {
|
|
|
1691
2077
|
function isPendMethod(method) {
|
|
1692
2078
|
return method === globalEnv.rawAppend || method === globalEnv.rawPrepend;
|
|
1693
2079
|
}
|
|
1694
|
-
|
|
1695
|
-
|
|
1696
|
-
|
|
1697
|
-
|
|
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
|
+
}
|
|
1698
2099
|
}
|
|
1699
2100
|
/**
|
|
1700
2101
|
* method of handle new node
|
|
@@ -1712,37 +2113,11 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1712
2113
|
newChild.__MICRO_APP_NAME__ = newChild.__MICRO_APP_NAME__ || currentAppName;
|
|
1713
2114
|
const app = appInstanceMap.get(newChild.__MICRO_APP_NAME__);
|
|
1714
2115
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1715
|
-
|
|
1716
|
-
|
|
1717
|
-
if (newChild.hasAttribute('src')) {
|
|
1718
|
-
globalEnv.rawSetAttribute.call(newChild, 'src', CompletionPath(newChild.getAttribute('src'), app.url));
|
|
1719
|
-
}
|
|
1720
|
-
if (newChild.hasAttribute('srcset')) {
|
|
1721
|
-
globalEnv.rawSetAttribute.call(newChild, 'srcset', CompletionPath(newChild.getAttribute('srcset'), app.url));
|
|
1722
|
-
}
|
|
1723
|
-
}
|
|
1724
|
-
else if (/^link$/i.test(newChild.tagName) && newChild.hasAttribute('href')) {
|
|
1725
|
-
globalEnv.rawSetAttribute.call(newChild, 'href', CompletionPath(newChild.getAttribute('href'), app.url));
|
|
1726
|
-
}
|
|
1727
|
-
}
|
|
1728
|
-
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(parent, newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
1729
|
-
}
|
|
1730
|
-
else if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1731
|
-
return rawMethod.call(parent, newChild);
|
|
2116
|
+
completePathDynamic(app, newChild);
|
|
2117
|
+
return invokePrototypeMethod(app, rawMethod, parent, handleNewNode(newChild, app), passiveChild && getMappingNode(passiveChild));
|
|
1732
2118
|
}
|
|
1733
2119
|
}
|
|
1734
|
-
|
|
1735
|
-
if (!isNode(newChild) && currentAppName) {
|
|
1736
|
-
const app = appInstanceMap.get(currentAppName);
|
|
1737
|
-
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
1738
|
-
if (parent === document.head) {
|
|
1739
|
-
return rawMethod.call(app.querySelector('micro-app-head'), newChild);
|
|
1740
|
-
}
|
|
1741
|
-
else if (parent === document.body) {
|
|
1742
|
-
return rawMethod.call(app.querySelector('micro-app-body'), newChild);
|
|
1743
|
-
}
|
|
1744
|
-
}
|
|
1745
|
-
}
|
|
2120
|
+
if (rawMethod === globalEnv.rawAppend || rawMethod === globalEnv.rawPrepend) {
|
|
1746
2121
|
return rawMethod.call(parent, newChild);
|
|
1747
2122
|
}
|
|
1748
2123
|
return rawMethod.call(parent, newChild, passiveChild);
|
|
@@ -1752,33 +2127,37 @@ function commonElementHandler(parent, newChild, passiveChild, rawMethod) {
|
|
|
1752
2127
|
*/
|
|
1753
2128
|
function patchElementAndDocument() {
|
|
1754
2129
|
patchDocument();
|
|
2130
|
+
const rawRootElement = globalEnv.rawRootElement;
|
|
1755
2131
|
// prototype methods of add element👇
|
|
1756
|
-
|
|
2132
|
+
rawRootElement.prototype.appendChild = function appendChild(newChild) {
|
|
1757
2133
|
return commonElementHandler(this, newChild, null, globalEnv.rawAppendChild);
|
|
1758
2134
|
};
|
|
1759
|
-
|
|
2135
|
+
rawRootElement.prototype.insertBefore = function insertBefore(newChild, refChild) {
|
|
1760
2136
|
return commonElementHandler(this, newChild, refChild, globalEnv.rawInsertBefore);
|
|
1761
2137
|
};
|
|
1762
|
-
|
|
2138
|
+
rawRootElement.prototype.replaceChild = function replaceChild(newChild, oldChild) {
|
|
1763
2139
|
return commonElementHandler(this, newChild, oldChild, globalEnv.rawReplaceChild);
|
|
1764
2140
|
};
|
|
1765
|
-
|
|
2141
|
+
rawRootElement.prototype.append = function append(...nodes) {
|
|
1766
2142
|
let i = 0;
|
|
1767
|
-
|
|
1768
|
-
|
|
1769
|
-
|
|
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);
|
|
1770
2147
|
i++;
|
|
1771
2148
|
}
|
|
1772
2149
|
};
|
|
1773
|
-
|
|
2150
|
+
rawRootElement.prototype.prepend = function prepend(...nodes) {
|
|
1774
2151
|
let i = nodes.length;
|
|
1775
2152
|
while (i > 0) {
|
|
1776
|
-
|
|
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);
|
|
1777
2156
|
i--;
|
|
1778
2157
|
}
|
|
1779
2158
|
};
|
|
1780
2159
|
// prototype methods of delete element👇
|
|
1781
|
-
|
|
2160
|
+
rawRootElement.prototype.removeChild = function removeChild(oldChild) {
|
|
1782
2161
|
if (oldChild === null || oldChild === void 0 ? void 0 : oldChild.__MICRO_APP_NAME__) {
|
|
1783
2162
|
const app = appInstanceMap.get(oldChild.__MICRO_APP_NAME__);
|
|
1784
2163
|
if (app === null || app === void 0 ? void 0 : app.container) {
|
|
@@ -1793,8 +2172,20 @@ function patchElementAndDocument() {
|
|
|
1793
2172
|
}
|
|
1794
2173
|
return globalEnv.rawRemoveChild.call(this, oldChild);
|
|
1795
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
|
+
};
|
|
1796
2187
|
// patch cloneNode
|
|
1797
|
-
|
|
2188
|
+
rawRootElement.prototype.cloneNode = function cloneNode(deep) {
|
|
1798
2189
|
const clonedNode = globalEnv.rawCloneNode.call(this, deep);
|
|
1799
2190
|
this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
|
|
1800
2191
|
return clonedNode;
|
|
@@ -1814,17 +2205,63 @@ function patchElementAndDocument() {
|
|
|
1814
2205
|
}
|
|
1815
2206
|
return null;
|
|
1816
2207
|
}
|
|
1817
|
-
|
|
2208
|
+
rawRootElement.prototype.querySelector = function querySelector(selectors) {
|
|
1818
2209
|
var _a;
|
|
1819
2210
|
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1820
2211
|
return globalEnv.rawElementQuerySelector.call(target, selectors);
|
|
1821
2212
|
};
|
|
1822
|
-
|
|
2213
|
+
rawRootElement.prototype.querySelectorAll = function querySelectorAll(selectors) {
|
|
1823
2214
|
var _a;
|
|
1824
2215
|
const target = (_a = getQueryTarget(this)) !== null && _a !== void 0 ? _a : this;
|
|
1825
2216
|
return globalEnv.rawElementQuerySelectorAll.call(target, selectors);
|
|
1826
2217
|
};
|
|
1827
|
-
|
|
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', {
|
|
1828
2265
|
configurable: true,
|
|
1829
2266
|
enumerable: true,
|
|
1830
2267
|
get() {
|
|
@@ -1840,7 +2277,9 @@ function patchElementAndDocument() {
|
|
|
1840
2277
|
});
|
|
1841
2278
|
}
|
|
1842
2279
|
});
|
|
1843
|
-
|
|
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
|
+
*/
|
|
1844
2283
|
// rawDefineProperty(Node.prototype, 'parentNode', {
|
|
1845
2284
|
// configurable: true,
|
|
1846
2285
|
// enumerable: true,
|
|
@@ -1857,8 +2296,8 @@ function patchElementAndDocument() {
|
|
|
1857
2296
|
// * BUG:
|
|
1858
2297
|
// * 1. vue2 umdMode, throw error when render again (<div id='app'></div> will be deleted when render again )
|
|
1859
2298
|
// */
|
|
1860
|
-
// if (result
|
|
1861
|
-
// return
|
|
2299
|
+
// if (isMicroAppBody(result) && appInstanceMap.get(this.__MICRO_APP_NAME__)?.container) {
|
|
2300
|
+
// return document.body
|
|
1862
2301
|
// }
|
|
1863
2302
|
// return result
|
|
1864
2303
|
// },
|
|
@@ -1895,33 +2334,35 @@ function patchDocument() {
|
|
|
1895
2334
|
const element = globalEnv.rawCreateDocumentFragment.call(getBindTarget(this));
|
|
1896
2335
|
return markElement(element);
|
|
1897
2336
|
};
|
|
2337
|
+
// rawRootDocument.prototype.createTextNode = function createTextNode (data: string): Text {
|
|
2338
|
+
// const element = globalEnv.rawCreateTextNode.call(getBindTarget(this), data)
|
|
2339
|
+
// return markElement(element)
|
|
2340
|
+
// }
|
|
1898
2341
|
// query element👇
|
|
1899
2342
|
function querySelector(selectors) {
|
|
1900
|
-
var _a, _b
|
|
2343
|
+
var _a, _b;
|
|
1901
2344
|
const _this = getBindTarget(this);
|
|
1902
2345
|
const currentAppName = getCurrentAppName();
|
|
1903
2346
|
if (!currentAppName ||
|
|
1904
|
-
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1905
2347
|
!selectors ||
|
|
1906
2348
|
isUniqueElement(selectors) ||
|
|
1907
2349
|
// see https://github.com/micro-zoe/micro-app/issues/56
|
|
1908
2350
|
rawDocument !== _this) {
|
|
1909
2351
|
return globalEnv.rawQuerySelector.call(_this, selectors);
|
|
1910
2352
|
}
|
|
1911
|
-
return (
|
|
2353
|
+
return (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
1912
2354
|
}
|
|
1913
2355
|
function querySelectorAll(selectors) {
|
|
1914
|
-
var _a, _b
|
|
2356
|
+
var _a, _b;
|
|
1915
2357
|
const _this = getBindTarget(this);
|
|
1916
2358
|
const currentAppName = getCurrentAppName();
|
|
1917
2359
|
if (!currentAppName ||
|
|
1918
|
-
!((_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.container) ||
|
|
1919
2360
|
!selectors ||
|
|
1920
2361
|
isUniqueElement(selectors) ||
|
|
1921
2362
|
rawDocument !== _this) {
|
|
1922
2363
|
return globalEnv.rawQuerySelectorAll.call(_this, selectors);
|
|
1923
2364
|
}
|
|
1924
|
-
return (
|
|
2365
|
+
return (_b = (_a = appInstanceMap.get(currentAppName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
1925
2366
|
}
|
|
1926
2367
|
rawRootDocument.prototype.querySelector = querySelector;
|
|
1927
2368
|
rawRootDocument.prototype.querySelectorAll = querySelectorAll;
|
|
@@ -1979,45 +2420,6 @@ function patchDocument() {
|
|
|
1979
2420
|
}
|
|
1980
2421
|
};
|
|
1981
2422
|
}
|
|
1982
|
-
/**
|
|
1983
|
-
* patchSetAttribute is different from other patch
|
|
1984
|
-
* NOTE:
|
|
1985
|
-
* 1. it not dependent on sandbox
|
|
1986
|
-
* 2. it should exec when first micro-app-element created & release when all app unmounted
|
|
1987
|
-
*/
|
|
1988
|
-
let hasRewriteSetAttribute = false;
|
|
1989
|
-
function patchSetAttribute() {
|
|
1990
|
-
if (hasRewriteSetAttribute)
|
|
1991
|
-
return;
|
|
1992
|
-
hasRewriteSetAttribute = true;
|
|
1993
|
-
Element.prototype.setAttribute = function setAttribute(key, value) {
|
|
1994
|
-
if (/^micro-app(-\S+)?/i.test(this.tagName) && key === 'data') {
|
|
1995
|
-
if (isPlainObject(value)) {
|
|
1996
|
-
const cloneValue = {};
|
|
1997
|
-
Object.getOwnPropertyNames(value).forEach((ownKey) => {
|
|
1998
|
-
if (!(isString(ownKey) && ownKey.indexOf('__') === 0)) {
|
|
1999
|
-
cloneValue[ownKey] = value[ownKey];
|
|
2000
|
-
}
|
|
2001
|
-
});
|
|
2002
|
-
this.data = cloneValue;
|
|
2003
|
-
}
|
|
2004
|
-
else if (value !== '[object Object]') {
|
|
2005
|
-
logWarn('property data must be an object', this.getAttribute('name'));
|
|
2006
|
-
}
|
|
2007
|
-
}
|
|
2008
|
-
else {
|
|
2009
|
-
const appName = this.__MICRO_APP_NAME__ || getCurrentAppName();
|
|
2010
|
-
if (appName &&
|
|
2011
|
-
appInstanceMap.has(appName) &&
|
|
2012
|
-
(((key === 'src' || key === 'srcset') && /^(img|script|video|audio|source|embed)$/i.test(this.tagName)) ||
|
|
2013
|
-
(key === 'href' && /^link$/i.test(this.tagName)))) {
|
|
2014
|
-
const app = appInstanceMap.get(appName);
|
|
2015
|
-
value = CompletionPath(value, app.url);
|
|
2016
|
-
}
|
|
2017
|
-
globalEnv.rawSetAttribute.call(this, key, value);
|
|
2018
|
-
}
|
|
2019
|
-
};
|
|
2020
|
-
}
|
|
2021
2423
|
function releasePatchDocument() {
|
|
2022
2424
|
const rawRootDocument = globalEnv.rawRootDocument;
|
|
2023
2425
|
rawRootDocument.prototype.createElement = globalEnv.rawCreateElement;
|
|
@@ -2034,21 +2436,18 @@ function releasePatchDocument() {
|
|
|
2034
2436
|
function releasePatchElementAndDocument() {
|
|
2035
2437
|
removeDomScope();
|
|
2036
2438
|
releasePatchDocument();
|
|
2037
|
-
|
|
2038
|
-
|
|
2039
|
-
|
|
2040
|
-
|
|
2041
|
-
|
|
2042
|
-
|
|
2043
|
-
|
|
2044
|
-
|
|
2045
|
-
|
|
2046
|
-
|
|
2047
|
-
|
|
2048
|
-
|
|
2049
|
-
function releasePatchSetAttribute() {
|
|
2050
|
-
hasRewriteSetAttribute = false;
|
|
2051
|
-
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);
|
|
2052
2451
|
}
|
|
2053
2452
|
// Set the style of micro-app-head and micro-app-body
|
|
2054
2453
|
let hasRejectMicroAppStyle = false;
|
|
@@ -2077,676 +2476,326 @@ function initGlobalEnv() {
|
|
|
2077
2476
|
const rawWindow = window.rawWindow || Function('return window')();
|
|
2078
2477
|
const rawDocument = window.rawDocument || Function('return document')();
|
|
2079
2478
|
const rawRootDocument = rawWindow.Document || Function('return Document')();
|
|
2080
|
-
const
|
|
2081
|
-
|
|
2082
|
-
|
|
2083
|
-
|
|
2084
|
-
|
|
2085
|
-
const
|
|
2086
|
-
const
|
|
2087
|
-
const
|
|
2088
|
-
const
|
|
2089
|
-
const
|
|
2090
|
-
const
|
|
2091
|
-
const
|
|
2092
|
-
const
|
|
2093
|
-
const
|
|
2094
|
-
const
|
|
2095
|
-
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(
|
|
2096
|
-
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
|
|
2097
2497
|
const rawCreateElement = rawRootDocument.prototype.createElement;
|
|
2098
2498
|
const rawCreateElementNS = rawRootDocument.prototype.createElementNS;
|
|
2099
2499
|
const rawCreateDocumentFragment = rawRootDocument.prototype.createDocumentFragment;
|
|
2100
|
-
const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
|
|
2101
|
-
const rawQuerySelector = rawRootDocument.prototype.querySelector;
|
|
2102
|
-
const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
|
|
2103
|
-
const rawGetElementById = rawRootDocument.prototype.getElementById;
|
|
2104
|
-
const rawGetElementsByClassName = rawRootDocument.prototype.getElementsByClassName;
|
|
2105
|
-
const rawGetElementsByTagName = rawRootDocument.prototype.getElementsByTagName;
|
|
2106
|
-
const rawGetElementsByName = rawRootDocument.prototype.getElementsByName;
|
|
2107
|
-
const ImageProxy = new Proxy(Image, {
|
|
2108
|
-
construct(Target, args) {
|
|
2109
|
-
const elementImage = new Target(...args);
|
|
2110
|
-
|
|
2111
|
-
|
|
2112
|
-
|
|
2113
|
-
|
|
2114
|
-
|
|
2115
|
-
* save effect raw methods
|
|
2116
|
-
* pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
|
|
2117
|
-
*/
|
|
2118
|
-
const rawSetInterval = rawWindow.setInterval;
|
|
2119
|
-
const rawSetTimeout = rawWindow.setTimeout;
|
|
2120
|
-
const rawClearInterval = rawWindow.clearInterval;
|
|
2121
|
-
const rawClearTimeout = rawWindow.clearTimeout;
|
|
2122
|
-
const rawPushState = rawWindow.history.pushState;
|
|
2123
|
-
const rawReplaceState = rawWindow.history.replaceState;
|
|
2124
|
-
const rawWindowAddEventListener = rawWindow.addEventListener;
|
|
2125
|
-
const rawWindowRemoveEventListener = rawWindow.removeEventListener;
|
|
2126
|
-
const rawDocumentAddEventListener = rawDocument.addEventListener;
|
|
2127
|
-
const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
|
|
2128
|
-
// TODO: 统一使用 EventTarget 去掉上面四个
|
|
2129
|
-
const rawAddEventListener = EventTarget.prototype.addEventListener;
|
|
2130
|
-
const rawRemoveEventListener = EventTarget.prototype.removeEventListener;
|
|
2131
|
-
assign(globalEnv, {
|
|
2132
|
-
// common global vars
|
|
2133
|
-
rawWindow,
|
|
2134
|
-
rawDocument,
|
|
2135
|
-
rawRootDocument,
|
|
2136
|
-
supportModuleScript,
|
|
2137
|
-
// source/patch
|
|
2138
|
-
rawSetAttribute,
|
|
2139
|
-
rawAppendChild,
|
|
2140
|
-
rawInsertBefore,
|
|
2141
|
-
rawReplaceChild,
|
|
2142
|
-
rawRemoveChild,
|
|
2143
|
-
rawAppend,
|
|
2144
|
-
rawPrepend,
|
|
2145
|
-
rawCloneNode,
|
|
2146
|
-
rawElementQuerySelector,
|
|
2147
|
-
rawElementQuerySelectorAll,
|
|
2148
|
-
rawInnerHTMLDesc,
|
|
2149
|
-
rawParentNodeDesc,
|
|
2150
|
-
rawCreateElement,
|
|
2151
|
-
rawCreateElementNS,
|
|
2152
|
-
rawCreateDocumentFragment,
|
|
2153
|
-
rawCreateTextNode,
|
|
2154
|
-
rawQuerySelector,
|
|
2155
|
-
rawQuerySelectorAll,
|
|
2156
|
-
rawGetElementById,
|
|
2157
|
-
rawGetElementsByClassName,
|
|
2158
|
-
rawGetElementsByTagName,
|
|
2159
|
-
rawGetElementsByName,
|
|
2160
|
-
ImageProxy,
|
|
2161
|
-
// sandbox/effect
|
|
2162
|
-
rawWindowAddEventListener,
|
|
2163
|
-
rawWindowRemoveEventListener,
|
|
2164
|
-
rawSetInterval,
|
|
2165
|
-
rawSetTimeout,
|
|
2166
|
-
rawClearInterval,
|
|
2167
|
-
rawClearTimeout,
|
|
2168
|
-
rawDocumentAddEventListener,
|
|
2169
|
-
rawDocumentRemoveEventListener,
|
|
2170
|
-
rawPushState,
|
|
2171
|
-
rawReplaceState,
|
|
2172
|
-
rawAddEventListener,
|
|
2173
|
-
rawRemoveEventListener,
|
|
2174
|
-
});
|
|
2175
|
-
// global effect
|
|
2176
|
-
rejectMicroAppStyle();
|
|
2177
|
-
}
|
|
2178
|
-
}
|
|
2179
|
-
|
|
2180
|
-
const scriptTypes = ['text/javascript', 'text/ecmascript', 'application/javascript', 'application/ecmascript', 'module', 'systemjs-module', 'systemjs-importmap'];
|
|
2181
|
-
// whether use type='module' script
|
|
2182
|
-
function isTypeModule(app, scriptInfo) {
|
|
2183
|
-
return scriptInfo.appSpace[app.name].module && (!app.useSandbox || app.iframe);
|
|
2184
|
-
}
|
|
2185
|
-
// special script element
|
|
2186
|
-
function isSpecialScript(app, scriptInfo) {
|
|
2187
|
-
const attrs = scriptInfo.appSpace[app.name].attrs;
|
|
2188
|
-
return attrs.has('id');
|
|
2189
|
-
}
|
|
2190
|
-
/**
|
|
2191
|
-
* whether to run js in inline mode
|
|
2192
|
-
* scene:
|
|
2193
|
-
* 1. inline config for app
|
|
2194
|
-
* 2. inline attr in script element
|
|
2195
|
-
* 3. module script
|
|
2196
|
-
* 4. script with special attr
|
|
2197
|
-
*/
|
|
2198
|
-
function isInlineMode(app, scriptInfo) {
|
|
2199
|
-
return (app.inline ||
|
|
2200
|
-
scriptInfo.appSpace[app.name].inline ||
|
|
2201
|
-
isTypeModule(app, scriptInfo) ||
|
|
2202
|
-
isSpecialScript(app, scriptInfo) ||
|
|
2203
|
-
app.iframe);
|
|
2204
|
-
}
|
|
2205
|
-
// TODO: iframe重新插入window前后不一致,通过iframe Function创建的函数无法复用
|
|
2206
|
-
function getEffectWindow(app) {
|
|
2207
|
-
return app.iframe ? app.sandBox.microAppWindow : globalEnv.rawWindow;
|
|
2208
|
-
}
|
|
2209
|
-
// Convert string code to function
|
|
2210
|
-
function code2Function(app, code) {
|
|
2211
|
-
const targetWindow = getEffectWindow(app);
|
|
2212
|
-
return new targetWindow.Function(code);
|
|
2213
|
-
}
|
|
2214
|
-
/**
|
|
2215
|
-
* If the appSpace of the current js address has other app, try to reuse parsedFunction of other app
|
|
2216
|
-
* @param appName app.name
|
|
2217
|
-
* @param scriptInfo scriptInfo of current address
|
|
2218
|
-
* @param currentCode pure code of current address
|
|
2219
|
-
*/
|
|
2220
|
-
function getExistParseResult(app, scriptInfo, currentCode) {
|
|
2221
|
-
const appSpace = scriptInfo.appSpace;
|
|
2222
|
-
for (const item in appSpace) {
|
|
2223
|
-
if (item !== app.name) {
|
|
2224
|
-
const appSpaceData = appSpace[item];
|
|
2225
|
-
if (appSpaceData.parsedCode === currentCode && appSpaceData.parsedFunction) {
|
|
2226
|
-
return appSpaceData.parsedFunction;
|
|
2227
|
-
}
|
|
2228
|
-
}
|
|
2229
|
-
}
|
|
2230
|
-
}
|
|
2231
|
-
/**
|
|
2232
|
-
* get parsedFunction from exist data or parsedCode
|
|
2233
|
-
* @returns parsedFunction
|
|
2234
|
-
*/
|
|
2235
|
-
function getParsedFunction(app, scriptInfo, parsedCode) {
|
|
2236
|
-
return getExistParseResult(app, scriptInfo, parsedCode) || code2Function(app, parsedCode);
|
|
2237
|
-
}
|
|
2238
|
-
// Prevent randomly created strings from repeating
|
|
2239
|
-
function getUniqueNonceSrc() {
|
|
2240
|
-
const nonceStr = createNonceSrc();
|
|
2241
|
-
if (sourceCenter.script.hasInfo(nonceStr)) {
|
|
2242
|
-
return getUniqueNonceSrc();
|
|
2243
|
-
}
|
|
2244
|
-
return nonceStr;
|
|
2245
|
-
}
|
|
2246
|
-
// transfer the attributes on the script to convertScript
|
|
2247
|
-
function setConvertScriptAttr(convertScript, attrs) {
|
|
2248
|
-
attrs.forEach((value, key) => {
|
|
2249
|
-
if ((key === 'type' && value === 'module') || key === 'defer' || key === 'async')
|
|
2250
|
-
return;
|
|
2251
|
-
if (key === 'src')
|
|
2252
|
-
key = 'data-origin-src';
|
|
2253
|
-
convertScript.setAttribute(key, value);
|
|
2254
|
-
});
|
|
2255
|
-
}
|
|
2256
|
-
// wrap code in sandbox
|
|
2257
|
-
function isWrapInSandBox(app, scriptInfo) {
|
|
2258
|
-
return app.useSandbox && !isTypeModule(app, scriptInfo);
|
|
2259
|
-
}
|
|
2260
|
-
function getSandboxType(app, scriptInfo) {
|
|
2261
|
-
return isWrapInSandBox(app, scriptInfo) ? app.iframe ? 'iframe' : 'with' : 'disable';
|
|
2262
|
-
}
|
|
2263
|
-
/**
|
|
2264
|
-
* Extract script elements
|
|
2265
|
-
* @param script script element
|
|
2266
|
-
* @param parent parent element of script
|
|
2267
|
-
* @param app app
|
|
2268
|
-
* @param isDynamic dynamic insert
|
|
2269
|
-
*/
|
|
2270
|
-
function extractScriptElement(script, parent, app, isDynamic = false) {
|
|
2271
|
-
var _a;
|
|
2272
|
-
let replaceComment = null;
|
|
2273
|
-
let src = script.getAttribute('src');
|
|
2274
|
-
if (src)
|
|
2275
|
-
src = CompletionPath(src, app.url);
|
|
2276
|
-
if (script.hasAttribute('exclude') || checkExcludeUrl(src, app.name)) {
|
|
2277
|
-
replaceComment = document.createComment('script element with exclude attribute removed by micro-app');
|
|
2278
|
-
}
|
|
2279
|
-
else if ((script.type &&
|
|
2280
|
-
!scriptTypes.includes(script.type)) ||
|
|
2281
|
-
script.hasAttribute('ignore') ||
|
|
2282
|
-
checkIgnoreUrl(src, app.name)) {
|
|
2283
|
-
// 配置为忽略的脚本,清空 rawDocument.currentScript,避免被忽略的脚本内获取 currentScript 出错
|
|
2284
|
-
if ((_a = globalEnv.rawDocument) === null || _a === void 0 ? void 0 : _a.currentScript) {
|
|
2285
|
-
delete globalEnv.rawDocument.currentScript;
|
|
2286
|
-
}
|
|
2287
|
-
return null;
|
|
2288
|
-
}
|
|
2289
|
-
else if ((globalEnv.supportModuleScript && script.noModule) ||
|
|
2290
|
-
(!globalEnv.supportModuleScript && script.type === 'module')) {
|
|
2291
|
-
replaceComment = document.createComment(`${script.noModule ? 'noModule' : 'module'} script ignored by micro-app`);
|
|
2292
|
-
}
|
|
2293
|
-
else if (src) { // remote script
|
|
2294
|
-
let scriptInfo = sourceCenter.script.getInfo(src);
|
|
2295
|
-
const appSpaceData = {
|
|
2296
|
-
async: script.hasAttribute('async'),
|
|
2297
|
-
defer: script.defer || script.type === 'module',
|
|
2298
|
-
module: script.type === 'module',
|
|
2299
|
-
inline: script.hasAttribute('inline'),
|
|
2300
|
-
pure: script.hasAttribute('pure'),
|
|
2301
|
-
attrs: getAttributes(script),
|
|
2302
|
-
};
|
|
2303
|
-
if (!scriptInfo) {
|
|
2304
|
-
scriptInfo = {
|
|
2305
|
-
code: '',
|
|
2306
|
-
isExternal: true,
|
|
2307
|
-
appSpace: {
|
|
2308
|
-
[app.name]: appSpaceData,
|
|
2309
|
-
}
|
|
2310
|
-
};
|
|
2311
|
-
}
|
|
2312
|
-
else {
|
|
2313
|
-
/**
|
|
2314
|
-
* Reuse when appSpace exists
|
|
2315
|
-
* NOTE:
|
|
2316
|
-
* 1. The same static script, appSpace must be the same (in fact, it may be different when url change)
|
|
2317
|
-
* 2. The same dynamic script, appSpace may be the same, but we still reuse appSpace, which should pay attention
|
|
2318
|
-
*/
|
|
2319
|
-
scriptInfo.appSpace[app.name] = scriptInfo.appSpace[app.name] || appSpaceData;
|
|
2320
|
-
}
|
|
2321
|
-
sourceCenter.script.setInfo(src, scriptInfo);
|
|
2322
|
-
if (!isDynamic) {
|
|
2323
|
-
app.source.scripts.add(src);
|
|
2324
|
-
replaceComment = document.createComment(`script with src='${src}' extract by micro-app`);
|
|
2325
|
-
}
|
|
2326
|
-
else {
|
|
2327
|
-
return { address: src, scriptInfo };
|
|
2328
|
-
}
|
|
2329
|
-
}
|
|
2330
|
-
else if (script.textContent) { // inline script
|
|
2331
|
-
/**
|
|
2332
|
-
* NOTE:
|
|
2333
|
-
* 1. Each inline script is unique
|
|
2334
|
-
* 2. Every dynamic created inline script will be re-executed
|
|
2335
|
-
* ACTION:
|
|
2336
|
-
* 1. Delete dynamic inline script info after exec
|
|
2337
|
-
* 2. Delete static inline script info when destroy
|
|
2338
|
-
*/
|
|
2339
|
-
const nonceStr = getUniqueNonceSrc();
|
|
2340
|
-
const scriptInfo = {
|
|
2341
|
-
code: script.textContent,
|
|
2342
|
-
isExternal: false,
|
|
2343
|
-
appSpace: {
|
|
2344
|
-
[app.name]: {
|
|
2345
|
-
async: false,
|
|
2346
|
-
defer: script.type === 'module',
|
|
2347
|
-
module: script.type === 'module',
|
|
2348
|
-
inline: script.hasAttribute('inline'),
|
|
2349
|
-
pure: script.hasAttribute('pure'),
|
|
2350
|
-
attrs: getAttributes(script),
|
|
2351
|
-
}
|
|
2352
|
-
}
|
|
2353
|
-
};
|
|
2354
|
-
if (!isDynamic) {
|
|
2355
|
-
app.source.scripts.add(nonceStr);
|
|
2356
|
-
sourceCenter.script.setInfo(nonceStr, scriptInfo);
|
|
2357
|
-
replaceComment = document.createComment('inline script extract by micro-app');
|
|
2358
|
-
}
|
|
2359
|
-
else {
|
|
2360
|
-
// Because each dynamic script is unique, it is not put into sourceCenter
|
|
2361
|
-
return { address: nonceStr, scriptInfo };
|
|
2362
|
-
}
|
|
2363
|
-
}
|
|
2364
|
-
else if (!isDynamic) {
|
|
2365
|
-
/**
|
|
2366
|
-
* script with empty src or empty script.textContent remove in static html
|
|
2367
|
-
* & not removed if it created by dynamic
|
|
2368
|
-
*/
|
|
2369
|
-
replaceComment = document.createComment('script element removed by micro-app');
|
|
2370
|
-
}
|
|
2371
|
-
if (isDynamic) {
|
|
2372
|
-
return { replaceComment };
|
|
2373
|
-
}
|
|
2374
|
-
else {
|
|
2375
|
-
return parent.replaceChild(replaceComment, script);
|
|
2376
|
-
}
|
|
2377
|
-
}
|
|
2378
|
-
/**
|
|
2379
|
-
* get assets plugins
|
|
2380
|
-
* @param appName app name
|
|
2381
|
-
*/
|
|
2382
|
-
function getAssetsPlugins(appName) {
|
|
2383
|
-
var _a, _b, _c;
|
|
2384
|
-
const globalPlugins = ((_a = microApp.options.plugins) === null || _a === void 0 ? void 0 : _a.global) || [];
|
|
2385
|
-
const modulePlugins = ((_c = (_b = microApp.options.plugins) === null || _b === void 0 ? void 0 : _b.modules) === null || _c === void 0 ? void 0 : _c[appName]) || [];
|
|
2386
|
-
return [...globalPlugins, ...modulePlugins];
|
|
2387
|
-
}
|
|
2388
|
-
/**
|
|
2389
|
-
* whether the address needs to be excluded
|
|
2390
|
-
* @param address css or js link
|
|
2391
|
-
* @param plugins microApp plugins
|
|
2392
|
-
*/
|
|
2393
|
-
function checkExcludeUrl(address, appName) {
|
|
2394
|
-
if (!address)
|
|
2395
|
-
return false;
|
|
2396
|
-
const plugins = getAssetsPlugins(appName) || [];
|
|
2397
|
-
return plugins.some(plugin => {
|
|
2398
|
-
if (!plugin.excludeChecker)
|
|
2399
|
-
return false;
|
|
2400
|
-
return plugin.excludeChecker(address);
|
|
2401
|
-
});
|
|
2402
|
-
}
|
|
2403
|
-
/**
|
|
2404
|
-
* whether the address needs to be ignore
|
|
2405
|
-
* @param address css or js link
|
|
2406
|
-
* @param plugins microApp plugins
|
|
2407
|
-
*/
|
|
2408
|
-
function checkIgnoreUrl(address, appName) {
|
|
2409
|
-
if (!address)
|
|
2410
|
-
return false;
|
|
2411
|
-
const plugins = getAssetsPlugins(appName) || [];
|
|
2412
|
-
return plugins.some(plugin => {
|
|
2413
|
-
if (!plugin.ignoreChecker)
|
|
2414
|
-
return false;
|
|
2415
|
-
return plugin.ignoreChecker(address);
|
|
2416
|
-
});
|
|
2417
|
-
}
|
|
2418
|
-
/**
|
|
2419
|
-
* Get remote resources of script
|
|
2420
|
-
* @param wrapElement htmlDom
|
|
2421
|
-
* @param app app
|
|
2422
|
-
*/
|
|
2423
|
-
function fetchScriptsFromHtml(wrapElement, app) {
|
|
2424
|
-
const scriptList = Array.from(app.source.scripts);
|
|
2425
|
-
const fetchScriptPromise = [];
|
|
2426
|
-
const fetchScriptPromiseInfo = [];
|
|
2427
|
-
for (const address of scriptList) {
|
|
2428
|
-
const scriptInfo = sourceCenter.script.getInfo(address);
|
|
2429
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2430
|
-
if ((!appSpaceData.defer && !appSpaceData.async) || (app.isPrefetch && !app.isPrerender)) {
|
|
2431
|
-
fetchScriptPromise.push(scriptInfo.code ? scriptInfo.code : fetchSource(address, app.name));
|
|
2432
|
-
fetchScriptPromiseInfo.push([address, scriptInfo]);
|
|
2433
|
-
}
|
|
2434
|
-
}
|
|
2435
|
-
const fiberScriptTasks = app.isPrefetch || app.fiber ? [] : null;
|
|
2436
|
-
if (fetchScriptPromise.length) {
|
|
2437
|
-
promiseStream(fetchScriptPromise, (res) => {
|
|
2438
|
-
injectFiberTask(fiberScriptTasks, () => fetchScriptSuccess(fetchScriptPromiseInfo[res.index][0], fetchScriptPromiseInfo[res.index][1], res.data, app));
|
|
2439
|
-
}, (err) => {
|
|
2440
|
-
logError(err, app.name);
|
|
2441
|
-
}, () => {
|
|
2442
|
-
if (fiberScriptTasks) {
|
|
2443
|
-
fiberScriptTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2444
|
-
serialExecFiberTasks(fiberScriptTasks);
|
|
2445
|
-
}
|
|
2446
|
-
else {
|
|
2447
|
-
app.onLoad(wrapElement);
|
|
2448
|
-
}
|
|
2500
|
+
const rawCreateTextNode = rawRootDocument.prototype.createTextNode;
|
|
2501
|
+
const rawQuerySelector = rawRootDocument.prototype.querySelector;
|
|
2502
|
+
const rawQuerySelectorAll = rawRootDocument.prototype.querySelectorAll;
|
|
2503
|
+
const rawGetElementById = rawRootDocument.prototype.getElementById;
|
|
2504
|
+
const rawGetElementsByClassName = rawRootDocument.prototype.getElementsByClassName;
|
|
2505
|
+
const rawGetElementsByTagName = rawRootDocument.prototype.getElementsByTagName;
|
|
2506
|
+
const rawGetElementsByName = rawRootDocument.prototype.getElementsByName;
|
|
2507
|
+
const ImageProxy = new Proxy(Image, {
|
|
2508
|
+
construct(Target, args) {
|
|
2509
|
+
const elementImage = new Target(...args);
|
|
2510
|
+
const currentAppName = getCurrentAppName();
|
|
2511
|
+
if (currentAppName)
|
|
2512
|
+
elementImage.__MICRO_APP_NAME__ = currentAppName;
|
|
2513
|
+
return elementImage;
|
|
2514
|
+
},
|
|
2449
2515
|
});
|
|
2450
|
-
|
|
2451
|
-
|
|
2452
|
-
|
|
2516
|
+
/**
|
|
2517
|
+
* save effect raw methods
|
|
2518
|
+
* pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
|
|
2519
|
+
*/
|
|
2520
|
+
const rawSetInterval = rawWindow.setInterval;
|
|
2521
|
+
const rawSetTimeout = rawWindow.setTimeout;
|
|
2522
|
+
const rawClearInterval = rawWindow.clearInterval;
|
|
2523
|
+
const rawClearTimeout = rawWindow.clearTimeout;
|
|
2524
|
+
const rawPushState = rawWindow.history.pushState;
|
|
2525
|
+
const rawReplaceState = rawWindow.history.replaceState;
|
|
2526
|
+
const rawAddEventListener = rawRootEventTarget.prototype.addEventListener;
|
|
2527
|
+
const rawRemoveEventListener = rawRootEventTarget.prototype.removeEventListener;
|
|
2528
|
+
assign(globalEnv, {
|
|
2529
|
+
supportModuleScript: isSupportModuleScript(),
|
|
2530
|
+
// common global vars
|
|
2531
|
+
rawWindow,
|
|
2532
|
+
rawDocument,
|
|
2533
|
+
rawRootDocument,
|
|
2534
|
+
rawRootElement,
|
|
2535
|
+
rawRootNode,
|
|
2536
|
+
// source/patch
|
|
2537
|
+
rawSetAttribute,
|
|
2538
|
+
rawAppendChild,
|
|
2539
|
+
rawInsertBefore,
|
|
2540
|
+
rawReplaceChild,
|
|
2541
|
+
rawRemoveChild,
|
|
2542
|
+
rawAppend,
|
|
2543
|
+
rawPrepend,
|
|
2544
|
+
rawCloneNode,
|
|
2545
|
+
rawElementQuerySelector,
|
|
2546
|
+
rawElementQuerySelectorAll,
|
|
2547
|
+
rawInsertAdjacentElement,
|
|
2548
|
+
rawInnerHTMLDesc,
|
|
2549
|
+
rawParentNodeDesc,
|
|
2550
|
+
rawCreateElement,
|
|
2551
|
+
rawCreateElementNS,
|
|
2552
|
+
rawCreateDocumentFragment,
|
|
2553
|
+
rawCreateTextNode,
|
|
2554
|
+
rawQuerySelector,
|
|
2555
|
+
rawQuerySelectorAll,
|
|
2556
|
+
rawGetElementById,
|
|
2557
|
+
rawGetElementsByClassName,
|
|
2558
|
+
rawGetElementsByTagName,
|
|
2559
|
+
rawGetElementsByName,
|
|
2560
|
+
ImageProxy,
|
|
2561
|
+
// sandbox/effect
|
|
2562
|
+
rawSetInterval,
|
|
2563
|
+
rawSetTimeout,
|
|
2564
|
+
rawClearInterval,
|
|
2565
|
+
rawClearTimeout,
|
|
2566
|
+
rawPushState,
|
|
2567
|
+
rawReplaceState,
|
|
2568
|
+
rawAddEventListener,
|
|
2569
|
+
rawRemoveEventListener,
|
|
2570
|
+
});
|
|
2571
|
+
// global effect
|
|
2572
|
+
rejectMicroAppStyle();
|
|
2453
2573
|
}
|
|
2454
2574
|
}
|
|
2575
|
+
|
|
2455
2576
|
/**
|
|
2456
|
-
*
|
|
2457
|
-
* @param
|
|
2458
|
-
* @param
|
|
2459
|
-
* @param data code
|
|
2577
|
+
*
|
|
2578
|
+
* @param appName app.name
|
|
2579
|
+
* @param linkInfo linkInfo of current address
|
|
2460
2580
|
*/
|
|
2461
|
-
function
|
|
2462
|
-
|
|
2463
|
-
|
|
2464
|
-
|
|
2465
|
-
|
|
2466
|
-
|
|
2467
|
-
|
|
2468
|
-
* 2. if app is inline or script is esmodule, skip this step
|
|
2469
|
-
* 3. if global parseResult not exist, the current script occupies the position, when js is reused, parseResult is reference
|
|
2470
|
-
*/
|
|
2471
|
-
if (app.isPrefetch && app.prefetchLevel === 2) {
|
|
2472
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2473
|
-
/**
|
|
2474
|
-
* 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.
|
|
2475
|
-
* This causes parsedCode to already exist when preloading ends
|
|
2476
|
-
* e.g.
|
|
2477
|
-
* 1. prefetch app.url different from <micro-app></micro-app>
|
|
2478
|
-
* 2. prefetch param different from <micro-app></micro-app>
|
|
2479
|
-
*/
|
|
2480
|
-
if (!appSpaceData.parsedCode) {
|
|
2481
|
-
appSpaceData.parsedCode = bindScope(address, app, code, scriptInfo);
|
|
2482
|
-
appSpaceData.sandboxType = getSandboxType(app, scriptInfo);
|
|
2483
|
-
if (!isInlineMode(app, scriptInfo)) {
|
|
2484
|
-
try {
|
|
2485
|
-
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2486
|
-
}
|
|
2487
|
-
catch (err) {
|
|
2488
|
-
logError('Something went wrong while handling preloaded resources', app.name, '\n', err);
|
|
2489
|
-
}
|
|
2581
|
+
function getExistParseCode(appName, prefix, linkInfo) {
|
|
2582
|
+
const appSpace = linkInfo.appSpace;
|
|
2583
|
+
for (const item in appSpace) {
|
|
2584
|
+
if (item !== appName) {
|
|
2585
|
+
const appSpaceData = appSpace[item];
|
|
2586
|
+
if (appSpaceData.parsedCode) {
|
|
2587
|
+
return appSpaceData.parsedCode.replace(new RegExp(createPrefix(item, true), 'g'), prefix);
|
|
2490
2588
|
}
|
|
2491
2589
|
}
|
|
2492
2590
|
}
|
|
2493
2591
|
}
|
|
2592
|
+
// transfer the attributes on the link to convertStyle
|
|
2593
|
+
function setConvertStyleAttr(convertStyle, attrs) {
|
|
2594
|
+
attrs.forEach((value, key) => {
|
|
2595
|
+
if (key === 'rel')
|
|
2596
|
+
return;
|
|
2597
|
+
if (key === 'href')
|
|
2598
|
+
key = 'data-origin-href';
|
|
2599
|
+
globalEnv.rawSetAttribute.call(convertStyle, key, value);
|
|
2600
|
+
});
|
|
2601
|
+
}
|
|
2494
2602
|
/**
|
|
2495
|
-
*
|
|
2603
|
+
* Extract link elements
|
|
2604
|
+
* @param link link element
|
|
2605
|
+
* @param parent parent element of link
|
|
2496
2606
|
* @param app app
|
|
2497
|
-
* @param
|
|
2607
|
+
* @param microAppHead micro-app-head element
|
|
2608
|
+
* @param isDynamic dynamic insert
|
|
2498
2609
|
*/
|
|
2499
|
-
function
|
|
2500
|
-
const
|
|
2501
|
-
|
|
2502
|
-
|
|
2503
|
-
|
|
2504
|
-
|
|
2505
|
-
|
|
2506
|
-
const appSpaceData =
|
|
2507
|
-
|
|
2508
|
-
|
|
2509
|
-
|
|
2510
|
-
|
|
2511
|
-
|
|
2512
|
-
|
|
2513
|
-
|
|
2514
|
-
|
|
2515
|
-
}
|
|
2516
|
-
deferScriptInfo.push([address, scriptInfo]);
|
|
2517
|
-
isTypeModule(app, scriptInfo) && (initHook.moduleCount = initHook.moduleCount ? ++initHook.moduleCount : 1);
|
|
2610
|
+
function extractLinkFromHtml(link, parent, app, isDynamic = false) {
|
|
2611
|
+
const rel = link.getAttribute('rel');
|
|
2612
|
+
let href = link.getAttribute('href');
|
|
2613
|
+
let replaceComment = null;
|
|
2614
|
+
if (rel === 'stylesheet' && href) {
|
|
2615
|
+
href = CompletionPath(href, app.url);
|
|
2616
|
+
let linkInfo = sourceCenter.link.getInfo(href);
|
|
2617
|
+
const appSpaceData = {
|
|
2618
|
+
attrs: getAttributes(link),
|
|
2619
|
+
};
|
|
2620
|
+
if (!linkInfo) {
|
|
2621
|
+
linkInfo = {
|
|
2622
|
+
code: '',
|
|
2623
|
+
appSpace: {
|
|
2624
|
+
[app.name]: appSpaceData,
|
|
2625
|
+
}
|
|
2626
|
+
};
|
|
2518
2627
|
}
|
|
2519
2628
|
else {
|
|
2520
|
-
|
|
2521
|
-
|
|
2522
|
-
|
|
2523
|
-
|
|
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;
|
|
2636
|
+
}
|
|
2637
|
+
else {
|
|
2638
|
+
return { address: href, linkInfo };
|
|
2524
2639
|
}
|
|
2525
2640
|
}
|
|
2526
|
-
if (
|
|
2527
|
-
|
|
2528
|
-
|
|
2529
|
-
|
|
2530
|
-
}, (err) => {
|
|
2531
|
-
initHook.errorCount = initHook.errorCount ? ++initHook.errorCount : 1;
|
|
2532
|
-
logError(err, app.name);
|
|
2533
|
-
}, () => {
|
|
2534
|
-
deferScriptInfo.forEach(([address, scriptInfo]) => {
|
|
2535
|
-
if (isString(scriptInfo.code)) {
|
|
2536
|
-
injectFiberTask(fiberScriptTasks, () => {
|
|
2537
|
-
runScript(address, app, scriptInfo, initHook);
|
|
2538
|
-
!isTypeModule(app, scriptInfo) && initHook(false);
|
|
2539
|
-
});
|
|
2540
|
-
}
|
|
2541
|
-
});
|
|
2542
|
-
/**
|
|
2543
|
-
* Fiber wraps js in requestIdleCallback and executes it in sequence
|
|
2544
|
-
* NOTE:
|
|
2545
|
-
* 1. In order to ensure the execution order, wait for all js loaded and then execute
|
|
2546
|
-
* 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
|
|
2547
|
-
*
|
|
2548
|
-
* BUG: NOTE.2 - execution order problem
|
|
2549
|
-
*/
|
|
2550
|
-
if (fiberScriptTasks) {
|
|
2551
|
-
fiberScriptTasks.push(() => Promise.resolve(initHook(isUndefined(initHook.moduleCount) ||
|
|
2552
|
-
initHook.errorCount === deferScriptPromise.length)));
|
|
2553
|
-
serialExecFiberTasks(fiberScriptTasks);
|
|
2554
|
-
}
|
|
2555
|
-
else {
|
|
2556
|
-
initHook(isUndefined(initHook.moduleCount) ||
|
|
2557
|
-
initHook.errorCount === deferScriptPromise.length);
|
|
2558
|
-
}
|
|
2559
|
-
});
|
|
2560
|
-
}
|
|
2561
|
-
else {
|
|
2562
|
-
if (fiberScriptTasks) {
|
|
2563
|
-
fiberScriptTasks.push(() => Promise.resolve(initHook(true)));
|
|
2564
|
-
serialExecFiberTasks(fiberScriptTasks);
|
|
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`);
|
|
2565
2645
|
}
|
|
2566
2646
|
else {
|
|
2567
|
-
|
|
2647
|
+
parent === null || parent === void 0 ? void 0 : parent.removeChild(link);
|
|
2568
2648
|
}
|
|
2569
2649
|
}
|
|
2650
|
+
else if (href) {
|
|
2651
|
+
// dns-prefetch preconnect modulepreload search ....
|
|
2652
|
+
globalEnv.rawSetAttribute.call(link, 'href', CompletionPath(href, app.url));
|
|
2653
|
+
}
|
|
2654
|
+
if (isDynamic) {
|
|
2655
|
+
return { replaceComment };
|
|
2656
|
+
}
|
|
2657
|
+
else if (replaceComment) {
|
|
2658
|
+
return parent === null || parent === void 0 ? void 0 : parent.replaceChild(replaceComment, link);
|
|
2659
|
+
}
|
|
2570
2660
|
}
|
|
2571
2661
|
/**
|
|
2572
|
-
*
|
|
2573
|
-
* @param
|
|
2662
|
+
* Get link remote resources
|
|
2663
|
+
* @param wrapElement htmlDom
|
|
2574
2664
|
* @param app app
|
|
2575
|
-
* @param
|
|
2576
|
-
* @param callback callback of module script
|
|
2665
|
+
* @param microAppHead micro-app-head
|
|
2577
2666
|
*/
|
|
2578
|
-
function
|
|
2579
|
-
|
|
2580
|
-
|
|
2581
|
-
const
|
|
2582
|
-
|
|
2583
|
-
|
|
2584
|
-
|
|
2585
|
-
|
|
2586
|
-
|
|
2587
|
-
|
|
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
|
|
2588
2683
|
*/
|
|
2589
|
-
if (
|
|
2590
|
-
|
|
2591
|
-
|
|
2592
|
-
|
|
2593
|
-
|
|
2594
|
-
if (isInlineMode(app, scriptInfo)) {
|
|
2595
|
-
const scriptElement = replaceElement || pureCreateElement('script');
|
|
2596
|
-
runCode2InlineScript(address, appSpaceData.parsedCode, isTypeModule(app, scriptInfo), scriptElement, appSpaceData.attrs, callback);
|
|
2597
|
-
if (!replaceElement) {
|
|
2598
|
-
// TEST IGNORE
|
|
2599
|
-
const parent = app.iframe ? app.sandBox.microBody : app.querySelector('micro-app-body');
|
|
2600
|
-
parent === null || parent === void 0 ? void 0 : parent.appendChild(scriptElement);
|
|
2601
|
-
}
|
|
2684
|
+
if (fiberStyleResult) {
|
|
2685
|
+
fiberStyleResult.then(() => {
|
|
2686
|
+
fiberLinkTasks.push(() => Promise.resolve(app.onLoad(wrapElement)));
|
|
2687
|
+
serialExecFiberTasks(fiberLinkTasks);
|
|
2688
|
+
});
|
|
2602
2689
|
}
|
|
2603
2690
|
else {
|
|
2604
|
-
|
|
2691
|
+
app.onLoad(wrapElement);
|
|
2605
2692
|
}
|
|
2606
|
-
}
|
|
2607
|
-
catch (e) {
|
|
2608
|
-
console.error(`[micro-app from ${replaceElement ? 'runDynamicScript' : 'runScript'}] app ${app.name}: `, e, address);
|
|
2609
|
-
}
|
|
2693
|
+
});
|
|
2610
2694
|
}
|
|
2611
2695
|
/**
|
|
2612
|
-
*
|
|
2613
|
-
*
|
|
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
|
|
2614
2706
|
* @param app app instance
|
|
2615
|
-
* @param scriptInfo scriptInfo
|
|
2616
|
-
* @param originScript origin script element
|
|
2617
2707
|
*/
|
|
2618
|
-
function
|
|
2619
|
-
|
|
2620
|
-
|
|
2621
|
-
|
|
2622
|
-
|
|
2623
|
-
|
|
2624
|
-
|
|
2625
|
-
|
|
2626
|
-
|
|
2627
|
-
|
|
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);
|
|
2628
2729
|
}
|
|
2629
|
-
|
|
2630
|
-
|
|
2631
|
-
|
|
2632
|
-
|
|
2633
|
-
|
|
2634
|
-
}
|
|
2635
|
-
else {
|
|
2636
|
-
fetchSource(address, app.name).then((code) => {
|
|
2637
|
-
scriptInfo.code = code;
|
|
2638
|
-
runDynamicScript();
|
|
2639
|
-
}).catch((err) => {
|
|
2640
|
-
logError(err, app.name);
|
|
2641
|
-
dispatchOnErrorEvent(originScript);
|
|
2642
|
-
});
|
|
2730
|
+
else {
|
|
2731
|
+
microAppHead.appendChild(convertStyle);
|
|
2732
|
+
}
|
|
2733
|
+
// clear placeholder
|
|
2734
|
+
appSpaceData.placeholder = null;
|
|
2643
2735
|
}
|
|
2644
|
-
return replaceElement;
|
|
2645
2736
|
}
|
|
2646
2737
|
/**
|
|
2647
|
-
* Get
|
|
2648
|
-
*
|
|
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
|
|
2649
2743
|
* @param app app instance
|
|
2650
|
-
* @param
|
|
2651
|
-
|
|
2652
|
-
|
|
2653
|
-
|
|
2654
|
-
runScript(address, app, scriptInfo, void 0, replaceElement);
|
|
2655
|
-
return replaceElement;
|
|
2656
|
-
}
|
|
2657
|
-
/**
|
|
2658
|
-
* common handle for inline script
|
|
2659
|
-
* @param address script address
|
|
2660
|
-
* @param code bound code
|
|
2661
|
-
* @param module type='module' of script
|
|
2662
|
-
* @param scriptElement target script element
|
|
2663
|
-
* @param attrs attributes of script element
|
|
2664
|
-
* @param callback callback of module script
|
|
2744
|
+
* @param address resource address
|
|
2745
|
+
* @param convertStyle converted style
|
|
2746
|
+
* @param linkInfo linkInfo in sourceCenter
|
|
2747
|
+
* @param attrs attrs of link
|
|
2665
2748
|
*/
|
|
2666
|
-
function
|
|
2667
|
-
if (
|
|
2668
|
-
|
|
2669
|
-
|
|
2670
|
-
|
|
2671
|
-
|
|
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;
|
|
2672
2763
|
}
|
|
2673
2764
|
else {
|
|
2674
|
-
|
|
2675
|
-
}
|
|
2676
|
-
scriptElement.setAttribute('type', 'module');
|
|
2677
|
-
if (callback) {
|
|
2678
|
-
callback.moduleCount && callback.moduleCount--;
|
|
2679
|
-
/**
|
|
2680
|
-
* module script will execute onload method only after it insert to document/iframe
|
|
2681
|
-
*/
|
|
2682
|
-
scriptElement.onload = callback.bind(scriptElement, callback.moduleCount === 0);
|
|
2765
|
+
convertStyle.textContent = appSpaceData.parsedCode;
|
|
2683
2766
|
}
|
|
2684
2767
|
}
|
|
2685
2768
|
else {
|
|
2686
|
-
|
|
2687
|
-
}
|
|
2688
|
-
setConvertScriptAttr(scriptElement, attrs);
|
|
2689
|
-
}
|
|
2690
|
-
// init & run code2Function
|
|
2691
|
-
function runParsedFunction(app, scriptInfo) {
|
|
2692
|
-
const appSpaceData = scriptInfo.appSpace[app.name];
|
|
2693
|
-
if (!appSpaceData.parsedFunction) {
|
|
2694
|
-
appSpaceData.parsedFunction = getParsedFunction(app, scriptInfo, appSpaceData.parsedCode);
|
|
2769
|
+
convertStyle.textContent = linkInfo.code;
|
|
2695
2770
|
}
|
|
2696
|
-
|
|
2771
|
+
setConvertStyleAttr(convertStyle, attrs);
|
|
2697
2772
|
}
|
|
2698
2773
|
/**
|
|
2699
|
-
*
|
|
2774
|
+
* Handle css of dynamic link
|
|
2775
|
+
* @param address link address
|
|
2700
2776
|
* @param app app
|
|
2701
|
-
* @param
|
|
2702
|
-
* @param
|
|
2703
|
-
*/
|
|
2704
|
-
function bindScope(address, app, code, scriptInfo) {
|
|
2705
|
-
// TODO: 1、cache 2、esm code is null
|
|
2706
|
-
if (isPlainObject(microApp.options.plugins)) {
|
|
2707
|
-
code = usePlugins(address, code, app.name, microApp.options.plugins);
|
|
2708
|
-
}
|
|
2709
|
-
if (isWrapInSandBox(app, scriptInfo)) {
|
|
2710
|
-
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__);`;
|
|
2711
|
-
}
|
|
2712
|
-
return code;
|
|
2713
|
-
}
|
|
2714
|
-
/**
|
|
2715
|
-
* actions before run script
|
|
2716
|
-
*/
|
|
2717
|
-
function actionsBeforeRunScript(app) {
|
|
2718
|
-
setActiveProxyWindow(app);
|
|
2719
|
-
}
|
|
2720
|
-
/**
|
|
2721
|
-
* set active sandBox.proxyWindow to window.__MICRO_APP_PROXY_WINDOW__
|
|
2777
|
+
* @param linkInfo linkInfo
|
|
2778
|
+
* @param originLink origin link element
|
|
2722
2779
|
*/
|
|
2723
|
-
function
|
|
2724
|
-
|
|
2725
|
-
|
|
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);
|
|
2726
2788
|
}
|
|
2727
|
-
|
|
2728
|
-
|
|
2729
|
-
|
|
2730
|
-
|
|
2731
|
-
|
|
2732
|
-
|
|
2733
|
-
|
|
2734
|
-
|
|
2735
|
-
function usePlugins(address, code, appName, plugins) {
|
|
2736
|
-
var _a;
|
|
2737
|
-
const newCode = processCode(plugins.global, code, address);
|
|
2738
|
-
return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, address);
|
|
2739
|
-
}
|
|
2740
|
-
function processCode(configs, code, address) {
|
|
2741
|
-
if (!isArray(configs)) {
|
|
2742
|
-
return code;
|
|
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
|
+
});
|
|
2743
2797
|
}
|
|
2744
|
-
return
|
|
2745
|
-
if (isPlainObject(config) && isFunction(config.loader)) {
|
|
2746
|
-
return config.loader(preCode, address);
|
|
2747
|
-
}
|
|
2748
|
-
return preCode;
|
|
2749
|
-
}, code);
|
|
2798
|
+
return convertStyle;
|
|
2750
2799
|
}
|
|
2751
2800
|
|
|
2752
2801
|
/**
|
|
@@ -2778,7 +2827,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2778
2827
|
extractLinkFromHtml(dom, parent, app);
|
|
2779
2828
|
}
|
|
2780
2829
|
else if (dom.hasAttribute('href')) {
|
|
2781
|
-
|
|
2830
|
+
globalEnv.rawSetAttribute.call(dom, 'href', CompletionPath(dom.getAttribute('href'), app.url));
|
|
2782
2831
|
}
|
|
2783
2832
|
}
|
|
2784
2833
|
else if (isStyleElement(dom)) {
|
|
@@ -2793,7 +2842,7 @@ function flatChildren(parent, app, microAppHead, fiberStyleTasks) {
|
|
|
2793
2842
|
extractScriptElement(dom, parent, app);
|
|
2794
2843
|
}
|
|
2795
2844
|
else if (isImageElement(dom) && dom.hasAttribute('src')) {
|
|
2796
|
-
|
|
2845
|
+
globalEnv.rawSetAttribute.call(dom, 'src', CompletionPath(dom.getAttribute('src'), app.url));
|
|
2797
2846
|
}
|
|
2798
2847
|
/**
|
|
2799
2848
|
* Don't remove meta and title, they have some special scenes
|
|
@@ -2845,6 +2894,40 @@ function extractSourceDom(htmlStr, app) {
|
|
|
2845
2894
|
}
|
|
2846
2895
|
}
|
|
2847
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
|
+
|
|
2848
2931
|
class EventCenter {
|
|
2849
2932
|
constructor() {
|
|
2850
2933
|
this.eventList = new Map();
|
|
@@ -3300,148 +3383,197 @@ function initEnvOfNestedApp() {
|
|
|
3300
3383
|
}
|
|
3301
3384
|
}
|
|
3302
3385
|
|
|
3303
|
-
|
|
3304
|
-
|
|
3305
|
-
|
|
3306
|
-
|
|
3307
|
-
|
|
3308
|
-
|
|
3309
|
-
|
|
3310
|
-
|
|
3311
|
-
|
|
3312
|
-
|
|
3313
|
-
|
|
3314
|
-
|
|
3315
|
-
function bindFunctionToRawTarget(value, rawTarget, key = 'WINDOW') {
|
|
3316
|
-
if (isFunction(value) && !isConstructorFunction(value) && !isBoundedFunction(value)) {
|
|
3317
|
-
const cacheKey = `__MICRO_APP_BOUND_${key}_FUNCTION__`;
|
|
3318
|
-
if (value[cacheKey])
|
|
3319
|
-
return value[cacheKey];
|
|
3320
|
-
const bindRawObjectValue = value.bind(rawTarget);
|
|
3321
|
-
for (const key in value) {
|
|
3322
|
-
bindRawObjectValue[key] = value[key];
|
|
3323
|
-
}
|
|
3324
|
-
if (value.hasOwnProperty('prototype')) {
|
|
3325
|
-
rawDefineProperty(bindRawObjectValue, 'prototype', {
|
|
3326
|
-
value: value.prototype,
|
|
3327
|
-
configurable: true,
|
|
3328
|
-
enumerable: false,
|
|
3329
|
-
writable: true,
|
|
3330
|
-
});
|
|
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);
|
|
3331
3398
|
}
|
|
3332
|
-
return value[cacheKey] = bindRawObjectValue;
|
|
3333
3399
|
}
|
|
3334
|
-
|
|
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');
|
|
3415
|
+
},
|
|
3416
|
+
set(target, key, value) {
|
|
3417
|
+
Reflect.set(target, key, value);
|
|
3418
|
+
return true;
|
|
3419
|
+
}
|
|
3420
|
+
}));
|
|
3421
|
+
return MicroDocument;
|
|
3335
3422
|
}
|
|
3336
|
-
|
|
3337
|
-
// document.onclick binding list, the binding function of each application is unique
|
|
3338
|
-
const documentClickListMap = new Map();
|
|
3339
|
-
let hasRewriteDocumentOnClick = false;
|
|
3340
3423
|
/**
|
|
3341
|
-
*
|
|
3424
|
+
* Create new document and Document
|
|
3342
3425
|
*/
|
|
3343
|
-
function
|
|
3344
|
-
|
|
3345
|
-
|
|
3346
|
-
|
|
3347
|
-
|
|
3348
|
-
const
|
|
3349
|
-
|
|
3350
|
-
|
|
3351
|
-
|
|
3352
|
-
|
|
3353
|
-
isFunction(f) && f.call(document, e);
|
|
3354
|
-
});
|
|
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;
|
|
3355
3436
|
}
|
|
3356
|
-
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
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));
|
|
3370
3482
|
}
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
|
|
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__);
|
|
3374
3494
|
}
|
|
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;
|
|
3375
3504
|
}
|
|
3376
|
-
|
|
3377
|
-
|
|
3378
|
-
|
|
3379
|
-
|
|
3380
|
-
|
|
3381
|
-
*/
|
|
3382
|
-
const documentEventListenerMap = new Map();
|
|
3383
|
-
function effectDocumentEvent() {
|
|
3384
|
-
const { rawDocument, rawDocumentAddEventListener, rawDocumentRemoveEventListener, } = globalEnv;
|
|
3385
|
-
!hasRewriteDocumentOnClick && overwriteDocumentOnClick();
|
|
3386
|
-
document.addEventListener = function (type, listener, options) {
|
|
3387
|
-
const appName = getCurrentAppName();
|
|
3388
|
-
/**
|
|
3389
|
-
* ignore bound function of document event in umd mode, used to solve problem of react global events
|
|
3390
|
-
* update in 2022-09-02:
|
|
3391
|
-
* boundFunction is no longer exclude, because events in UMD mode will not cleared from v1.0.0-alpha.4
|
|
3392
|
-
* if (appName && !(appInstanceMap.get(appName)?.umdMode && isBoundFunction(listener))) {
|
|
3393
|
-
*/
|
|
3394
|
-
if (appName) {
|
|
3395
|
-
const appListenersMap = documentEventListenerMap.get(appName);
|
|
3396
|
-
if (appListenersMap) {
|
|
3397
|
-
const appListenerList = appListenersMap.get(type);
|
|
3398
|
-
if (appListenerList) {
|
|
3399
|
-
appListenerList.add(listener);
|
|
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);
|
|
3400
3510
|
}
|
|
3401
|
-
|
|
3402
|
-
|
|
3511
|
+
});
|
|
3512
|
+
eventListenerMap.clear();
|
|
3513
|
+
}
|
|
3514
|
+
};
|
|
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);
|
|
3403
3541
|
}
|
|
3542
|
+
onClickHandler = value;
|
|
3404
3543
|
}
|
|
3405
3544
|
else {
|
|
3406
|
-
|
|
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);
|
|
3407
3550
|
}
|
|
3408
|
-
|
|
3551
|
+
return true;
|
|
3409
3552
|
}
|
|
3410
|
-
|
|
3411
|
-
|
|
3412
|
-
|
|
3413
|
-
|
|
3414
|
-
|
|
3415
|
-
|
|
3416
|
-
|
|
3417
|
-
|
|
3418
|
-
|
|
3419
|
-
if (appName) {
|
|
3420
|
-
const appListenersMap = documentEventListenerMap.get(appName);
|
|
3421
|
-
if (appListenersMap) {
|
|
3422
|
-
const appListenerList = appListenersMap.get(type);
|
|
3423
|
-
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
3424
|
-
appListenerList.delete(listener);
|
|
3425
|
-
}
|
|
3426
|
-
}
|
|
3553
|
+
});
|
|
3554
|
+
return {
|
|
3555
|
+
proxyDocument,
|
|
3556
|
+
MicroDocument: createMicroDocument(appName, proxyDocument),
|
|
3557
|
+
documentEffect: {
|
|
3558
|
+
reset,
|
|
3559
|
+
record,
|
|
3560
|
+
rebuild,
|
|
3561
|
+
release,
|
|
3427
3562
|
}
|
|
3428
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener, options);
|
|
3429
3563
|
};
|
|
3430
3564
|
}
|
|
3431
|
-
|
|
3432
|
-
function releaseEffectDocumentEvent() {
|
|
3433
|
-
document.addEventListener = globalEnv.rawDocumentAddEventListener;
|
|
3434
|
-
document.removeEventListener = globalEnv.rawDocumentRemoveEventListener;
|
|
3435
|
-
}
|
|
3565
|
+
|
|
3436
3566
|
/**
|
|
3437
3567
|
* Rewrite side-effect events
|
|
3438
3568
|
* @param microAppWindow micro window
|
|
3439
3569
|
*/
|
|
3440
|
-
function
|
|
3570
|
+
function patchWindowEffect(appName, microAppWindow) {
|
|
3441
3571
|
const eventListenerMap = new Map();
|
|
3572
|
+
const sstEventListenerMap = new Map();
|
|
3442
3573
|
const intervalIdMap = new Map();
|
|
3443
3574
|
const timeoutIdMap = new Map();
|
|
3444
|
-
const { rawWindow,
|
|
3575
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener, rawSetInterval, rawSetTimeout, rawClearInterval, rawClearTimeout, } = globalEnv;
|
|
3576
|
+
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
3445
3577
|
// listener may be null, e.g test-passive
|
|
3446
3578
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
3447
3579
|
type = formatEventName(type, appName);
|
|
@@ -3453,7 +3585,7 @@ function effect(appName, microAppWindow) {
|
|
|
3453
3585
|
eventListenerMap.set(type, new Set([listener]));
|
|
3454
3586
|
}
|
|
3455
3587
|
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
3456
|
-
|
|
3588
|
+
rawAddEventListener.call(rawWindow, type, listener, options);
|
|
3457
3589
|
};
|
|
3458
3590
|
microAppWindow.removeEventListener = function (type, listener, options) {
|
|
3459
3591
|
type = formatEventName(type, appName);
|
|
@@ -3461,7 +3593,7 @@ function effect(appName, microAppWindow) {
|
|
|
3461
3593
|
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
3462
3594
|
listenerList.delete(listener);
|
|
3463
3595
|
}
|
|
3464
|
-
|
|
3596
|
+
rawRemoveEventListener.call(rawWindow, type, listener, options);
|
|
3465
3597
|
};
|
|
3466
3598
|
microAppWindow.setInterval = function (handler, timeout, ...args) {
|
|
3467
3599
|
const intervalId = rawSetInterval.call(rawWindow, handler, timeout, ...args);
|
|
@@ -3481,14 +3613,9 @@ function effect(appName, microAppWindow) {
|
|
|
3481
3613
|
timeoutIdMap.delete(timeoutId);
|
|
3482
3614
|
rawClearTimeout.call(rawWindow, timeoutId);
|
|
3483
3615
|
};
|
|
3484
|
-
const sstWindowListenerMap = new Map();
|
|
3485
|
-
const sstDocumentListenerMap = new Map();
|
|
3486
|
-
let sstOnClickHandler;
|
|
3487
3616
|
// reset snapshot data
|
|
3488
3617
|
const reset = () => {
|
|
3489
|
-
|
|
3490
|
-
sstDocumentListenerMap.clear();
|
|
3491
|
-
sstOnClickHandler = null;
|
|
3618
|
+
sstEventListenerMap.clear();
|
|
3492
3619
|
};
|
|
3493
3620
|
/**
|
|
3494
3621
|
* NOTE:
|
|
@@ -3504,57 +3631,33 @@ function effect(appName, microAppWindow) {
|
|
|
3504
3631
|
// record window event
|
|
3505
3632
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3506
3633
|
if (listenerList.size) {
|
|
3507
|
-
|
|
3634
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
3508
3635
|
}
|
|
3509
3636
|
});
|
|
3510
|
-
// record onclick handler
|
|
3511
|
-
sstOnClickHandler = sstOnClickHandler || documentClickListMap.get(appName);
|
|
3512
|
-
// record document event
|
|
3513
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
3514
|
-
if (documentAppListenersMap) {
|
|
3515
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
3516
|
-
if (listenerList.size) {
|
|
3517
|
-
sstDocumentListenerMap.set(type, new Set(listenerList));
|
|
3518
|
-
}
|
|
3519
|
-
});
|
|
3520
|
-
}
|
|
3521
3637
|
};
|
|
3522
3638
|
// rebuild event and timer before remount app
|
|
3523
3639
|
const rebuild = () => {
|
|
3524
3640
|
// rebuild window event
|
|
3525
|
-
|
|
3641
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
3526
3642
|
for (const listener of listenerList) {
|
|
3527
3643
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3528
3644
|
}
|
|
3529
3645
|
});
|
|
3530
|
-
// rebuild onclick event
|
|
3531
|
-
sstOnClickHandler && documentClickListMap.set(appName, sstOnClickHandler);
|
|
3532
|
-
/**
|
|
3533
|
-
* rebuild document event
|
|
3534
|
-
* WARNING!!: do not delete setCurrentAppName & removeDomScope
|
|
3535
|
-
*/
|
|
3536
|
-
setCurrentAppName(appName);
|
|
3537
|
-
sstDocumentListenerMap.forEach((listenerList, type) => {
|
|
3538
|
-
for (const listener of listenerList) {
|
|
3539
|
-
document.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
3540
|
-
}
|
|
3541
|
-
});
|
|
3542
|
-
removeDomScope();
|
|
3543
3646
|
reset();
|
|
3544
3647
|
};
|
|
3545
3648
|
// release all event listener & interval & timeout when unmount app
|
|
3546
|
-
const release = (
|
|
3649
|
+
const release = (clearTimer) => {
|
|
3547
3650
|
// Clear window binding events
|
|
3548
3651
|
if (eventListenerMap.size) {
|
|
3549
3652
|
eventListenerMap.forEach((listenerList, type) => {
|
|
3550
3653
|
for (const listener of listenerList) {
|
|
3551
|
-
|
|
3654
|
+
rawRemoveEventListener.call(rawWindow, type, listener);
|
|
3552
3655
|
}
|
|
3553
3656
|
});
|
|
3554
3657
|
eventListenerMap.clear();
|
|
3555
3658
|
}
|
|
3556
3659
|
// default mode(not keep-alive or isPrerender)
|
|
3557
|
-
if (
|
|
3660
|
+
if (clearTimer) {
|
|
3558
3661
|
intervalIdMap.forEach((_, intervalId) => {
|
|
3559
3662
|
rawClearInterval.call(rawWindow, intervalId);
|
|
3560
3663
|
});
|
|
@@ -3564,18 +3667,6 @@ function effect(appName, microAppWindow) {
|
|
|
3564
3667
|
intervalIdMap.clear();
|
|
3565
3668
|
timeoutIdMap.clear();
|
|
3566
3669
|
}
|
|
3567
|
-
// Clear the function bound by micro application through document.onclick
|
|
3568
|
-
documentClickListMap.delete(appName);
|
|
3569
|
-
// Clear document binding event
|
|
3570
|
-
const documentAppListenersMap = documentEventListenerMap.get(appName);
|
|
3571
|
-
if (documentAppListenersMap) {
|
|
3572
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
3573
|
-
for (const listener of listenerList) {
|
|
3574
|
-
rawDocumentRemoveEventListener.call(rawDocument, type, listener);
|
|
3575
|
-
}
|
|
3576
|
-
});
|
|
3577
|
-
documentAppListenersMap.clear();
|
|
3578
|
-
}
|
|
3579
3670
|
};
|
|
3580
3671
|
return {
|
|
3581
3672
|
reset,
|
|
@@ -4788,6 +4879,7 @@ const { createMicroEventSource, clearMicroEventSource } = useMicroEventSource();
|
|
|
4788
4879
|
const globalPropertyList$1 = ['window', 'self', 'globalThis'];
|
|
4789
4880
|
class WithSandBox {
|
|
4790
4881
|
constructor(appName, url) {
|
|
4882
|
+
this.active = false;
|
|
4791
4883
|
/**
|
|
4792
4884
|
* Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
|
|
4793
4885
|
* Fix https://github.com/micro-zoe/micro-app/issues/234
|
|
@@ -4795,24 +4887,20 @@ class WithSandBox {
|
|
|
4795
4887
|
this.scopeProperties = [];
|
|
4796
4888
|
// Properties that can be escape to rawWindow
|
|
4797
4889
|
this.escapeProperties = [];
|
|
4798
|
-
// Properties newly added to microAppWindow
|
|
4799
|
-
this.injectedKeys = new Set();
|
|
4800
4890
|
// Properties escape to rawWindow, cleared when unmount
|
|
4801
4891
|
this.escapeKeys = new Set();
|
|
4802
|
-
//
|
|
4803
|
-
|
|
4804
|
-
// sandbox state
|
|
4805
|
-
this.active = false;
|
|
4892
|
+
// Properties newly added to microAppWindow
|
|
4893
|
+
this.injectedKeys = new Set();
|
|
4806
4894
|
this.microAppWindow = {}; // Proxy target
|
|
4807
4895
|
this.adapter = new Adapter();
|
|
4808
4896
|
// get scopeProperties and escapeProperties from plugins
|
|
4809
4897
|
this.getSpecialProperties(appName);
|
|
4810
|
-
//
|
|
4811
|
-
this.
|
|
4812
|
-
//
|
|
4813
|
-
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);
|
|
4814
4902
|
// inject global properties
|
|
4815
|
-
this.initStaticGlobalKeys(
|
|
4903
|
+
this.initStaticGlobalKeys(appName, url, this.microAppWindow);
|
|
4816
4904
|
}
|
|
4817
4905
|
/**
|
|
4818
4906
|
* open sandbox and perform some initial actions
|
|
@@ -4823,38 +4911,38 @@ class WithSandBox {
|
|
|
4823
4911
|
* @param disablePatchRequest prevent patchRequestApi
|
|
4824
4912
|
*/
|
|
4825
4913
|
start({ umdMode, baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
4826
|
-
if (
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
4832
|
-
this.initRouteState(defaultPage);
|
|
4833
|
-
// unique listener of popstate event for sub app
|
|
4834
|
-
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4835
|
-
}
|
|
4836
|
-
else {
|
|
4837
|
-
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
4838
|
-
}
|
|
4839
|
-
/**
|
|
4840
|
-
* Target: Ensure default mode action exactly same to first time when render again
|
|
4841
|
-
* 1. The following globalKey maybe modified when render, reset them when render again in default mode
|
|
4842
|
-
* 2. Umd mode will not delete any keys during sandBox.stop, ignore umd mode
|
|
4843
|
-
* 3. When sandbox.start called for the first time, it must be the default mode
|
|
4844
|
-
*/
|
|
4845
|
-
if (!umdMode) {
|
|
4846
|
-
this.initGlobalKeysWhenStart(this.microAppWindow, this.microAppWindow.__MICRO_APP_NAME__, this.microAppWindow.__MICRO_APP_URL__, disablePatchRequest);
|
|
4847
|
-
}
|
|
4848
|
-
if (++globalEnv.activeSandbox === 1) {
|
|
4849
|
-
patchElementAndDocument();
|
|
4850
|
-
patchHistory();
|
|
4851
|
-
}
|
|
4852
|
-
if (++WithSandBox.activeCount === 1) {
|
|
4853
|
-
effectDocumentEvent();
|
|
4854
|
-
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);
|
|
4855
4920
|
}
|
|
4856
|
-
|
|
4921
|
+
this.initRouteState(defaultPage);
|
|
4922
|
+
// unique listener of popstate event for sub app
|
|
4923
|
+
this.removeHistoryListener = addHistoryListener(this.microAppWindow.__MICRO_APP_NAME__);
|
|
4857
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);
|
|
4936
|
+
}
|
|
4937
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
4938
|
+
patchElementAndDocument();
|
|
4939
|
+
patchHistory();
|
|
4940
|
+
}
|
|
4941
|
+
if (++WithSandBox.activeCount === 1) {
|
|
4942
|
+
// effectDocumentEvent()
|
|
4943
|
+
initEnvOfNestedApp();
|
|
4944
|
+
}
|
|
4945
|
+
fixBabelPolyfill6();
|
|
4858
4946
|
}
|
|
4859
4947
|
/**
|
|
4860
4948
|
* close sandbox and perform some clean up actions
|
|
@@ -4864,39 +4952,61 @@ class WithSandBox {
|
|
|
4864
4952
|
* @param clearData clear data from base app
|
|
4865
4953
|
*/
|
|
4866
4954
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
4867
|
-
if (this.active)
|
|
4868
|
-
|
|
4869
|
-
|
|
4870
|
-
|
|
4871
|
-
|
|
4872
|
-
|
|
4873
|
-
|
|
4874
|
-
|
|
4875
|
-
|
|
4876
|
-
|
|
4877
|
-
|
|
4878
|
-
|
|
4879
|
-
|
|
4880
|
-
|
|
4881
|
-
|
|
4882
|
-
|
|
4883
|
-
|
|
4884
|
-
|
|
4885
|
-
|
|
4886
|
-
|
|
4887
|
-
|
|
4888
|
-
|
|
4889
|
-
|
|
4890
|
-
|
|
4891
|
-
|
|
4892
|
-
|
|
4893
|
-
|
|
4894
|
-
|
|
4895
|
-
if (--WithSandBox.activeCount === 0) {
|
|
4896
|
-
releaseEffectDocumentEvent();
|
|
4897
|
-
}
|
|
4898
|
-
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();
|
|
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();
|
|
4899
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);
|
|
4900
5010
|
}
|
|
4901
5011
|
/**
|
|
4902
5012
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -4927,7 +5037,8 @@ class WithSandBox {
|
|
|
4927
5037
|
* 2. unmount prerender app manually
|
|
4928
5038
|
*/
|
|
4929
5039
|
resetEffectSnapshot() {
|
|
4930
|
-
this.
|
|
5040
|
+
this.windowEffect.reset();
|
|
5041
|
+
this.documentEffect.reset();
|
|
4931
5042
|
resetDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4932
5043
|
}
|
|
4933
5044
|
/**
|
|
@@ -4938,20 +5049,14 @@ class WithSandBox {
|
|
|
4938
5049
|
* 3. after init prerender app
|
|
4939
5050
|
*/
|
|
4940
5051
|
recordEffectSnapshot() {
|
|
4941
|
-
|
|
4942
|
-
this.
|
|
5052
|
+
this.windowEffect.record();
|
|
5053
|
+
this.documentEffect.record();
|
|
4943
5054
|
recordDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4944
|
-
// this.recordUmdInjectedValues = new Map<PropertyKey, unknown>()
|
|
4945
|
-
// this.injectedKeys.forEach((key: PropertyKey) => {
|
|
4946
|
-
// this.recordUmdInjectedValues!.set(key, Reflect.get(this.microAppWindow, key))
|
|
4947
|
-
// })
|
|
4948
5055
|
}
|
|
4949
5056
|
// rebuild umd snapshot before remount umd app
|
|
4950
5057
|
rebuildEffectSnapshot() {
|
|
4951
|
-
|
|
4952
|
-
|
|
4953
|
-
// })
|
|
4954
|
-
this.effectController.rebuild();
|
|
5058
|
+
this.windowEffect.rebuild();
|
|
5059
|
+
this.documentEffect.rebuild();
|
|
4955
5060
|
rebuildDataCenterSnapshot(this.microAppWindow.microApp);
|
|
4956
5061
|
}
|
|
4957
5062
|
/**
|
|
@@ -4960,19 +5065,17 @@ class WithSandBox {
|
|
|
4960
5065
|
* 1. unmount of default/umd app
|
|
4961
5066
|
* 2. hidden keep-alive app
|
|
4962
5067
|
* 3. after init prerender app
|
|
5068
|
+
* @param umdMode is umd mode
|
|
4963
5069
|
* @param clearData clear data from base app
|
|
4964
5070
|
* @param isPrerender is prerender app
|
|
4965
5071
|
* @param keepAlive is keep-alive app
|
|
4966
5072
|
* @param destroy completely destroy
|
|
4967
5073
|
*/
|
|
4968
|
-
releaseGlobalEffect({ clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
5074
|
+
releaseGlobalEffect({ umdMode = false, clearData = false, isPrerender = false, keepAlive = false, destroy = false, }) {
|
|
4969
5075
|
var _a, _b, _c;
|
|
4970
|
-
|
|
4971
|
-
|
|
4972
|
-
|
|
4973
|
-
keepAlive,
|
|
4974
|
-
destroy,
|
|
4975
|
-
});
|
|
5076
|
+
// default mode(not keep-alive or isPrerender)
|
|
5077
|
+
this.windowEffect.release((!umdMode && !keepAlive && !isPrerender) || destroy);
|
|
5078
|
+
this.documentEffect.release();
|
|
4976
5079
|
(_a = this.microAppWindow.microApp) === null || _a === void 0 ? void 0 : _a.clearDataListener();
|
|
4977
5080
|
(_b = this.microAppWindow.microApp) === null || _b === void 0 ? void 0 : _b.clearGlobalDataListener();
|
|
4978
5081
|
if (clearData) {
|
|
@@ -5008,10 +5111,10 @@ class WithSandBox {
|
|
|
5008
5111
|
}
|
|
5009
5112
|
}
|
|
5010
5113
|
// create proxyWindow with Proxy(microAppWindow)
|
|
5011
|
-
createProxyWindow(appName) {
|
|
5114
|
+
createProxyWindow(appName, microAppWindow) {
|
|
5012
5115
|
const rawWindow = globalEnv.rawWindow;
|
|
5013
5116
|
const descriptorTargetMap = new Map();
|
|
5014
|
-
return new Proxy(
|
|
5117
|
+
return new Proxy(microAppWindow, {
|
|
5015
5118
|
get: (target, key) => {
|
|
5016
5119
|
throttleDeferForSetAppName(appName);
|
|
5017
5120
|
if (Reflect.has(target, key) ||
|
|
@@ -5021,41 +5124,39 @@ class WithSandBox {
|
|
|
5021
5124
|
return bindFunctionToRawTarget(Reflect.get(rawWindow, key), rawWindow);
|
|
5022
5125
|
},
|
|
5023
5126
|
set: (target, key, value) => {
|
|
5024
|
-
|
|
5025
|
-
|
|
5026
|
-
|
|
5027
|
-
|
|
5028
|
-
|
|
5029
|
-
|
|
5030
|
-
|
|
5031
|
-
|
|
5032
|
-
|
|
5033
|
-
|
|
5034
|
-
|
|
5035
|
-
|
|
5036
|
-
|
|
5037
|
-
|
|
5038
|
-
|
|
5039
|
-
|
|
5040
|
-
|
|
5041
|
-
|
|
5042
|
-
|
|
5043
|
-
|
|
5044
|
-
|
|
5045
|
-
|
|
5046
|
-
|
|
5047
|
-
|
|
5048
|
-
|
|
5049
|
-
|
|
5050
|
-
|
|
5051
|
-
|
|
5052
|
-
|
|
5053
|
-
|
|
5054
|
-
|
|
5055
|
-
|
|
5056
|
-
|
|
5057
|
-
Reflect.set(rawWindow, key, value);
|
|
5058
|
-
}
|
|
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);
|
|
5059
5160
|
}
|
|
5060
5161
|
return true;
|
|
5061
5162
|
},
|
|
@@ -5102,40 +5203,24 @@ class WithSandBox {
|
|
|
5102
5203
|
},
|
|
5103
5204
|
});
|
|
5104
5205
|
}
|
|
5105
|
-
// set __MICRO_APP_PRE_RENDER__ state
|
|
5106
|
-
setPreRenderState(state) {
|
|
5107
|
-
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
5108
|
-
}
|
|
5109
|
-
markUmdMode(state) {
|
|
5110
|
-
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
5111
|
-
}
|
|
5112
5206
|
/**
|
|
5113
|
-
*
|
|
5114
|
-
* @param microAppWindow micro window
|
|
5207
|
+
* create proxyWindow, rewrite window event & timer of child app
|
|
5115
5208
|
* @param appName app name
|
|
5116
|
-
* @param
|
|
5117
|
-
* @param useMemoryRouter whether use memory router
|
|
5209
|
+
* @param microAppWindow Proxy target
|
|
5118
5210
|
*/
|
|
5119
|
-
|
|
5120
|
-
|
|
5121
|
-
|
|
5122
|
-
|
|
5123
|
-
|
|
5124
|
-
microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
|
|
5125
|
-
microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
5126
|
-
microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
5127
|
-
microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
5128
|
-
microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
5129
|
-
microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
5130
|
-
removeDomScope,
|
|
5131
|
-
pureCreateElement,
|
|
5132
|
-
router,
|
|
5133
|
-
});
|
|
5134
|
-
this.setProxyDocument(microAppWindow, appName);
|
|
5135
|
-
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);
|
|
5136
5216
|
}
|
|
5137
|
-
|
|
5138
|
-
|
|
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);
|
|
5139
5224
|
rawDefineProperties(microAppWindow, {
|
|
5140
5225
|
document: {
|
|
5141
5226
|
configurable: false,
|
|
@@ -5154,6 +5239,14 @@ class WithSandBox {
|
|
|
5154
5239
|
},
|
|
5155
5240
|
}
|
|
5156
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;
|
|
5157
5250
|
}
|
|
5158
5251
|
// properties associated with the native window
|
|
5159
5252
|
setMappingPropertiesWithRawDescriptor(microAppWindow) {
|
|
@@ -5166,6 +5259,7 @@ class WithSandBox {
|
|
|
5166
5259
|
topValue = rawWindow.top;
|
|
5167
5260
|
parentValue = rawWindow.parent;
|
|
5168
5261
|
}
|
|
5262
|
+
// TODO: 用rawDefineProperties
|
|
5169
5263
|
rawDefineProperty(microAppWindow, 'top', this.createDescriptorForMicroAppWindow('top', topValue));
|
|
5170
5264
|
rawDefineProperty(microAppWindow, 'parent', this.createDescriptorForMicroAppWindow('parent', parentValue));
|
|
5171
5265
|
globalPropertyList$1.forEach((key) => {
|
|
@@ -5189,15 +5283,15 @@ class WithSandBox {
|
|
|
5189
5283
|
* @param url app url
|
|
5190
5284
|
* @param disablePatchRequest prevent rewrite request method of child app
|
|
5191
5285
|
*/
|
|
5192
|
-
initGlobalKeysWhenStart(
|
|
5286
|
+
initGlobalKeysWhenStart(appName, url, microAppWindow, disablePatchRequest) {
|
|
5193
5287
|
microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
|
|
5194
|
-
this.setHijackProperty(
|
|
5288
|
+
this.setHijackProperty(appName, microAppWindow);
|
|
5195
5289
|
if (!disablePatchRequest)
|
|
5196
|
-
this.patchRequestApi(
|
|
5290
|
+
this.patchRequestApi(appName, url, microAppWindow);
|
|
5197
5291
|
this.setScopeProperties(microAppWindow);
|
|
5198
5292
|
}
|
|
5199
5293
|
// set hijack Properties to microAppWindow
|
|
5200
|
-
setHijackProperty(
|
|
5294
|
+
setHijackProperty(appName, microAppWindow) {
|
|
5201
5295
|
let modifiedEval, modifiedImage;
|
|
5202
5296
|
rawDefineProperties(microAppWindow, {
|
|
5203
5297
|
eval: {
|
|
@@ -5225,7 +5319,7 @@ class WithSandBox {
|
|
|
5225
5319
|
});
|
|
5226
5320
|
}
|
|
5227
5321
|
// rewrite fetch, XMLHttpRequest, EventSource
|
|
5228
|
-
patchRequestApi(
|
|
5322
|
+
patchRequestApi(appName, url, microAppWindow) {
|
|
5229
5323
|
let microFetch = createMicroFetch(url);
|
|
5230
5324
|
let microXMLHttpRequest = createMicroXMLHttpRequest(url);
|
|
5231
5325
|
let microEventSource = createMicroEventSource(appName, url);
|
|
@@ -5275,7 +5369,7 @@ class WithSandBox {
|
|
|
5275
5369
|
});
|
|
5276
5370
|
}
|
|
5277
5371
|
// set location & history for memory router
|
|
5278
|
-
setMicroAppRouter(
|
|
5372
|
+
setMicroAppRouter(appName, url, microAppWindow) {
|
|
5279
5373
|
const { microLocation, microHistory } = createMicroRouter(appName, url);
|
|
5280
5374
|
rawDefineProperties(microAppWindow, {
|
|
5281
5375
|
location: {
|
|
@@ -5325,85 +5419,26 @@ class WithSandBox {
|
|
|
5325
5419
|
actionBeforeExecScripts(container) {
|
|
5326
5420
|
this.patchStaticElement(container);
|
|
5327
5421
|
}
|
|
5328
|
-
/**
|
|
5329
|
-
* Create new document and Document
|
|
5330
|
-
*/
|
|
5331
|
-
createProxyDocument(appName) {
|
|
5332
|
-
const rawDocument = globalEnv.rawDocument;
|
|
5333
|
-
const rawRootDocument = globalEnv.rawRootDocument;
|
|
5334
|
-
const createElement = function (tagName, options) {
|
|
5335
|
-
const element = globalEnv.rawCreateElement.call(rawDocument, tagName, options);
|
|
5336
|
-
element.__MICRO_APP_NAME__ = appName;
|
|
5337
|
-
return element;
|
|
5338
|
-
};
|
|
5339
|
-
const proxyDocument = new Proxy(rawDocument, {
|
|
5340
|
-
get: (target, key) => {
|
|
5341
|
-
throttleDeferForSetAppName(appName);
|
|
5342
|
-
throttleDeferForParentNode(proxyDocument);
|
|
5343
|
-
if (key === 'createElement')
|
|
5344
|
-
return createElement;
|
|
5345
|
-
if (key === Symbol.toStringTag)
|
|
5346
|
-
return 'ProxyDocument';
|
|
5347
|
-
if (key === 'defaultView')
|
|
5348
|
-
return this.proxyWindow;
|
|
5349
|
-
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
5350
|
-
},
|
|
5351
|
-
set: (target, key, value) => {
|
|
5352
|
-
/**
|
|
5353
|
-
* 1. Fix TypeError: Illegal invocation when set document.title
|
|
5354
|
-
* 2. If the set method returns false, and the assignment happened in strict-mode code, a TypeError will be thrown.
|
|
5355
|
-
*/
|
|
5356
|
-
Reflect.set(target, key, value);
|
|
5357
|
-
return true;
|
|
5358
|
-
}
|
|
5359
|
-
});
|
|
5360
|
-
class MicroDocument {
|
|
5361
|
-
static [Symbol.hasInstance](target) {
|
|
5362
|
-
let proto = target;
|
|
5363
|
-
while (proto = Object.getPrototypeOf(proto)) {
|
|
5364
|
-
if (proto === MicroDocument.prototype) {
|
|
5365
|
-
return true;
|
|
5366
|
-
}
|
|
5367
|
-
}
|
|
5368
|
-
return (target === proxyDocument ||
|
|
5369
|
-
target instanceof rawRootDocument);
|
|
5370
|
-
}
|
|
5371
|
-
}
|
|
5372
|
-
/**
|
|
5373
|
-
* TIP:
|
|
5374
|
-
* 1. child class __proto__, which represents the inherit of the constructor, always points to the parent class
|
|
5375
|
-
* 2. child class prototype.__proto__, which represents the inherit of methods, always points to parent class prototype
|
|
5376
|
-
* e.g.
|
|
5377
|
-
* class B extends A {}
|
|
5378
|
-
* B.__proto__ === A // true
|
|
5379
|
-
* B.prototype.__proto__ === A.prototype // true
|
|
5380
|
-
*/
|
|
5381
|
-
Object.setPrototypeOf(MicroDocument, rawRootDocument);
|
|
5382
|
-
// Object.create(rawRootDocument.prototype) will cause MicroDocument and proxyDocument methods not same when exec Document.prototype.xxx = xxx in child app
|
|
5383
|
-
Object.setPrototypeOf(MicroDocument.prototype, new Proxy(rawRootDocument.prototype, {
|
|
5384
|
-
get(target, key) {
|
|
5385
|
-
throttleDeferForSetAppName(appName);
|
|
5386
|
-
return bindFunctionToRawTarget(Reflect.get(target, key), rawDocument, 'DOCUMENT');
|
|
5387
|
-
},
|
|
5388
|
-
set(target, key, value) {
|
|
5389
|
-
Reflect.set(target, key, value);
|
|
5390
|
-
return true;
|
|
5391
|
-
}
|
|
5392
|
-
}));
|
|
5393
|
-
return {
|
|
5394
|
-
proxyDocument,
|
|
5395
|
-
MicroDocument,
|
|
5396
|
-
};
|
|
5397
|
-
}
|
|
5398
5422
|
}
|
|
5399
5423
|
WithSandBox.activeCount = 0; // number of active sandbox
|
|
5400
5424
|
|
|
5401
|
-
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
|
|
5402
5430
|
const microHistory = microAppWindow.history;
|
|
5403
5431
|
microAppWindow.rawReplaceState = microHistory.replaceState;
|
|
5404
5432
|
assign(microHistory, createMicroHistory(appName, microAppWindow.location));
|
|
5405
|
-
|
|
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
|
+
*/
|
|
5406
5439
|
updateMicroLocation(appName, childFullPath, microAppWindow.location, 'prevent');
|
|
5440
|
+
// create proxyLocation
|
|
5441
|
+
return createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
5407
5442
|
}
|
|
5408
5443
|
|
|
5409
5444
|
function patchIframeWindow(appName, microAppWindow) {
|
|
@@ -5469,15 +5504,16 @@ function patchIframeWindow(appName, microAppWindow) {
|
|
|
5469
5504
|
logWarn(e, appName);
|
|
5470
5505
|
}
|
|
5471
5506
|
});
|
|
5472
|
-
return
|
|
5507
|
+
return patchWindowEffect$1(microAppWindow);
|
|
5473
5508
|
}
|
|
5474
|
-
function
|
|
5475
|
-
const { rawWindow, rawAddEventListener, rawRemoveEventListener
|
|
5509
|
+
function patchWindowEffect$1(microAppWindow) {
|
|
5510
|
+
const { rawWindow, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5476
5511
|
const eventListenerMap = new Map();
|
|
5477
|
-
const
|
|
5512
|
+
const sstEventListenerMap = new Map();
|
|
5478
5513
|
function getEventTarget(type) {
|
|
5479
5514
|
return scopeIframeWindowEvent.includes(type) ? microAppWindow : rawWindow;
|
|
5480
5515
|
}
|
|
5516
|
+
// TODO: listener 是否需要绑定microAppWindow,否则函数中的this指向原生window
|
|
5481
5517
|
microAppWindow.addEventListener = function (type, listener, options) {
|
|
5482
5518
|
const listenerList = eventListenerMap.get(type);
|
|
5483
5519
|
if (listenerList) {
|
|
@@ -5497,7 +5533,7 @@ function windowEffect(microAppWindow) {
|
|
|
5497
5533
|
rawRemoveEventListener.call(getEventTarget(type), type, listener, options);
|
|
5498
5534
|
};
|
|
5499
5535
|
const reset = () => {
|
|
5500
|
-
|
|
5536
|
+
sstEventListenerMap.clear();
|
|
5501
5537
|
};
|
|
5502
5538
|
/**
|
|
5503
5539
|
* NOTE:
|
|
@@ -5515,14 +5551,14 @@ function windowEffect(microAppWindow) {
|
|
|
5515
5551
|
// record window event
|
|
5516
5552
|
eventListenerMap.forEach((listenerList, type) => {
|
|
5517
5553
|
if (listenerList.size) {
|
|
5518
|
-
|
|
5554
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
5519
5555
|
}
|
|
5520
5556
|
});
|
|
5521
5557
|
};
|
|
5522
5558
|
// rebuild event and timer before remount app
|
|
5523
5559
|
const rebuild = () => {
|
|
5524
5560
|
// rebuild window event
|
|
5525
|
-
|
|
5561
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
5526
5562
|
for (const listener of listenerList) {
|
|
5527
5563
|
microAppWindow.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5528
5564
|
}
|
|
@@ -5556,18 +5592,26 @@ function windowEffect(microAppWindow) {
|
|
|
5556
5592
|
function patchIframeDocument(appName, microAppWindow, proxyLocation) {
|
|
5557
5593
|
patchDocumentPrototype(appName, microAppWindow);
|
|
5558
5594
|
patchDocumentProperties(appName, microAppWindow, proxyLocation);
|
|
5559
|
-
return
|
|
5595
|
+
return patchDocumentEffect(appName, microAppWindow);
|
|
5560
5596
|
}
|
|
5561
5597
|
function patchDocumentPrototype(appName, microAppWindow) {
|
|
5562
5598
|
const rawDocument = globalEnv.rawDocument;
|
|
5563
5599
|
const microRootDocument = microAppWindow.Document;
|
|
5564
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;
|
|
5565
5609
|
microRootDocument.prototype.createElement = function createElement(tagName, options) {
|
|
5566
|
-
const element =
|
|
5610
|
+
const element = rawMicroCreateElement.call(this, tagName, options);
|
|
5567
5611
|
return updateElementInfo(element, appName);
|
|
5568
5612
|
};
|
|
5569
5613
|
microRootDocument.prototype.createTextNode = function createTextNode(data) {
|
|
5570
|
-
const element =
|
|
5614
|
+
const element = rawMicroCreateTextNode.call(this, data);
|
|
5571
5615
|
return updateElementInfo(element, appName);
|
|
5572
5616
|
};
|
|
5573
5617
|
function getDefaultRawTarget(target) {
|
|
@@ -5576,19 +5620,21 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5576
5620
|
// query element👇
|
|
5577
5621
|
function querySelector(selectors) {
|
|
5578
5622
|
var _a, _b;
|
|
5579
|
-
if (
|
|
5623
|
+
if (!selectors ||
|
|
5624
|
+
isUniqueElement(selectors) ||
|
|
5580
5625
|
microDocument !== this) {
|
|
5581
5626
|
const _this = getDefaultRawTarget(this);
|
|
5582
|
-
return
|
|
5627
|
+
return rawMicroQuerySelector.call(_this, selectors);
|
|
5583
5628
|
}
|
|
5584
5629
|
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelector(selectors)) !== null && _b !== void 0 ? _b : null;
|
|
5585
5630
|
}
|
|
5586
5631
|
function querySelectorAll(selectors) {
|
|
5587
5632
|
var _a, _b;
|
|
5588
|
-
if (
|
|
5633
|
+
if (!selectors ||
|
|
5634
|
+
isUniqueElement(selectors) ||
|
|
5589
5635
|
microDocument !== this) {
|
|
5590
5636
|
const _this = getDefaultRawTarget(this);
|
|
5591
|
-
return
|
|
5637
|
+
return rawMicroQuerySelectorAll.call(_this, selectors);
|
|
5592
5638
|
}
|
|
5593
5639
|
return (_b = (_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.querySelectorAll(selectors)) !== null && _b !== void 0 ? _b : [];
|
|
5594
5640
|
}
|
|
@@ -5597,25 +5643,25 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5597
5643
|
microRootDocument.prototype.getElementById = function getElementById(key) {
|
|
5598
5644
|
const _this = getDefaultRawTarget(this);
|
|
5599
5645
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5600
|
-
return
|
|
5646
|
+
return rawMicroGetElementById.call(_this, key);
|
|
5601
5647
|
}
|
|
5602
5648
|
try {
|
|
5603
5649
|
return querySelector.call(this, `#${key}`);
|
|
5604
5650
|
}
|
|
5605
5651
|
catch (_a) {
|
|
5606
|
-
return
|
|
5652
|
+
return rawMicroGetElementById.call(_this, key);
|
|
5607
5653
|
}
|
|
5608
5654
|
};
|
|
5609
5655
|
microRootDocument.prototype.getElementsByClassName = function getElementsByClassName(key) {
|
|
5610
5656
|
const _this = getDefaultRawTarget(this);
|
|
5611
5657
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5612
|
-
return
|
|
5658
|
+
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5613
5659
|
}
|
|
5614
5660
|
try {
|
|
5615
5661
|
return querySelectorAll.call(this, `.${key}`);
|
|
5616
5662
|
}
|
|
5617
5663
|
catch (_a) {
|
|
5618
|
-
return
|
|
5664
|
+
return rawMicroGetElementsByClassName.call(_this, key);
|
|
5619
5665
|
}
|
|
5620
5666
|
};
|
|
5621
5667
|
microRootDocument.prototype.getElementsByTagName = function getElementsByTagName(key) {
|
|
@@ -5624,25 +5670,25 @@ function patchDocumentPrototype(appName, microAppWindow) {
|
|
|
5624
5670
|
if (isUniqueElement(key) ||
|
|
5625
5671
|
isInvalidQuerySelectorKey(key) ||
|
|
5626
5672
|
(!((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.inline) && /^script$/i.test(key))) {
|
|
5627
|
-
return
|
|
5673
|
+
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5628
5674
|
}
|
|
5629
5675
|
try {
|
|
5630
5676
|
return querySelectorAll.call(this, key);
|
|
5631
5677
|
}
|
|
5632
5678
|
catch (_b) {
|
|
5633
|
-
return
|
|
5679
|
+
return rawMicroGetElementsByTagName.call(_this, key);
|
|
5634
5680
|
}
|
|
5635
5681
|
};
|
|
5636
5682
|
microRootDocument.prototype.getElementsByName = function getElementsByName(key) {
|
|
5637
5683
|
const _this = getDefaultRawTarget(this);
|
|
5638
5684
|
if (isInvalidQuerySelectorKey(key)) {
|
|
5639
|
-
return
|
|
5685
|
+
return rawMicroGetElementsByName.call(_this, key);
|
|
5640
5686
|
}
|
|
5641
5687
|
try {
|
|
5642
5688
|
return querySelectorAll.call(this, `[name=${key}]`);
|
|
5643
5689
|
}
|
|
5644
5690
|
catch (_a) {
|
|
5645
|
-
return
|
|
5691
|
+
return rawMicroGetElementsByName.call(_this, key);
|
|
5646
5692
|
}
|
|
5647
5693
|
};
|
|
5648
5694
|
}
|
|
@@ -5698,46 +5744,37 @@ function patchDocumentProperties(appName, microAppWindow, proxyLocation) {
|
|
|
5698
5744
|
enumerable: true,
|
|
5699
5745
|
configurable: true,
|
|
5700
5746
|
get: () => rawDocument[tagName],
|
|
5701
|
-
set:
|
|
5747
|
+
set: (value) => { rawDocument[tagName] = value; },
|
|
5702
5748
|
});
|
|
5703
5749
|
});
|
|
5704
5750
|
}
|
|
5705
|
-
function
|
|
5706
|
-
const
|
|
5707
|
-
const
|
|
5751
|
+
function patchDocumentEffect(appName, microAppWindow) {
|
|
5752
|
+
const { rawDocument, rawAddEventListener, rawRemoveEventListener } = globalEnv;
|
|
5753
|
+
const eventListenerMap = new Map();
|
|
5754
|
+
const sstEventListenerMap = new Map();
|
|
5708
5755
|
let onClickHandler = null;
|
|
5709
5756
|
let sstOnClickHandler = null;
|
|
5710
5757
|
const microRootDocument = microAppWindow.Document;
|
|
5711
5758
|
const microDocument = microAppWindow.document;
|
|
5712
|
-
const { rawDocument, rawAddEventListener, rawRemoveEventListener, } = globalEnv;
|
|
5713
5759
|
function getEventTarget(type, bindTarget) {
|
|
5714
5760
|
return scopeIframeDocumentEvent.includes(type) ? bindTarget : rawDocument;
|
|
5715
5761
|
}
|
|
5716
5762
|
microRootDocument.prototype.addEventListener = function (type, listener, options) {
|
|
5717
5763
|
const handler = isFunction(listener) ? (listener.__MICRO_APP_BOUND_FUNCTION__ = listener.__MICRO_APP_BOUND_FUNCTION__ || listener.bind(this)) : listener;
|
|
5718
|
-
const
|
|
5719
|
-
if (
|
|
5720
|
-
|
|
5721
|
-
if (appListenerList) {
|
|
5722
|
-
appListenerList.add(listener);
|
|
5723
|
-
}
|
|
5724
|
-
else {
|
|
5725
|
-
appListenersMap.set(type, new Set([listener]));
|
|
5726
|
-
}
|
|
5764
|
+
const listenerList = eventListenerMap.get(type);
|
|
5765
|
+
if (listenerList) {
|
|
5766
|
+
listenerList.add(listener);
|
|
5727
5767
|
}
|
|
5728
5768
|
else {
|
|
5729
|
-
|
|
5769
|
+
eventListenerMap.set(type, new Set([listener]));
|
|
5730
5770
|
}
|
|
5731
5771
|
listener && (listener.__MICRO_APP_MARK_OPTIONS__ = options);
|
|
5732
5772
|
rawAddEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
5733
5773
|
};
|
|
5734
5774
|
microRootDocument.prototype.removeEventListener = function (type, listener, options) {
|
|
5735
|
-
const
|
|
5736
|
-
if (
|
|
5737
|
-
|
|
5738
|
-
if ((appListenerList === null || appListenerList === void 0 ? void 0 : appListenerList.size) && appListenerList.has(listener)) {
|
|
5739
|
-
appListenerList.delete(listener);
|
|
5740
|
-
}
|
|
5775
|
+
const listenerList = eventListenerMap.get(type);
|
|
5776
|
+
if ((listenerList === null || listenerList === void 0 ? void 0 : listenerList.size) && listenerList.has(listener)) {
|
|
5777
|
+
listenerList.delete(listener);
|
|
5741
5778
|
}
|
|
5742
5779
|
const handler = (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener;
|
|
5743
5780
|
rawRemoveEventListener.call(getEventTarget(type, this), type, handler, options);
|
|
@@ -5789,7 +5826,7 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5789
5826
|
}
|
|
5790
5827
|
});
|
|
5791
5828
|
const reset = () => {
|
|
5792
|
-
|
|
5829
|
+
sstEventListenerMap.clear();
|
|
5793
5830
|
sstOnClickHandler = null;
|
|
5794
5831
|
};
|
|
5795
5832
|
/**
|
|
@@ -5805,21 +5842,18 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5805
5842
|
// record onclick handler
|
|
5806
5843
|
sstOnClickHandler = sstOnClickHandler || onClickHandler;
|
|
5807
5844
|
// record document event
|
|
5808
|
-
|
|
5809
|
-
|
|
5810
|
-
|
|
5811
|
-
|
|
5812
|
-
|
|
5813
|
-
}
|
|
5814
|
-
});
|
|
5815
|
-
}
|
|
5845
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5846
|
+
if (listenerList.size) {
|
|
5847
|
+
sstEventListenerMap.set(type, new Set(listenerList));
|
|
5848
|
+
}
|
|
5849
|
+
});
|
|
5816
5850
|
};
|
|
5817
5851
|
// rebuild event and timer before remount app
|
|
5818
5852
|
const rebuild = () => {
|
|
5819
5853
|
// rebuild onclick event
|
|
5820
5854
|
if (sstOnClickHandler)
|
|
5821
5855
|
microDocument.onclick = sstOnClickHandler;
|
|
5822
|
-
|
|
5856
|
+
sstEventListenerMap.forEach((listenerList, type) => {
|
|
5823
5857
|
for (const listener of listenerList) {
|
|
5824
5858
|
microDocument.addEventListener(type, listener, listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_MARK_OPTIONS__);
|
|
5825
5859
|
}
|
|
@@ -5827,20 +5861,19 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5827
5861
|
reset();
|
|
5828
5862
|
};
|
|
5829
5863
|
const release = () => {
|
|
5830
|
-
// Clear the function bound by micro
|
|
5864
|
+
// Clear the function bound by micro app through document.onclick
|
|
5831
5865
|
if (isFunction(onClickHandler)) {
|
|
5832
5866
|
rawRemoveEventListener.call(rawDocument, 'click', onClickHandler);
|
|
5833
5867
|
onClickHandler = null;
|
|
5834
5868
|
}
|
|
5835
5869
|
// Clear document binding event
|
|
5836
|
-
|
|
5837
|
-
|
|
5838
|
-
documentAppListenersMap.forEach((listenerList, type) => {
|
|
5870
|
+
if (eventListenerMap.size) {
|
|
5871
|
+
eventListenerMap.forEach((listenerList, type) => {
|
|
5839
5872
|
for (const listener of listenerList) {
|
|
5840
5873
|
rawRemoveEventListener.call(getEventTarget(type, microDocument), type, (listener === null || listener === void 0 ? void 0 : listener.__MICRO_APP_BOUND_FUNCTION__) || listener);
|
|
5841
5874
|
}
|
|
5842
5875
|
});
|
|
5843
|
-
|
|
5876
|
+
eventListenerMap.clear();
|
|
5844
5877
|
}
|
|
5845
5878
|
};
|
|
5846
5879
|
return {
|
|
@@ -5851,33 +5884,38 @@ function documentEffect(appName, microAppWindow) {
|
|
|
5851
5884
|
};
|
|
5852
5885
|
}
|
|
5853
5886
|
|
|
5854
|
-
function patchIframeElement(appName, url, microAppWindow,
|
|
5855
|
-
patchIframeNode(appName, microAppWindow,
|
|
5887
|
+
function patchIframeElement(appName, url, microAppWindow, sandbox) {
|
|
5888
|
+
patchIframeNode(appName, microAppWindow, sandbox);
|
|
5856
5889
|
patchIframeAttribute(appName, url, microAppWindow);
|
|
5857
5890
|
}
|
|
5858
|
-
function patchIframeNode(appName, microAppWindow,
|
|
5859
|
-
const
|
|
5891
|
+
function patchIframeNode(appName, microAppWindow, sandbox) {
|
|
5892
|
+
const rawRootElement = globalEnv.rawRootElement; // native root Element
|
|
5860
5893
|
const rawDocument = globalEnv.rawDocument;
|
|
5894
|
+
const microDocument = microAppWindow.document;
|
|
5861
5895
|
const microRootNode = microAppWindow.Node;
|
|
5862
5896
|
const microRootElement = microAppWindow.Element;
|
|
5863
5897
|
// const rawMicroGetRootNode = microRootNode.prototype.getRootNode
|
|
5864
5898
|
const rawMicroAppendChild = microRootNode.prototype.appendChild;
|
|
5865
5899
|
const rawMicroInsertBefore = microRootNode.prototype.insertBefore;
|
|
5866
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;
|
|
5867
5905
|
const rawMicroCloneNode = microRootNode.prototype.cloneNode;
|
|
5868
5906
|
const rawInnerHTMLDesc = Object.getOwnPropertyDescriptor(microRootElement.prototype, 'innerHTML');
|
|
5869
5907
|
const rawParentNodeLDesc = Object.getOwnPropertyDescriptor(microRootNode.prototype, 'parentNode');
|
|
5870
5908
|
const isPureNode = (target) => {
|
|
5871
5909
|
return (isScriptElement(target) || isBaseElement(target)) && target.__PURE_ELEMENT__;
|
|
5872
5910
|
};
|
|
5873
|
-
const getRawTarget = (
|
|
5874
|
-
if (
|
|
5911
|
+
const getRawTarget = (parent) => {
|
|
5912
|
+
if (parent === sandbox.microHead) {
|
|
5875
5913
|
return rawDocument.head;
|
|
5876
5914
|
}
|
|
5877
|
-
else if (
|
|
5915
|
+
else if (parent === sandbox.microBody) {
|
|
5878
5916
|
return rawDocument.body;
|
|
5879
5917
|
}
|
|
5880
|
-
return
|
|
5918
|
+
return parent;
|
|
5881
5919
|
};
|
|
5882
5920
|
microRootNode.prototype.getRootNode = function getRootNode() {
|
|
5883
5921
|
return microDocument;
|
|
@@ -5888,46 +5926,70 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5888
5926
|
};
|
|
5889
5927
|
microRootNode.prototype.appendChild = function appendChild(node) {
|
|
5890
5928
|
updateElementInfo(node, appName);
|
|
5891
|
-
// TODO:只有script才可以这样拦截,link、style不应该拦截
|
|
5892
5929
|
if (isPureNode(node)) {
|
|
5893
5930
|
return rawMicroAppendChild.call(this, node);
|
|
5894
5931
|
}
|
|
5895
|
-
|
|
5896
|
-
if (_this !== this) {
|
|
5897
|
-
return _this.appendChild(node);
|
|
5898
|
-
}
|
|
5899
|
-
return rawMicroAppendChild.call(_this, node);
|
|
5932
|
+
return rawRootElement.prototype.appendChild.call(getRawTarget(this), node);
|
|
5900
5933
|
};
|
|
5901
|
-
// TODO: 更多场景适配
|
|
5902
5934
|
microRootNode.prototype.insertBefore = function insertBefore(node, child) {
|
|
5903
5935
|
updateElementInfo(node, appName);
|
|
5904
5936
|
if (isPureNode(node)) {
|
|
5905
5937
|
return rawMicroInsertBefore.call(this, node, child);
|
|
5906
5938
|
}
|
|
5907
|
-
|
|
5908
|
-
if (_this !== this) {
|
|
5909
|
-
if (child && !_this.contains(child)) {
|
|
5910
|
-
return _this.appendChild(node);
|
|
5911
|
-
}
|
|
5912
|
-
return _this.insertBefore(node, child);
|
|
5913
|
-
}
|
|
5914
|
-
return rawMicroInsertBefore.call(_this, node, child);
|
|
5939
|
+
return rawRootElement.prototype.insertBefore.call(getRawTarget(this), node, child);
|
|
5915
5940
|
};
|
|
5916
|
-
// TODO: 更多场景适配
|
|
5917
5941
|
microRootNode.prototype.replaceChild = function replaceChild(node, child) {
|
|
5918
5942
|
updateElementInfo(node, appName);
|
|
5919
5943
|
if (isPureNode(node)) {
|
|
5920
5944
|
return rawMicroReplaceChild.call(this, node, child);
|
|
5921
5945
|
}
|
|
5922
|
-
|
|
5923
|
-
|
|
5924
|
-
|
|
5925
|
-
|
|
5926
|
-
|
|
5927
|
-
|
|
5928
|
-
|
|
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);
|
|
5929
5991
|
}
|
|
5930
|
-
return
|
|
5992
|
+
return rawRootElement.prototype.insertAdjacentElement.call(getRawTarget(this), where, element);
|
|
5931
5993
|
};
|
|
5932
5994
|
// patch cloneNode
|
|
5933
5995
|
microRootNode.prototype.cloneNode = function cloneNode(deep) {
|
|
@@ -5954,7 +6016,7 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5954
6016
|
configurable: true,
|
|
5955
6017
|
enumerable: true,
|
|
5956
6018
|
get() {
|
|
5957
|
-
var _a;
|
|
6019
|
+
var _a, _b, _c;
|
|
5958
6020
|
// set html.parentNode to microDocument
|
|
5959
6021
|
throttleDeferForParentNode(microDocument);
|
|
5960
6022
|
const result = rawParentNodeLDesc.get.call(this);
|
|
@@ -5967,12 +6029,11 @@ function patchIframeNode(appName, microAppWindow, iframeSandbox) {
|
|
|
5967
6029
|
* Will it cause other problems ?
|
|
5968
6030
|
* e.g. target.parentNode.remove(target)
|
|
5969
6031
|
*/
|
|
5970
|
-
if ((result
|
|
5971
|
-
return rawDocument.body;
|
|
6032
|
+
if (isMicroAppBody(result) && ((_a = appInstanceMap.get(appName)) === null || _a === void 0 ? void 0 : _a.container)) {
|
|
6033
|
+
return ((_c = (_b = microApp.options).getRootElementParentNode) === null || _c === void 0 ? void 0 : _c.call(_b, this, appName)) || rawDocument.body;
|
|
5972
6034
|
}
|
|
5973
6035
|
return result;
|
|
5974
6036
|
},
|
|
5975
|
-
set: undefined,
|
|
5976
6037
|
});
|
|
5977
6038
|
// Adapt to new image(...) scene
|
|
5978
6039
|
const ImageProxy = new Proxy(microAppWindow.Image, {
|
|
@@ -6012,6 +6073,12 @@ function patchIframeAttribute(appName, url, microAppWindow) {
|
|
|
6012
6073
|
[microAppWindow.HTMLScriptElement.prototype, 'src'],
|
|
6013
6074
|
[microAppWindow.HTMLLinkElement.prototype, 'href'],
|
|
6014
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
|
+
*/
|
|
6015
6082
|
protoAttrList.forEach(([target, attr]) => {
|
|
6016
6083
|
const { enumerable, configurable, get, set } = Object.getOwnPropertyDescriptor(target, attr) || {
|
|
6017
6084
|
enumerable: true,
|
|
@@ -6044,23 +6111,30 @@ class IframeSandbox {
|
|
|
6044
6111
|
};
|
|
6045
6112
|
const rawLocation = globalEnv.rawWindow.location;
|
|
6046
6113
|
const browserHost = rawLocation.protocol + '//' + rawLocation.host;
|
|
6047
|
-
const childStaticLocation = new URL(url);
|
|
6048
|
-
const childHost = childStaticLocation.protocol + '//' + childStaticLocation.host;
|
|
6049
|
-
const childFullPath = childStaticLocation.pathname + childStaticLocation.search + childStaticLocation.hash;
|
|
6050
6114
|
this.deleteIframeElement = this.createIframeElement(appName, browserHost);
|
|
6051
6115
|
this.microAppWindow = this.iframe.contentWindow;
|
|
6052
|
-
// TODO: 优化代码
|
|
6053
|
-
// exec before initStaticGlobalKeys
|
|
6054
|
-
this.createProxyLocation(appName, url, this.microAppWindow, childStaticLocation, browserHost, childHost);
|
|
6055
|
-
this.createProxyWindow(appName, this.microAppWindow);
|
|
6056
|
-
this.initStaticGlobalKeys(appName, url);
|
|
6057
|
-
// get escapeProperties from plugins
|
|
6058
|
-
this.getSpecialProperties(appName);
|
|
6059
6116
|
this.patchIframe(this.microAppWindow, (resolve) => {
|
|
6117
|
+
// TODO: 优化代码
|
|
6118
|
+
// create new html to iframe
|
|
6060
6119
|
this.createIframeTemplate(this.microAppWindow);
|
|
6061
|
-
|
|
6120
|
+
// get escapeProperties from plugins
|
|
6121
|
+
this.getSpecialProperties(appName);
|
|
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
|
|
6062
6134
|
this.windowEffect = patchIframeWindow(appName, this.microAppWindow);
|
|
6135
|
+
// rewrite document of child app
|
|
6063
6136
|
this.documentEffect = patchIframeDocument(appName, this.microAppWindow, this.proxyLocation);
|
|
6137
|
+
// rewrite Node & Element of child app
|
|
6064
6138
|
patchIframeElement(appName, url, this.microAppWindow, this);
|
|
6065
6139
|
resolve();
|
|
6066
6140
|
});
|
|
@@ -6097,53 +6171,80 @@ class IframeSandbox {
|
|
|
6097
6171
|
});
|
|
6098
6172
|
}
|
|
6099
6173
|
start({ baseroute, useMemoryRouter, defaultPage, disablePatchRequest, }) {
|
|
6100
|
-
if (
|
|
6101
|
-
|
|
6102
|
-
|
|
6103
|
-
|
|
6104
|
-
|
|
6105
|
-
|
|
6106
|
-
|
|
6107
|
-
|
|
6108
|
-
|
|
6109
|
-
this.microAppWindow.__MICRO_APP_BASE_ROUTE__ = this.microAppWindow.__MICRO_APP_BASE_URL__ = baseroute;
|
|
6110
|
-
}
|
|
6111
|
-
/**
|
|
6112
|
-
* create base element to iframe
|
|
6113
|
-
* WARNING: This will also affect a, image, link and script
|
|
6114
|
-
*/
|
|
6115
|
-
if (!disablePatchRequest) {
|
|
6116
|
-
this.createIframeBase();
|
|
6117
|
-
}
|
|
6118
|
-
if (++globalEnv.activeSandbox === 1) {
|
|
6119
|
-
patchElementAndDocument();
|
|
6120
|
-
patchHistory();
|
|
6121
|
-
}
|
|
6122
|
-
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__);
|
|
6123
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();
|
|
6193
|
+
}
|
|
6194
|
+
if (++globalEnv.activeSandbox === 1) {
|
|
6195
|
+
patchElementAndDocument();
|
|
6196
|
+
patchHistory();
|
|
6197
|
+
}
|
|
6198
|
+
if (++IframeSandbox.activeCount === 1) ;
|
|
6124
6199
|
}
|
|
6125
6200
|
stop({ umdMode, keepRouteState, destroy, clearData, }) {
|
|
6126
|
-
if (this.active)
|
|
6127
|
-
|
|
6128
|
-
|
|
6129
|
-
|
|
6130
|
-
|
|
6131
|
-
|
|
6132
|
-
|
|
6133
|
-
|
|
6134
|
-
|
|
6135
|
-
|
|
6136
|
-
|
|
6137
|
-
|
|
6138
|
-
|
|
6139
|
-
|
|
6140
|
-
|
|
6141
|
-
|
|
6142
|
-
|
|
6143
|
-
|
|
6144
|
-
if (--IframeSandbox.activeCount === 0) ;
|
|
6145
|
-
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();
|
|
6215
|
+
}
|
|
6216
|
+
if (--globalEnv.activeSandbox === 0) {
|
|
6217
|
+
releasePatchElementAndDocument();
|
|
6218
|
+
releasePatchHistory();
|
|
6146
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
|
+
});
|
|
6147
6248
|
}
|
|
6148
6249
|
/**
|
|
6149
6250
|
* Record global effect and then release (effect: global event, timeout, data listener)
|
|
@@ -6221,42 +6322,33 @@ class IframeSandbox {
|
|
|
6221
6322
|
setPreRenderState(state) {
|
|
6222
6323
|
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = state;
|
|
6223
6324
|
}
|
|
6325
|
+
// record umdMode
|
|
6224
6326
|
markUmdMode(state) {
|
|
6225
6327
|
this.microAppWindow.__MICRO_APP_UMD_MODE__ = state;
|
|
6226
6328
|
}
|
|
6227
|
-
initStaticGlobalKeys(appName, url) {
|
|
6228
|
-
this.microAppWindow.__MICRO_APP_ENVIRONMENT__ = true;
|
|
6229
|
-
this.microAppWindow.__MICRO_APP_NAME__ = appName;
|
|
6230
|
-
this.microAppWindow.__MICRO_APP_URL__ = url;
|
|
6231
|
-
this.microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
|
|
6232
|
-
this.microAppWindow.__MICRO_APP_WINDOW__ = this.microAppWindow;
|
|
6233
|
-
this.microAppWindow.__MICRO_APP_PRE_RENDER__ = false;
|
|
6234
|
-
this.microAppWindow.__MICRO_APP_UMD_MODE__ = false;
|
|
6235
|
-
this.microAppWindow.__MICRO_APP_SANDBOX__ = this;
|
|
6236
|
-
this.microAppWindow.__MICRO_APP_PROXY_WINDOW__ = this.proxyWindow;
|
|
6237
|
-
this.microAppWindow.rawWindow = globalEnv.rawWindow;
|
|
6238
|
-
this.microAppWindow.rawDocument = globalEnv.rawDocument;
|
|
6239
|
-
this.microAppWindow.microApp = assign(new EventCenterForMicroApp(appName), {
|
|
6240
|
-
removeDomScope,
|
|
6241
|
-
pureCreateElement,
|
|
6242
|
-
location: this.proxyLocation,
|
|
6243
|
-
router,
|
|
6244
|
-
});
|
|
6245
|
-
}
|
|
6246
6329
|
// TODO: RESTRUCTURE
|
|
6247
6330
|
patchIframe(microAppWindow, cb) {
|
|
6331
|
+
const oldMicroDocument = microAppWindow.document;
|
|
6248
6332
|
this.sandboxReady = new Promise((resolve) => {
|
|
6249
6333
|
(function iframeLocationReady() {
|
|
6250
6334
|
setTimeout(() => {
|
|
6251
|
-
|
|
6252
|
-
|
|
6335
|
+
try {
|
|
6336
|
+
if (microAppWindow.document === oldMicroDocument) {
|
|
6337
|
+
iframeLocationReady();
|
|
6338
|
+
}
|
|
6339
|
+
else {
|
|
6340
|
+
/**
|
|
6341
|
+
* NOTE:
|
|
6342
|
+
* 1. microAppWindow will not be recreated
|
|
6343
|
+
* 2. the properties of microAppWindow may be recreated, such as document
|
|
6344
|
+
* 3. the variables added to microAppWindow may be cleared
|
|
6345
|
+
*/
|
|
6346
|
+
microAppWindow.stop();
|
|
6347
|
+
cb(resolve);
|
|
6348
|
+
}
|
|
6253
6349
|
}
|
|
6254
|
-
|
|
6255
|
-
|
|
6256
|
-
* microAppWindow.document rebuild
|
|
6257
|
-
*/
|
|
6258
|
-
microAppWindow.stop();
|
|
6259
|
-
cb(resolve);
|
|
6350
|
+
catch (e) {
|
|
6351
|
+
iframeLocationReady();
|
|
6260
6352
|
}
|
|
6261
6353
|
}, 0);
|
|
6262
6354
|
})();
|
|
@@ -6282,12 +6374,9 @@ class IframeSandbox {
|
|
|
6282
6374
|
this.updateIframeBase();
|
|
6283
6375
|
this.microHead.appendChild(this.baseElement);
|
|
6284
6376
|
}
|
|
6285
|
-
|
|
6286
|
-
this.proxyLocation = createMicroLocation(appName, url, microAppWindow, childStaticLocation, browserHost, childHost);
|
|
6287
|
-
}
|
|
6288
|
-
createProxyWindow(appName, microAppWindow) {
|
|
6377
|
+
createProxyWindow(microAppWindow) {
|
|
6289
6378
|
const rawWindow = globalEnv.rawWindow;
|
|
6290
|
-
|
|
6379
|
+
return new Proxy(microAppWindow, {
|
|
6291
6380
|
get: (target, key) => {
|
|
6292
6381
|
if (key === 'location') {
|
|
6293
6382
|
return this.proxyLocation;
|
|
@@ -6298,20 +6387,18 @@ class IframeSandbox {
|
|
|
6298
6387
|
return bindFunctionToRawTarget(Reflect.get(target, key), target);
|
|
6299
6388
|
},
|
|
6300
6389
|
set: (target, key, value) => {
|
|
6301
|
-
|
|
6302
|
-
|
|
6303
|
-
|
|
6304
|
-
|
|
6305
|
-
|
|
6306
|
-
|
|
6307
|
-
|
|
6308
|
-
|
|
6309
|
-
|
|
6310
|
-
|
|
6311
|
-
|
|
6312
|
-
|
|
6313
|
-
Reflect.set(rawWindow, key, value);
|
|
6314
|
-
}
|
|
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);
|
|
6315
6402
|
}
|
|
6316
6403
|
return true;
|
|
6317
6404
|
},
|
|
@@ -6640,7 +6727,7 @@ class CreateApp {
|
|
|
6640
6727
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6641
6728
|
}
|
|
6642
6729
|
catch (e) {
|
|
6643
|
-
logError('An error occurred in
|
|
6730
|
+
logError('An error occurred in window.mount \n', this.name, e);
|
|
6644
6731
|
}
|
|
6645
6732
|
}
|
|
6646
6733
|
else if (isFinished === true) {
|
|
@@ -6655,7 +6742,7 @@ class CreateApp {
|
|
|
6655
6742
|
this.handleMounted(this.umdHookMount(microApp.getData(this.name, true)));
|
|
6656
6743
|
}
|
|
6657
6744
|
catch (e) {
|
|
6658
|
-
logError('An error occurred in
|
|
6745
|
+
logError('An error occurred in window.mount \n', this.name, e);
|
|
6659
6746
|
}
|
|
6660
6747
|
}
|
|
6661
6748
|
}
|
|
@@ -6673,7 +6760,7 @@ class CreateApp {
|
|
|
6673
6760
|
if (isPromise(umdHookMountResult)) {
|
|
6674
6761
|
umdHookMountResult
|
|
6675
6762
|
.then(() => this.dispatchMountedEvent())
|
|
6676
|
-
.catch((
|
|
6763
|
+
.catch(() => this.dispatchMountedEvent());
|
|
6677
6764
|
}
|
|
6678
6765
|
else {
|
|
6679
6766
|
this.dispatchMountedEvent();
|
|
@@ -6701,7 +6788,8 @@ class CreateApp {
|
|
|
6701
6788
|
}
|
|
6702
6789
|
/**
|
|
6703
6790
|
* unmount app
|
|
6704
|
-
* NOTE:
|
|
6791
|
+
* NOTE:
|
|
6792
|
+
* 1. do not add any params on account of unmountApp
|
|
6705
6793
|
* @param destroy completely destroy, delete cache resources
|
|
6706
6794
|
* @param clearData clear data of dateCenter
|
|
6707
6795
|
* @param keepRouteState keep route state when unmount, default is false
|
|
@@ -6711,33 +6799,35 @@ class CreateApp {
|
|
|
6711
6799
|
var _a;
|
|
6712
6800
|
destroy = destroy || this.state === appStates.LOAD_FAILED;
|
|
6713
6801
|
this.setAppState(appStates.UNMOUNT);
|
|
6714
|
-
// result of unmount function
|
|
6715
6802
|
let umdHookUnmountResult = null;
|
|
6716
|
-
/**
|
|
6717
|
-
* send an unmount event to the micro app or call umd unmount hook
|
|
6718
|
-
* before the sandbox is cleared
|
|
6719
|
-
*/
|
|
6720
6803
|
try {
|
|
6804
|
+
// call umd unmount hook before the sandbox is cleared
|
|
6721
6805
|
umdHookUnmountResult = (_a = this.umdHookUnmount) === null || _a === void 0 ? void 0 : _a.call(this, microApp.getData(this.name, true));
|
|
6722
6806
|
}
|
|
6723
6807
|
catch (e) {
|
|
6724
|
-
logError('An error occurred in
|
|
6808
|
+
logError('An error occurred in window.unmount \n', this.name, e);
|
|
6725
6809
|
}
|
|
6726
6810
|
// dispatch unmount event to micro app
|
|
6727
6811
|
dispatchCustomEventToMicroApp(this, 'unmount');
|
|
6728
6812
|
// call window.onunmount of child app
|
|
6729
6813
|
execMicroAppGlobalHook(this.getMicroAppGlobalHook(microGlobalEvent.ONUNMOUNT), this.name, microGlobalEvent.ONUNMOUNT);
|
|
6730
|
-
this.handleUnmounted(
|
|
6814
|
+
this.handleUnmounted({
|
|
6815
|
+
destroy,
|
|
6816
|
+
clearData,
|
|
6817
|
+
keepRouteState,
|
|
6818
|
+
unmountcb,
|
|
6819
|
+
umdHookUnmountResult,
|
|
6820
|
+
});
|
|
6731
6821
|
}
|
|
6732
6822
|
/**
|
|
6733
6823
|
* handle for promise umdHookUnmount
|
|
6734
6824
|
* @param destroy completely destroy, delete cache resources
|
|
6735
6825
|
* @param clearData clear data of dateCenter
|
|
6736
6826
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6737
|
-
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6738
6827
|
* @param unmountcb callback of unmount
|
|
6828
|
+
* @param umdHookUnmountResult result of umdHookUnmount
|
|
6739
6829
|
*/
|
|
6740
|
-
handleUnmounted(destroy, clearData, keepRouteState, umdHookUnmountResult,
|
|
6830
|
+
handleUnmounted({ destroy, clearData, keepRouteState, unmountcb, umdHookUnmountResult, }) {
|
|
6741
6831
|
const nextAction = () => this.actionsForUnmount({
|
|
6742
6832
|
destroy,
|
|
6743
6833
|
clearData,
|
|
@@ -6745,6 +6835,8 @@ class CreateApp {
|
|
|
6745
6835
|
unmountcb,
|
|
6746
6836
|
});
|
|
6747
6837
|
if (isPromise(umdHookUnmountResult)) {
|
|
6838
|
+
// async window.unmount will cause appName bind error in nest app
|
|
6839
|
+
removeDomScope();
|
|
6748
6840
|
umdHookUnmountResult.then(nextAction).catch(nextAction);
|
|
6749
6841
|
}
|
|
6750
6842
|
else {
|
|
@@ -6758,7 +6850,7 @@ class CreateApp {
|
|
|
6758
6850
|
* @param keepRouteState keep route state when unmount, default is false
|
|
6759
6851
|
* @param unmountcb callback of unmount
|
|
6760
6852
|
*/
|
|
6761
|
-
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb }) {
|
|
6853
|
+
actionsForUnmount({ destroy, clearData, keepRouteState, unmountcb, }) {
|
|
6762
6854
|
var _a;
|
|
6763
6855
|
if (this.umdMode && this.container && !destroy) {
|
|
6764
6856
|
cloneContainer(this.container, this.source.html, false);
|
|
@@ -6775,9 +6867,6 @@ class CreateApp {
|
|
|
6775
6867
|
destroy,
|
|
6776
6868
|
clearData: clearData || destroy,
|
|
6777
6869
|
});
|
|
6778
|
-
if (!getActiveApps().length) {
|
|
6779
|
-
releasePatchSetAttribute();
|
|
6780
|
-
}
|
|
6781
6870
|
// dispatch unmount event to base app
|
|
6782
6871
|
dispatchLifecyclesEvent(this.container, this.name, lifeCycles.UNMOUNT);
|
|
6783
6872
|
this.clearOptions(destroy);
|
|
@@ -6794,6 +6883,7 @@ class CreateApp {
|
|
|
6794
6883
|
this.sandBox = null;
|
|
6795
6884
|
if (destroy)
|
|
6796
6885
|
this.actionsForCompletelyDestroy();
|
|
6886
|
+
removeDomScope();
|
|
6797
6887
|
}
|
|
6798
6888
|
// actions for completely destroy
|
|
6799
6889
|
actionsForCompletelyDestroy() {
|
|
@@ -6903,8 +6993,8 @@ class CreateApp {
|
|
|
6903
6993
|
return {};
|
|
6904
6994
|
}
|
|
6905
6995
|
getMicroAppGlobalHook(eventName) {
|
|
6906
|
-
var _a;
|
|
6907
|
-
const listener = ((_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow)[eventName];
|
|
6996
|
+
var _a, _b;
|
|
6997
|
+
const listener = (_b = (_a = this.sandBox) === null || _a === void 0 ? void 0 : _a.proxyWindow) === null || _b === void 0 ? void 0 : _b[eventName];
|
|
6908
6998
|
return isFunction(listener) ? listener : null;
|
|
6909
6999
|
}
|
|
6910
7000
|
querySelector(selectors) {
|
|
@@ -6927,7 +7017,7 @@ function isIframeSandbox(appName) {
|
|
|
6927
7017
|
function defineElement(tagName) {
|
|
6928
7018
|
class MicroAppElement extends HTMLElement {
|
|
6929
7019
|
constructor() {
|
|
6930
|
-
super();
|
|
7020
|
+
super(...arguments);
|
|
6931
7021
|
this.isWaiting = false;
|
|
6932
7022
|
this.cacheData = null;
|
|
6933
7023
|
this.connectedCount = 0;
|
|
@@ -6979,8 +7069,6 @@ function defineElement(tagName) {
|
|
|
6979
7069
|
this.setAttribute('name', this.appName);
|
|
6980
7070
|
}
|
|
6981
7071
|
};
|
|
6982
|
-
// patchSetAttribute hijiack data attribute, it needs exec first
|
|
6983
|
-
patchSetAttribute();
|
|
6984
7072
|
}
|
|
6985
7073
|
static get observedAttributes() {
|
|
6986
7074
|
return ['name', 'url'];
|
|
@@ -7249,6 +7337,7 @@ function defineElement(tagName) {
|
|
|
7249
7337
|
*/
|
|
7250
7338
|
handleAppMount(app) {
|
|
7251
7339
|
app.isPrefetch = false;
|
|
7340
|
+
// TODO: Can defer be removed?
|
|
7252
7341
|
defer(() => this.mount(app));
|
|
7253
7342
|
}
|
|
7254
7343
|
/**
|
|
@@ -7390,6 +7479,30 @@ function defineElement(tagName) {
|
|
|
7390
7479
|
this.getAttribute('defaultPage') ||
|
|
7391
7480
|
'');
|
|
7392
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
|
+
}
|
|
7393
7506
|
/**
|
|
7394
7507
|
* Data from the base application
|
|
7395
7508
|
*/
|