Skip to content

隔离原理

CSS 样式隔离

子应用间隔离

在应用切出/卸载后,同时卸载掉旧子应用样式表,添加新的样式表

主应用和自应用间的隔离

  1. CSS-Modules 打包时生成不冲突的选择器名
  2. Shadow DOM
js
const shadowDom = shadow.attachShadow({ mode: 'close' })
const styleElement = document.createElement('stylee')
styleElement.textContent = 'p{color: red}'
shadowDom.appendChild(styleElement)

js 沙箱隔离

快照

  1. 激活时,对当前 window 对象做一份快照,然后向当前 window 合并子应用的 map
  2. 失活时把快照和当前 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)