微前端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-',
    }),
  ],
}
相关推荐
崔庆才丨静觅2 小时前
hCaptcha 验证码图像识别 API 对接教程
前端
passerby60612 小时前
完成前端时间处理的另一块版图
前端·github·web components
掘了2 小时前
「2025 年终总结」在所有失去的人中,我最怀念我自己
前端·后端·年终总结
崔庆才丨静觅3 小时前
实用免费的 Short URL 短链接 API 对接说明
前端
崔庆才丨静觅3 小时前
5分钟快速搭建 AI 平台并用它赚钱!
前端
崔庆才丨静觅3 小时前
比官方便宜一半以上!Midjourney API 申请及使用
前端
Moment3 小时前
富文本编辑器在 AI 时代为什么这么受欢迎
前端·javascript·后端
崔庆才丨静觅4 小时前
刷屏全网的“nano-banana”API接入指南!0.1元/张量产高清创意图,开发者必藏
前端
剪刀石头布啊4 小时前
jwt介绍
前端
爱敲代码的小鱼4 小时前
AJAX(异步交互的技术来实现从服务端中获取数据):
前端·javascript·ajax