解读微前端的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}`)
		})
	}
})
相关推荐
亿元程序员1 分钟前
大佬,现在AI游戏开发教程那么多,你不搞点卖给大学生吗?
前端
未来龙皇小蓝12 分钟前
RBAC前端架构-02:集成Vue Router、Vuex和Axios实现基本认证实现
前端·vue.js·架构
晓得迷路了26 分钟前
栗子前端技术周刊第 116 期 - 2025 JS 状态调查结果、Babel 7.29.0、Vue Router 5...
前端·javascript·vue.js
淡忘_cx40 分钟前
使用Jenkins自动化部署vue项目(2.528.2版本)
vue.js·自动化·jenkins
顾北1241 分钟前
AI对话应用接口开发全解析:同步接口+SSE流式+智能体+前端对接
前端·人工智能
iDao技术魔方1 小时前
深入Vue 3响应式系统:为什么嵌套对象修改后界面不更新?
javascript·vue.js·ecmascript
摸鱼的春哥1 小时前
春哥的Agent通关秘籍07:5分钟实现文件归类助手【实战】
前端·javascript·后端
念念不忘 必有回响1 小时前
viepress:vue组件展示和源码功能
前端·javascript·vue.js
C澒1 小时前
多场景多角色前端架构方案:基于页面协议化与模块标准化的通用能力沉淀
前端·架构·系统架构·前端框架
崔庆才丨静觅1 小时前
稳定好用的 ADSL 拨号代理,就这家了!
前端