什么是微前端
微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略
微前端具有以下特性:
- 与技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
- 独立开发 独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
- 增量升级 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或者重构,而微前端是一种非常好的实现渐进式重构的手段和策略
- 独立运行 每个微应用之间状态隔离,运行时状态不共享
微前端的目的就是解决在一个长时间跨度下,由于项目参与人员和团队的变多和变迁,使得普通的应用变得越来越大,导致后面的应用维护起来困难的问题
为什么不是iframe
- iframe的好处在于提供了原生浏览器的硬隔离方案,不论是样式隔离还是js隔离
- iframe的问题:
-
url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
-
UI 不同步,DOM 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中..
-
全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
-
慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程
目前框架
- single-spa
- qiankun qiankun是基于single-spa封装的
不同:
- Single-Spa 采用 JS Entry 加载子应用的方案
- qiankun 采用 HTML Entry 方式进行了替代优化
HTML 里我们有 CSS、JS 链接、有应用要挂载的根路由 root 的 DOM。这些信息是非常全面的,比单纯你拿 JS 和 CSS 组成一份资源列表作为入口,要清晰和完整得多。同时 HTML Entry 这样的设计,也使得我们在接入一些老旧应用的时候,更加简单。
如果你是选择资源列表或者 JS 作为子应用的入口,那么子应用挂载的时候,DOM 节点往往需要和主应用作一个约定,这就产生了一定程度的耦合
微前端框架面临的两大问题
- 问题一是应用的加载与切换。包括路由的处理、应用加载的处理和应用入口的选择。
- 问题二是应用的隔离与通信。这是应用已经加载之后面临的问题,它们包括 JS 的隔离(也就是副作用的隔离)、样式的隔离、也包括父子应用和子子应用之间的通信问题。
qiankun沙箱隔离
qiankun框架为了实现js隔离,提供了三种不同场景使用的沙箱,分别是 snapshotSandbox
、proxySandbox
、legacySandbox
快照沙箱就是在应用沙箱挂载和卸载的时候记录快照,在应用切换的时候依据快照恢复环境
snapshotSandbox(快照沙箱)
激活沙箱时,将window
的快照信息存到windowSnapshot
中, 如果modifyPropsMap
有值,还需要还原上次的状态;激活期间,可能修改了window
的数据;退出沙箱时,将修改过的信息存到modifyPropsMap
里面,并且把window
还原成初始进入的状态
整体流程
- 激活沙箱时,将window的快照信息存到
windowSnapshot
,并从modifyPropsMap
还原上次的值 - 退出沙箱时,对windowSnapshot和当前window进行diff比较,将变更的值存到
modifyPropsMap
,同时将windowSnapshot还原给window
snapshotSandbox
会污染全局window,但是可以支持不兼容Proxy
的浏览器
legacySandbox(单例代理沙箱)
legacySandbox
设置了三个参数来记录全局变量,分别是:
- 记录沙箱新增的全局变量
addedPropsMapInSandbox
- 记录沙箱更新的全局变量
modifiedPropsOriginalValueMapInSandbox
- 持续记录更新增和修改的全局变量
currentUpdatedPropsValueMap
整体流程
- 沙箱激活时,根据
currentUpdatedPropsValueMap
还原到上次修改的值 - 如果是取值,直接从rawWindow中取
- 如果是设置值,要判断属性是否存在于
rawWindow
中,如果不存在,说明是新增属性,则通过addedPropsMapInSandbox
记录,如果不是新增属性,则判断属性是否在modifiedPropsOriginalValueMapInSandbox
,如果不在则从rawWindow
中取值,存到modifiedPropsOriginalValueMapInSandbox
中,最后在currentUpdatedPropsValueMap记录修改的值 - 退出沙箱时,将记录的发生更新的值的原始值(存在
modifiedPropsOriginalValueMapInSandbox
里)还原给window,在将新增的addedPropsMapInSandbox
属性从window中删除
同样会对window造成污染,但是性能比快照沙箱好,不用遍历window对象
proxySandbox(多例沙箱)
原理:活沙箱后,每次对window
取值的时候,先从自己沙箱环境的fakeWindow
里面找,如果不存在,就从rawWindow
(外部的window
)里去找;当对沙箱内部的window
对象赋值的时候,会直接操作fakeWindow
,而不会影响到rawWindow
整体流程
- 激活沙箱时,取值就先从
fakeWindow
里面查找,没找到就从外部window取,赋值就直接赋值给fakeWindow
样式隔离
- 工程化手段,比如css module,通过编译生成不冲突的属性名。
- 严格样式隔离,通过shadow DOM实现完全的样式隔离,但是绝大部分情况下,你还是不能无脑的开启严格样式隔离的。比如说你在使用一些弹窗组件的时候(弹窗很多情况下都是默认添加到了
document.body
)这个时候它就跳过了阴影边界,跑到了主应用里面,样式就丢了