Appearance
微前端常见问题与解决方案
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
- 确保子应用的样式具有局部作用域
子应用样式影响主应用样式
问题原因
- 子应用的全局样式(如
body、html选择器)会泄漏到主应用 - 子应用的样式可能覆盖主应用的样式
解决方案
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
- 确保样式完全隔离
最佳实践
样式隔离最佳实践
- 优先使用 Shadow DOM:提供最彻底的样式隔离
- 使用 CSS Module:避免类名冲突
- 添加命名空间:为子应用样式添加唯一前缀
- 限制全局样式:减少使用全局选择器
- 合理配置 qiankun:根据实际场景选择合适的隔离方案
JS 隔离最佳实践
- 多实例场景使用 ProxySandbox:确保多个微应用同时运行时的隔离
- 避免修改全局对象:微应用应尽量避免修改全局对象
- 使用模块化:采用 ES 模块或 CommonJS 模块,减少对全局变量的依赖
- 合理使用生命周期:在微应用的生命周期钩子中处理资源的加载和卸载
总结
qiankun 通过多种沙箱机制实现了微应用的隔离,包括 JS 隔离和 CSS 隔离。针对不同的场景,可以选择合适的隔离方案:
- JS 隔离:根据是否需要多实例运行,选择快照沙箱或代理沙箱
- CSS 隔离:根据兼容性和需求,选择动态样式表、Shadow DOM 或 CSS Module
通过合理配置和最佳实践,可以有效解决主应用与子应用之间、子应用之间的样式冲突问题,确保微前端架构的稳定性和可维护性。