面试题[微前端]
1. 微前端基础
1.1 什么是微前端
微前端(Micro-frontend)是一种将后端微服务理念扩展到前端的架构模式,其核心思想是“分而治之”——将大型前端应用拆分为多个独立的小型子应用,每个子应用可独立开发、测试、部署,最终在浏览器中集成运行。微前端借鉴了微服务的架构理念,将微服务的概念扩展到了前端。
1.2 为什么需要微前端 / 解决了什么问题
传统单体架构在大规模前端应用中逐渐暴露三大痛点:
- 协作效率低下:多团队并行开发时,代码冲突、依赖冲突频繁发生,构建部署耗时超过30分钟成为常态。
- 技术栈绑定:统一技术栈限制了团队创新空间,新框架引入成本高。
- 部署风险集中:任意模块的代码变更都需全量发布,影响整体稳定性。
微前端架构通过“分而治之”的治理模式,实现独立开发、独立部署、故障隔离和弹性扩展四大核心价值。据2025年行业调研显示,采用微前端架构的企业平均提升40%的研发效率,降低35%的运维成本。
1.3 微前端适合什么场景
适合的场景:
- 跨团队协作的大型网站(如电商平台、企业管理系统)
- 需整合遗留系统与新功能的迭代型项目
- 要求高频发布且需保障系统稳定性的业务平台(如金融科技网站、在线教育平台)
- 子应用数量超过5个以上的大型项目
不适合的场景:小型、简单的项目,使用微前端是“杀鸡用牛刀”,反而会增加维护成本。
1.4 主流框架对比
主流框架概况
| 框架 | 开发公司 | 核心技术 | 首次发布 |
|---|---|---|---|
| qiankun(乾坤) | 蚂蚁集团 | 基于Single-SPA + Proxy沙箱 | 2019.08 |
| wujie(无界) | 腾讯 | iframe + Proxy沙箱 | 2022.03 |
| micro-app | 京东 | WebComponents + Shadow DOM | 2021.04 |
| single-spa | 社区驱动 | 路由劫持 + 生命周期 | 2018.01 |
| Module Federation | Webpack5 | 构建时模块联邦 | 2020 |
核心能力对比
| 能力 | qiankun | wujie | micro-app | single-spa |
|---|---|---|---|---|
| 沙箱隔离 | Proxy+快照沙箱 | iframe原生隔离 | Shadow DOM / 代理沙箱 | 需手动实现 |
| 通信机制 | props + globalState + 事件 | props + window通信 + postMessage | 数据通信 + 事件总线 | 自定义实现 |
| 子应用保活 | ❌ | ✅ | ✅ | ❌ |
| 多应用同时激活 | ❌ | ✅ | ✅ | ❌ |
| 上手难度 | 中等 | 简单 | 简单 | 困难 |
| Vite兼容性 | 需插件 | 原生支持 | 原生支持 | 需适配 |
| 隔离安全性 | 高 | 极高 | 高 | 低 |
⚠️ 注意:qiankun在2024年后维护频率明显下降(近6个月commit次数为0),选型时需关注社区活跃度。
各框架优缺点
qiankun(乾坤):
- 优点:成熟稳定、经过大规模生产验证、沙箱机制完善
- 缺点:侵入性较强、沙箱有性能开销、社区维护放缓
- 适用场景:大型企业级应用、混合技术栈迁移、对隔离性要求较高
wujie(无界):
- 优点:原生隔离、轻量级、低侵入性、支持保活
- 缺点:iframe性能开销较大、功能相对局限
- 适用场景:高安全需求场景、嵌入第三方页面、需要子应用保活
micro-app:
- 优点:组件化接入、低成本接入、性能优异
- 缺点:生态相对较小、部分UI库不兼容Shadow DOM
- 适用场景:快速集成、跨团队协作、移动端兼容
1.5 在微前端技术选型的时候是如何考虑的
1.6 在子应用单独启动的情况下,怎么获取主应用的 cookie 信息
在子应用单独启动的情况下,要获取主应用的cookie信息,通常需要进行跨域访问,并且主应用需要开放相应的跨域访问权限。具体方法如下:
- 跨域访问设置:主应用需要配置允许跨域访问的策略,通常是通过设置CORS(跨源资源共享)策略来实现。可以在主应用的服务器端配置Access-Control-Allow-Origin头部,允许子应用的域名进行跨域访问。
- 在子应用中发送请求:子应用可以通过发送HTTP请求到主应用的服务器来获取cookie信息。这可以是一个简单的GET请求,或者使用XMLHttpRequest、Fetch API等技术。
- 处理响应:主应用服务器收到子应用发送的请求后,如果已经配置了允许跨域访问,会将响应发送给子应用。子应用可以从响应中获取到主应用的cookie信息。
- 处理Cookie:在子应用中接收到主应用的响应后,可以通过相应的方式获取cookie信息,例如,使用Document.cookie属性来获取cookie信息。
需要注意的是,获取主应用的cookie信息可能涉及到安全性和隐私问题,需要确保获取cookie的操作是合法且安全的,同时用户需要明确同意共享这些信息。
2. 微前端进阶
2.1 微前端需要解决哪些核心问题
主要需解决四大关键问题:
| 核心问题 | 具体内容 |
|---|---|
| JS隔离(沙箱) | 防止子应用间的全局变量污染(不同子应用可能依赖不同版本的Vue/React) |
| CSS隔离(样式隔离) | 防止不同子应用的样式相互干扰、覆盖 |
| 路由管理 | 子应用路由与主应用路由的协调、嵌套路由支持 |
| 跨应用通信 | 主/子应用之间、子应用之间的数据共享与事件传递 |
JS隔离的原理与实现方案
微前端场景中,不同子应用可能依赖不同版本的Vue/React,甚至会修改window上的全局变量(如Vue、$)。若不做隔离,子应用A的修改会覆盖子应用B的全局变量,导致功能异常。
常见的JS隔离方案有:
① 快照沙箱(SnapshotSandbox)
- 原理:子应用挂载前给window拍“快照”,卸载时根据快照恢复window状态
- 实现:挂载前遍历window保存所有属性的初始值;卸载时新增属性直接删除,修改属性还原为初始值
- 优点:逻辑简单;缺点:需全量遍历window性能较差,同一时间只能运行一个子应用
② Proxy沙箱(ProxySandbox)
- 原理:为每个子应用创建独立的
fakeWindow,通过Proxy代理对window的访问 - 实现:
get拦截从fakeWindow优先读取,set拦截写入fakeWindow而非真实window - 优点:真正的环境隔离;缺点:Proxy无法完全代理所有window操作
③ iframe原生隔离
- 原理:完全独立的浏览器上下文,天然隔离
- 优点:隔离性最强、安全性高;缺点:性能开销较大,通信复杂
CSS样式隔离的原理与实现方案
由于CSS的全局性,不同子应用之间的样式可能会相互干扰。主流方案包括:
| 方案 | 原理 | 优缺点 |
|---|---|---|
| CSS命名空间 | 为子应用的CSS类名添加唯一前缀(如.app-prefix-btn) | 兼容性好;子应用内部仍可能相互影响 |
| Shadow DOM | 浏览器原生API,将子应用DOM和样式封装在隔离环境中 | 隔离彻底;部分UI库不兼容,样式穿透困难 |
| 动态样式表 | 子应用加载时动态添加style标签,卸载时移除 | 灵活可控;切换时可能有闪烁 |
主子应用如何通信
主要有以下几种通信方式:
| 方式 | 说明 | 适用场景 |
|---|---|---|
| Props传递 | 主应用通过props向子应用传递数据 | 简单数据传递 |
| 全局状态管理(initGlobalState) | qiankun提供的全局状态池,支持跨应用状态共享 | 复杂状态共享、跨子应用数据同步 |
| 自定义事件 | 基于window.addEventListener/dispatchEvent | 松散耦合的事件通知 |
| postMessage / BroadcastChannel | 利用HTML5通信API | iframe方案下跨窗口通信 |
| 共享状态(Redux/Vuex) | 通过共享的状态管理库实现 | 统一技术栈的项目 |
路由冲突如何解决
微前端中,主子应用各自维护路由实例。解决方案:
- 主应用监听history变化,匹配激活规则决定加载哪个子应用
- 子应用的路由基于基座应用的URL路径前缀进行匹配
- 采用路径前缀隔离策略:主应用路由
/app1/*、/app2/*分别对应不同子应用
生命周期管理
需定义标准化的生命周期钩子,主应用统一调度子应用的启动、挂载、卸载:
const lifecycle = {
bootstrap: (props) => Promise, // 初始化
mount: (props) => Promise, // 挂载
unmount: (props) => Promise // 卸载
}3. qiankun
3.1 为什么选择 qiankun
3.2 qiankun 的原理
3.3 qiankun 的微应用加载方案
qiankun 的微应用加载方案是其架构的核心,精髓在于通过HTML Entry解决了传统方案的痛点,并基于此实现了一套高效的加载与隔离机制。
它替代了 single-spa 的 JS Entry,允许你直接提供一个子应用的HTML地址作为入口。
registerMicroApps([
{
name: 'app react',
entry: '//localhost:7100', // 直接提供一个HTML地址
container: '#subapp-container',
activeRule: '/app-react'
}
]);这样做有两个很明显的好处:
- 接入更自然:直接提供HTML入口,无需关心JS文件打包的哈希名变化,避免主应用配置频繁变更。
- 体验更完整:保持了子应用原有的优化能力,比如按需加载、CSS独立打包等都能保留。
核心加载器:import-html-entry
要实现HTML Entry,qiankun封装了专门解析HTML的库:import-html-entry。import-html-entry 的核心任务是将一个HTML地址,转化为一个可执行的子应用:
- 获取与解析:通过
fetch获取子应用入口HTML文件内容。 - 资源分离:使用正则表达式解析HTML,将内容分解为三部分:
template:处理后的HTML结构。scripts:所有内联和外部引用的JavaScript脚本。styles:所有内联和外部引用的CSS样式。
- 处理样式:将所有获取到的CSS(无论是内联还是外部链接)转换为
<style>标签并内联进template。 - 准备脚本:通过
getExternalScripts获取所有JS文件的文本内容。 - 执行脚本:通过
execScripts在沙箱环境中按顺序执行JS代码,从而获取子应用导出的bootstrap,mount,unmount等生命周期函数。
微应用加载的具体流程
整个过程在loadApp方法中被串联起来:
- 触发:URL的变化匹配到预设规则,触发子应用的加载。
- 加载:调用
import-html-entry获取资源模板与生命周期函数。 - 隔离:创建JS沙箱和CSS隔离环境,防止应用间相互干扰。
- 挂载:将处理后的
template挂载到指定的DOM容器中,依次调用bootstrap和mount生命周期函数。 - 缓存:资源会被缓存,再次加载时速度将大幅提升。
预加载与性能优化
为了优化切换体验,qiankun 提供了智能的预加载机制。默认策略是懒加载,即只在用户首次访问时加载对应子应用资源。
你也可以在主应用启动时,通过start方法的prefetch属性开启预加载:
start({
prefetch: true, // 默认行为:在第一个子应用加载完成后,利用空闲时间预加载其他应用[reference:18]
// prefetch: 'all', // 启动后立即预加载所有应用[reference:19]
// prefetch: ['app1', 'app2'], // 只预加载指定的应用[reference:20]
});沙箱方面,qiankun 提供了三代演进方案:
- 快照沙箱(SnapshotSandbox):最早版本,性能较差,仅用于兼容旧浏览器。
- 单应用代理沙箱(LegacySandbox):性能得到优化,但存在全局污染,同一时刻只能激活一个子应用。
- 多应用代理沙箱(ProxySandbox):当前默认且最先进的方案。为每个子应用创建独立的虚拟
window对象,实现真正的多实例共存,互不干扰。
3.4 qiankun 的 JavaScript 沙箱原理
JavaScript 沙箱:从“快照”到“代理”的演进。qiankun 的 JS 沙箱策略经历了三代演进,其核心矛盾在于如何在兼容性、隔离性和性能之间找到最佳平衡。当前版本会自动检测浏览器环境,在不支持 Proxy 时降级为快照沙箱。
| 演进阶段 | 核心技术与适用场景 | 优点 | 缺点 |
|---|---|---|---|
| 快照沙箱 (SnapshotSandbox) | 无差别“复制-粘贴”,兼容所有浏览器 | - 原理简单 - 兼容性好 | - 性能差(全量遍历) - 仅支持单例 |
| 单例代理沙箱 (LegacySandbox) | 只记录变更,基于Proxy实现 | - 性能优化,无需全量遍历 | - 存在全局污染风险 - 仅支持单例 |
| 多例代理沙箱 (ProxySandbox) | 每个应用一个虚拟 Window 对象 | - 真正意义的隔离 - 支持多实例 | - 不兼容旧浏览器 |
3.5 qiankun 的 CSS 沙箱原理
CSS 沙箱:默认隔离与两种加强方案。qiankun 的 CSS 沙箱默认是自动开启的,其设计兼顾了开箱即用和灵活可控。
- 基础:动态样式隔离(默认开启)
- 原理:利用
import-html-entry解析子应用的 HTML 和 CSS,在卸载子应用时,主动移除其注入的所有样式表,保证应用切换时样式环境干净。 - 局限:仅保证子应用间的样式互不影响,但无法完全隔离主子应用之间的样式冲突。
- 原理:利用
- 加强方案 1:严格样式隔离(strictStyleIsolation)
- 实现:通过
strictStyleIsolation: true开启,将整个子应用挂载到一个 Shadow DOM 节点下。 - 原理:Shadow DOM 样式天然隔离,CSS 选择器无法穿透,是浏览器级别的隔离方案。
- 代价:可能引发第三方 UI 库弹窗(如 Ant Design)找不到 body 而样式错乱等兼容性问题。
- 实现:通过
- 加强方案 2:实验性作用域沙箱(experimentalStyleIsolation)
- 实现:通过
experimentalStyleIsolation: true开启。 - 原理:自动为子应用的所有 CSS 规则添加
div[data-qiankun-子应用名]这样的属性选择器前缀,将其作用域限定在特定容器内。 - 代价:可能因选择器权重增加,或弹窗逃逸出限定容器而产生样式意外。
- 实现:通过