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

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