必须用 domparser 解析 html entry 后手动分发资源,而非直接 innerhtml = htmlstring,否则会跳过沙箱、逃逸样式、执行全局脚本;需提取 scripts、styles 和 template,分别走沙箱执行、注入和挂载,并确保所有动态插入的 style 标签被清理。

HTML Entry 拉取后怎么安全注入 DOM?
直接 innerHTML = htmlString 会跳过沙箱、逃逸样式、执行全局脚本,90% 的白屏和样式污染都源于此。必须用 DOMParser 解析,再手动分发资源。
常见错误现象:
- 子应用弹窗挂到
document.body,卸载后样式残留 -
document.write或内联<script></script>直接污染window - 动态插入的
<style></style>标签没被清理,导致多应用样式叠加
实操建议:
- 用
new DOMParser().parseFromString(html, 'text/html')获取解析后的doc - 提取
doc.head.querySelectorAll('link[rel="stylesheet"], style'),缓存内容或 URL - 提取
doc.body.innerHTML作为模板挂载点,**不保留原始head** - 所有
<script src="..."></script>必须拦截并走沙箱加载(如qiankun的execScripts)
为什么样式快照(snapshot)不能只靠移除 DOM 节点?
移除整个子应用根节点确实能清掉大部分 <style></style> 和 <link>,但以下情况快照机制会失效:
- 子应用在挂载后调用
document.head.appendChild(styleEl)—— 这个节点不在容器内,卸载时不会被删 - 使用
ant-design等组件库,默认把弹窗挂到document.body,其<style></style>是独立插入的 - 子应用 HTML 中有全局重置样式(如
body { margin: 0 }),快照只记录初始状态,不监控运行时变更
实操建议:
- 主应用需在
unmount阶段主动扫描并移除所有已知注入的style标签(按 class 或 data-mark 标记) - 强制子应用通过
getContainer或rootNode参数限定渲染范围,禁止直接操作document.body - 对第三方库做 wrapper 封装,劫持其
appendChild调用,重定向到子应用容器节点
如何让子应用 HTML 中的相对路径资源正常加载?
子应用 index.html 里写 src="./main.js" 或 href="./app.css",主应用 fetch 后直接解析,必然 404 —— 因为浏览器以主应用域名 + 当前路径解析,不是子应用部署路径。
关键不是改子应用代码,而是主应用加载时重写路径:
- 方案一:主应用注入
__webpack_public_path__ = 'https://cdn.example.com/subapp-v1/',子应用构建时需启用该变量 - 方案二:用正则或
DOMParser提取所有src/href属性,在加载前拼接绝对路径(如new URL(attrValue, subAppEntryUrl).href) - 方案三:子应用构建时设
publicPath: 'auto'(Webpack 5+),配合<base href="/subapp/">标签,但需确保主应用容器支持 base 标签作用域
注意:<base> 在 Shadow DOM 中无效,import-html-entry 默认不处理它,必须由主应用提前提取并应用。
Shadow DOM + adoptedStyleSheets 能替代样式快照吗?
不能。二者定位不同:adoptedStyleSheets 是作用域隔离,snapshot 是生命周期清理。前者防“写入污染”,后者防“残留污染”。
常见误用:
- 以为
shadowRoot.adoptedStyleSheets = [sheet]就万事大吉,结果子应用运行时又动态插入document.styleSheets[0].insertRule,逃逸出 shadow - 用
innerHTML注入含<style></style>的 HTML,导致样式写入 light DOM,adoptedStyleSheets完全不生效 - 忽略
@import和url(./img.png)在CSSStyleSheet中无法自动解析,需预编译或代理请求
实操建议:
- 只对静态 CSS 文本调用
new CSSStyleSheet().replace(text),再adopt;动态规则必须走shadowRoot.styleSheets[0].insertRule() - 禁用子应用直接访问
document.styleSheets,用沙箱代理或重写 getter - 若用
mode: 'closed',外部无法读取shadowRoot,调试时需暴露__debugShadow全局钩子
最易被忽略的是:样式快照依赖 DOM 移除触发浏览器 CSSOM 重建,而 Shadow DOM 的 adoptedStyleSheets 不触发该机制 —— 两者必须共存,不能互替。
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











