qiankun 是一个基于 single-spa 的微前端解决方案,它提供了沙箱隔离机制,以防止子应用之间的全局污染。
qiankun 的沙箱实现主要有两种方式:Proxy 沙箱和快照沙箱。
Proxy 沙箱:这是 qiankun 的默认沙箱实现方式。它使用 JavaScript 的 Proxy 对象创建一个全局对象的代理,通过这个代理隔离子应用对全局对象的影响。当子应用试图修改全局对象时,这个代理会拦截这个操作,将修改应用到代理对象上,而不是全局对象上。这样,子应用就可以在沙箱中自由地修改全局对象,而不会影响到其他子应用。
快照沙箱:这是 qiankun 的另一种沙箱实现方式。它在子应用加载时对全局对象进行快照,保存全局对象的当前状态。然后,在子应用卸载时,将全局对象恢复到加载时的状态。这样,子应用就可以在沙箱中自由地修改全局对象,而不会影响到其他子应用。
在实际使用中,qiankun 会根据环境和配置选择使用 Proxy 沙箱或快照沙箱。例如,如果浏览器不支持 Proxy,或者配置了 singleton: false,那么 qiankun 就会使用快照沙箱。
总的来说,qiankun 的沙箱实现主要是通过 Proxy 和快照两种方式,来隔离子应用对全局对象的影响,防止全局污染。
在qiankun中,Proxy沙箱的实现主要是通过JavaScript的Proxy对象来创建一个全局对象的代理。以下是一个简化的示例:
class ProxySandbox {
constructor() {
this.proxy = null;
this.rawWindow = window;
this.fakeWindow = {};
}
active() {
this.proxy = new Proxy(this.rawWindow, {
get: (target, p) => {
return this.fakeWindow[p] || this.rawWindow[p];
},
set: (target, p, value) => {
this.fakeWindow[p] = value;
return true;
},
});
}
inactive() {
this.proxy = null;
}
}
// 使用
const sandbox = new ProxySandbox();
sandbox.active(); // 激活沙箱环境
window.a = 1; // 在沙箱环境中修改全局变量
console.log(window.a); // 输出:1
sandbox.inactive(); // 关闭沙箱环境
console.log(window.a); // 输出:undefined
在这个示例中,我们创建了一个ProxySandbox类,它有两个方法:active和inactive。active方法会创建一个全局对象的代理,并将这个代理设置为当前的全局对象。inactive方法则会将全局对象恢复为原来的对象。
在代理对象中,我们定义了get和set陷阱。get陷阱会在读取属性时被触发,它会先从fakeWindow对象中查找属性,如果找不到,再从原来的全局对象中查找。set陷阱会在修改属性时被触发,它会将修改应用到fakeWindow对象上,而不是全局对象上。
这样,当我们在沙箱环境中修改全局变量时,实际上是在修改fakeWindow对象,而不是真正的全局对象。当我们关闭沙箱环境后,全局变量会恢复为原来的状态,不会被沙箱环境中的修改影响。
请注意,这只是一个简化的示例,实际的qiankun Proxy沙箱实现会更复杂,需要处理更多的情况,例如删除属性、调用函数等。
快照沙箱的实现原理是在子应用加载时对全局对象进行快照,保存全局对象的当前状态。然后,在子应用卸载时,将全局对象恢复到加载时的状态。这样,子应用就可以在沙箱中自由地修改全局对象,而不会影响到其他子应用。
以下是一个简化的示例:
class SnapshotSandbox {
constructor() {
this.snapshot = null; // 保存全局对象的快照
this.rawWindow = window; // 保存原始的全局对象
}
active() {
this.snapshot = {}; // 创建一个新的对象来保存全局对象的快照
// 遍历全局对象,将所有属性和值复制到快照中
for (const prop in this.rawWindow) {
if (this.rawWindow.hasOwnProperty(prop)) {
this.snapshot[prop] = this.rawWindow[prop];
}
}
}
inactive() {
// 遍历全局对象,将所有属性恢复到快照时的状态
for (const prop in this.rawWindow) {
if (this.rawWindow.hasOwnProperty(prop)) {
this.rawWindow[prop] = this.snapshot[prop];
}
}
}
}
// 使用
const sandbox = new SnapshotSandbox();
sandbox.active(); // 激活沙箱环境
window.a = 1; // 在沙箱环境中修改全局变量
console.log(window.a); // 输出:1
sandbox.inactive(); // 关闭沙箱环境
console.log(window.a); // 输出:undefined
在这个示例中,我们创建了一个SnapshotSandbox类,它有两个方法:active和inactive。active方法会对全局对象进行快照,保存全局对象的当前状态。inactive方法则会将全局对象恢复到快照时的状态。
这样,当我们在沙箱环境中修改全局变量时,实际上是在修改全局对象。但是当我们关闭沙箱环境后,全局变量会恢复为快照时的状态,不会被沙箱环境中的修改影响。
请注意,这只是一个简化的示例,实际的qiankun快照沙箱实现可能会更复杂,需要处理更多的情况,例如处理全局对象的原型链、处理全局函数等。