解读微前端的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}`)
		})
	}
})
相关推荐
lilu88888881 小时前
AI代码生成器赋能房地产:ScriptEcho如何革新VR/AR房产浏览体验
前端·人工智能·ar·vr
LCG元1 小时前
Vue.js组件开发-实现对视频预览
前端·vue.js·音视频
傻小胖1 小时前
shallowRef和shallowReactive的用法以及使用场景和ref和reactive的区别
javascript·vue.js·ecmascript
阿芯爱编程1 小时前
vue3 react区别
前端·react.js·前端框架
烛.照1032 小时前
Nginx部署的前端项目刷新404问题
运维·前端·nginx
YoloMari2 小时前
组件中的emit
前端·javascript·vue.js·微信小程序·uni-app
浪浪山小白兔2 小时前
HTML5 Web Worker 的使用与实践
前端·html·html5
疯狂小料3 小时前
React 路由导航与传参详解
前端·react.js·前端框架
customer084 小时前
【开源免费】基于SpringBoot+Vue.JS贸易行业crm系统(JAVA毕业设计)
java·vue.js·spring boot·后端·spring cloud·开源
追光少年33224 小时前
Learning Vue 读书笔记 Chapter 2
前端·javascript·vue.js·vue3