使用微前端在项目中主要是解决使用iframe引入第三方页面时遇到的框架受限,页面交互不统一等问题,项目中遇到的问题大概如下:
除此之外,微前端的初衷是解决遗留老项目更新维护困难的问题,那么到底什么是微前端呢?
如果我们把页面看成是最终向用户展示产品的窗口,那么窗口里面的每一项,每一个小块,每一个功能,都可以由不同的技术,不同的框架来完成。
在这个图中,我们的窗口包含头部、左侧、内容和脚部 这四部分,中间是内容区,内容区的部分可以加载任何符合规范的前端代码,不论你是用 react、vue还是 angular 来开发的,只要你符合规范的约定,我就可以把你的内容加载过来。
它把前端开发从原来的基于一个大框架下的开发,拆分成了基于功能的若干微小的开发,各个端之间业务独立,互不影响,一个端出问题了也不会影响到其它端,所以把它称之为微前端。
微前端的特点:
1、与技术栈无关
2、子应用独立部署
3、子应用与主应用无缝衔接,主应用对子应用可控,子应用可获取主应用资源(看上去就是一个应用一样)
其中第三点就是区别于 iframe 的地方,因为 iframe 无法做到这一点
介绍完什么是微前端后,那接下来介绍下微前端的实现原理
微前端实现原理是 主工程在运行时获取应用配置,然后注册应用和路由,先加载主应用(菜单等),当url 地址变化时,通过路由管理器和应用管理器动态加载对应的子应用
路由管理器是指把所有子应用的路由统一放在一个总路由里管理,应用管理器是把所有子应用打包后的实例放在一个应用管理器里,当URL和路由管理器中的子应用路由匹配时,通过应用管理器加载对应的子应用
基于这个原理,我画了一个流程图:
子应用在加载前会创建基于自身的生命周期实例和路由,然后注册到主工程中,当页面URL跳转时,通过路由管理器和应用管理器匹配子应用,在加载子应用的过程中,有三个生命周期,bootstrap是初始化,这个时候页面显示loading,也就是正在加载中,然后走到mount,开始加载页面,不需要显示当前子应用时,通过unmount卸载子应用
systemjs 提供通用的模块导入途径,支持传统模块和ES6的模块,相当于加载器,主要用来调度子应用,决定何时展示哪个子应用。
single-spa 包装器,可以把现有的应用包装,使得加载器可以使用它们
说下这两个技术点的原理,最核心的原理其实很简单,抛出 各个规范不讲, 只讲最核心的 JS 函数。
1.根据主应用的注册信息,找到所有的子应用。
3. 然后根据路由匹配的情况,发起一个路由匹配应用事件(single-spa:routing-event),在结合 SystemJS.import 方法去加载文件
我将按照项目架构、路由分发、应用加载和公用依赖加载这四个流程来为大家介绍
首先看下项目架构,这是主框架,由 index.html 和公用部分navbar 及子应用 app1 组成,其他子应用和 app1的实现原理一样
index.html 相当于总入口,配置所有资源
然后说下路由分发,也就是主框架是怎样通过路由找到每个子应用的
以demo中的菜单为例,菜单navbar 和首页index 以及弹窗遮罩APP1 都是单独的子应用,这些子应用的路由都放在主框架的路由管理器里,运行页面就加载菜单栏,所以主框架初始化就运行navbar路由,默认导航到首页,点击弹窗遮罩菜单项,url变成 /app1,通过路由分发 ,路由管理器找到 app1 对应的子应用名称,再去应用管理器里找到这个子应用,加载到主框架
先说子应用,子应用创建 vue 的实例和项目加载前,加载后,卸载时的钩子函数,并暴露到全局,通过setPublicPath这个方法生成对应的路由,这个路由是唯一的,并暴露到全局,这样子应用的路由和实例都暴露到全局中,在主框架中就容易拿到子应用的配置
主框架通过 SystemJS 把子应用的入口 js 文件加载进来,通过singleSpa.registerApplication注册路由和应用,
当url前缀和应用的路由匹配时,就会加载应用
最后说下公共依赖是怎么加载的
公共依赖是指子应用和主框架可以共用的依赖,像 vue、vue-router、webpack等
这些公共依赖放在主框架中,子应用在vue.config.js文件通过config.externals 配置共用依赖,这样需要时,就从主框架加载
主框架通过 systemjs-importmap 把需要的公用依赖文件导入进来,通过 System.import 使用依赖
目前项目已经改造完成,踩了不少坑,微前端已封装成插件放到前端生态中,整体是参考阿里 qiankun 框架,后续也会不断总结并发布到博客中。