微前端概念是从微服务概念扩展而来的,摒弃大型单体方式,将前端整体分解为小而简单的块,这些块可以独立开发、测试和部署,同时仍然聚合为一个产品出现在客户面前。可以理解微前端是一种将多个可独立交付的小型前端应用聚合为一个整体的架构风格。
1、技术栈无关:主框架不限制接入应用的技术栈,微应用具备完全自主权
2、独立开发、独立部署:微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
3、增量升级:在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
4、独立运行:每个微应用之间状态隔离,运行时状态不共享
1、iframe
iframe 最大的特性就是提供了浏览器原生的硬隔离方案,不论是样式隔离、js 隔离这类问题统统都能被完美解决。
但他的最大问题也在于他的隔离性无法被突破,导致应用间上下文无法被共享(主要是本地存储、全局变量和公共插件),两个项目不同源(跨域)情况下数据传输需要依赖 postMessage,随之带来的开发体验、产品体验的问题。
2、single-spa 方案
Single-spa 是一个将多个单页面应用聚合为一个整体应用的 JavaScript 微前端框架(GitHub 主页)。简单来说就是将子项目的内容(包括容器、js)插入到主项目,从而呈现出子项目的内容。
相对于 iframe,single-spa 让父子项目属于同一个 document,这样做既有好处,也有坏处。好处就是数据/文件都可以共享,公共插件共享,子项目加载就更快了,缺点是带来了 js/css 污染。
single-spa 上手并不简单,也不能开箱即用,开发部署更是需要修改大量的 webpack 配置,对子项目的改造也非常多。
qiankun 是一个基于 single-spa 的微前端实现库,它在 single-spa 的基础上,实现了开箱即用,除一些必要的修改外,子项目只需要做很少的改动,就能很容易的接入。
1、基于 single-spa 封装,提供了更加开箱即用的 API。
2、技术栈无关,任意技术栈的应用均可 使用/接入,不论是 React/Vue/Angular/JQuery 还是其他等框架。
3、HTML Entry 接入方式,让我们接入微应用像使用 iframe 一样简单
4、样式隔离,确保微应用之间样式互相不干扰。
5、JS 沙箱,确保微应用之间 全局变量/事件 不冲突。
6、资源预加载,在浏览器空闲时间预加载未打开的微应用资源,加速微应用打开速度。
7、umi 插件,提供了 @umijs/plugin-qiankun 供 umi 应用一键切换成微前端架构系统。
微前端需要解决的问题分为两大类:
1、应用的加载与切换
应用的加载与切换要解决的问题包括: 路由问题、应用入口、应用加载
2、应用的隔离与通信
应用的隔离与通信需要解决的问题包括:js隔离、css样式隔离、应用间通信
1、路由
【1】single-spa是通过监听hashChange和popState这两个原生事件来检测路由变化的
【2】当路由变化时,single-spa会监听到,并触发urlReroute
【3】接着它会调用reroute,该函数正确设置各个应用的状态后调用getAppChanges获取 待清除、待卸载、待加载、待挂载4种不通状态下应用的数据。
【4】对不同的数组执行不同的生命周期方法。
流程图如下:
2、应用入口
只要你的应用实现了 bootstrap 、mount 和 unmount 三个生命周期钩子,有这三个函数导出,我们的框架应用就可以知道如何加载这个子应用。这三个钩子也正好是子应用的生命周期钩子。当子应用第一次挂载的时候,我们会执行 bootstrap 做一些初始化,然后执行 mount 将它挂载。当你应用切换走的时候,我们会执行 unmount 把应用卸载掉。
3、应用加载
qiankun采用的应用加载是在运行是通过加载子应用的HTML。
【1】检查是否有缓存,如果有,直接从缓存中返回
【2】如果没有则通过fetch函数去下载配置的html入口、并返回字符串
【3】通过process函数处理字符串、返回模版、外联脚本、外联样式、和应用入口脚本。
【4】调用getEmbedHTML把外联的样式下载下来,并替换到模板内,使其变成内部样式
【5】返回一个对象,该对象包含处理后的模板,以及getExternalScripts、getExternalStyleSheets、execScripts等几个核心方法。
应用加载及process函数处理流程图:
4、JS隔离
qiankun的隔离方式有两种:
•基于proxy对全局window生成一个代理对象
•通过快照沙箱在沙箱挂载和卸载的时候记录快照,在应用切换的时候依据快照恢复环境。
5、样式隔离
qiankun内置了两种样式隔离的方法:
•ShadowDOM
•样式隔离 RFC
6、应用间通信
基于一个全局的globalState对象。这个对象由基座应用负责创建,内部包含一组用于通信的变量,以及两个分别用于修改变量值和监听变量变化的方法:setGlobalState和onGlobalStateChange。
虽然阿里说:“可能是你见过最完善的微前端解决方案”。但是qiankun 也有一些事情没有做的。比如没有对 localStorage 进行隔离,如果多个子应用都用到 localStorage 就有可能冲突了,除此之外,还有 cookie, indexedDB 的共享等。
附demo
GitHub - 14130110048/qiankun-demo: 微前端-qiankun框架demo