mustard-app
Version:
个人前端微应用建设中。。。
94 lines (76 loc) • 3.46 kB
text/typescript
import { getCompletePath } from '.';
let templateStyle:HTMLStyleElement;
function scopedStyleRule (rule:CSSStyleRule, prefix:string, path?:string) {
const { selectorText, cssText } = rule;
let str = '';
// 处理选择器
if(/^((html[\s>~,]+body)|(html|body|:root))$/.test(selectorText)) {
// 处理顶层选择器,如 body,html 都转换为 micro-app[name=xxx]
str = cssText.replace(/^((html[\s>~,]+body)|(html|body|:root))/, prefix) + '\n';
}else {
// 选择器添加前缀
str = cssText.replace(/^[\s\S]*{/, cssHead => {
return cssHead.replace(/(^|,)([^,]+)/g, (_, $1, $2)=>{
if(/^[\s]*((html|body|:root)|(html[\s>~]+body))/.test($2)) {
return `${$1} ${$2.replace(/^[\s]*((html[\s>~]+body)|(html|body|:root))/, prefix)}` + '\n';
}
return `${$1} ${prefix} ${$2} \n`;
});
});
}
// 处理样式里的相对地址
return str.replace(/url\(((".+?")|('.+?')|(.+?))\)/gi, (_, url) => {
const src = url.replace(/["']/g, '');
return `url(${getCompletePath(src, path)})`;
});
}
// 处理媒体查询和样式支持查询
function scopedStyleRuleOther (rule:CSSMediaRule|CSSSupportsRule, prefix:string, packName:string, path?:string) {
// eslint-disable-next-line no-use-before-define
const rules = scopedStyleRules(rule.cssRules, prefix, path);
return `@${packName} ${rule.conditionText} {\n${rules}\n}`;
}
function scopedStyleRules (cssRules:CSSRuleList, prefix:string, path?:string) {
let rules = '';
if(cssRules?.length) {
Array.from(cssRules).forEach((cssRule) => {
switch (cssRule.type) {
case 1: // STYLE_RULE
rules += scopedStyleRule(cssRule as CSSStyleRule, prefix, path) + '\n';
break;
case 4: // MEDIA_RULE 媒体查询
rules += scopedStyleRuleOther(cssRule as CSSMediaRule, prefix, 'media', path) + '\n';
break;
case 12: // SUPPORTS_RULE 样式支持
rules += scopedStyleRuleOther(cssRule as CSSSupportsRule, prefix, 'supports', path) + '\n';
break;
default:
rules += cssRule.cssText;
break;
}
});
}
return rules;
}
export function scopedCSSTextContent (textContent:string, appName:string, path?:string) {
const prefix = `mustard-app[name='${appName}'] `; // 样式前缀
const s = new Date();
if(!templateStyle) {
templateStyle = document.createElement('style');
document.body.appendChild(templateStyle);
if(templateStyle?.sheet) {
templateStyle.sheet.disabled = false; // 样式标记不可用
}
}
if(textContent && templateStyle.sheet?.cssRules) {
templateStyle.textContent = textContent;
const _textContent = scopedStyleRules(templateStyle.sheet.cssRules, prefix, path);
templateStyle.textContent = '';
console.log('============', new Date().getTime() - s.getTime());
return _textContent;
}
return textContent;
}
export function scopedCSS (styleEle:HTMLElement, appName:string, path?:string) {
styleEle.textContent = scopedCSSTextContent(styleEle.textContent, appName, path);
}