微前端基础知识讲解

564 阅读5分钟

什么是微前端

微前端是一种多个团队通过独立发布功能的方式来共同构建现代化 web 应用的技术手段及方法策略

微前端具有以下特性:

  • 与技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权
  • 独立开发 独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
  • 增量升级 在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或者重构,而微前端是一种非常好的实现渐进式重构的手段和策略
  • 独立运行 每个微应用之间状态隔离,运行时状态不共享

微前端的目的就是解决在一个长时间跨度下,由于项目参与人员和团队的变多和变迁,使得普通的应用变得越来越大,导致后面的应用维护起来困难的问题

为什么不是iframe

  1. iframe的好处在于提供了原生浏览器的硬隔离方案,不论是样式隔离还是js隔离
  2. 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 节点往往需要和主应用作一个约定,这就产生了一定程度的耦合

截屏2022-01-08 下午10.51.29.png

微前端框架面临的两大问题

  • 问题一是应用的加载与切换。包括路由的处理、应用加载的处理和应用入口的选择。
  • 问题二是应用的隔离与通信。这是应用已经加载之后面临的问题,它们包括 JS 的隔离(也就是副作用的隔离)、样式的隔离、也包括父子应用和子子应用之间的通信问题。

qiankun沙箱隔离

# 15分钟快速理解qiankun的js沙箱原理及其实现

qiankun框架为了实现js隔离,提供了三种不同场景使用的沙箱,分别是 snapshotSandboxproxySandboxlegacySandbox

快照沙箱就是在应用沙箱挂载和卸载的时候记录快照,在应用切换的时候依据快照恢复环境

snapshotSandbox(快照沙箱)

激活沙箱时,将window的快照信息存到windowSnapshot中, 如果modifyPropsMap有值,还需要还原上次的状态;激活期间,可能修改了window的数据;退出沙箱时,将修改过的信息存到modifyPropsMap里面,并且把window还原成初始进入的状态

整体流程

  1. 激活沙箱时,将window的快照信息存到windowSnapshot,并从modifyPropsMap还原上次的值
  2. 退出沙箱时,对windowSnapshot和当前window进行diff比较,将变更的值存到modifyPropsMap,同时将windowSnapshot还原给window

snapshotSandbox会污染全局window,但是可以支持不兼容Proxy的浏览器

legacySandbox(单例代理沙箱)

legacySandbox设置了三个参数来记录全局变量,分别是:

  • 记录沙箱新增的全局变量addedPropsMapInSandbox
  • 记录沙箱更新的全局变量modifiedPropsOriginalValueMapInSandbox
  • 持续记录更新增和修改的全局变量currentUpdatedPropsValueMap

整体流程

  1. 沙箱激活时,根据currentUpdatedPropsValueMap还原到上次修改的值
  2. 如果是取值,直接从rawWindow中取
  3. 如果是设置值,要判断属性是否存在于rawWindow中,如果不存在,说明是新增属性,则通过addedPropsMapInSandbox记录,如果不是新增属性,则判断属性是否在modifiedPropsOriginalValueMapInSandbox,如果不在则从rawWindow中取值,存到modifiedPropsOriginalValueMapInSandbox中,最后在currentUpdatedPropsValueMap记录修改的值
  4. 退出沙箱时,将记录的发生更新的值的原始值(存在modifiedPropsOriginalValueMapInSandbox里)还原给window,在将新增的addedPropsMapInSandbox属性从window中删除

同样会对window造成污染,但是性能比快照沙箱好,不用遍历window对象

proxySandbox(多例沙箱)

原理:活沙箱后,每次对window取值的时候,先从自己沙箱环境的fakeWindow里面找,如果不存在,就从rawWindow(外部的window)里去找;当对沙箱内部的window对象赋值的时候,会直接操作fakeWindow,而不会影响到rawWindow

整体流程

  1. 激活沙箱时,取值就先从fakeWindow里面查找,没找到就从外部window取,赋值就直接赋值给fakeWindow

样式隔离

  1. 工程化手段,比如css module,通过编译生成不冲突的属性名。
  2. 严格样式隔离,通过shadow DOM实现完全的样式隔离,但是绝大部分情况下,你还是不能无脑的开启严格样式隔离的。比如说你在使用一些弹窗组件的时候(弹窗很多情况下都是默认添加到了 document.body )这个时候它就跳过了阴影边界,跑到了主应用里面,样式就丢了

qiankun实现一个demo

根据qiankun实现的Demo

参考链接

# 微前端连载 6/7:微前端框架 - qiankun 大法好

# 15分钟快速理解qiankun的js沙箱原理及其实现

qiankun 官网