微前端是一种将复杂单体应用拆分为多个小型独立前端应用,然后将这些小应用按需加载并集成到主应用的技术方案。
每个子应用都有自己的 JavaScript 和 CSS 代码。
单页Web应用(single page web application,SPA),就是只有一张Web页面的应用。所有页面都来回在这张页面上切换。
所以很容易暴漏出来单页面应用的两个缺点。
单页面SPA的两种路由形式:
Hash与History
本质区别:
Hash:锚点。通过锚点跳到对应位置
History:History栈。通过history.pushState
或者history.replaceState
向栈内维护信息,并跳转到对应位置。
SystemJS是一个模块加载器,
用于在浏览器和Node.js环境中加载JavaScript模块
。它提供了动态导入
和加载模块
的功能,使得开发者可以按需加载
代码,提高应用程序的性能和响应速度。
import-html-entry 做的就是把如上代码中的 js、css 通过 fetch 拉取出源代码并内嵌到这个 html 中,变为一个包含内嵌 js、css 源码的 html 文件。
SystemJS
不仅是个模块加载工具更是有一套标准的模块规范,single-spa
赖 SystemJS 规范通过JS Entry 实现微应用、微模块的加载。 import-html-entry
只支持 umd 的 js 文件,qiankun
通过 import-html-entry解析 html 模板分析资源 实现 HTML Entry 的方式加载 微应用。1.iframe
iframe大家都很熟悉,通过iframe实现的话就是每个子应用通过iframe标签来嵌入到父应用中,iframe具有天然的隔离属性,各个子应用之间以及子应用和父应用之间都可以做到互不影响。但是iframe保护性太强了,导致了很多问题
当我们登陆element-ui,并且打开table页面后,刷新整体html页面。element-ui又会回到主页
html的内存与iframe中的不共享
我打开element-ui的loading,只能在200*200的区域显示,整体html没法显示
并且慢
2.single-spa
3.qiankun
为啥要了解single-spa,是因为qiankun 是一个基于 single-spa 的微前端。由single-spa优化而来的库
single-spa 微前端框架主要就完成了一件事:就是在 url 变化的时候,加载、卸载对应的子应用
single-spa 长期开发后,会遇到的问题:
1. 打包逻辑的问题
一般我们会结合 SystemJS 来用,简化加载的逻辑,但是依然要知道子应用有哪些资源要加载,子应用打包逻辑变了,这里加载的方式就要跟着变
。
能不能把这个加载过程给自动化了呢?
比如我根据 url 加载子应用的 html,然后解析出其中的 JS、CSS,自动去加载。
qiankun 就是按照这个思路来解决的:
它会加载入口 html,解析出 scripts、styles 的部分,单独去加载,而其余的部分,会做一些转换之后放到 dom 里。 (HTML Entry)
2. JS、CSS 沙箱
子应用之间肯定要实现隔离,不能相互影响,也就是要实现 JS 和 CSS 的隔离。single-spa 没有做这方面的处理,而 qiankun 实现了这个功能。
JS 的隔离也就是要隔离 window 这个全局变量,其余的不会有啥冲突,本来就是在不同函数的作用域执行的。
qiankun 实现 window 隔离有三种思路:
快照
,加载子应用前记录下 window 的属性,卸载之后恢复到之前的快照diff
,加载子应用之后记录对 window 属性的增删改,卸载之后恢复回去Proxy
,创建一个代理对象,每个子应用访问到的都是这个代理对象一般常用的还是第三种 Proxy 的思路
qiankun 实现 CSS 的隔离有两种思路:
shadow dom
节点,从而确保微应用的样式不会对全局造成影响3.应用间的状态管理
多个子应用、子应用和主应用之间自然有一些状态管理的需求,qiankun 也实现了这个功能。
主应用里做全局状态的初始化
,定义子应用获取全局状态的方法
getGlobalState 和全局状态变化时的处理函数 onGlobalStateChange子应用里可以通过参数拿到
global state 的 get、set 方法: