微前端子应用样式隔离方案实践

267 阅读1分钟

前提:singal-sap + systemjs 的微前端体系;子应用挂载在普通dom下,子应用引用第三方库如 antd,自身使用less

关于思路:借鉴CSS Modules,在子应用各样式最外层加一层选择器做隔离; 问题:1,子应用引用的第三方库如antd 按需加载没开启CSS Modules,工程内部使用less部分开启css modules,部分未开启,会导致最外层的选择器被编译后加hash值,导致未开启css modules部分样式不生效,2第三方库等基于绝对定位的组件如modal组件,该组件并未挂载在子应用的dom树下,会使该类组件样式失效。 3,less中 :global {} 下的选择器不被编译hash,导致这部分会失效

解决方案:

自定义postcss plugin

const postcss = require('postcss')


const exceptionCss = (exceptionCssArr, rule)=>{
    // 探测是否含有不需要处理的选择器 antd modal类的样式除外,此类样式不加前缀,防止失效,需要特殊处理
    return new RegExp(exceptionCssArr.join("|")).test(rule.selector)
}

module.exports = postcss.plugin("self-plugin", (opts)=>{
    // IdSelector, classSelector  两个选择器前缀应对css modules 编译hash值和:global 不编译hash值
    const {IdSelector, classSelector, exceptionCssArr} = opts
    return (root)=>{
        root.walkRules(rule=>{
            const hasExc = exceptionCss(exceptionCssArr,rule)
            if(!hasExc){
                
                const tempSe =  rule.selector
                // 选择器应对css modules 编译hash值
                rule.selector = classSelector + " " + rule.selector
                // 选择器应对css modules :global 不编译hash值
                rule.selector = tempSe.replace(":global ", ":global "+ IdSelector+ " ")
            }
        })
    }
})

根html

function App() {
  return (
    <div id="noCssModules">
      <div className="cssModules">
        <div className="App">
          <UglyTree datas={treeDatas}/>
        </div>
      </div>
    </div>
  );
}

postcss.config.js

const plugin = require('./cssModulePlugin')

module.exports = {
    plugins: [
      new plugin({
        IdSelector:"noCssModules",
        classSelector:"cssModules",
        exceptionCssArr:['ant-modal']
      })
    ]
  }

后记:代码仅为样例,实际工程需要考虑边界特殊情况,工作原因,投产代码无法展示。类似antd提供prefix功能做样式隔离效果更佳。