常用知识点汇总
微前端的概念
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略 具备几个核心价值:
- 与技术栈无关
- 独立开发,独立部署
- 增量升级
- 独立运行,每个微应用之间状态隔离,运行时状态不共享
qiankun和single-spa的关系
为什么不使用iframe代替qiankun
如果不考虑体验问题,iframe是最完美的微前端解决方案
iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享,随之带来的开发体验、产品体验的问题。
- url不同步,浏览器刷新iframe url丢失,后退前进按钮无法使用
- UI 不同步,DOM结构不共享, 弹框等元素无法基于整体位置放置
- 全局上下文完全隔离,变量不共享,需要的内容需要借助ifame内外通信才可以传递到内部
- 慢,每次进入子应用都是一次浏览器上下文的重建.
qiankun的生命周期
路由模式挂载生命周期,作用在主服务
- beforeLoad - `Lifecycle | Array<Lifecycle>` - 可选
- beforeMount - `Lifecycle | Array<Lifecycle>` - 可选
- afterMount - `Lifecycle | Array<Lifecycle>` - 可选
- beforeUnmount - `Lifecycle | Array<Lifecycle>` - 可选
- afterUnmount - `Lifecycle | Array<Lifecycle>` - 可选
bootstrap (初始化)
-
触发时机:子应用首次被加载时调用,且在整个主应用运行期间只执行一次。
-
主要用途:
- 执行全局性的初始化逻辑。
- 预加载一些全局资源(如字体、公共库等)。
- 准备初始状态。
-
注意:不要在此处进行 DOM 操作或挂载应用,因为它只运行一次,多次切换子应用时不会重复执行。
mount (挂载/渲染)
-
触发时机:每次子应用被激活(路由匹配到该子应用)时调用。
-
主要用途:
- 渲染 UI:将子应用的根组件挂载到主应用提供的容器节点中。
- 启动业务逻辑:启动路由监听、定时器等。
- 接收 props:接收主应用传递的状态、通信方法等参数。
-
关键点:
- 必须是一个异步函数(返回 Promise)。
- 需要确保每次挂载都是干净的,避免重复挂载导致内存泄漏或 DOM 异常。
- 通常需要判断实例是否已存在,若存在则先卸载再重新挂载,或者直接复用(取决于框架特性)。
unmount (卸载/清理)
-
触发时机:每次子应用离开(路由切换走)时调用。
-
主要用途:
- 清理资源:销毁组件实例、移除事件监听器、清除定时器。
- 卸载 DOM:将子应用的 DOM 从容器中移除。
- 重置状态:清理全局变量或单例状态(如 Pinia/Vuex store 的状态重置),防止影响下一次加载。
-
关键点:
- 必须是一个异步函数(返回 Promise)。
- 这是防止内存泄漏最关键的一步,务必彻底清理副作用。
qiankun是如何进行的样式隔离
默认情况下沙箱可以确保单实例场景子应用之间的样式隔离,但是无法确保主应用跟子应用、或者多实例场景的子应用样式隔离。当配置为 { strictStyleIsolation: true } 时表示开启严格的样式隔离模式。这种模式下 qiankun 会为每个微应用的容器包裹上一个 shadow dom 节点,从而确保微应用的样式不会对全局造成影响。
为什么不推荐使用Shadow Dom
虽然 Shadow DOM 提供了原生的、最强的样式隔离能力,但在实际的微前端落地场景中,它带来的副作用往往大于收益。\
- 事件冒泡中断:Shadow DOM 会阻断事件冒泡。如果子应用在 Shadow Root 内部触发事件,主应用或其他子应用可能无法监听到的,除非显式地配置
composed: true,这增加了开发复杂度
2.全局对象访问受限:许多第三方库(如弹窗组件、Tooltip、日期选择器等)依赖document.body或全局 DOM 树来计算位置或挂载节点。在 Shadow DOM 模式下,这些库可能无法正确获取上下文,导致渲染错误或位置偏移
3.CSS 变量继承问题:虽然 Shadow DOM 支持 CSS 变量继承,但某些特定的全局主题切换逻辑如果依赖于直接操作document.documentElement上的类名或属性,可能在 Shadow DOM 内部失效或需要额外的透传逻辑
4.样式编写限制:开发者无法再随意使用全局样式覆盖。如果子应用需要依赖主应用的某些全局样式(例如重置样式 reset.css),必须显式地将这些样式引入到 Shadow Root 内部,否则会出现样式丢失或表现不一致。
5.目前主流的前端 UI 库(如 Element Plus, Ant Design, Material UI 等)大多不是为 Shadow DOM 原生设计的。 - 挂载点问题:很多组件(如 Modal 对话框、Message 通知、Select 下拉框)默认会将自身挂载到document.body以确保层级最高。在 Shadow DOM 中,这些组件如果依然挂载到外部的body,就会失去样式隔离(因为样式定义在 Shadow Root 内,外部 body 拿不到);如果强制挂载到 Shadow Root 内,又可能因为z-index上下文不同而被遮挡。
所以相对于使用shadow DOM,作者更推荐使用experimentalStyleIsolation,当 experimentalStyleIsolation 被设置为 true 时,qiankun 会改写子应用所添加的样式为所有样式规则增加一个特殊的选择器规则来限定其影响范围,因此改写后的代码会表达类似为如下结构:
// 假设应用名是 react16
.app-main {
font-size: 14px;
}
div[data-qiankun-react16] .app-main {
font-size: 14px;
}
如何进行的数据之间的传递
- 使用localstorage,sessionStorange,cookie进行传递
- 使用qiankun提供的props传值
// 主应用
registerMicroApps([
{
name: 'app1',
entry: '//localhost:7100',
container: '#container',
activeRule: '/app1',
props: {
token: 'xyz-123',
userInfo: { name: 'Alice' },
setGlobalState: (state) => { /* 回调函数 */ }
},
},
]);
// 子应用 (entry.js)
export async function mount(props) {
console.log('收到主应用数据:', props.token);
// 初始化渲染
render(props);
}
- 缺点:
- 非响应式:
props只在mount阶段传递一次。如果主应用后续修改了数据,子应用不会自动感知更新(除非主应用重新加载子应用,这不可接受)。 - 无法反向通信:虽然可以通过 props 传递回调函数实现子->主通信,但不如专门的状态管理工具直观。
- 非响应式:
- 基于发布订阅模式(Pub/Sub)。
- 主应用定义全局状态
microAppState。 - 子应用通过
onGlobalStateChange监听变化,通过setGlobalState修改状态
// 主应用
import { initGlobalState } from '@qiankunjs/shared';
const state = { user: null, token: '' };
const actions = initGlobalState(state);
// 子应用
export async function mount(props) {
// 监听变化
props.onGlobalStateChange((state, prev) => {
console.log('全局状态变了:', state);
}, true); // true 表示首次立即触发
// 修改状态
props.setGlobalState({ token: 'new-token' });
}
- 全局状态管理,使用reactx,vuex,pinia等状态管理工具.
将导出的store,通过props传递给子应用,此时父子应用都可以管理state