一、背景介绍承接上文《【实践】微前端 qiankun 解决 Vue3 子应用样式污染问题》,团队的中台项目在完成微前端 qiankun 改造后,出现了 Vue3 子应用的样式污染问题。在 qiankun 主应用开启experimentalStyleIsolation: true的情况下,sub-vue3-a/sub-vue3-b(Vite + Vue3)激活后,所有样式均直接挂载到主文档的全局head下,且未被加上div[data-qiankun="xxx"]前缀,导致 Vue3 子应用的 CSS 发生泄漏并污染了 Vue2 子应用的样式。而sub-vue2(vue-cli / Webpack)在同等配置下,样式隔离表现正常。经分析,根因在于 Vue3 子应用走的是 Vite ESM 路径,绕开了 qiankun 的 JS 沙箱。qiankun 的experimentalStyleIsolation依赖 JS 沙箱捕获样式插入操作:它代理了document.head.appendChild和insertBefore,通过isInvokedByMicroApp判断插入动作是否来自子应用;命中后调用css.process()为选择器添加前缀,并将style移入子应用容器;未命中则原样放入全局head且不做改写。而命中与否,取决于子应用 JS 是否运行在 qiankun 的代理window中。最终选择的解决方案是在Vite 构建/转换阶段主动为 CSS 选择器加上前缀,使其与 qiankun 在容器上添加的data-qiankun="sub-vue3-a"属性对齐。然而,该方案解决的是样式污染问题,尚有一个遗留问题亟待处理——Vue3 子应用失活后的样式残留问题。Vue3 子应用卸载后,挂载在全局head中的style并不会被销毁;而带有data-qiankun="sub-vue3-a"属性的容器div则会被 qiankun 移除。此时,head中残留的 style 规则虽然仍在,但其选择器的锚点 DOM 已不存在,这些规则实际上匹配 0 个元素。切换至 Vue2 时,由于 Vue2 的 DOM 中不存在data-qiankun="sub-vue3-a"属性,因此不会被命中,不会影响渲染——本质上只是head中多了一堆「死」规则。这些残留规则的存在会带来两个维度的影响:整洁性与调试体验:DevTools 中head显得冗杂混乱。内存与 CSSOM 体积:HMR 反复切换会不断累积,长时间运行会造成一定资源浪费。如果项目对这两点不敏感,可以选择不做处理。但本文选择对其进行根治。二、问题分析2.1 为什么 Vue2 能自动清理,Vue3 不能?qiankun 清理动态样式的机制并非显式remove,而是依赖「寄生销毁」。查看forLooseSandbox.js中的注释:// As now the sub app content all wrapped with a special id container,// the dynamic style sheet would be removed automatically while unmounting其机制可概括为:Mount 阶段:qiankun 拦截appendChild,将style插入子应用的appWrapper(容器div)中,而非真正的document.head。Unmount 阶段:qiankun 将整个appWrapper从 DOM 树中移除;容器内的style作为子节点,随容器一同被销毁。Remount 阶段:调用rebuildCSSRules,将之前记录的style重新append回容器。2.2 Vite ESM 缓存的叠加效应Vite 的一个关键特性是:ESM 模块由浏览器进行级缓存,CSS import 仅执行一次。因此,Vue3 子应用第一次 mount 时样式被注入到head,之后的 unmount / remount 过程中,这些 style 既不会被清理,也不会重新注入——它们便永久驻留在head中了。三、解决方案3.1 核心思路将漏到document.head的 style「劫持」进子应用容器,使其重新享受 qiankun 的「寄生销毁」机制;同时处理 ESM 缓存导致 remount 时不会重新注入样式的问题。3.2 实现方案在sub-vue3-a/src/下新建style-hijack.js:letobserver=nullconstcachedNodes=[]