解读微前端的css沙箱

qiankun 的 css 沙箱的原理是重写 HTMLHeadElement.prototype.appendChild 事件,记录子项目运行时新增的 style/link 标签,卸载子项目时移除这些标签。

在子系统卸载的时候,将子系统引入css使用的、标签移除掉。移除的办法是重写标签的appendChild方法,办法类似定时器的重写。 子系统加载时,会将所需要的js/css文件插入到标签,而重写的appendChild方法会记录所插入的标签,然后子系统卸载的时候,会移除这些标签。

注意:无法解决多个子项目同时运行时的 css 污染,以及子项目对主项目的 css 污染

我们可以借助换肤的思路来解决css污染,首先css-scoped解决95%的样式污染,然后就是全局样式可能会造成污染,我们只需要将全局样式用一个id/class包裹着就可以了,这样这些全局样式仅在这个id/class范围内生效。

具体做法就是:在子系统加载时(mount)给加一个特殊的id/class,然后在子系统卸载时(unmount)删掉这个id/class。而子系统的全局样式都仅在这个id/class范围内生效,如果子系统独立运行,只需要在子系统的入口文件index.html里面给手动加上这个id/class即可。 代码如下:

javascript 复制代码
async function mount(props){
  //给body加class,以解决全局样式污染
  document.body.classList.add('app-vue-history')
}
async function unmount(props){
  //去掉body的class
  document.body.classList.remove('app-vue-history')
}

当然了,你写的全局样式也在这个class下面:

less 复制代码
.app-vue-history{
    h1{
        color: red
    }
}

样式的隔离有很多种处理方式,如:BEM、CSS Module、css前缀、动态加载/卸载样式表、Web Components自带隔离机制等。

约定式编程 这里我们可以采用一定的编程约束:

  • 尽量不要使用可能冲突全局的 class 或者直接为标签定义样式;
  • 定义唯一的 class 前缀,现在的项目都是用诸如 antd 这样的组件库,这类组件库都支持自定义组件 class 前缀;
  • 主应用一定要有自定义的 class 前缀;

此次采用添加 css 前缀来隔离样式,比如 postcss 插件:postcss-plugin-namespace。但是这个插件并不满足需求,我们的应用分布在 src/下,并以 name.app 的方式命名,需要给不同的应用添加不同的前缀。因此使用自己定制的插件:

javascript 复制代码
postcss.plugin('postcss-plugin-namespace', function() {
	return function(css) {
		css.walkRules(rule => {
			if (rule.parent && rule.parent.type === 'atrule' && rule.parent.name !== 'media') return
			const filePath = rule.source && rule.source.input.file
			const appName = /src\/(\S*?)\//.exec(filePath)[1] || ''
			const namespace = appName.split('.')[0] || ''

			rule.selectors = rule.selectors.map(s => `#${namespace} ${s === 'body' ? '' : s}`)
		})
	}
})
相关推荐
疯狂的沙粒20 分钟前
在web-view 加载的本地及远程HTML中调用uniapp的API及网页和vue页面是如何通讯的?
前端·uni-app·html
程序员秘密基地21 分钟前
基于vscode,idea,java,html,css,vue,echart,maven,springboot,mysql数据库,在线考试系统
java·vue.js·spring boot·spring·web app
小妖66624 分钟前
html 滚动条滚动过快会留下边框线
前端·html
heroboyluck38 分钟前
Svelte 核心语法详解:Vue/React 开发者如何快速上手?
前端·svelte
海的诗篇_39 分钟前
前端开发面试题总结-JavaScript篇(二)
开发语言·前端·javascript·typescript
琹箐1 小时前
ant-design4.xx实现数字输入框; 某些输入法数字需要连续输入两次才显示
前端·javascript·anti-design-vue
程序员-小李1 小时前
VuePress完美整合Toast消息提示
前端·javascript·vue.js
Uyker2 小时前
从零开始制作小程序简单概述
前端·微信小程序·小程序
EndingCoder6 小时前
React从基础入门到高级实战:React 实战项目 - 项目三:实时聊天应用
前端·react.js·架构·前端框架
阿阳微客7 小时前
Steam 搬砖项目深度拆解:从抵触到真香的转型之路
前端·笔记·学习·游戏