qiankun 的沙箱隔离实现主要通过 JS 沙箱和 CSS 隔离两种机制,确保微前端子应用之间的运行时环境独立,避免全局变量、样式等冲突。以下是核心实现原理:
一、JS 沙箱隔离
qiankun 提供了两种主要的 JS 沙箱模式,分别适用于不同场景:
1. SnapshotSandbox(快照沙箱)
- 适用场景:单实例场景(同一时间只运行一个子应用)。
- 实现原理:
- 记录快照:子应用挂载时,保存当前
window
对象的快照(浅拷贝)。 - 隔离修改:子应用运行期间,所有对
window
的修改会记录在modifyPropsMap
中。 - 恢复环境:子应用卸载时,通过快照恢复全局
window
,并将子应用的修改存入内存,下次挂载时重新应用这些修改。
- 记录快照:子应用挂载时,保存当前
- 缺点:无法支持多实例同时运行,且频繁的快照操作可能影响性能。
2. ProxySandbox(代理沙箱)
- 适用场景:多实例场景(多个子应用同时运行)。
- 实现原理:
- 创建代理对象:为每个子应用创建一个假的全局对象(
fakeWindow
),通过Proxy
代理对window
的访问。 - 隔离读写:
- 读操作:优先从
fakeWindow
读取,若不存在则从真实window
读取(如内置 API)。 - 写操作:所有修改仅作用于
fakeWindow
,不会污染真实window
。
- 读操作:优先从
- 示例代码:
const fakeWindow = {}; const proxy = new Proxy(fakeWindow, { get(target, key) { return target[key] || window[key]; // 优先返回子应用的变量 }, set(target, key, value) { target[key] = value; // 修改仅作用于 fakeWindow return true; }, });
- 创建代理对象:为每个子应用创建一个假的全局对象(
- 优点:支持多实例,隔离性更好。
- 限制:依赖 ES6
Proxy
,不支持 IE 浏览器(可通过关闭沙箱降级)。
二、CSS 隔离
qiankun 通过以下方式避免子应用样式污染:
1. Shadow DOM 隔离
- 将子应用的 DOM 结构包裹在 Shadow DOM 中,天然实现样式隔离。
- 缺点:某些 UI 库(如弹窗组件)可能无法在 Shadow DOM 内正常运行。
2. Scoped CSS
- 动态改写样式:子应用挂载时,为所有
<style>
和<link>
标签的 CSS 规则添加 前缀选择器,限制样式仅作用于当前子应用容器。 - 实现示例:
/* 原始样式 */ .button { color: red; } /* 改写后 */ [data-qiankun="app1"] .button { color: red; }
- 性能注意:动态加载的样式文件需通过
postcss
等工具处理。
3. 工程化隔离
- 约定子应用使用 CSS Modules、CSS-in-JS 等局部作用域方案。
三、其他隔离细节
- 事件监听隔离:重写
addEventListener
等方法,确保子应用卸载时自动清理事件。 - 动态脚本拦截:劫持
document.createElement
,拦截动态加载的脚本并包裹在沙箱中执行。 - 全局 API 代理:对
setInterval
、location
等全局 API 做劫持,确保子应用卸载后清除副作用。
四、配置与注意事项
- 关闭沙箱:可通过配置
{ sandbox: false }
关闭沙箱(不推荐)。 - 兼容性问题:Proxy 无法降级时,需回退到快照沙箱或限制浏览器环境。
- 逃逸场景:直接操作
window.parent
或未代理的全局 API 可能导致隔离失效,需代码规范约束。
通过上述机制,qiankun 实现了子应用间的运行时隔离,平衡了隔离性和性能。实际应用中需根据场景选择合适的沙箱模式,并避免直接操作全局对象。