@micro-zoe/micro-app 0.8.1 → 0.8.5

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/README.md CHANGED
@@ -152,7 +152,7 @@ For more commands, see [DEVELP](https://github.com/micro-zoe/micro-app/blob/mast
152
152
  </details>
153
153
 
154
154
  # Contributors
155
- <a href="https://github.com/micro-zoe/micro-app/graphs/contributors"><img src="./.github/contributors.svg" /></a>
155
+ <a href="https://github.com/micro-zoe/micro-app/graphs/contributors"><img src="https://micro-zoe.com/contributors.svg?height=55&people=11" /></a>
156
156
  <!-- opencollective is inaccurate -->
157
157
  <!-- <a href="https://github.com/micro-zoe/micro-app/graphs/contributors"><img src="https://opencollective.com/micro-app/contributors.svg?width=890&button=false" /></a> -->
158
158
 
package/README.zh-cn.md CHANGED
@@ -153,7 +153,7 @@ yarn start # 访问 http://localhost:3000
153
153
  </details>
154
154
 
155
155
  # 贡献者们
156
- <a href="https://github.com/micro-zoe/micro-app/graphs/contributors"><img src="./.github/contributors.svg" /></a>
156
+ <a href="https://github.com/micro-zoe/micro-app/graphs/contributors"><img src="https://micro-zoe.com/contributors.svg?height=55&people=11" /></a>
157
157
  <!-- opencollective is inaccurate -->
158
158
  <!-- <a href="https://github.com/micro-zoe/micro-app/graphs/contributors"><img src="https://opencollective.com/micro-app/contributors.svg?width=890&button=false" /></a> -->
159
159
 
package/lib/index.d.ts CHANGED
@@ -190,6 +190,7 @@ declare module '@micro-zoe/micro-app/libs/utils' {
190
190
  * trim start & end
191
191
  */
192
192
  export function trim(str: string): string;
193
+ export function isFireFox(): boolean;
193
194
  }
194
195
 
195
196
  declare module '@micro-zoe/micro-app/interact' {
package/lib/index.esm.js CHANGED
@@ -1,4 +1,4 @@
1
- const version = '0.8.1';
1
+ const version = '0.8.5';
2
2
  // do not use isUndefined
3
3
  const isBrowser = typeof window !== 'undefined';
4
4
  // do not use isUndefined
@@ -224,7 +224,7 @@ const requestIdleCallback = globalThis.requestIdleCallback ||
224
224
  return Math.max(0, 50 - (Date.now() - lastTime));
225
225
  },
226
226
  });
227
- }, 1);
227
+ }, 50);
228
228
  };
229
229
  /**
230
230
  * Record the currently running app.name
@@ -303,6 +303,9 @@ function getRootContainer(target) {
303
303
  function trim(str) {
304
304
  return str ? str.replace(/^\s+|\s+$/g, '') : '';
305
305
  }
306
+ function isFireFox() {
307
+ return navigator.userAgent.indexOf('Firefox') > -1;
308
+ }
306
309
 
307
310
  var ObservedAttrName;
308
311
  (function (ObservedAttrName) {
@@ -359,9 +362,8 @@ function fetchSource(url, appName = null, options = {}) {
359
362
  // common reg
360
363
  const rootSelectorREG = /(^|\s+)(html|:root)(?=[\s>~[.#:]+|$)/;
361
364
  const bodySelectorREG = /(^|\s+)((html[\s>~]+body)|body)(?=[\s>~[.#:]+|$)/;
362
- const cssUrlREG = /url\(["']?([^)"']+)["']?\)/gm;
363
365
  function parseError(msg, linkPath) {
364
- msg = linkPath ? `${linkPath}:${msg}` : msg;
366
+ msg = linkPath ? `${linkPath} ${msg}` : msg;
365
367
  const err = new Error(msg);
366
368
  err.reason = msg;
367
369
  if (linkPath) {
@@ -370,7 +372,7 @@ function parseError(msg, linkPath) {
370
372
  throw err;
371
373
  }
372
374
  /**
373
- * Reference resources https://github.com/reworkcss/css
375
+ * Reference https://github.com/reworkcss/css
374
376
  * CSSParser mainly deals with 3 scenes: styleRule, @, and comment
375
377
  * And scopecss deals with 2 scenes: selector & url
376
378
  * And can also disable scopecss with inline comments
@@ -404,7 +406,7 @@ class CSSParser {
404
406
  this.baseURI = baseURI;
405
407
  this.linkPath = linkPath || '';
406
408
  this.matchRules();
407
- return this.result;
409
+ return isFireFox() ? decodeURIComponent(this.result) : this.result;
408
410
  }
409
411
  reset() {
410
412
  this.cssText = this.prefix = this.baseURI = this.linkPath = this.result = '';
@@ -423,92 +425,76 @@ class CSSParser {
423
425
  }
424
426
  // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleRule
425
427
  matchStyleRule() {
426
- const selectorList = this.formatSelector();
428
+ const selectors = this.formatSelector(true);
427
429
  // reset scopecssDisableNextLine
428
430
  this.scopecssDisableNextLine = false;
429
- if (!selectorList)
431
+ if (!selectors)
430
432
  return parseError('selector missing', this.linkPath);
431
- this.result += selectorList.join(', ');
433
+ this.recordResult(selectors);
432
434
  this.matchComments();
433
435
  this.styleDeclarations();
434
436
  this.matchLeadingSpaces();
435
437
  return true;
436
438
  }
439
+ formatSelector(skip) {
440
+ const m = this.commonMatch(/^([^{]+)/, skip);
441
+ if (!m)
442
+ return false;
443
+ return m[0].replace(/(^|,[\n\s]*)([^,]+)/g, (_, separator, selector) => {
444
+ selector = trim(selector);
445
+ if (!(this.scopecssDisableNextLine ||
446
+ (this.scopecssDisable && (!this.scopecssDisableSelectors.length ||
447
+ this.scopecssDisableSelectors.includes(selector))) ||
448
+ rootSelectorREG.test(selector))) {
449
+ if (bodySelectorREG.test(selector)) {
450
+ selector = selector.replace(bodySelectorREG, this.prefix + ' micro-app-body');
451
+ }
452
+ else {
453
+ selector = this.prefix + ' ' + selector;
454
+ }
455
+ }
456
+ return separator + selector;
457
+ });
458
+ }
437
459
  // https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration
438
460
  styleDeclarations() {
439
461
  if (!this.matchOpenBrace())
440
462
  return parseError("Declaration missing '{'", this.linkPath);
441
- this.matchComments();
442
- while (this.styleDeclaration()) {
443
- this.matchComments();
444
- }
463
+ this.matchAllDeclarations();
445
464
  if (!this.matchCloseBrace())
446
465
  return parseError("Declaration missing '}'", this.linkPath);
447
466
  return true;
448
467
  }
449
- // match one styleDeclaration at a time
450
- styleDeclaration() {
451
- // css property
452
- if (!this.commonMatch(/^(\*?[-#+\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/))
453
- return false;
454
- // match :
455
- if (!this.commonMatch(/^:\s*/))
456
- return parseError("property missing ':'", this.linkPath);
457
- // match css value
458
- const r = this.commonMatch(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/, true);
459
- let cssValue = r ? r[0] : '';
460
- if (!this.scopecssDisableNextLine &&
461
- (!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
462
- cssValue = cssValue.replace(cssUrlREG, (all, $1) => {
463
- if (/^((data|blob):|#)/.test($1) || /^(https?:)?\/\//.test($1)) {
464
- return all;
465
- }
466
- // ./a/b.png ../a/b.png a/b.png
467
- if (/^((\.\.?\/)|[^/])/.test($1) && this.linkPath) {
468
- this.baseURI = getLinkFileDir(this.linkPath);
469
- }
470
- return `url("${CompletionPath($1, this.baseURI)}")`;
471
- });
468
+ matchAllDeclarations() {
469
+ let cssValue = this.commonMatch(/^(?:url\(["']?(?:[^)"'}]+)["']?\)|[^}/])*/, true)[0];
470
+ if (cssValue) {
471
+ if (!this.scopecssDisableNextLine &&
472
+ (!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
473
+ cssValue = cssValue.replace(/url\(["']?([^)"']+)["']?\)/gm, (all, $1) => {
474
+ if (/^((data|blob):|#)/.test($1) || /^(https?:)?\/\//.test($1)) {
475
+ return all;
476
+ }
477
+ // ./a/b.png ../a/b.png a/b.png
478
+ if (/^((\.\.?\/)|[^/])/.test($1) && this.linkPath) {
479
+ this.baseURI = getLinkFileDir(this.linkPath);
480
+ }
481
+ return `url("${CompletionPath($1, this.baseURI)}")`;
482
+ });
483
+ }
484
+ this.recordResult(cssValue);
472
485
  }
473
486
  // reset scopecssDisableNextLine
474
487
  this.scopecssDisableNextLine = false;
475
- this.result += cssValue;
476
- this.matchLeadingSpaces();
477
- this.commonMatch(/^[;\s]*/);
478
- return true;
479
- }
480
- formatSelector() {
481
- const m = this.commonMatch(/^([^{]+)/, true);
482
- if (!m)
483
- return false;
484
- return trim(m[0])
485
- .replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, '')
486
- .replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, (r) => {
487
- return r.replace(/,/g, '\u200C');
488
- })
489
- .split(/\s*(?![^(]*\)),\s*/)
490
- .map((s) => {
491
- const selectorText = s.replace(/\u200C/g, ',');
492
- if (this.scopecssDisableNextLine) {
493
- return selectorText;
494
- }
495
- else if (this.scopecssDisable) {
496
- if (!this.scopecssDisableSelectors.length ||
497
- this.scopecssDisableSelectors.includes(selectorText)) {
498
- return selectorText;
499
- }
500
- }
501
- if (selectorText === '*') {
502
- return this.prefix + ' *';
503
- }
504
- else if (bodySelectorREG.test(selectorText)) {
505
- return selectorText.replace(bodySelectorREG, this.prefix + ' micro-app-body');
506
- }
507
- else if (rootSelectorREG.test(selectorText)) { // ignore root selector
508
- return selectorText;
509
- }
510
- return this.prefix + ' ' + selectorText;
511
- });
488
+ if (!this.cssText || this.cssText.charAt(0) === '}')
489
+ return;
490
+ // extract comments in declarations
491
+ if (this.cssText.charAt(0) === '/' && this.cssText.charAt(1) === '*') {
492
+ this.matchComments();
493
+ }
494
+ else {
495
+ this.commonMatch(/\/+/);
496
+ }
497
+ return this.matchAllDeclarations();
512
498
  }
513
499
  matchAtRule() {
514
500
  if (this.cssText[0] !== '@')
@@ -569,7 +555,7 @@ class CSSParser {
569
555
  pageRule() {
570
556
  if (!this.commonMatch(/^@page */))
571
557
  return false;
572
- this.formatSelector();
558
+ this.formatSelector(false);
573
559
  // reset scopecssDisableNextLine
574
560
  this.scopecssDisableNextLine = false;
575
561
  return this.commonHandlerForAtRuleWithSelfRule('page');
@@ -602,17 +588,14 @@ class CSSParser {
602
588
  if (!this.commonMatch(reg))
603
589
  return false;
604
590
  this.matchLeadingSpaces();
605
- return false;
591
+ return true;
606
592
  };
607
593
  }
608
594
  // common handler for @font-face, @page
609
595
  commonHandlerForAtRuleWithSelfRule(name) {
610
596
  if (!this.matchOpenBrace())
611
597
  return parseError(`@${name} missing '{'`, this.linkPath);
612
- this.matchComments();
613
- while (this.styleDeclaration()) {
614
- this.matchComments();
615
- }
598
+ this.matchAllDeclarations();
616
599
  if (!this.matchCloseBrace())
617
600
  return parseError(`@${name} missing '}'`, this.linkPath);
618
601
  this.matchLeadingSpaces();
@@ -638,7 +621,7 @@ class CSSParser {
638
621
  }
639
622
  // get comment content
640
623
  let commentText = this.cssText.slice(2, i - 2);
641
- this.result += `/*${commentText}*/`;
624
+ this.recordResult(`/*${commentText}*/`);
642
625
  commentText = trim(commentText.replace(/^\s*!/, ''));
643
626
  // set ignore config
644
627
  if (commentText === 'scopecss-disable-next-line') {
@@ -671,7 +654,7 @@ class CSSParser {
671
654
  const matchStr = matchArray[0];
672
655
  this.cssText = this.cssText.slice(matchStr.length);
673
656
  if (!skip)
674
- this.result += matchStr;
657
+ this.recordResult(matchStr);
675
658
  return matchArray;
676
659
  }
677
660
  matchOpenBrace() {
@@ -684,6 +667,16 @@ class CSSParser {
684
667
  matchLeadingSpaces() {
685
668
  this.commonMatch(/^\s*/);
686
669
  }
670
+ // splice string
671
+ recordResult(strFragment) {
672
+ // Firefox is slow when string contain special characters, see https://github.com/micro-zoe/micro-app/issues/256
673
+ if (isFireFox()) {
674
+ this.result += encodeURIComponent(strFragment);
675
+ }
676
+ else {
677
+ this.result += strFragment;
678
+ }
679
+ }
687
680
  }
688
681
  /**
689
682
  * common method of bind CSS
@@ -698,7 +691,7 @@ function commonAction(styleElement, appName, prefix, baseURI, linkPath) {
698
691
  }
699
692
  catch (e) {
700
693
  parser.reset();
701
- logError('CSSParser: An error occurred while parsing CSS', appName, e);
694
+ logError('An error occurred while parsing CSS:\n', appName, e);
702
695
  }
703
696
  if (result)
704
697
  styleElement.textContent = result;
@@ -834,11 +827,9 @@ function extractLinkFromHtml(link, parent, app, isDynamic = false) {
834
827
  */
835
828
  function fetchLinksFromHtml(wrapElement, app, microAppHead) {
836
829
  const linkEntries = Array.from(app.source.links.entries());
837
- const fetchLinkPromise = [];
838
- for (const [url] of linkEntries) {
839
- const globalLinkCode = globalLinks.get(url);
840
- globalLinkCode ? fetchLinkPromise.push(globalLinkCode) : fetchLinkPromise.push(fetchSource(url, app.name));
841
- }
830
+ const fetchLinkPromise = linkEntries.map(([url]) => {
831
+ return globalLinks.has(url) ? globalLinks.get(url) : fetchSource(url, app.name);
832
+ });
842
833
  promiseStream(fetchLinkPromise, (res) => {
843
834
  fetchLinkSuccess(linkEntries[res.index][0], linkEntries[res.index][1], res.data, microAppHead, app);
844
835
  }, (err) => {
@@ -1115,6 +1106,27 @@ function patchElementPrototypeMethods() {
1115
1106
  this.__MICRO_APP_NAME__ && (clonedNode.__MICRO_APP_NAME__ = this.__MICRO_APP_NAME__);
1116
1107
  return clonedNode;
1117
1108
  };
1109
+ // patch getBoundingClientRect
1110
+ // TODO: scenes test
1111
+ // Element.prototype.getBoundingClientRect = function getBoundingClientRect () {
1112
+ // const rawRect: DOMRect = globalEnv.rawGetBoundingClientRect.call(this)
1113
+ // if (this.__MICRO_APP_NAME__) {
1114
+ // const app = appInstanceMap.get(this.__MICRO_APP_NAME__)
1115
+ // if (!app?.container) {
1116
+ // return rawRect
1117
+ // }
1118
+ // const appBody = app.container.querySelector('micro-app-body')
1119
+ // const appBodyRect: DOMRect = globalEnv.rawGetBoundingClientRect.call(appBody)
1120
+ // const computedRect: DOMRect = new DOMRect(
1121
+ // rawRect.x - appBodyRect.x,
1122
+ // rawRect.y - appBodyRect.y,
1123
+ // rawRect.width,
1124
+ // rawRect.height,
1125
+ // )
1126
+ // return computedRect
1127
+ // }
1128
+ // return rawRect
1129
+ // }
1118
1130
  }
1119
1131
  /**
1120
1132
  * Mark the newly created element in the micro application
@@ -1281,6 +1293,7 @@ function releasePatches() {
1281
1293
  Element.prototype.append = globalEnv.rawAppend;
1282
1294
  Element.prototype.prepend = globalEnv.rawPrepend;
1283
1295
  Element.prototype.cloneNode = globalEnv.rawCloneNode;
1296
+ // Element.prototype.getBoundingClientRect = globalEnv.rawGetBoundingClientRect
1284
1297
  }
1285
1298
  // Set the style of micro-app-head and micro-app-body
1286
1299
  let hasRejectMicroAppStyle = false;
@@ -1334,6 +1347,7 @@ function initGlobalEnv() {
1334
1347
  const rawAppend = Element.prototype.append;
1335
1348
  const rawPrepend = Element.prototype.prepend;
1336
1349
  const rawCloneNode = Element.prototype.cloneNode;
1350
+ // const rawGetBoundingClientRect = Element.prototype.getBoundingClientRect
1337
1351
  const rawCreateElement = Document.prototype.createElement;
1338
1352
  const rawCreateElementNS = Document.prototype.createElementNS;
1339
1353
  const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
@@ -1377,6 +1391,7 @@ function initGlobalEnv() {
1377
1391
  rawAppend,
1378
1392
  rawPrepend,
1379
1393
  rawCloneNode,
1394
+ // rawGetBoundingClientRect,
1380
1395
  rawCreateElement,
1381
1396
  rawCreateElementNS,
1382
1397
  rawCreateDocumentFragment,
@@ -1497,7 +1512,7 @@ function fetchScriptsFromHtml(wrapElement, app) {
1497
1512
  if (globalScriptText) {
1498
1513
  info.code = globalScriptText;
1499
1514
  }
1500
- else if (!info.defer && !info.async) {
1515
+ else if ((!info.defer && !info.async) || app.isPrefetch) {
1501
1516
  fetchScriptPromise.push(fetchSource(url, app.name));
1502
1517
  fetchScriptPromiseInfo.push([url, info]);
1503
1518
  }
@@ -1590,7 +1605,7 @@ function execScripts(scriptList, app, initHook) {
1590
1605
  function runScript(url, app, info, isDynamic, callback) {
1591
1606
  var _a;
1592
1607
  try {
1593
- const code = bindScope(url, app, info.code, info.module);
1608
+ const code = bindScope(url, app, info.code, info);
1594
1609
  if (app.inline || info.module) {
1595
1610
  const scriptElement = pureCreateElement('script');
1596
1611
  runCode2InlineScript(url, code, info.module, scriptElement, callback);
@@ -1643,7 +1658,7 @@ function runDynamicRemoteScript(url, info, app, originScript) {
1643
1658
  app.source.scripts.set(url, info);
1644
1659
  info.isGlobal && globalScripts.set(url, code);
1645
1660
  try {
1646
- code = bindScope(url, app, code, info.module);
1661
+ code = bindScope(url, app, code, info);
1647
1662
  if (app.inline || info.module) {
1648
1663
  runCode2InlineScript(url, code, info.module, replaceElement, dispatchScriptOnLoadEvent);
1649
1664
  }
@@ -1699,13 +1714,13 @@ function runCode2Function(code, info) {
1699
1714
  * @param url script address
1700
1715
  * @param app app
1701
1716
  * @param code code
1702
- * @param module type='module' of script
1717
+ * @param info source script info
1703
1718
  */
1704
- function bindScope(url, app, code, module) {
1719
+ function bindScope(url, app, code, info) {
1705
1720
  if (isPlainObject(microApp.plugins)) {
1706
- code = usePlugins(url, code, app.name, microApp.plugins);
1721
+ code = usePlugins(url, code, app.name, microApp.plugins, info);
1707
1722
  }
1708
- if (app.sandBox && !module) {
1723
+ if (app.sandBox && !info.module) {
1709
1724
  globalEnv.rawWindow.__MICRO_APP_PROXY_WINDOW__ = app.sandBox.proxyWindow;
1710
1725
  return `;(function(proxyWindow){with(proxyWindow.__MICRO_APP_WINDOW__){(function(${globalKeyToBeCached}){;${code}\n}).call(proxyWindow,${globalKeyToBeCached})}})(window.__MICRO_APP_PROXY_WINDOW__);`;
1711
1726
  }
@@ -1717,19 +1732,20 @@ function bindScope(url, app, code, module) {
1717
1732
  * @param code code
1718
1733
  * @param appName app name
1719
1734
  * @param plugins plugin list
1735
+ * @param info source script info
1720
1736
  */
1721
- function usePlugins(url, code, appName, plugins) {
1737
+ function usePlugins(url, code, appName, plugins, info) {
1722
1738
  var _a;
1723
- const newCode = processCode(plugins.global, code, url);
1724
- return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, url);
1739
+ const newCode = processCode(plugins.global, code, url, info);
1740
+ return processCode((_a = plugins.modules) === null || _a === void 0 ? void 0 : _a[appName], newCode, url, info);
1725
1741
  }
1726
- function processCode(configs, code, url) {
1742
+ function processCode(configs, code, url, info) {
1727
1743
  if (!isArray(configs)) {
1728
1744
  return code;
1729
1745
  }
1730
1746
  return configs.reduce((preCode, config) => {
1731
1747
  if (isPlainObject(config) && isFunction(config.loader)) {
1732
- return config.loader(preCode, url, config.options);
1748
+ return config.loader(preCode, url, config.options, info);
1733
1749
  }
1734
1750
  return preCode;
1735
1751
  }, code);
@@ -2432,8 +2448,11 @@ const escapeSetterKeyList = [
2432
2448
  const globalPropertyList = ['window', 'self', 'globalThis'];
2433
2449
  class SandBox {
2434
2450
  constructor(appName, url) {
2435
- // Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
2436
- this.scopeProperties = ['webpackJsonp'];
2451
+ /**
2452
+ * Scoped global Properties(Properties that can only get and set in microAppWindow, will not escape to rawWindow)
2453
+ * https://github.com/micro-zoe/micro-app/issues/234
2454
+ */
2455
+ this.scopeProperties = ['webpackJsonp', 'Vue'];
2437
2456
  // Properties that can be escape to rawWindow
2438
2457
  this.escapeProperties = [];
2439
2458
  // Properties newly added to microAppWindow
@@ -2631,10 +2650,12 @@ class SandBox {
2631
2650
  microAppWindow.__MICRO_APP_NAME__ = appName;
2632
2651
  microAppWindow.__MICRO_APP_PUBLIC_PATH__ = getEffectivePath(url);
2633
2652
  microAppWindow.__MICRO_APP_WINDOW__ = microAppWindow;
2634
- microAppWindow.microApp = new EventCenterForMicroApp(appName);
2653
+ microAppWindow.microApp = Object.assign(new EventCenterForMicroApp(appName), {
2654
+ removeDomScope,
2655
+ pureCreateElement,
2656
+ });
2635
2657
  microAppWindow.rawWindow = globalEnv.rawWindow;
2636
2658
  microAppWindow.rawDocument = globalEnv.rawDocument;
2637
- microAppWindow.removeDomScope = removeDomScope;
2638
2659
  microAppWindow.hasOwnProperty = (key) => rawHasOwnProperty.call(microAppWindow, key) || rawHasOwnProperty.call(globalEnv.rawWindow, key);
2639
2660
  this.setMappingPropertiesWithRawDescriptor(microAppWindow);
2640
2661
  this.setHijackProperties(microAppWindow, appName);
@@ -2779,6 +2800,7 @@ class CreateApp {
2779
2800
  this.libraryName = null;
2780
2801
  this.umdMode = false;
2781
2802
  this.isPrefetch = false;
2803
+ this.prefetchResolve = null;
2782
2804
  this.container = null;
2783
2805
  this.baseroute = '';
2784
2806
  this.sandBox = null;
@@ -2807,12 +2829,17 @@ class CreateApp {
2807
2829
  * When resource is loaded, mount app if it is not prefetch or unmount
2808
2830
  */
2809
2831
  onLoad(html) {
2832
+ var _a;
2810
2833
  if (++this.loadSourceLevel === 2) {
2811
2834
  this.source.html = html;
2812
- if (this.isPrefetch || appStates.UNMOUNT === this.state)
2813
- return;
2814
- this.state = appStates.LOAD_SOURCE_FINISHED;
2815
- this.mount();
2835
+ if (this.isPrefetch) {
2836
+ (_a = this.prefetchResolve) === null || _a === void 0 ? void 0 : _a.call(this);
2837
+ this.prefetchResolve = null;
2838
+ }
2839
+ else if (appStates.UNMOUNT !== this.state) {
2840
+ this.state = appStates.LOAD_SOURCE_FINISHED;
2841
+ this.mount();
2842
+ }
2816
2843
  }
2817
2844
  }
2818
2845
  /**
@@ -2821,6 +2848,10 @@ class CreateApp {
2821
2848
  */
2822
2849
  onLoadError(e) {
2823
2850
  this.loadSourceLevel = -1;
2851
+ if (this.prefetchResolve) {
2852
+ this.prefetchResolve();
2853
+ this.prefetchResolve = null;
2854
+ }
2824
2855
  if (appStates.UNMOUNT !== this.state) {
2825
2856
  this.onerror(e);
2826
2857
  this.state = appStates.LOAD_SOURCE_ERROR;
@@ -3406,21 +3437,6 @@ function defineElement(tagName) {
3406
3437
  window.customElements.define(tagName, MicroAppElement);
3407
3438
  }
3408
3439
 
3409
- function filterPreFetchTarget(apps) {
3410
- const validApps = [];
3411
- if (isArray(apps)) {
3412
- apps.forEach((item) => {
3413
- if (isPlainObject(item)) {
3414
- item.name = formatAppName(item.name);
3415
- item.url = formatAppURL(item.url, item.name);
3416
- if (item.name && item.url && !appInstanceMap.has(item.name)) {
3417
- validApps.push(item);
3418
- }
3419
- }
3420
- });
3421
- }
3422
- return validApps;
3423
- }
3424
3440
  /**
3425
3441
  * preFetch([
3426
3442
  * {
@@ -3442,16 +3458,37 @@ function preFetch(apps) {
3442
3458
  }
3443
3459
  requestIdleCallback(() => {
3444
3460
  isFunction(apps) && (apps = apps());
3445
- filterPreFetchTarget(apps).forEach((item) => {
3461
+ if (isArray(apps)) {
3462
+ apps.reduce((pre, next) => pre.then(() => preFetchInSerial(next)), Promise.resolve());
3463
+ }
3464
+ });
3465
+ }
3466
+ // sequential preload app
3467
+ function preFetchInSerial(prefetchApp) {
3468
+ return new Promise((resolve) => {
3469
+ requestIdleCallback(() => {
3446
3470
  var _a, _b;
3447
- const app = new CreateApp({
3448
- name: item.name,
3449
- url: item.url,
3450
- scopecss: !((_a = item.disableScopecss) !== null && _a !== void 0 ? _a : microApp.disableScopecss),
3451
- useSandbox: !((_b = item.disableSandbox) !== null && _b !== void 0 ? _b : microApp.disableSandbox),
3452
- });
3453
- app.isPrefetch = true;
3454
- appInstanceMap.set(item.name, app);
3471
+ if (isPlainObject(prefetchApp) && navigator.onLine) {
3472
+ prefetchApp.name = formatAppName(prefetchApp.name);
3473
+ prefetchApp.url = formatAppURL(prefetchApp.url, prefetchApp.name);
3474
+ if (prefetchApp.name && prefetchApp.url && !appInstanceMap.has(prefetchApp.name)) {
3475
+ const app = new CreateApp({
3476
+ name: prefetchApp.name,
3477
+ url: prefetchApp.url,
3478
+ scopecss: !((_a = prefetchApp.disableScopecss) !== null && _a !== void 0 ? _a : microApp.disableScopecss),
3479
+ useSandbox: !((_b = prefetchApp.disableSandbox) !== null && _b !== void 0 ? _b : microApp.disableSandbox),
3480
+ });
3481
+ app.isPrefetch = true;
3482
+ app.prefetchResolve = resolve;
3483
+ appInstanceMap.set(prefetchApp.name, app);
3484
+ }
3485
+ else {
3486
+ resolve();
3487
+ }
3488
+ }
3489
+ else {
3490
+ resolve();
3491
+ }
3455
3492
  });
3456
3493
  });
3457
3494
  }
@@ -3462,38 +3499,24 @@ function preFetch(apps) {
3462
3499
  function getGlobalAssets(assets) {
3463
3500
  if (isPlainObject(assets)) {
3464
3501
  requestIdleCallback(() => {
3465
- if (isArray(assets.js)) {
3466
- const effectiveJs = assets.js.filter((path) => isString(path) && path.includes('.js') && !globalScripts.has(path));
3467
- const fetchJSPromise = [];
3468
- effectiveJs.forEach((path) => {
3469
- fetchJSPromise.push(fetchSource(path));
3470
- });
3471
- // fetch js with stream
3472
- promiseStream(fetchJSPromise, (res) => {
3473
- const path = effectiveJs[res.index];
3474
- if (!globalScripts.has(path)) {
3475
- globalScripts.set(path, res.data);
3476
- }
3477
- }, (err) => {
3478
- logError(err);
3479
- });
3480
- }
3481
- if (isArray(assets.css)) {
3482
- const effectiveCss = assets.css.filter((path) => isString(path) && path.includes('.css') && !globalLinks.has(path));
3483
- const fetchCssPromise = [];
3484
- effectiveCss.forEach((path) => {
3485
- fetchCssPromise.push(fetchSource(path));
3486
- });
3487
- // fetch css with stream
3488
- promiseStream(fetchCssPromise, (res) => {
3489
- const path = effectiveCss[res.index];
3490
- if (!globalLinks.has(path)) {
3491
- globalLinks.set(path, res.data);
3492
- }
3493
- }, (err) => {
3494
- logError(err);
3495
- });
3502
+ fetchGlobalResources(assets.js, 'js', globalScripts);
3503
+ fetchGlobalResources(assets.css, 'css', globalLinks);
3504
+ });
3505
+ }
3506
+ }
3507
+ // TODO: requestIdleCallback for every file
3508
+ function fetchGlobalResources(resources, suffix, cache) {
3509
+ if (isArray(resources)) {
3510
+ const effectiveResource = resources.filter((path) => isString(path) && path.includes(`.${suffix}`) && !cache.has(path));
3511
+ const fetchResourcePromise = effectiveResource.map((path) => fetchSource(path));
3512
+ // fetch resource with stream
3513
+ promiseStream(fetchResourcePromise, (res) => {
3514
+ const path = effectiveResource[res.index];
3515
+ if (!cache.has(path)) {
3516
+ cache.set(path, res.data);
3496
3517
  }
3518
+ }, (err) => {
3519
+ logError(err);
3497
3520
  });
3498
3521
  }
3499
3522
  }