html entry通过fetch拉取子应用index.html后,必须用domparser解析提取scripts、styles和template三类内容,再分别注入执行挂载,禁用innerhtml直接赋值以防沙箱逃逸。

HTML Entry 是怎么被 fetch + DOMParser 解析出来的
主应用不会 import 子应用 JS,而是用 fetch 拉取子应用的 index.html,再用 DOMParser 解析。关键不是“拿到 HTML 字符串”,而是从中提取三类内容:scripts(JS URL 或内联代码)、styles(link 或 style 标签内容)、template(body.innerHTML)。这些内容后续被分别注入、执行、挂载——整个流程绕开了直接执行全局脚本的风险。
常见错误现象:
-
fetch返回 404:子应用 HTML 中script src="./main.js"是相对路径,但主应用没设__webpack_public_path__,也没重写<base href> - 内联脚本污染
window:比如<script>window.utils = {...}</script>在沙箱接管前就执行了 - 动态执行逃逸:子应用用了
document.write或eval('...'),跳过了沙箱包装逻辑
实操建议:
- 子应用所有静态资源(JS/CSS/图片)在 HTML Entry 中必须为绝对路径,或由主应用统一注入
__webpack_public_path__ - 避免在 HTML 中写内联脚本;如有,确保其执行被沙箱框架(如 qiankun 的
execScripts)包裹 -
DOMParser解析后,真正挂载的是doc.body.innerHTML,不是原始 HTML 字符串——别直接innerHTML = rawHtml
为什么 iframe 是 HTML 层唯一真正的 JS 沙箱
浏览器对 iframe 的隔离是引擎级的:它拥有独立的 window、document、history、location,甚至独立事件循环。只要 src="about:blank" 且同域,就能通过 iframe.contentWindow 安全拿到一个干净、隔离、可编程的全局对象——这不是模拟,是真实副本。
其他纯 JS 方案(Proxy 快照、with 劫持)都绕不开一个问题:代码最终仍在主页面 JS 引擎里跑。子应用仍可通过 eval、Function 构造器、with、Symbol.unscopables 等方式逃逸;快照沙箱更是在主 window 上直接改,靠“还原”假装隔离。
实操建议:
- 不要用
win.eval()或win.execScript()注入脚本——那等于把代码拉回主上下文执行,沙箱失效 - 正确做法是:把子应用 HTML 写入
iframe.document,再调用doc.close()触发解析与执行 - 必须设置
<base href="%24%7BsubAppBase%7D">,否则子应用内相对路径的fetch、图片、样式会 404 - 跨域场景下可用
sandbox="allow-scripts allow-same-origin",但同域about:blank更轻量、无 CSP 阻断风险
样式隔离为什么卸载时自动生效,又为什么还会逃逸
HTML Entry 模式下,子应用卸载时主应用会连同整个子应用 DOM 节点(含所有动态插入的 style、link)一并移除。浏览器收到 DOM 删除指令后,自动触发 CSSOM 重建,原样式表立即失效——这比手动遍历删 style 标签更可靠,也无需依赖 shadow DOM 或 CSS-in-JS。
但以下情况仍会逃逸:
- 子应用挂载后又通过
document.head.appendChild插入新style,该标签不在子应用根节点下,卸载时不会被清理 - 第三方组件库(如 ant-design)弹窗默认挂载到
document.body,样式脱离容器,沙箱无法回收 - 子应用 HTML 中有全局作用的
<style>body { margin: 0 }</style>,且未启用样式沙箱快照机制
实操建议:
- 强制子应用所有 UI 渲染限定在容器节点内,对 ant-design 等组件库显式传入
getContainer配置 - 禁用子应用直接操作
document.head;如需动态加样式,应走主应用提供的通信接口或 props 注入 - qiankun 默认开启样式沙箱,但对 CSS-in-JS(styled-components/emotion)无效,需配合
CSS Modules或scoped style
micro-app 中 script 标签引入后 JS 不执行或样式丢失怎么办
根本原因是 micro-app 默认启用沙箱(sandbox=true),会拦截全局变量访问和 document.head.appendChild 等 DOM 操作。老框架(jQuery 插件、某些 UI 库)依赖 window 属性或直接操作 document.head,导致失效。
常见错误现象:
- 控制台报
Failed to resolve module specifier:说明子应用用了 ES Module 语法,但没配好type="module"或模块解析路径 - 样式丢失:子应用用了 CSS-in-JS 或动态插入
style标签,被沙箱拦截 - JS 不执行:内联脚本未被
execScripts包裹,或子应用调用了history.pushState被沙箱阻断
实操建议:
- 临时调试可加
sandbox="false",但上线必须关掉——失去隔离不值得 - 稳妥做法是在子应用中利用
import-html-entry生命周期钩子,在execScripts后手动补全局变量(如window.$ = jQuery) - CSS 丢失时改用
micro-app提供的appendStyle方法注入样式,而非直接操作head - 子应用路由必须用
app.router或监听popstate,禁用原生history.pushState
前端入门到VUE实战笔记:立即使用
在学习笔记中,你将探索 前端 的入门与实战技巧!











