Skip to content
微信公众号

qiankun落地问题

CSS 隔离

qiankun 加载子项目 css 样式机制大体为:挂载子应用时将子应用的 css 样式以 style 标签的形式插入并做快照,卸载子应用时再将快照内的 style 样式删除。

所以在加载子应用期间,若未开启 css 沙箱隔离,后加载的这些样式,可能会对整个系统的样式产生影响,对此,qiankun 提供了两种 css 沙箱功能,可以将子应用的样式包裹在沙箱容器内部,以此来达到样式隔离的目的。

qiankun 严格沙箱

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

缺点:

  • 子应用的弹窗、抽屉、popover 因找不到主应用的 body 会丢失,或跑到整个屏幕外
  • 主应用不方便去修改子应用的样式

实验性沙箱

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

缺点:

  • 子应用的弹窗、抽屉、popover因插入到了主应用的body,所以导致样式丢失或应用了主应用了样式。例如 elementUI 的 Popover 弹出框、Dropdown 下拉菜单、嵌套的 Drawer 、嵌套的 dialog 等

找到根本的原因,其实就好解决了。

在乾坤出现之前,饿了么组件就已经用的很多了,但是当时的组件设计师们,也没有考虑到后续会有这种微前端集成的需求,再加上现在组件维护不及时,所以就导致现在网上流行说的这些坑。例如 antd 下通过 ConfigProvider getPopupContainer 指定弹框渲染的范围,这样就解决了上面说的逃逸问题。

或者重写了子应用的 document.body.appendChild,让dialog挂载到子应用的节点中,如果有多应用保活,重写后的appendChild会导致其他子应用也挂载到重写的那个子应用中,导致其他子应用出现dialog消失的问题。

使用 postcss-selector-namespace

在子应用中,配置 postcss 插件,给子应用添加类前缀:

例如在vue.config.js中添加

js
const selectorNamespace = require("postcss-selector-namespace");

css: {
    loaderOptions: {
      postcss: {
        postcssOptions: {
          plugins: [
            selectorNamespace({
              namespace(css) {
                console.log('================postcss==============');
                console.log(css);
                /* 无需添加的样式 */
                if (css.includes("element-variables.scss")) return "";
                return ".vue2-app";
              }
            })
          ]
        }
      }
    }
  },

或者在postcss.config.js中

js
module.exports = {
    'plugins': {
        // 为微前端模块添加样式前缀,避免与其他应用冲突
        'postcss-selector-namespace': {
            namespace() {
                return '.vue2-app'
            }
        },
    }
}

记得在子应用根节点中加入与之匹配的样式前缀。

还是会存在上面插入 body 中的样式没有成功的问题,需要特殊处理。

element-ui和element-plus样式影响问题

主应用用element-plus,子应用用element-ui,导致样式发生变形。由于element-ui和element-plus前缀相同、命名规则相同,但内部部分样式实现方式不同,从而导致使用element-ui的样式会被污染,页面样式混乱

解决方案是写一个webpack loader替换element-ui class前缀,写一个postcss plugin替换样式前缀。

  1. npm i change-prefix-loader postcss-change-css-prefix -D

  2. 在vue.config.js中添加如下代码

js
chainWebpack(config){
    config.module
    .rule('change-prefix')
    .test(/\.js$/)
    .include.add(path.resolve(__dirname,'./node_modules/element-ui/lib'))
    .end()
    .use('change-prefix')
    .loader('change-prefix-loader')
    .options({
      prefix:'el-',
      replace: 'portal-'
    })
  },

3.新建postcss.config.js文件

js
const addCssPrefix = require('postcss-change-css-prefix')

module.exports = {
  plugins: [
    addCssPrefix({
      prefix: 'el-',
      replace: 'portal-',
    }),
  ],
}

来自:记录elementui增加样式前缀 其他方案:微前端(qiankun)子应用样式影响其他应用样式

Released under the MIT License.