@micro-zoe/micro-app 1.0.0-beta.1 → 1.0.0-beta.2

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