各大微前端学习笔记

# 什么是微前端?

微前端是一套架构体系。将Web应用由**单一应用**转变为**多个小型应用**聚合为一的应用。各个前端应用可以独立运行,独立开发,独立部署

# 微前端解决了什么问题?

1.  **解决了大型项目开发维护的难题**

-   降低代码耦合度:随着应用功能的丰富,单页应用变得越来越庞大,难以维护。微前端的意义就是将这些庞大的应用进行拆分解耦,每个部分单独进行维护和部署,提升效率,减低风险。
-   提高代码的可维护性:单体应用中修改一处代码都可能产生意想不到的结果,微前端架构下,子应用的独立性,修改后不需要担心其他模块。

2.  **技术栈灵活使用和升级**

-   微前端架构下,允许每个应用根据自身业务需求选择最合适的技术栈。
-   实现技术栈升级:单体应用技术栈统一,升级困难。 使用微前端,各模块可按需选择技术栈,方便技术迭代。

3.  **提升团队协作与效率**

-   独立开发与部属:微前端架构下,不同的应用可以不同的团队和小组独立进行开发测试部署。每个团队可以根据自己的节奏进行工作,不需要其他小组完成。
-   明确职责分工:微前端架构下,使得每个小组专注自己负责的子应用的业务逻辑和功能的实现。

4.  **优化用户体验和应用性能**

-   按需加载资源:微前端架构下,按需加载,只有当用户访问到某个子应用对应的功能,才会加载子应用的代码和资源。 这可以减少应用的初始加载时间,提高用户体验。
-   并行加载子应用:有些情况下,多个子应用可以并行加载,充分利用浏览器的并发请求能力,提升应用的整体加载速度。

# 实现微前端的方案

## 通过Nginx路由分发资源

通过Nginx配置反向代理,实现不同路由映射不同的应用。这种方式,主要是在运维侧配置,不属于前端改造层面。

优点:

-   实现简单
-   不用前端改造
-   技术栈无关

缺点:

-   体验差,每次切换应用重新加载页面
-   子应用无法共存
-   子应用之间通信困难

## iframe

优点

-   实现简单
-   天然实现沙盒机制,实现css js隔离。
-   多个子应用可以共存
-   技术栈无关

缺点

-   全局上下文完全隔离,内存变量不共享,子应用之间的通信,**数据同步过程比较复杂**(postmessage)。
-   UI不友好: 只能局限于iframe宽高中。例如想要将iframe中的弹窗,居中显示
-   额外的资源消耗:iframe的加载速度和构建环境导致**白屏时间过长**。
-   路由状态消失:页面刷新之后,iframe的url状态丢失。
-   iframe加载失败时,主应用无法感知

## Web Component

原生提供的api,允许你创建可重用的定制元素(它们的功能封装在你的代码之外)并且在你的 web 应用中使用它们。

主要有三项技术组成:

-   Custom element(自定义元素):通过调用Api创建一个自定义的标签。比如创建一个<my-element></my-element>.有自己的生命周期。
-   Shadow Dom(影子dom):为元素创建一个独立的Dom树,与主文档的Dom树分离,从而实现元素功能的私有,不用担心和文档的其他部分发生冲突。
-   HTML template(HTML)模板:可以编写不呈现在页面上的标记模板, 然后可以被作为自定义结构,多从使用。

优点:

-   技术栈无关:原生组件,在任何框架中都可以使用
-   应用隔离:Shdow DOM的特性, 使得各个子应用可以达到隔离的效果。
-   多个子应用可以共存

缺点:

-   改造困难,组件通信困难
-   浏览器新特性需要考虑兼容性问题。

## 路由分发+资源处理

每个子应用独立构建和部署,运行时由基座应用进行路由管理子应用的生命周期。再建立通信机制。是当下各个业务普遍采用的方案。

优点:

-   纯前端改造,体验好
-   无感知切换
-   子应用相互隔离

缺点:

-   需要设计和开发,
-   需要解决css冲突,js 对象污染,通信等问题

# 前端框架

结合上面的这些方案, 可以得出结论:要想实现一个微前端框架,需要解决三个问题:

-   实现路由分发:主应用中对其他微应用的路由转发
-   实现css,js隔离
-   解决通信问题


### single-spa框架 2017年

single-spa方案中应用分为两类:基座应用和主应用。 会在基座应用中维护一个路由表,每个路由对应一个子应用。切换路由的时候,动态加载js脚本。通过路由匹配的的机制实现对子应用生命周期的管理。

优点:

-   单页面设计,切换应用不需要重新加载页面
-   多个子应用可以共存

缺点:

-   不支持JS沙箱隔离机制,CSS样式隔离。
-   无法预加载

single-spa不支持JS隔离和CSS隔离。如果再设计JS沙箱隔离机制,CSS样式隔离,那就可以组合成完善的体系。这也就是很多框架对single-spa进行了二次封装。

基于**single-spa** 实现的方案qiankun、 Garfish等。

### qiankun(阿里巴巴:可能是你见过最完善的微前端解决方案)2019年

基于single-spa框架二次封装,目前国内影响力最大的微前端方案。 single-spa官方推荐。

qiankun主要的技术点:

-   继续延用single-spa处理路由和生命周期
-   import-html-entry 加载子应用,并尝试未脚本提供一个隔离的执行环境,从而实现子应用的独立加载和运行,提供了一定的资源管理和隔离能力。
-   实现了隔离/通信机制

#### js隔离:

qiankun使用沙箱实现。 沙箱:给运行中的程序提供的隔离环境。 通过沙盒,为每个子应用提供隔离的运行环境。保证**全局变量**独属于当前**子应用**。

也就是说,每个子应用有自己的window。实现沙箱的原理如何理解呢?

1.  给每一个子应用创建一个独有的window对象
1.  解析每个子应用的js脚本字符串,包装成立即执行函数,将独有的window对象注入到各自的js代码中
1.  通过eval手动触发。

现在业界流行的沙箱分为两种:快照沙箱和Proxy沙箱。

qiankun在支持Proxy的环境中使用Proxy沙箱,否则使用快照沙箱。

**快照沙箱:**

原理:在子应用**激活**时,记录**当前**全局变量的状态,在子应用**卸载**时,将全局变量**恢复**到之前的状态,从而避免子应用对全局变量的修改影响到全局。

1.  在激活时,遍历window上的变量,存一个**快照**。
1.  卸载时,再次遍历window和之前的快照对比, 将变更的记录下来,再将window恢复到快照状态。
1.  当应用再次切换的时候,就可以把上次变更的变量恢复到window上,实现沙箱的切换。

**Proxy沙箱:**

原理:利用ES6的Proxy对象创建一个代理对象,拦截对全局变量的读和写,通过维护一个独立的变量存储空间,实现子应用对全局变量的操作隔离。这种方式比快照沙箱更加高效,因为它不需要每次激活和卸载时进行全局变量的快照和恢复的操作。天然允许多实例的存在(一个页面挂在多个子应用)

1.  先创建一个空对象,fakeWindow。通过proxy代理,作为全局对象。
1.  子应用需要添加全局变量的时候, 直接再fakeWindow上添加,
1.  子应用需要读取的时候,先从fakeWindow读取,读不到就直接从window上获取。

#### css隔离

-   严格隔离:基于Web Component的shadow Dom实现。qiankun中并不是所有的子应用都可以使用,因为shadow dom可能会限制某些样式和布局的灵活性,并且不是所有的HTML元素都能最为Shadow Dom的宿主。
-   scoped样式隔离:在不使用Shadow Dom的时候,通过过遍历html中所有的style节点,为每一个css添加一个唯一前缀。通过属性的配置进行隔离。 如果一些动态添加样式的情况,qiankun会对操作进行劫持。

#### 通信

子应用通信方面。qiankun使用了基于**发布订阅模式**实现。 基座应用中会定义事件中心Event,每个微应用分别来注册事件,触发的时候再统一下发。

缺点: 不支持子应用保活。不支持vite等esmodule脚本运行。资源重复加载。

### micro app(京东) 2020年

基于webCompont实现

js隔离:和qiankun一样

css隔离:shadow dom 或者 添加前缀

路由:使用虚拟路由,对子应用的路由操作进行劫持。

### 无界(腾讯)2021年

”继承iframe的优点,不足iframe的 缺点“

基于 Web Components + iframe

#### js隔离

利用iframe的隔离性,把js代码放到iframe里执行。

#### css隔离

使用shadow Dom隔离css。

在A应用中构造一个shadow和iframe。 将B应用的HTML写入shadow中, js运行在iframe中,iframe的url和A应用保持同域并且保留B应用的路由信息,这样保证在iframe中运行路由正确。

如何解决iframe的缺点呢?

-   dom割裂严重问题:主应用中提供一个容器,将子应用的shdowRoot插入到这个容器中。shadowRoot内部,是可以设置css属性相对于主应用视图。
-   路由状态丢失问题:使用URL存储路由状态,当iframe重新加载时,根据url中的信息恢复之前的状态。 在iframe中操作路由时,也会同步到主应用。
-   通信困难问题:在将子应用放在iframe中执行的时候,保持了同域,这样就解决了通信问题。还实现了去中心化的通信机制。每个子应用都可以作为事件的发布订阅,不需要依赖统一的事件中心。子应用间可以直接通信, 并且还可以提供了筛选机制,让事件只能在某几个子应用之间使用。使用时需要注意每个子应用都应该有明确的事件注册和注销机制,防止内存泄漏。
-   加载慢白屏问题: wujie实例可以提前实例化,加快首屏展示。 切换白屏问题,无界可以将实例缓存下来,子应用切换成本降低。

一些细节

-   为子应用创建iframe后,会设置src和主应用同域,这时候就会加载主应用的资源,这时候必须在iframe实例化完成后资源未加载完时,及时中断,防止污染。
-   子应用在iframe内部访问widow,document,location都会被劫持到对应的proxy。
-   iframe中拦截document对象,统一将dom指向shadowDom,完成约束(确保修改自己的dom)
-   拦截window对象,共享一个window
-   拦截location对象,处理子应用的跳转操作,避免刷新页面; 通过拦截,可以将子应用的路由状态保存,保存路由状态。

缺点:shadowRoot和proxy的兼容性问题。 内存花销大。

### Garfish(字节跳动)

字节跳动自研框架。设计层面采取的仍然是 基座+子应用。

在js隔离代码执行器方面, qiankun使用的eval执行,Grafish使用的 new Function();

传入一个字符串之后,后面执行的都是同一个函数,但是eval需要每次都处理,性能上更高一些。

Garfish在部署层 通过分析子应用的依赖信息提取公共基础库解决**依赖重复加载**的问题。

# 总结
需要了解什么是微前端? 微前端解决了什么问题? 如何实现沙箱隔离? 各大框架的核心是什么?

# 参考文章

-   [微前端学习系列(一):微前端介绍](https://juejin.cn/post/6955341801381167112#heading-15)
-   [微前端-最容易看懂的微前端知识](https://juejin.cn/post/6844904162509979662?searchId=20250112112714247869C1C2AA06AC19D4#heading-4)
-   [除了 Qiankun, 这些微前端框架或许更适合你「建议收藏」](https://juejin.cn/post/7121883538311348238?searchId=202501132256327C8868AAB4A77A21B5B6#heading-8)
-   [微前端五大门派大 Battle](https://juejin.cn/post/7338230967390224435?searchId=20250112112714247869C1C2AA06AC19D4#heading-11)
-   [京东零售前端团队 | 微前端框架MicroApp 1.0正式发布](https://juejin.cn/post/7327892137880649782?searchId=202501152208169BDFDB074C01DEC6C182#heading-6)
-   [浅析micro-app](https://juejin.cn/post/7233697025711013943#heading-10)
-   [wujie官网](https://wujie-micro.github.io/doc/)
-   [Garfish微前端架构设计](https://www.garfishjs.org/blog/architecture.html)

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值