@micro-zoe/micro-app 0.7.1 → 0.8.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/lib/index.d.ts +4 -0
- package/lib/index.esm.js +434 -218
- package/lib/index.esm.js.map +1 -1
- package/lib/index.min.js +1 -1
- package/lib/index.min.js.map +1 -1
- package/lib/index.umd.js +1 -1
- package/lib/index.umd.js.map +1 -1
- package/package.json +1 -1
package/lib/index.esm.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
const version = '0.
|
|
1
|
+
const version = '0.8.0';
|
|
2
2
|
// do not use isUndefined
|
|
3
3
|
const isBrowser = typeof window !== 'undefined';
|
|
4
4
|
// do not use isUndefined
|
|
@@ -252,10 +252,6 @@ function getCurrentAppName() {
|
|
|
252
252
|
function removeDomScope() {
|
|
253
253
|
setCurrentAppName(null);
|
|
254
254
|
}
|
|
255
|
-
// is safari browser
|
|
256
|
-
function isSafari() {
|
|
257
|
-
return /Safari/.test(navigator.userAgent) && !/Chrome/.test(navigator.userAgent);
|
|
258
|
-
}
|
|
259
255
|
/**
|
|
260
256
|
* Create pure elements
|
|
261
257
|
*/
|
|
@@ -304,6 +300,12 @@ function isUniqueElement(key) {
|
|
|
304
300
|
function getRootContainer(target) {
|
|
305
301
|
return (isShadowRoot(target) ? target.host : target);
|
|
306
302
|
}
|
|
303
|
+
/**
|
|
304
|
+
* trim start & end
|
|
305
|
+
*/
|
|
306
|
+
function trim(str) {
|
|
307
|
+
return str ? str.replace(/^\s+|\s+$/g, '') : '';
|
|
308
|
+
}
|
|
307
309
|
|
|
308
310
|
var ObservedAttrName;
|
|
309
311
|
(function (ObservedAttrName) {
|
|
@@ -357,221 +359,355 @@ function fetchSource(url, appName = null, options = {}) {
|
|
|
357
359
|
});
|
|
358
360
|
}
|
|
359
361
|
|
|
360
|
-
|
|
361
|
-
|
|
362
|
-
|
|
363
|
-
|
|
364
|
-
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
372
|
-
const rawAppendChild = Element.prototype.appendChild;
|
|
373
|
-
const rawInsertBefore = Element.prototype.insertBefore;
|
|
374
|
-
const rawReplaceChild = Element.prototype.replaceChild;
|
|
375
|
-
const rawRemoveChild = Element.prototype.removeChild;
|
|
376
|
-
const rawAppend = Element.prototype.append;
|
|
377
|
-
const rawPrepend = Element.prototype.prepend;
|
|
378
|
-
const rawCloneNode = Element.prototype.cloneNode;
|
|
379
|
-
const rawCreateElement = Document.prototype.createElement;
|
|
380
|
-
const rawCreateElementNS = Document.prototype.createElementNS;
|
|
381
|
-
const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
|
|
382
|
-
const rawQuerySelector = Document.prototype.querySelector;
|
|
383
|
-
const rawQuerySelectorAll = Document.prototype.querySelectorAll;
|
|
384
|
-
const rawGetElementById = Document.prototype.getElementById;
|
|
385
|
-
const rawGetElementsByClassName = Document.prototype.getElementsByClassName;
|
|
386
|
-
const rawGetElementsByTagName = Document.prototype.getElementsByTagName;
|
|
387
|
-
const rawGetElementsByName = Document.prototype.getElementsByName;
|
|
388
|
-
const ImageProxy = new Proxy(Image, {
|
|
389
|
-
construct(Target, args) {
|
|
390
|
-
const elementImage = new Target(...args);
|
|
391
|
-
elementImage.__MICRO_APP_NAME__ = getCurrentAppName();
|
|
392
|
-
return elementImage;
|
|
393
|
-
},
|
|
394
|
-
});
|
|
395
|
-
const rawWindow = Function('return window')();
|
|
396
|
-
const rawDocument = Function('return document')();
|
|
397
|
-
const supportModuleScript = isSupportModuleScript();
|
|
398
|
-
const templateStyle = rawDocument.body.querySelector('#micro-app-template-style');
|
|
399
|
-
/**
|
|
400
|
-
* save effect raw methods
|
|
401
|
-
* pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
|
|
402
|
-
*/
|
|
403
|
-
const rawWindowAddEventListener = rawWindow.addEventListener;
|
|
404
|
-
const rawWindowRemoveEventListener = rawWindow.removeEventListener;
|
|
405
|
-
const rawSetInterval = rawWindow.setInterval;
|
|
406
|
-
const rawSetTimeout = rawWindow.setTimeout;
|
|
407
|
-
const rawClearInterval = rawWindow.clearInterval;
|
|
408
|
-
const rawClearTimeout = rawWindow.clearTimeout;
|
|
409
|
-
const rawDocumentAddEventListener = rawDocument.addEventListener;
|
|
410
|
-
const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
|
|
411
|
-
// mark current application as base application
|
|
412
|
-
window.__MICRO_APP_BASE_APPLICATION__ = true;
|
|
413
|
-
Object.assign(globalEnv, {
|
|
414
|
-
// source/patch
|
|
415
|
-
rawSetAttribute,
|
|
416
|
-
rawAppendChild,
|
|
417
|
-
rawInsertBefore,
|
|
418
|
-
rawReplaceChild,
|
|
419
|
-
rawRemoveChild,
|
|
420
|
-
rawAppend,
|
|
421
|
-
rawPrepend,
|
|
422
|
-
rawCloneNode,
|
|
423
|
-
rawCreateElement,
|
|
424
|
-
rawCreateElementNS,
|
|
425
|
-
rawCreateDocumentFragment,
|
|
426
|
-
rawQuerySelector,
|
|
427
|
-
rawQuerySelectorAll,
|
|
428
|
-
rawGetElementById,
|
|
429
|
-
rawGetElementsByClassName,
|
|
430
|
-
rawGetElementsByTagName,
|
|
431
|
-
rawGetElementsByName,
|
|
432
|
-
ImageProxy,
|
|
433
|
-
// common global vars
|
|
434
|
-
rawWindow,
|
|
435
|
-
rawDocument,
|
|
436
|
-
supportModuleScript,
|
|
437
|
-
templateStyle,
|
|
438
|
-
// sandbox/effect
|
|
439
|
-
rawWindowAddEventListener,
|
|
440
|
-
rawWindowRemoveEventListener,
|
|
441
|
-
rawSetInterval,
|
|
442
|
-
rawSetTimeout,
|
|
443
|
-
rawClearInterval,
|
|
444
|
-
rawClearTimeout,
|
|
445
|
-
rawDocumentAddEventListener,
|
|
446
|
-
rawDocumentRemoveEventListener,
|
|
447
|
-
});
|
|
448
|
-
}
|
|
449
|
-
}
|
|
450
|
-
|
|
451
|
-
/**
|
|
452
|
-
* Bind css scope
|
|
453
|
-
* Special case:
|
|
454
|
-
* 1. html-abc | abc-html
|
|
455
|
-
* 2. html body.abc
|
|
456
|
-
* 3. abchtml | htmlabc | abcbody | bodyabc
|
|
457
|
-
* 4. html + body | html > body | html.body | html[name=xx] | body[name=xx]
|
|
458
|
-
* 5. xxx, html xxx, body xxx
|
|
459
|
-
*
|
|
460
|
-
* TODO: BUG
|
|
461
|
-
.test-b {
|
|
462
|
-
border: 1px solid var(--color-a);
|
|
463
|
-
border-bottom-color: var(--color-b);
|
|
464
|
-
}
|
|
465
|
-
*/
|
|
466
|
-
function scopedStyleRule(rule, prefix) {
|
|
467
|
-
const { selectorText, cssText } = rule;
|
|
468
|
-
if (/^((html[\s>~,]+body)|(html|body|:root))$/.test(selectorText)) {
|
|
469
|
-
return cssText.replace(/^((html[\s>~,]+body)|(html|body|:root))/, prefix);
|
|
470
|
-
}
|
|
471
|
-
else if (selectorText === '*') {
|
|
472
|
-
return cssText.replace('*', `${prefix} *`);
|
|
473
|
-
}
|
|
474
|
-
const builtInRootSelectorRE = /(^|\s+)((html[\s>~]+body)|(html|body|:root))(?=[\s>~]+|$)/;
|
|
475
|
-
return cssText.replace(/^[\s\S]+{/, (selectors) => {
|
|
476
|
-
return selectors.replace(/(^|,)([^,]+)/g, (all, $1, $2) => {
|
|
477
|
-
if (builtInRootSelectorRE.test($2)) {
|
|
478
|
-
// body[name=xx]|body.xx|body#xx etc. do not need to handle
|
|
479
|
-
return all.replace(builtInRootSelectorRE, prefix);
|
|
480
|
-
}
|
|
481
|
-
return `${$1} ${prefix} ${$2.replace(/^\s*/, '')}`;
|
|
482
|
-
});
|
|
483
|
-
});
|
|
362
|
+
// common reg
|
|
363
|
+
const rootSelectorREG = /(^|\s+)(html|:root)(?=[\s>~[.#:]+|$)/;
|
|
364
|
+
const bodySelectorREG = /(^|\s+)((html[\s>~]+body)|body)(?=[\s>~[.#:]+|$)/;
|
|
365
|
+
const cssUrlREG = /url\(["']?([^)"']+)["']?\)/gm;
|
|
366
|
+
function parseError(msg, linkpath) {
|
|
367
|
+
msg = linkpath ? `${linkpath}:${msg}` : msg;
|
|
368
|
+
const err = new Error(msg);
|
|
369
|
+
err.reason = msg;
|
|
370
|
+
if (linkpath) {
|
|
371
|
+
err.filename = linkpath;
|
|
372
|
+
}
|
|
373
|
+
throw err;
|
|
484
374
|
}
|
|
485
375
|
/**
|
|
486
|
-
*
|
|
487
|
-
*
|
|
488
|
-
*
|
|
489
|
-
*
|
|
490
|
-
* @param linkpath link resource address, if it is the style converted from link, it will have linkpath
|
|
376
|
+
* Reference resources https://github.com/reworkcss/css
|
|
377
|
+
* CSSParser mainly deals with 3 scenes: styleRule, @, and comment
|
|
378
|
+
* And scopecss deals with 2 scenes: selector & url
|
|
379
|
+
* It can also disable scopecss with inline comments
|
|
491
380
|
*/
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
381
|
+
class CSSParser {
|
|
382
|
+
constructor() {
|
|
383
|
+
this.cssText = ''; // css content
|
|
384
|
+
this.prefix = ''; // prefix as micro-app[name=xxx]
|
|
385
|
+
this.baseURI = ''; // domain name
|
|
386
|
+
this.linkpath = ''; // link resource address, if it is the style converted from link, it will have linkpath
|
|
387
|
+
this.result = ''; // parsed cssText
|
|
388
|
+
this.scopecssDisable = false; // use block comments /* scopecss-disable */ to disable scopecss in your file, and use /* scopecss-enable */ to enable scopecss
|
|
389
|
+
this.scopecssDisableSelectors = []; // disable or enable scopecss for specific selectors
|
|
390
|
+
this.scopecssDisableNextLine = false; // use block comments /* scopecss-disable-next-line */ to disable scopecss on a specific line
|
|
391
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSMediaRule
|
|
392
|
+
this.mediaRule = this.createMatcherForAtRuleWithChildRule(/^@media *([^{]+)/, 'media');
|
|
393
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSSupportsRule
|
|
394
|
+
this.supportsRule = this.createMatcherForAtRuleWithChildRule(/^@supports *([^{]+)/, 'supports');
|
|
395
|
+
this.documentRule = this.createMatcherForAtRuleWithChildRule(/^@([-\w]+)?document *([^{]+)/, 'document');
|
|
396
|
+
this.hostRule = this.createMatcherForAtRuleWithChildRule(/^@host\s*/, 'host');
|
|
397
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSImportRule
|
|
398
|
+
this.importRule = this.createMatcherForNoneBraceAtRule('import');
|
|
399
|
+
// Removed in most browsers
|
|
400
|
+
this.charsetRule = this.createMatcherForNoneBraceAtRule('charset');
|
|
401
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSNamespaceRule
|
|
402
|
+
this.namespaceRule = this.createMatcherForNoneBraceAtRule('namespace');
|
|
403
|
+
}
|
|
404
|
+
exec(cssText, prefix, baseURI, linkpath) {
|
|
405
|
+
this.cssText = cssText;
|
|
406
|
+
this.prefix = prefix;
|
|
407
|
+
this.baseURI = baseURI;
|
|
408
|
+
this.linkpath = linkpath || '';
|
|
409
|
+
this.matchRules();
|
|
410
|
+
return this.result;
|
|
411
|
+
}
|
|
412
|
+
reset() {
|
|
413
|
+
this.cssText = this.prefix = this.baseURI = this.linkpath = this.result = '';
|
|
414
|
+
this.scopecssDisable = this.scopecssDisableNextLine = false;
|
|
415
|
+
this.scopecssDisableSelectors = [];
|
|
416
|
+
}
|
|
417
|
+
// core action for match rules
|
|
418
|
+
matchRules() {
|
|
419
|
+
this.matchLeadingSpaces();
|
|
420
|
+
this.matchComments();
|
|
421
|
+
while (this.cssText.length &&
|
|
422
|
+
this.cssText.charAt(0) !== '}' &&
|
|
423
|
+
(this.matchAtRule() || this.matchStyleRule())) {
|
|
424
|
+
this.matchComments();
|
|
425
|
+
}
|
|
426
|
+
}
|
|
427
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleRule
|
|
428
|
+
matchStyleRule() {
|
|
429
|
+
const selectorList = this.formatSelector();
|
|
430
|
+
// reset scopecssDisableNextLine
|
|
431
|
+
this.scopecssDisableNextLine = false;
|
|
432
|
+
if (!selectorList)
|
|
433
|
+
return parseError('selector missing', this.linkpath);
|
|
434
|
+
this.result += selectorList.join(', ');
|
|
435
|
+
this.matchComments();
|
|
436
|
+
this.styleDeclarations();
|
|
437
|
+
this.matchLeadingSpaces();
|
|
438
|
+
return true;
|
|
439
|
+
}
|
|
440
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSStyleDeclaration
|
|
441
|
+
styleDeclarations() {
|
|
442
|
+
if (!this.matchOpenBrace())
|
|
443
|
+
return parseError("Declaration missing '{'", this.linkpath);
|
|
444
|
+
this.matchComments();
|
|
445
|
+
while (this.styleDeclaration()) {
|
|
446
|
+
this.matchComments();
|
|
447
|
+
}
|
|
448
|
+
if (!this.matchCloseBrace())
|
|
449
|
+
return parseError("Declaration missing '}'", this.linkpath);
|
|
450
|
+
return true;
|
|
451
|
+
}
|
|
452
|
+
// match one styleDeclaration at a time
|
|
453
|
+
styleDeclaration() {
|
|
454
|
+
// css property
|
|
455
|
+
if (!this.commonMatch(/^(\*?[-#\/\*\\\w]+(\[[0-9a-z_-]+\])?)\s*/))
|
|
456
|
+
return false;
|
|
457
|
+
// match :
|
|
458
|
+
if (!this.commonMatch(/^:\s*/))
|
|
459
|
+
return parseError("property missing ':'", this.linkpath);
|
|
460
|
+
// match css value
|
|
461
|
+
const r = this.commonMatch(/^((?:'(?:\\'|.)*?'|"(?:\\"|.)*?"|\([^\)]*?\)|[^};])+)/, true);
|
|
462
|
+
let cssValue = r ? r[0] : '';
|
|
463
|
+
if (!this.scopecssDisableNextLine &&
|
|
464
|
+
(!this.scopecssDisable || this.scopecssDisableSelectors.length)) {
|
|
465
|
+
cssValue = cssValue.replace(cssUrlREG, (all, $1) => {
|
|
466
|
+
if (/^((data|blob):|#)/.test($1) || /^(https?:)?\/\//.test($1)) {
|
|
504
467
|
return all;
|
|
505
468
|
}
|
|
469
|
+
// ./a/b.png ../a/b.png a/b.png
|
|
470
|
+
if (/^((\.\.?\/)|[^/])/.test($1) && this.linkpath) {
|
|
471
|
+
this.baseURI = getLinkFileDir(this.linkpath);
|
|
472
|
+
}
|
|
473
|
+
return `url("${CompletionPath($1, this.baseURI)}")`;
|
|
474
|
+
});
|
|
475
|
+
}
|
|
476
|
+
// reset scopecssDisableNextLine
|
|
477
|
+
this.scopecssDisableNextLine = false;
|
|
478
|
+
this.result += cssValue;
|
|
479
|
+
this.matchLeadingSpaces();
|
|
480
|
+
this.commonMatch(/^[;\s]*/);
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
formatSelector() {
|
|
484
|
+
const m = this.commonMatch(/^([^{]+)/, true);
|
|
485
|
+
if (!m)
|
|
486
|
+
return false;
|
|
487
|
+
return trim(m[0])
|
|
488
|
+
.replace(/\/\*([^*]|[\r\n]|(\*+([^*/]|[\r\n])))*\*\/+/g, '')
|
|
489
|
+
.replace(/"(?:\\"|[^"])*"|'(?:\\'|[^'])*'/g, (r) => {
|
|
490
|
+
return r.replace(/,/g, '\u200C');
|
|
491
|
+
})
|
|
492
|
+
.split(/\s*(?![^(]*\)),\s*/)
|
|
493
|
+
.map((s) => {
|
|
494
|
+
const selectorText = s.replace(/\u200C/g, ',');
|
|
495
|
+
if (this.scopecssDisableNextLine) {
|
|
496
|
+
return selectorText;
|
|
497
|
+
}
|
|
498
|
+
else if (this.scopecssDisable) {
|
|
499
|
+
if (!this.scopecssDisableSelectors.length ||
|
|
500
|
+
this.scopecssDisableSelectors.includes(selectorText)) {
|
|
501
|
+
return selectorText;
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
if (selectorText === '*') {
|
|
505
|
+
return this.prefix + ' *';
|
|
506
|
+
}
|
|
507
|
+
else if (bodySelectorREG.test(selectorText)) {
|
|
508
|
+
return selectorText.replace(bodySelectorREG, this.prefix + ' micro-app-body');
|
|
509
|
+
}
|
|
510
|
+
else if (rootSelectorREG.test(selectorText)) { // ignore root selector
|
|
511
|
+
return selectorText;
|
|
512
|
+
}
|
|
513
|
+
return this.prefix + ' ' + selectorText;
|
|
514
|
+
});
|
|
515
|
+
}
|
|
516
|
+
matchAtRule() {
|
|
517
|
+
if (this.cssText[0] !== '@')
|
|
518
|
+
return false;
|
|
519
|
+
// reset scopecssDisableNextLine
|
|
520
|
+
this.scopecssDisableNextLine = false;
|
|
521
|
+
return this.keyframesRule() ||
|
|
522
|
+
this.mediaRule() ||
|
|
523
|
+
this.custommediaRule() ||
|
|
524
|
+
this.supportsRule() ||
|
|
525
|
+
this.importRule() ||
|
|
526
|
+
this.charsetRule() ||
|
|
527
|
+
this.namespaceRule() ||
|
|
528
|
+
this.documentRule() ||
|
|
529
|
+
this.pageRule() ||
|
|
530
|
+
this.hostRule() ||
|
|
531
|
+
this.fontfaceRule();
|
|
532
|
+
}
|
|
533
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSKeyframesRule
|
|
534
|
+
keyframesRule() {
|
|
535
|
+
if (!this.commonMatch(/^@([-\w]+)?keyframes\s*/))
|
|
536
|
+
return false;
|
|
537
|
+
if (!this.commonMatch(/^([-\w]+)\s*/))
|
|
538
|
+
return parseError('@keyframes missing name', this.linkpath);
|
|
539
|
+
this.matchComments();
|
|
540
|
+
if (!this.matchOpenBrace())
|
|
541
|
+
return parseError("@keyframes missing '{'", this.linkpath);
|
|
542
|
+
this.matchComments();
|
|
543
|
+
while (this.keyframeRule()) {
|
|
544
|
+
this.matchComments();
|
|
545
|
+
}
|
|
546
|
+
if (!this.matchCloseBrace())
|
|
547
|
+
return parseError("@keyframes missing '}'", this.linkpath);
|
|
548
|
+
this.matchLeadingSpaces();
|
|
549
|
+
return true;
|
|
550
|
+
}
|
|
551
|
+
keyframeRule() {
|
|
552
|
+
let r;
|
|
553
|
+
const valList = [];
|
|
554
|
+
while (r = this.commonMatch(/^((\d+\.\d+|\.\d+|\d+)%?|[a-z]+)\s*/)) {
|
|
555
|
+
valList.push(r[1]);
|
|
556
|
+
this.commonMatch(/^,\s*/);
|
|
557
|
+
}
|
|
558
|
+
if (!valList.length)
|
|
559
|
+
return false;
|
|
560
|
+
this.styleDeclarations();
|
|
561
|
+
this.matchLeadingSpaces();
|
|
562
|
+
return true;
|
|
563
|
+
}
|
|
564
|
+
// https://github.com/postcss/postcss-custom-media
|
|
565
|
+
custommediaRule() {
|
|
566
|
+
if (!this.commonMatch(/^@custom-media\s+(--[^\s]+)\s*([^{;]+);/))
|
|
567
|
+
return false;
|
|
568
|
+
this.matchLeadingSpaces();
|
|
569
|
+
return true;
|
|
570
|
+
}
|
|
571
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSPageRule
|
|
572
|
+
pageRule() {
|
|
573
|
+
if (!this.commonMatch(/^@page */))
|
|
574
|
+
return false;
|
|
575
|
+
this.formatSelector();
|
|
576
|
+
// reset scopecssDisableNextLine
|
|
577
|
+
this.scopecssDisableNextLine = false;
|
|
578
|
+
return this.commonHandlerForAtRuleWithSelfRule('page');
|
|
579
|
+
}
|
|
580
|
+
// https://developer.mozilla.org/en-US/docs/Web/API/CSSFontFaceRule
|
|
581
|
+
fontfaceRule() {
|
|
582
|
+
if (!this.commonMatch(/^@font-face\s*/))
|
|
583
|
+
return false;
|
|
584
|
+
return this.commonHandlerForAtRuleWithSelfRule('font-face');
|
|
585
|
+
}
|
|
586
|
+
// common matcher for @media, @supports, @document, @host
|
|
587
|
+
createMatcherForAtRuleWithChildRule(reg, name) {
|
|
588
|
+
return () => {
|
|
589
|
+
if (!this.commonMatch(reg))
|
|
590
|
+
return false;
|
|
591
|
+
if (!this.matchOpenBrace())
|
|
592
|
+
return parseError(`@${name} missing '{'`, this.linkpath);
|
|
593
|
+
this.matchComments();
|
|
594
|
+
this.matchRules();
|
|
595
|
+
if (!this.matchCloseBrace())
|
|
596
|
+
return parseError(`@${name} missing '}'`, this.linkpath);
|
|
597
|
+
this.matchLeadingSpaces();
|
|
598
|
+
return true;
|
|
599
|
+
};
|
|
600
|
+
}
|
|
601
|
+
// common matcher for @import, @charset, @namespace
|
|
602
|
+
createMatcherForNoneBraceAtRule(name) {
|
|
603
|
+
const reg = new RegExp('^@' + name + '\\s*([^;]+);');
|
|
604
|
+
return () => {
|
|
605
|
+
if (!this.commonMatch(reg))
|
|
606
|
+
return false;
|
|
607
|
+
this.matchLeadingSpaces();
|
|
608
|
+
return false;
|
|
609
|
+
};
|
|
610
|
+
}
|
|
611
|
+
// common handler for @font-face, @page
|
|
612
|
+
commonHandlerForAtRuleWithSelfRule(name) {
|
|
613
|
+
if (!this.matchOpenBrace())
|
|
614
|
+
return parseError(`@${name} missing '{'`, this.linkpath);
|
|
615
|
+
this.matchComments();
|
|
616
|
+
while (this.styleDeclaration()) {
|
|
617
|
+
this.matchComments();
|
|
618
|
+
}
|
|
619
|
+
if (!this.matchCloseBrace())
|
|
620
|
+
return parseError(`@${name} missing '}'`, this.linkpath);
|
|
621
|
+
this.matchLeadingSpaces();
|
|
622
|
+
return true;
|
|
623
|
+
}
|
|
624
|
+
// match and slice comments
|
|
625
|
+
matchComments() {
|
|
626
|
+
while (this.matchComment())
|
|
627
|
+
;
|
|
628
|
+
}
|
|
629
|
+
// css comment
|
|
630
|
+
matchComment() {
|
|
631
|
+
if (this.cssText.charAt(0) !== '/' || this.cssText.charAt(1) !== '*')
|
|
632
|
+
return false;
|
|
633
|
+
// reset scopecssDisableNextLine
|
|
634
|
+
this.scopecssDisableNextLine = false;
|
|
635
|
+
let i = 2;
|
|
636
|
+
while (this.cssText.charAt(i) !== '' && (this.cssText.charAt(i) !== '*' || this.cssText.charAt(i + 1) !== '/'))
|
|
637
|
+
++i;
|
|
638
|
+
i += 2;
|
|
639
|
+
if (this.cssText.charAt(i - 1) === '') {
|
|
640
|
+
return parseError('End of comment missing', this.linkpath);
|
|
641
|
+
}
|
|
642
|
+
// get comment content
|
|
643
|
+
let commentText = this.cssText.slice(2, i - 2);
|
|
644
|
+
this.result += `/*${commentText}*/`;
|
|
645
|
+
commentText = trim(commentText.replace(/^\s*!/, ''));
|
|
646
|
+
// set ignore config
|
|
647
|
+
if (commentText === 'scopecss-disable-next-line') {
|
|
648
|
+
this.scopecssDisableNextLine = true;
|
|
649
|
+
}
|
|
650
|
+
else if (/^scopecss-disable/.test(commentText)) {
|
|
651
|
+
if (commentText === 'scopecss-disable') {
|
|
652
|
+
this.scopecssDisable = true;
|
|
506
653
|
}
|
|
507
654
|
else {
|
|
508
|
-
|
|
655
|
+
this.scopecssDisable = true;
|
|
656
|
+
const ignoreRules = commentText.replace('scopecss-disable', '').split(',');
|
|
657
|
+
ignoreRules.forEach((rule) => {
|
|
658
|
+
this.scopecssDisableSelectors.push(trim(rule));
|
|
659
|
+
});
|
|
509
660
|
}
|
|
510
661
|
}
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
662
|
+
else if (commentText === 'scopecss-enable') {
|
|
663
|
+
this.scopecssDisable = false;
|
|
664
|
+
this.scopecssDisableSelectors = [];
|
|
514
665
|
}
|
|
515
|
-
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
case 'CSSSupportsRule':
|
|
540
|
-
result += scopedPackRule(rule, prefix, 'supports');
|
|
541
|
-
break;
|
|
542
|
-
default:
|
|
543
|
-
result += rule.cssText;
|
|
544
|
-
break;
|
|
545
|
-
}
|
|
546
|
-
}
|
|
547
|
-
return result.replace(/^\s+/, '');
|
|
666
|
+
this.cssText = this.cssText.slice(i);
|
|
667
|
+
this.matchLeadingSpaces();
|
|
668
|
+
return true;
|
|
669
|
+
}
|
|
670
|
+
commonMatch(reg, skip = false) {
|
|
671
|
+
const matchArray = reg.exec(this.cssText);
|
|
672
|
+
if (!matchArray)
|
|
673
|
+
return;
|
|
674
|
+
const matchStr = matchArray[0];
|
|
675
|
+
this.cssText = this.cssText.slice(matchStr.length);
|
|
676
|
+
if (!skip)
|
|
677
|
+
this.result += matchStr;
|
|
678
|
+
return matchArray;
|
|
679
|
+
}
|
|
680
|
+
matchOpenBrace() {
|
|
681
|
+
return this.commonMatch(/^{\s*/);
|
|
682
|
+
}
|
|
683
|
+
matchCloseBrace() {
|
|
684
|
+
return this.commonMatch(/^}/);
|
|
685
|
+
}
|
|
686
|
+
// match and slice the leading spaces
|
|
687
|
+
matchLeadingSpaces() {
|
|
688
|
+
this.commonMatch(/^\s*/);
|
|
689
|
+
}
|
|
548
690
|
}
|
|
549
691
|
/**
|
|
550
692
|
* common method of bind CSS
|
|
551
693
|
*/
|
|
552
|
-
function commonAction(
|
|
553
|
-
var _a, _b;
|
|
694
|
+
function commonAction(styleElement, appName, prefix, baseURI, linkpath) {
|
|
554
695
|
if (!styleElement.__MICRO_APP_HAS_SCOPED__) {
|
|
555
|
-
const rules = Array.from((_b = (_a = templateStyle.sheet) === null || _a === void 0 ? void 0 : _a.cssRules) !== null && _b !== void 0 ? _b : []);
|
|
556
|
-
let result = scopedHost(scopedRule(rules, prefix), baseURI, originContent, linkpath);
|
|
557
|
-
/**
|
|
558
|
-
* Solve the problem of missing content quotes in some Safari browsers
|
|
559
|
-
* docs: https://developer.mozilla.org/zh-CN/docs/Web/CSS/content
|
|
560
|
-
* If there are still problems, it is recommended to use the attr()
|
|
561
|
-
*/
|
|
562
|
-
if (isSafari()) {
|
|
563
|
-
result = result.replace(/([;{]\s*content:\s*)([^\s"][^";}]*)/gm, (all, $1, $2) => {
|
|
564
|
-
if ($2 === 'none' ||
|
|
565
|
-
/^(url\()|(counter\()|(attr\()|(open-quote)|(close-quote)/.test($2)) {
|
|
566
|
-
return all;
|
|
567
|
-
}
|
|
568
|
-
return `${$1}"${$2}"`;
|
|
569
|
-
});
|
|
570
|
-
}
|
|
571
|
-
styleElement.textContent = result;
|
|
572
696
|
styleElement.__MICRO_APP_HAS_SCOPED__ = true;
|
|
697
|
+
let result = null;
|
|
698
|
+
try {
|
|
699
|
+
result = parser.exec(styleElement.textContent, prefix, baseURI, linkpath);
|
|
700
|
+
parser.reset();
|
|
701
|
+
}
|
|
702
|
+
catch (e) {
|
|
703
|
+
parser.reset();
|
|
704
|
+
logError('CSSParser: An error occurred while parsing CSS', appName, e);
|
|
705
|
+
}
|
|
706
|
+
if (result)
|
|
707
|
+
styleElement.textContent = result;
|
|
573
708
|
}
|
|
574
709
|
}
|
|
710
|
+
let parser;
|
|
575
711
|
/**
|
|
576
712
|
* scopedCSS
|
|
577
713
|
* @param styleElement target style element
|
|
@@ -580,27 +716,18 @@ function commonAction(templateStyle, styleElement, originContent, prefix, baseUR
|
|
|
580
716
|
function scopedCSS(styleElement, app) {
|
|
581
717
|
if (app.scopecss) {
|
|
582
718
|
const prefix = `${microApp.tagName}[name=${app.name}]`;
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
globalEnv.templateStyle = templateStyle = pureCreateElement('style');
|
|
586
|
-
templateStyle.setAttribute('id', 'micro-app-template-style');
|
|
587
|
-
globalEnv.rawDocument.body.appendChild(templateStyle);
|
|
588
|
-
templateStyle.sheet.disabled = true;
|
|
589
|
-
}
|
|
719
|
+
if (!parser)
|
|
720
|
+
parser = new CSSParser();
|
|
590
721
|
if (styleElement.textContent) {
|
|
591
|
-
|
|
592
|
-
commonAction(templateStyle, styleElement, styleElement.textContent, prefix, app.url, styleElement.__MICRO_APP_LINK_PATH__);
|
|
593
|
-
templateStyle.textContent = '';
|
|
722
|
+
commonAction(styleElement, app.name, prefix, app.url, styleElement.__MICRO_APP_LINK_PATH__);
|
|
594
723
|
}
|
|
595
724
|
else {
|
|
596
725
|
const observer = new MutationObserver(function () {
|
|
597
|
-
var _a, _b;
|
|
598
726
|
observer.disconnect();
|
|
599
|
-
// styled-component will
|
|
600
|
-
if (
|
|
601
|
-
styleElement.
|
|
602
|
-
|
|
603
|
-
commonAction(styleElement, styleElement, styleElement.textContent, prefix, app.url, styleElement.__MICRO_APP_LINK_PATH__);
|
|
727
|
+
// styled-component will be ignore
|
|
728
|
+
if (styleElement.textContent && !styleElement.hasAttribute('data-styled')) {
|
|
729
|
+
commonAction(styleElement, app.name, prefix, app.url, styleElement.__MICRO_APP_LINK_PATH__);
|
|
730
|
+
}
|
|
604
731
|
});
|
|
605
732
|
observer.observe(styleElement, { childList: true });
|
|
606
733
|
}
|
|
@@ -785,6 +912,95 @@ function foramtDynamicLink(url, info, app, originLink, replaceStyle) {
|
|
|
785
912
|
});
|
|
786
913
|
}
|
|
787
914
|
|
|
915
|
+
const globalEnv = {};
|
|
916
|
+
/**
|
|
917
|
+
* Note loop nesting
|
|
918
|
+
* Only prototype or unique values can be put here
|
|
919
|
+
*/
|
|
920
|
+
function initGlobalEnv() {
|
|
921
|
+
if (isBrowser) {
|
|
922
|
+
/**
|
|
923
|
+
* save patch raw methods
|
|
924
|
+
* pay attention to this binding
|
|
925
|
+
*/
|
|
926
|
+
const rawSetAttribute = Element.prototype.setAttribute;
|
|
927
|
+
const rawAppendChild = Element.prototype.appendChild;
|
|
928
|
+
const rawInsertBefore = Element.prototype.insertBefore;
|
|
929
|
+
const rawReplaceChild = Element.prototype.replaceChild;
|
|
930
|
+
const rawRemoveChild = Element.prototype.removeChild;
|
|
931
|
+
const rawAppend = Element.prototype.append;
|
|
932
|
+
const rawPrepend = Element.prototype.prepend;
|
|
933
|
+
const rawCloneNode = Element.prototype.cloneNode;
|
|
934
|
+
const rawCreateElement = Document.prototype.createElement;
|
|
935
|
+
const rawCreateElementNS = Document.prototype.createElementNS;
|
|
936
|
+
const rawCreateDocumentFragment = Document.prototype.createDocumentFragment;
|
|
937
|
+
const rawQuerySelector = Document.prototype.querySelector;
|
|
938
|
+
const rawQuerySelectorAll = Document.prototype.querySelectorAll;
|
|
939
|
+
const rawGetElementById = Document.prototype.getElementById;
|
|
940
|
+
const rawGetElementsByClassName = Document.prototype.getElementsByClassName;
|
|
941
|
+
const rawGetElementsByTagName = Document.prototype.getElementsByTagName;
|
|
942
|
+
const rawGetElementsByName = Document.prototype.getElementsByName;
|
|
943
|
+
const ImageProxy = new Proxy(Image, {
|
|
944
|
+
construct(Target, args) {
|
|
945
|
+
const elementImage = new Target(...args);
|
|
946
|
+
elementImage.__MICRO_APP_NAME__ = getCurrentAppName();
|
|
947
|
+
return elementImage;
|
|
948
|
+
},
|
|
949
|
+
});
|
|
950
|
+
const rawWindow = Function('return window')();
|
|
951
|
+
const rawDocument = Function('return document')();
|
|
952
|
+
const supportModuleScript = isSupportModuleScript();
|
|
953
|
+
/**
|
|
954
|
+
* save effect raw methods
|
|
955
|
+
* pay attention to this binding, especially setInterval, setTimeout, clearInterval, clearTimeout
|
|
956
|
+
*/
|
|
957
|
+
const rawWindowAddEventListener = rawWindow.addEventListener;
|
|
958
|
+
const rawWindowRemoveEventListener = rawWindow.removeEventListener;
|
|
959
|
+
const rawSetInterval = rawWindow.setInterval;
|
|
960
|
+
const rawSetTimeout = rawWindow.setTimeout;
|
|
961
|
+
const rawClearInterval = rawWindow.clearInterval;
|
|
962
|
+
const rawClearTimeout = rawWindow.clearTimeout;
|
|
963
|
+
const rawDocumentAddEventListener = rawDocument.addEventListener;
|
|
964
|
+
const rawDocumentRemoveEventListener = rawDocument.removeEventListener;
|
|
965
|
+
// mark current application as base application
|
|
966
|
+
window.__MICRO_APP_BASE_APPLICATION__ = true;
|
|
967
|
+
Object.assign(globalEnv, {
|
|
968
|
+
// source/patch
|
|
969
|
+
rawSetAttribute,
|
|
970
|
+
rawAppendChild,
|
|
971
|
+
rawInsertBefore,
|
|
972
|
+
rawReplaceChild,
|
|
973
|
+
rawRemoveChild,
|
|
974
|
+
rawAppend,
|
|
975
|
+
rawPrepend,
|
|
976
|
+
rawCloneNode,
|
|
977
|
+
rawCreateElement,
|
|
978
|
+
rawCreateElementNS,
|
|
979
|
+
rawCreateDocumentFragment,
|
|
980
|
+
rawQuerySelector,
|
|
981
|
+
rawQuerySelectorAll,
|
|
982
|
+
rawGetElementById,
|
|
983
|
+
rawGetElementsByClassName,
|
|
984
|
+
rawGetElementsByTagName,
|
|
985
|
+
rawGetElementsByName,
|
|
986
|
+
ImageProxy,
|
|
987
|
+
// common global vars
|
|
988
|
+
rawWindow,
|
|
989
|
+
rawDocument,
|
|
990
|
+
supportModuleScript,
|
|
991
|
+
// sandbox/effect
|
|
992
|
+
rawWindowAddEventListener,
|
|
993
|
+
rawWindowRemoveEventListener,
|
|
994
|
+
rawSetInterval,
|
|
995
|
+
rawSetTimeout,
|
|
996
|
+
rawClearInterval,
|
|
997
|
+
rawClearTimeout,
|
|
998
|
+
rawDocumentAddEventListener,
|
|
999
|
+
rawDocumentRemoveEventListener,
|
|
1000
|
+
});
|
|
1001
|
+
}
|
|
1002
|
+
}
|
|
1003
|
+
|
|
788
1004
|
// Global scripts, reuse across apps
|
|
789
1005
|
const globalScripts = new Map();
|
|
790
1006
|
/**
|