微前端qiankun样式隔离总结

项目背景

主应用 vue2 + element;

子应用 vue3 + element-plus;

问题描述

主应用使用element而在子应用中使用element-plus,导致出现两个问题:

  1. 子应用中element-plus的样式和主应用中element的样式同名,导致被样式覆盖
  2. 由于像对话框等组件都是默认放在body下面的,所以会被放在主应用的body下而不是子应用的body下导致样式出现偏差

问题一场景复现

主应用触发

子应用触发

问题二场景复现

子应用的组件绑定到了主应用的body中

针对问题一的解决思考

使用严格沙箱

使用

在加载子应用时,添加strictStyleIsolation: true属性,实现形式为将整个子应用放到Shadow DOM内进行嵌入,实现主子应用完全隔离

js 复制代码
start({
  sandbox: {
    strictStyleIsolation: true,
  },
})

问题

vue3项目根本无法正常运行

问下chatGPT吧

既然如此就下发解决一下吧

js 复制代码
// 主
<div id="subapp-viewport"></div>

const apps = microApps.map(item => {
  return {
    ...item,
    container: '#subapp-viewport', // 子应用挂载的div
    props: {
      routerBase: item.activeRule, // 下发基础路由
      getGlobalState: store.getGlobalState // 下发getGlobalState方法
    }
  }
})

// 子
function render(props){
    const { container } = props
    app = createApp(App)
    app.use(store)
    app.use(router)
    debugger
    app.mount(container ? container.querySelector('#app') : '#app')
}

但是子应用的弹窗、抽屉、popover因找不到主应用的body会丢失,或跑到整个屏幕外

原因:element-plus 的全局变量是通过 :root 选择器来作用到根节点的,但是在 shadow dom 中,是无法通过 :root 来选中根节点的,也就导致了这部分的样式失效 解决:在 shadow dom 中也是存在根节点的,这个根节点名为 shadow host ,我们可以用 :host 来代替 :root 选中 shadow dom 对应的根节点 方案:写一个 loader,在 webpack 打包文件的时候把 :root 替换成 :host

js 复制代码
const replaceStyleLoader = function (source) { 
    return source.replace(/:root/g, ':host') 
} 
module.exports = myStyleLoader
js 复制代码
module: {
  rules: [
    {
      test: /\.scss$/,
      include: [
        path.resolve(__dirname, 'node_modules/element-plus/theme-chalk') 
      ],
      use: [
        'style-loader',
        'css-loader',
        'replace-style-loader',
        'sass-loader'
      ]
    }
  ]
}

还有一个无法解决的问题:子应用的弹窗、抽屉、popover因找不到主应用的body会丢失或绑定到主应用的body(绑定到body可以理解,丢失真的神奇不过就复现了一两次所以以后在研究吧...)

结论:放弃这种方式,太麻烦而且主应用不方便去修改子应用的样式,还有就是对react不友好

使用实验性沙箱

在加载子应用时,添加experimentalStyleIsolation: true属性,实现形式类似于vue中style标签中的scoped属性,qiankun会自动为子应用所有的样式增加后缀标签,如:div[data-qiankun-microName]

js 复制代码
start({
  sandbox: {
    experimentalStyleIsolation: true,
  },
})

也可以解决样式被覆盖的问题但同样无法解决子应用的弹窗、抽屉、popover因为绑定到主应用的body上而导致使用的是主应用的样式的问题

结论:放弃这种方式,无法解决问题二

针对问题二的思考

既然都无法解决问题二,第一个想到的点是实现元素隔离,但是qiankun并不支持该功能,重写的代价太大,所以就只能退而求其次将子应用的样式和class的el-前缀进行转换

思路一

使用element-plus的全局配置修改class和组件的名字(感觉就是主题色替换的思路),但是这里有个问题就是虽然class和组件的名字改变了但图标等个别组件是会通过已经打包好的样式引入的,所以还需要使用postCss插件替换一遍(注意:关闭qiankun的样式沙箱

js 复制代码
// app.vue
<el-config-provider :locale="local" namspace="subel">
<router-view />
</el-config-provider>
  
// 新建style/element/index.scss
// element前缀样式修改,el改为subel
@forward 'element-plus/theme-chalk/src/mixins/config.scss' with (
  $namespace: 'subel'
);
    
// vue.config.js
module:{
  rules:[
    {
      test: /\.(scss|sass)$/,
      exclude: resolve('src/style/element/index.scss'), 
      include: path.resolve(__dirname, './node_modules/element-plus/'),
      use: [
        {
          loader: "sass-loader",
          options: {
            implementation: require("sass"), 
            prependData: `@use "@/style/element/index.scss" as *;`,
          }
        }
      ]
    }
  ]
}  

// postcss.config.js
const addCssPrefix = require('postcss-change-css-prefix-namespace')
module.exports = {
  plugins: [
    'postcss-preset-env',
    addCssPrefix({
      prefix: 'el-',
      replace: 'subel-',
    }),
  ],
}

思路二(目前感觉最好的思路了...)

既然都需要postCss转换那我直接转了不就得了。。。。

js 复制代码
// app.vue
<el-config-provider :locale="local" namspace="subel">
<router-view />
</el-config-provider>

// postcss.config.js
const addCssPrefix = require('postcss-change-css-prefix-namespace')
module.exports = {
  plugins: [
    'postcss-preset-env',
    addCssPrefix({
      prefix: 'el-',
      replace: 'subel-',
    }),
  ],
}
相关推荐
李少兄6 分钟前
简单讲讲 SVG:前端开发中的矢量图形
前端·svg
前端小万8 分钟前
告别 CJS 库加载兼容坑
前端·前端工程化
恋猫de小郭8 分钟前
Flutter 3.38.1 之后,因为某些框架低级错误导致提交 Store 被拒
android·前端·flutter
JarvanMo12 分钟前
Flutter 需要 Hooks 吗?
前端
光影少年22 分钟前
前端如何虚拟列表优化?
前端·react native·react.js
Moment24 分钟前
一杯茶时间带你基于 Yjs 和 reactflow 构建协同流程图编辑器 😍😍😍
前端·后端·面试
invicinble41 分钟前
对于前端数据的生命周期的认识
前端
PieroPc1 小时前
用FastAPI 后端 和 HTML/CSS/JavaScript 前端写一个博客系统 例
前端·html·fastapi
hunter14501 小时前
2026.1.4 html简单制作
java·前端·笔记·html
鹏程十八少1 小时前
Android 深入剖析Android内存泄漏:ViewPager2与Fragment的生命周期陷阱
android·前端·app