直接 innerhtml 注入会破坏沙箱隔离契约,导致样式污染、脚本全局执行、dom 挂载越界;必须用 domparser 解析后分治处理 style/script,丢弃原始 head,通过 adoptedstylesheets 和沙箱执行注入。

为什么直接 innerHTML 注入子应用 HTML 会退化代码质量
不是“写法不规范”,而是破坏了沙箱的隔离契约:直接 shadowRoot.innerHTML = htmlString 或 el.innerHTML = htmlString 会让子应用的 <style></style> 和 <script></script> 逃逸到全局作用域,导致样式污染、脚本执行上下文错乱、DOM 节点挂载越界。这种写法在单体应用里能跑通,在微前端里就是技术债加速器。
- 子应用的
normalize.css重置了主应用body字体大小和 margin -
<script>document.body.classList.add('dark')</script>在全局执行,但此时document.body可能还没 ready,报错Failed to execute 'querySelector' on 'Document': The provided selector is empty - Ant Design Modal 默认挂载到
document.body,卸载后 DOM 节点残留,样式表仍留在document.styleSheets中
用 DOMParser 解析 HTML Entry 是强制步骤
HTML Entry(即子应用的 index.html 字符串)不能当普通字符串处理。必须走解析→提取→分发流程,否则所有后续隔离逻辑都建立在流沙之上。
- 调用
new DOMParser().parseFromString(html, 'text/html')得到标准Document对象 - 只取
doc.body.innerHTML作为模板内容挂载进容器,**丢弃原始doc.head** —— 它里面可能含全局<style></style>、<link rel="stylesheet">、<script></script> - 对
doc.head.querySelectorAll('style, link[rel="stylesheet"]')提取内容或 URL,统一走主应用提供的injectStyle()或adoptedStyleSheets注入路径 - 对
doc.head.querySelectorAll('script[src]')拦截加载,用沙箱环境(如重绑定this/window/document)执行,禁止eval或Function构造器直跑
Shadow DOM 下不能依赖 CSS Scoped 或 data-* 前缀
data-subapp="a" 这类属性本身不产生任何隔离效果,它只是个选择器锚点;而 Vue 的 scoped 或 PostCSS 的 css-scope 插件,只处理编译时静态样式,对子应用运行时动态插入的 <style></style> 标签完全无效。
- 真正起效的样式边界只有
attachShadow({ mode: 'closed' }),且必须在constructor()中调用 -
mode: 'open'允许外部脚本通过el.shadowRoot直接篡改内部样式表,生产环境等同于没隔离 -
adoptedStyleSheets不支持@import和相对路径资源(如url(./icon.png)),这些需提前做路径重写或预加载 - 第三方 UI 库(如 Ant Design)必须配置
getContainer: () => subAppRoot,否则其弹窗、提示框仍会挂到document.body,绕过 Shadow DOM 边界
iframe 不是“备选方案”,而是信任边界的硬性分界线
当子应用来自不可信第三方(如广告 SDK、支付嵌入页),或者你明确接受其性能开销和通信成本时,iframe 才是唯一合规解。其他所有 JS/CSS 隔离方案,本质上都是在主页面 JS 引擎里“模拟隔离”,无法阻止 eval、with、Symbol.unscopables 等逃逸手段。
- 同域下用
src="about:blank"创建 iframe,再通过iframe.contentWindow拿到干净全局对象 - 注入脚本必须写入
iframe.contentDocument后触发执行,**绝不能用win.eval()或win.execScript()** -
<base href="%24%7BsubAppBase%7D">必须写入 iframe 文档头,否则子应用内fetch('/api')、图片路径、CSSurl()全部 404 - iOS Safari 对
iframe height: 100%渲染不稳定,滚动条错位常见,需加min-height: 1pxhack 或监听 resize 重算高度
真实项目里最常被忽略的点:子应用卸载时,没人清理它动态插入的 <style></style> 标签——尤其那些通过 document.head.appendChild 加进去的。DOM 节点删了,样式还在 document.styleSheets 里,下一个子应用一挂载就覆盖。这问题不靠工具链自动修复,得靠每个子应用开发者守规矩。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











