微前端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-',
    }),
  ],
}
相关推荐
黑客老陈35 分钟前
新手小白如何挖掘cnvd通用漏洞之存储xss漏洞(利用xss钓鱼)
运维·服务器·前端·网络·安全·web3·xss
正小安40 分钟前
Vite系列课程 | 11. Vite 配置文件中 CSS 配置(Modules 模块化篇)
前端·vite
暴富的Tdy1 小时前
【CryptoJS库AES加密】
前端·javascript·vue.js
neeef_se1 小时前
Vue中使用a标签下载静态资源文件(比如excel、pdf等),纯前端操作
前端·vue.js·excel
m0_748235611 小时前
web 渗透学习指南——初学者防入狱篇
前端
z千鑫1 小时前
【前端】入门指南:Vue中使用Node.js进行数据库CRUD操作的详细步骤
前端·vue.js·node.js
m0_748250742 小时前
Web入门常用标签、属性、属性值
前端
m0_748230442 小时前
SSE(Server-Sent Events)返回n ,前端接收数据时被错误的截断【如何避免SSE消息中的换行符或回车符被解释为事件消息的结束】
前端