Skip to content

微前端常见问题与解决方案

qiankun 沙箱隔离原理

JS 隔离原理

qiankun 实现了两种 JS 沙箱模式:

1. 快照沙箱(SnapshotSandbox)

  • 原理:通过在应用激活和失活时,对全局对象(如 window)进行快照和恢复来实现隔离
  • 实现方式
    • 激活时,记录当前全局对象的状态作为快照
    • 应用运行时对全局对象的修改会被记录
    • 失活时,恢复全局对象到快照状态
  • 适用场景:单实例场景,即同一时刻只有一个微应用在运行

2. 代理沙箱(ProxySandbox)

  • 原理:使用 ES6 的 Proxy 对象创建一个代理环境,所有对全局对象的访问和修改都通过代理进行
  • 实现方式
    • 为每个微应用创建一个独立的代理对象
    • 微应用对 window 的访问实际上是访问代理对象
    • 代理对象会维护一个独立的状态,与其他微应用隔离
  • 适用场景:多实例场景,即多个微应用同时运行

CSS 隔离原理

qiankun 提供了三种 CSS 隔离方案:

1. 动态样式表隔离

  • 原理:通过动态添加和移除样式表来实现隔离
  • 实现方式
    • 微应用激活时,加载其样式表
    • 微应用失活时,移除其样式表

2. Shadow DOM 隔离

  • 原理:利用浏览器原生的 Shadow DOM 特性,创建一个独立的 DOM 树和样式作用域
  • 实现方式
    • 将微应用的根节点挂载到一个 Shadow DOM 中
    • Shadow DOM 内的样式不会影响外部,外部样式也不会影响内部

3. CSS Module 隔离

  • 原理:通过 CSS Module 技术,为每个样式生成唯一的类名
  • 实现方式
    • 微应用构建时,将类名转换为哈希值
    • 确保不同微应用的类名不会冲突

样式隔离问题及解决方案

主应用样式影响子应用样式

问题原因

  • 主应用的全局样式(如 reset.css、全局变量等)会通过 CSS 层叠规则影响子应用
  • 主应用的样式优先级可能高于子应用的样式

解决方案

1. 使用 Shadow DOM 隔离
javascript
// 主应用中配置
import { registerMicroApps, start } from 'qiankun'

registerMicroApps([
  {
    name: 'child-app',
    entry: '//localhost:8080',
    container: '#container',
    activeRule: '/child-app',
    props: {
      shadowDOM: true // 启用 Shadow DOM
    }
  }
])

start()
2. 为子应用添加样式前缀
  • 在子应用的构建配置中添加样式前缀
  • 例如,使用 postcss-prefix-selector 插件
3. 子应用使用 CSS Module 或 CSS-in-JS
  • 确保子应用的样式具有局部作用域

子应用样式影响主应用样式

问题原因

  • 子应用的全局样式(如 bodyhtml 选择器)会泄漏到主应用
  • 子应用的样式可能覆盖主应用的样式

解决方案

1. 动态样式表管理
  • qiankun 会自动管理子应用的样式表,在子应用失活时移除其样式
  • 确保子应用的样式表正确加载和卸载
2. 子应用样式作用域限制
  • 子应用的样式应该限制在其容器内
  • 使用 CSS 选择器限定作用域,如:
css
/* 子应用样式 */
#child-app-container {
  /* 子应用样式 */
}

#child-app-container .component {
  /* 组件样式 */
}
3. 禁用子应用的全局样式
  • 在子应用的构建配置中,禁用生成全局样式
  • 或者在子应用中避免使用全局选择器

子应用之间样式互相影响

问题原因

  • 多个子应用同时运行时,样式可能发生冲突
  • 不同子应用可能使用相同的类名或选择器

解决方案

1. 使用命名空间
  • 为每个子应用的样式添加唯一的命名空间
  • 例如:
css
/* 子应用 A */
.app-a .header {
  /* 样式 */
}

/* 子应用 B */
.app-b .header {
  /* 样式 */
}
2. 使用 CSS Module
  • 子应用使用 CSS Module,自动生成唯一的类名
  • 避免类名冲突
3. 配置 qiankun 的样式隔离选项
javascript
// 主应用中配置
start({
  sandbox: {
    strictStyleIsolation: true // 启用严格的样式隔离
  }
})
4. 使用 Shadow DOM
  • 为每个子应用启用 Shadow DOM
  • 确保样式完全隔离

最佳实践

样式隔离最佳实践

  1. 优先使用 Shadow DOM:提供最彻底的样式隔离
  2. 使用 CSS Module:避免类名冲突
  3. 添加命名空间:为子应用样式添加唯一前缀
  4. 限制全局样式:减少使用全局选择器
  5. 合理配置 qiankun:根据实际场景选择合适的隔离方案

JS 隔离最佳实践

  1. 多实例场景使用 ProxySandbox:确保多个微应用同时运行时的隔离
  2. 避免修改全局对象:微应用应尽量避免修改全局对象
  3. 使用模块化:采用 ES 模块或 CommonJS 模块,减少对全局变量的依赖
  4. 合理使用生命周期:在微应用的生命周期钩子中处理资源的加载和卸载

总结

qiankun 通过多种沙箱机制实现了微应用的隔离,包括 JS 隔离和 CSS 隔离。针对不同的场景,可以选择合适的隔离方案:

  • JS 隔离:根据是否需要多实例运行,选择快照沙箱或代理沙箱
  • CSS 隔离:根据兼容性和需求,选择动态样式表、Shadow DOM 或 CSS Module

通过合理配置和最佳实践,可以有效解决主应用与子应用之间、子应用之间的样式冲突问题,确保微前端架构的稳定性和可维护性。

基于 VitePress 的本地知识库