一、背景
现在没有哪家公司不使用微前端来进行作为项目的组织架构了。
但是这个东西的出现也带来了新的问题。
比如说各个业务团队使用的UI框架不一样的时候,就会导致如下这样的样式污染。
样式的污染,css-scoped或者css module解决了绝大部分,但是对于多子应用同时加载,主子应用之间的冲突,导致了所有的弹窗样式都是有问题的。
二、解决方案
使用qiankun沙盒模式隔离
这是一个坑。神光最近也写过相关的文章,想要详细的了解,可以自寻查找。下面我简单的总结一下:
qiankun的css沙箱的原理是重写HTMLHeadElement.prototype.appendChild事件,记录子项目运行时新增的style/link标签,卸载子项目时移除这些标签。
思路就是将子项目的样式局限到子项目的容器范围,不在这个范围样式不生效。但是对于一些弹窗就无能为力了,它们需要挂载到 body 上面,不在子应用容器中,样式就无法生效。
- 使用换肤的思路来解决 :在子项目给
body加一个唯一的id或class),在对应的全局的样式前面加上这个id/class。而single-spa模式则在mount周期给body/html加上这个唯一的id/class,在unmount周期去掉,这样就可以保证这个全局css只对这个项目生效了。
这两个方案的致命点都在于无法解决多个子项目同时运行时的 css 污染,以及子项目对主项目的 css 污染。
这两个方案已经能够把绝大多数问题解决。但是我们的项目中,是有一个看板的业务的。看板的业务就会把多个子应用同时加载。如果使用上面的两种方案,那么谁的包大,谁加载得慢,那么body的id/class就归谁的。物尽天择?
添加自定义命名空间
如果使用了element plus版本的简单很多了。2.20版本以上的,详情可以点击element-plus.gitee.io/zh-CN/guide…
核心代码如下:
// styles/element/index.scss
// we can add this to custom namespace, default is 'el'
@forward 'element-plus/theme-chalk/src/mixins/config.scss' with (
$namespace: 'ep'
);
// ...
使用postcss-plugin-namespace插件添加自定义命名空间
其他版本就需要借助插件来实现自定义命名空间了。有很多可以实现相同功能的插件,下面我以插件为例子。
npm i postcss-plugin-namespace -D
在根目录创建postcss.config.js 文件。
module.exports = (ctx) => {
return {
plugins: [
require('postcss-plugin-namespace')('#lee_project', {
ignore: [
'html', /body/, 'span', 'el-form-item', /[data/,
]
}),
]
}
}
ignore顾名思义就是忽略的class,也可以使用正则,如 /body/ 。里面有一个data,这是使用了style scroped之后,会给节点上面添加data-xxxx 。所以它也需要忽略掉。
直接覆盖样式
我劝你不要冲动,这是我们统计一部分样式污染的class名称:
主应用使用了和子应用不同的UI框架。我们为了让样式在加载我的应用的时候,需要全局复写上面的这些class名,并放在全局。
上面这些污染的class只是冰山一角哦,可自行评估一下需要多少工时。
三、容易疏忽的问题
字体属于静态资源。项目肯定是开启了协商缓存的。所以说,加载过之后的静态资源也是会污染全局的。而这个时候我们就需要处理两个问题。
自己从iconfont中下载下来的字体图标
直接修改iconfont的前缀即可。如下图配置:
element ui 内置的图标
并没有搞明白为什么什么的插件没有自动添加修改前缀。所以我们使用了最暴力的解决办法。不用element ui内置的图标,全部替换成iconfont的。问题解决就行。
这是因为我们项目的图标很少,所以能够这样干。如果你项目中有大量的图标的话,还是想想怎么使用插件来解决吧。解决了求求教教我。求求了!
四、总结
- 编程没有银弹,引入的qiankun解决了多团队协作的问题,也带来了新的问题。但是也要有我们在做技术选项的时候要有这样的心理预期。
- 自定义命名空间本质依旧是约定样式规范。
“开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 28 天, 点击查看活动详情 ”