乾坤(qiankun)实现沙箱机制,看这篇就够了
乾坤(Qiankun)是一个微前端框架,它通过沙箱机制来隔离各个微应用,确保它们在同一个页面中不会相互干扰。以下是乾坤实现沙箱的主要技术和步骤:
一,沙箱实现原理
- 全局变量隔离:
- 乾坤通过代理(Proxy)对象来拦截和管理全局变量(如 
window对象)的读写操作,从而实现全局变量的隔离。 - 当微应用尝试访问或修改全局变量时,沙箱会捕获这些操作并进行处理,确保不会影响其他微应用。
 
 - 样式隔离:
- 乾坤使用 Shadow DOM 或 scoped CSS 来隔离微应用的样式,防止样式冲突。
 - 对于不支持 Shadow DOM 的浏览器,乾坤会通过 CSS 前缀或其他方式来实现样式隔离。
 
 - 事件隔离:
- 乾坤会拦截和管理全局事件(如 
click、resize等),确保事件不会跨微应用传播。 - 通过事件代理和事件委托,实现事件的精确控制和隔离。
 
 - 生命周期管理:
- 乾坤为每个微应用定义了详细的生命周期钩子,包括 
bootstrap、mount和unmount,确保微应用在不同阶段的行为可控。 - 在 
unmount阶段,乾坤会清理微应用的全局变量、事件监听器等,确保微应用卸载后不会留下残留。 
 
沙箱机制代码实现示例
以下是一个简单的示例,展示了乾坤如何通过 Proxy 对象实现全局变量隔离:
// 沙箱类
class Sandbox {
constructor() {
this.originalWindow = window; // 保存原始的 window 对象
this.proxyWindow = new Proxy(window, {
get: (target, key) => {
// 检查是否已经存在隔离的变量
if (this[key] !== undefined) {
return this[key];
        }
return target[key];
      },
set: (target, key, value) => {
// 检查是否已经存在隔离的变量
if (this[key] !== undefined) {
this[key] = value;
return true;
        }
        target[key] = value;
return true;
      }
    });
  }
activate() {
// 激活沙箱,将 window 替换为 proxyWindow
window = this.proxyWindow;
  }
deactivate() {
// 恢复原始的 window 对象
window = this.originalWindow;
  }
clear() {
// 清理沙箱中的所有变量
for (const key in this) {
if (this.hasOwnProperty(key) && key !== 'originalWindow' && key !== 'proxyWindow') {
delete this[key];
      }
    }
  }
}
// 使用沙箱
const sandbox = new Sandbox();
// 激活沙箱
sandbox.activate();
// 模拟微应用的全局变量操作
window.myVar = 'Hello, Qiankun!';
// 检查沙箱中的全局变量
console.log(sandbox.myVar); // 输出: Hello, Qiankun!
// 恢复原始的 window 对象
sandbox.deactivate();
// 清理沙箱
sandbox.clear();
// 检查原始的 window 对象
console.log(window.myVar); // 输出: undefined
代码详细解释
- 构造函数:
constructor中保存了原始的window对象,并创建了一个Proxy对象proxyWindow,用于拦截对window的访问。
 - 拦截读取操作:
get方法拦截对window对象属性的读取操作。如果沙箱中已经存在该属性,则返回沙箱中的值;否则返回原始window对象中的值。
 - 拦截写入操作:
set方法拦截对window对象属性的写入操作。如果沙箱中已经存在该属性,则更新沙箱中的值;否则更新原始window对象中的值。
 - 激活和恢复:
activate方法将window替换为proxyWindow,激活沙箱。deactivate方法将window恢复为原始的window对象,退出沙箱。
 - 清理:
clear方法清理沙箱中的所有变量,确保微应用卸载后不会留下残留。
 
优势
- 隔离性:通过 
Proxy拦截,确保微应用对全局变量的读写操作不会影响其他微应用。 - 灵活性:可以在 
get和set方法中添加更多的逻辑,例如日志记录、权限检查等。 - 透明性:对微应用来说,使用 
window对象的体验与未使用沙箱时相同,无需修改微应用的代码。 
通过这种方式,乾坤等微前端框架能够有效地隔离各个微应用的全局变量,确保它们在同一个页面中稳定运行。
使用 Proxy 对象拦截和管理全局变量的读写操作
使用 Proxy 对象拦截和管理全局变量的读写操作是实现沙箱机制的一种常见方法。Proxy 是 JavaScript 提供的一个内置对象,用于定义自定义行为(也称为陷阱,traps)来拦截并控制对目标对象的操作。在微前端框架中,Proxy 可以用来拦截对 window 对象的访问,从而实现全局变量的隔离。
详细步骤
- 创建 
Proxy对象:- 使用 
new Proxy(target, handler)创建一个Proxy对象,其中target是要拦截的目标对象(通常是window),handler是一个对象,定义了各种拦截操作的自定义行为。 
 - 定义拦截行为:
handler对象中可以定义多种拦截操作,例如get、set、apply、construct等。这里主要关注get和set方法,用于拦截对全局变量的读取和写入操作。
 - 激活和恢复 
Proxy:- 在微应用启动时激活 
Proxy,在微应用卸载时恢复原始的window对象。 
 
二,Shadow DOM
Shadow DOM 是一种 Web 技术,允许你在文档中创建独立的 DOM 树,并将其附加到一个元素上。这些独立的 DOM 树与主文档的其余部分隔离,因此可以避免样式和脚本的冲突。
实现步骤
- 创建 Shadow Root:
- 为每个微应用的根元素创建一个 Shadow Root。
 
 - 插入样式:
- 将微应用的样式插入到 Shadow Root 中,而不是主文档的 
<head>中。 
 - 插入内容:
- 将微应用的内容插入到 Shadow Root 中。
 
 
Shadow Dom示例代码
!-- HTML 结构 -->
<div id="app-root"></div>
<script>
  // 获取微应用的根元素
  const rootElement = document.getElementById('micri-app-root');
  // 创建 Shadow Root
  const shadowRoot = rootElement.attachShadow({ mode: 'open' });
  // 插入样式
  const style = document.createElement('style');
style.textContent = `
    .app-header {
      background-color: blue;
      color: white;
    }
  `;
  shadowRoot.appendChild(style);
  // 插入内容
  const content = document.createElement('div');
content.className = 'app-header';
content.textContent = 'Hello, Qiankun!';
  shadowRoot.appendChild(content);
</script>
三,Scoped CSS
Scoped CSS 是一种在 HTML 中为特定组件或部分定义样式的机制。通过在 <style> 标签中使用 scoped 属性,可以确保样式仅应用于当前元素及其子元素。
Scoped CSS实现步骤
- 创建带有 
scoped属性的<style>标签:- 在微应用的根元素内部创建一个带有 
scoped属性的<style>标签。 
 - 插入样式:
- 将微应用的样式插入到带有 
scoped属性的<style>标签中。 
 - 插入内容:
- 将微应用的内容插入到根元素中。
 
 
Scoped CSS示例代码
<!-- HTML 结构 -->
<div id="micro-app-root">
<style scoped>
.app-header {
background-color: blue;
color: white;
    }
</style>
<div class="app-header">Hello, Qiankun!</div>
</div>
通过使用 Shadow DOM 和 scoped CSS,乾坤能够有效地隔离微应用的样式,防止样式冲突。这两种方法各有优缺点:
- Shadow DOM:
- 优点:完全隔离,不会受到外部样式的影响。
 - 缺点:浏览器兼容性稍差,某些旧浏览器不支持。
 
 - Scoped CSS:
- 优点:兼容性好,大多数现代浏览器都支持。
 - 缺点:样式隔离不如 Shadow DOM 完全,可能会受到一些外部样式的影响。
 
 
根据具体需求和项目环境,可以选择适合的样式隔离方式。
总结
乾坤通过以下技术实现了微应用的沙箱隔离:
- 全局变量隔离:使用 Proxy 对象拦截和管理全局变量的读写操作。
 - 样式隔离:使用 Shadow DOM 或 scoped CSS 防止样式冲突。
 - 事件隔离:拦截和管理全局事件,确保事件不会跨微应用传播。
 - 生命周期管理:定义详细的生命周期钩子,确保微应用在不同阶段的行为可控。
 
通过这些机制,乾坤能够有效地隔离各个微应用,确保它们在同一个页面中稳定运行。
PS:学会了记得,点赞,评论,收藏,分享
作者:AndyGoWei
来源:juejin.cn/post/7431455846150242354
                            来源:juejin.cn/post/7431455846150242354