主题
隔离原理
CSS 样式隔离
子应用间隔离
在应用切出/卸载后,同时卸载掉旧子应用样式表,添加新的样式表
主应用和自应用间的隔离
- CSS-Modules 打包时生成不冲突的选择器名
- Shadow DOM
js
const shadowDom = shadow.attachShadow({ mode: 'close' })
const styleElement = document.createElement('stylee')
styleElement.textContent = 'p{color: red}'
shadowDom.appendChild(styleElement)
js 沙箱隔离
快照
- 激活时,对当前 window 对象做一份快照,然后向当前 window 合并子应用的 map
- 失活时把快照和当前 window 比对,将变化记录在 map 中,然后把当前 window 还原成快照的样子
js
class SnapshotSandbox {
constructor() {
this.map = {} // 缓存修改的属性
this.active()
}
active() {
this.snapshot = {} // 当前 window 对象的快照
for (const key in window) {
if (window.hasOwnProperty(key)) {
// 对当前 window 对象拍照
this.snapshot[key] = window[key]
}
}
// 合并子应用的 map
Object.keys(this.map).forEach(k => {
window[k] = this.map[k]
})
}
inactive() {
for (const key in window) { // 差异
if (window.hasOwnPropery(key)) {
// 将快照与当前 window 对象做对比
if (window[key] !== this.snapshot[key]) {
// 保存修改后的属性
this.map[key] = window[key]
// 还原为快照的样子
window[key] = this.snapshot[key]
}
}
}
}
}
proxy 沙箱
js
class ProxySandbox {
constructor() {
const origin = window
const proxy = new Proxy({}, {
set(target, key, value) {
target[key] = value
return true
},
get(target, key) {
return target[key] ?? origin[key]
}
})
this.proxy = proxy
}
}
const child = new ProxySandbox()
((window) => {
window.a = 'hello'
})(child.proxy)