微前端框架single-spa子应用加载解析

前端,框架,single,spa,应用,加载,解析 · 浏览次数 : 108

小编点评

**single-spa函数库的加载和挂载流程** single-spa函数库提供一个函数库来帮助用户加载和挂载子应用。该函数库使用的是Vue的函数库,并通过调用不同的方法来实现子应用的加载和挂载。 **加载子应用** * `createApp`方法用于创建vue实例。 * `mount`方法用于挂载子应用到html页面上的dom元素。 * `update`方法用于更新子应用的dom元素。 * `unmount`方法用于卸载子应用的dom元素。 **挂载子应用** * `createApp`方法用于创建vue实例。 * `mount`方法用于挂载子应用到html页面上的dom元素。 * `update`方法用于更新子应用的dom元素。 * `unmount`方法用于卸载子应用的dom元素。 **生命周期方法** * `update`方法用于更新子应用的dom元素。 * `unmount`方法用于卸载子应用的dom元素。 **优化** * `createApp`方法中设置一个keep-alive配置项,以保持页面状态。 * `mount`方法中设置一个keep-alive配置项,以保持子应用的生命周期。 * `update`方法中使用`props`属性设置子应用的配置项。 **示例** ```single-spa-vue ``` **注意** * `single-spa`函数库支持多种加载和挂载方式,包括`createApp`、`mount`、`update`和`unmount`方法。 * `single-spa`函数库也支持`keep-alive`配置项,以保持页面状态。 * `single-spa`函数库使用的是Vue的函数库,因此需要在使用之前引入`Vue`模块。

正文

作者:京东物流 宁冲

1 前言

什么是微前端?
微前端是指存在于浏览器中的微服务。

本文主要通过对微前端框架single-spa的基座应用加载子应用的single-spa-vue函数库进行分析,通过代码维度分析让大家了解在single-spa加载子应用的时候都做了哪些事情。如何通过优化single-spa-vue函数库保持子应用的状态。

由于是在代码维度进行分析,要求读者对single-spa有一定的了解,阅读效果会更好。

2 single-spa加载子应用的过程

基座应用中配置的加载子应用配置,在配置子应用对象的app方法中会把子应用chunk-vendors.js、app.js插入到页面,并且执行chunk-vendors.js、app.js两个子应用依赖的js。

app方法执行结束以后,子应用依赖的js插入页面以后的dom结构。

由上面app方法的执行过程,我们可以看出基座应用加载子应用,和vue框架打包后加载js资源的方式类似。那么为什么只需要加载子应用的app.js和chunk-vendors.js就可以把子应用渲染到页面上面。下面我们再来看看子应用的入口文件main.js方法中是如何进行配置的。

3 子应用的main.js中的配置

在子应用main.js中我们可以看到,把常规的配置1替换为配置2的格式。

在配置2中我们会把当前vue的配置传给single-spa-vue函数库中。包括el、render方法、Vue对象。通过singleSpaVue的包装,返回single-spa生命周期方法bootstrap、mount、unmount。

  • bootstrap:引导函数,应用内容首次挂载到页面前调用,只会执行一次。
  • mount:挂载函数,子应用每次被挂载的时候都会执行。
  • unmount:卸载函数,子应用每次被卸载的时候都会执行。

也就是说基座应用在加载子应用的时候就是通过single-spa-vue函数的处理,生成了single-spa的各个生命周期,给基座应用在加载子应用的时候调用。
下面我们来看看single-spa-vue究竟是如何生成各种生命周期函数的。

4 single-spa-vue源码结构

single-spa-vue函数库可以帮助我们来生成加载子应用的生命周期。你可以通过下面链接:single-spa-vue GIT地址,下载single-spa-vue函数库的源码。
single-spa-vue的源码非常简单,只有几个生成single-spa生命周期的函数。

  • single-spa-vue方法:single-spa-vue函数库对外提供服务的唯一一个方法,用来接收配置项,并且返回一个包含各个single-spa生命周期的对象。
  • single-spa-vue中的其他方法bootstrap、mount、update、unmount是用来生成single-spa对应生命周期函数的方法。

下面我们详细介绍一下这几个方法的作用和实现。

5 single-spa-vue源码解析

single-spa-vue中提供的singleSpaVue方法会接收userOpts配置信息,配置信息会和默认的配置项defaultOpts合并以后再进行进行后续处理。

5.1 配置项defaultOpts

对于默认的配置项会有下面这几项,这里只介绍一下必填项,appOptions、Vue/createApp。其中的template在并没有在single-spa-vue中被用到,但是在single-spa-html中有使用到。

  1. // 默认配置项列表

  2. const defaultOpts = {

  3. // required opts

  4. appOptions: null,

  5. template: null,

  6. // sometimes require opts

  7. Vue: null,

  8. createApp: null,

  9. handleInstance: null

  10. }

1)appOptions配置项介绍

  • appOptions:应用的配置项,会在初始化Vue实例的时候作为参数传给Vue方法,下面具体介绍一下appOptions中的配置项。
  • el:子应用需要挂载的基座dom,即vue需要挂载的dom。
  • render/template:vue的render/template配置项。
  • data:初始化的参数对象,会在执行挂载函数mount的时候直接挂载到vue实例上。

2)Vue/createApp配置项介绍

Vue/createApp配置项是用来生成vue实例的,single-spa-vue函数库可以通过传入的Vue对象在mount方法中来生成vue实例。也可以传入createApp方法,由子应用在createApp方法中返回vue实例。

下面我们会在生命周期生成方法中看到这些配置项的作用

5.2 入口方法:singleSpaVue

singleSpaVue方法会对入参先进行下列有效性校验,具体校验的内容有一下四项。

  1. 配置项userOpts是否为对象。
  2. 用来创建vue实例的配置Vue/createApp是否存在。
  3. 用来生成vue实例的配置项appOptions是否存在。
  4. vue实例挂载的dom是否正确appOptions.el有效性校验。

有效性校验通过以后,会调用bootstrap、mount、unmount、update方法用来分别生成single-spa加载子应用的生命周期函数。
下面详细介绍一下各个生命周期函数是如何生成的。

5.3 引导函数:bootstrap

引导函数bootstrap,当应用内容首次挂载到页面前调用。

bootstrap函数,会先判断一下是否在配置项中存在loadRootComponent。配置项loadRootComponent笔者理解是可以用来加载当前子应用依赖的父级应用或者其他的依赖资源。
比如A页面依赖B组件,那在加载A页面的时候可以loadRootComponent方法中把B组件的静态资源加载下来,并且渲染到页面上,A页面就可以直接使用B组件中提供的一些资源或者dom。
如果未配置loadRootComponent,则直接返回,不做任何处理。

5.4 子应用挂载生命周期:mount

在子应用每次被挂载到页面上的时候,single-spa会执行mount生命周期函数,single-spa-vue在mount函数中用来初始化子应用的vue实例,并且把实例挂载到页面上。
mount函数会接收三个参数,分别是singleSpaVue传入的参数opts,single-spa-vue当前全局挂载的子应用实例列表mountedInstances,在基座应用中注册的当前子应用的single-spa实例props
props入参接收的数据,这里只用到了props的name属性,用来标识当前挂载的子应用。

在mount方法中主要做了以下几件事

1)格式化应用配置项appOptions

mount方法中会通过resolveAppOptions方法来格式化应用的配置项appOptions。
在resolveAppOptions方法来中如果appOptions是一个方法的话,则执行方法,并且传递基座应用通过customProps参数传入的参数props。
子应用可以在appOptions方法中获取父应用传递的参数、根据父应用的状态做不同的处理等。

2)初始化子应用需要挂载的DOM对象。

初始化dom的配置和方法比较多,会从很多个配置项中来获取el,代码比较简单,这里就不赘述了。只列出来取值的优先级供大家参考。
appOptions.el > props.domElement > props.name

dom节点被格式化完成以后,下面就开始把页面挂载到dom上面。

3)创建vue示例,并且挂载到页面上

在挂载页面之前会有一个配置项:replaceMode,replaceMode配置项是用来标识是否需要替换el节点下的内容。默认replaceMode为false是会在el节点下面新建一个class为single-spa-container的空白div来保存子应用。

以demo中的代码为例:

默认replaceMode为false的情况下,基座中的的内容和vue1中的内容会并存。如下图:

如果把replaceMode改为true的情况下,会发现基座中的内容会被vue1中的内容覆盖掉。
如下图:

设置挂载方式以后,就开始把子应用真正挂载到dom上面。
这里支持两种挂载方式,一种是使用vue3的createApp方式挂载,一种是使用vue2的new Vue方式进行挂载。这里的挂载方式其实和我们在使用vue挂载到dom方式的配置是一样的。

通过上面的步骤,此时子应用就被挂载到了html的页面中的dom上了。

5.5 更新生命周期函数:update

当调用parcel.update()会触发update方法,笔者由于并没有用的高级特性parcel,在此处不再做过多介绍。

5.6 子应用卸载生命周期:unmount

当页面url发生变化的时候,离开子应用页面路由的时候会触发unmount方法。
在unmount方法中主要做的事情有:

  1. 卸载vue应用
  2. 删除vue实例
  3. 同时清空页面dom。

执行unmount操作以后子应用的数据和dom就会被清除干净。

5.7 小结

以上就是single-spa官方提供的single-spa-vue函数库来挂载子应用的全部流程。通过上面的分析,我们发现single-spa-vue函数库会通过调用singleSpaVue方法返回一个包含bootstrap、mount、update、unmount四个方法的对象。在基座应用加载子应用的生命周期会执行对应的方法,通过执行方法把子应用挂载到基座应用或者从基座应用销毁子应用。

通过single-spa-vue中加载子应用的过程,single-spa把各个子应用组装成一个复杂的应用,在用户无感的情况下对各个子应用进行分别治理。

single-spa在加载子应用的时候,除了vue的版本之外,还有其他的版本,但是加载的思路类似,都是在函数库中来把子应用加载到html中,此处不再介绍其他类型的加载。
single-spa其他加载子应用方式:single-spa-react、single-spa-html

6 子应用状态保持

在实际开发的过程中笔者遇到有些页面需要使用vue中的keep-alive来保留状态,在页面切换的过程中虽然页面被销毁但是页面状态需要在保留,但是我们在分析single-spa-vue的unmount方法实现的时候发现,如果页面切换,子应用和vue实例被销毁,此时子应用中的keep-alive是没有生效的。

如下图:

当在input中输入内容以后,传统的spa项目可以通过keep-alive来记录状态,当页面路由切换以后,再切回来,仍然保持状态。但是如果直接使用single-spa-vue,当子应用触发unmount的时候input中的输入内容1111会被清空。针对这种情况,笔者对single-spa-vue类库进行了一些改造。

改造内容如下:

6.1 子应用由销毁改为隐藏

在single-spa-vue配置项中增加了一个配置项,根据配置项中是否存在isKeepAlive配置项,来判断把当前的dom隐藏掉,还是删除。这样当子应用unmount方法触发的时候,子应用并未被删除,而是仍然保留。

同时笔者对vue的route配置也进行了一些优化,当页面不存在的时候,此时会把子应用中的一个空组件挂载到dom上面,避免虽然页面被隐藏掉,但是dom仍然在html中,导致页面dom过多。

6.2 子应用由新建改为显示

在single-spa-vue配置项中调用mount方法挂载子应用的时候,会判断当前子应用是否存在,如果子应用存在则直接把子页面显示出来,由于子应用并未被销毁,此时子应用中的keep-alive就会一直生效,并且保存页面的状态。

通过对single-spa-vue类库的mount、unmount方法的优化,用户在使用页面的时候真正和使用vue那样流畅,并且可以保持页面状态,提升用户的体验。

与微前端框架single-spa子应用加载解析相似的内容:

微前端框架single-spa子应用加载解析

本文主要通过对微前端框架single-spa的基座应用加载子应用的single-spa-vue函数库进行分析,通过代码维度分析让大家了解在single-spa加载子应用的时候都做了哪些事情。如何通过优化single-spa-vue函数库保持子应用的状态。

Vue微前端架构与Qiankun实践理论指南

这篇文章介绍了微前端架构概念,聚焦于如何在Vue.js项目中应用Qiankun框架实现模块化和组件化,以达到高效开发和维护的目的。讨论了Qiankun的原理、如何设置主应用与子应用的通信,以及如何解决跨域问题和优化集成过程,从而实现前端应用的灵活扩展与组织。

qiankun微前端实践

为什么要使用微前端 微前端架构具备以下几个核心价值: 技术栈无关 主框架不限制接入应用的技术栈,微应用具备完全自主权 独立开发、独立部署 微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 增量升级在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前

[转帖]微服务并不是银弹

https://www.oschina.net/translate/microservices-not-a-silver-bullet?print 让我们看一个公司/客户与前端框架技术团队之间的典型对话。 这是你从公司/客户那里听到的,技术团队因此而疯狂。当整个世界都从微服务中获益时,为什么不应该采

02.前后端分离中台框架前端 admin.ui.plus 学习-介绍与简单使用

## 中台框架前台项目 admin.ui.plus 的初识 > 基于 vue3.x + CompositionAPI setup 语法糖 + typescript + vite + element plus + vue-router-next + pinia 技术,内置支持一键生成微服务接口,适配手

微服务下认证授权框架的探讨

前言 市面上关于认证授权的框架已经比较丰富了,大都是关于单体应用的认证授权,在分布式架构下,使用比较多的方案是--<应用网关>,网关里集中认证,将认证通过的请求再转发给代理的服务,这种中心化的方式并不适用于微服务,这里讨论另一种方案--<认证中心>,利用jwt去中心化的特性,减轻认证中心的压力,有理

中台框架模块开发实践-代码生成器的添加及使用

前言 之前已经分享过几篇关于中台项目框架的文章,相关介绍就不再赘述 所谓工欲善其事必先利其器,一个项目拥有一个代码生成器是很有必要的,能够大大的节省时间,减少手误,提供开发效率(ps:特别小团队搞微服务但是没有代码生成器,简直要了老命) 本文将分享如何在中台框架项目 Admin.Core 中添加代码

oidc-client.js踩坑吐槽贴

前言 前面选用了IdentityServer4做为认证授权的基础框架,感兴趣的可以看上篇<微服务下认证授权框架的探讨>,已经初步完成了authorization-code与implicit的简易demo(html+js 在IIS部署的站点),并实现了SSO,本想着将Demo迁移到vue工程是轻而易举

微前端中实现沙箱环境的方案调研

前言 在微前端实践过程中有一个必然会遇到的问题:全局作用域变量的污染问题,具体来说就是window对象挂载数据会被主子应用获取和修改导致数据相互污染问题,这时候如果能在应用之间做个数据隔离,最好能实现一个沙箱环境,对解决问题很有帮助。 iframe方案 说到沙箱隔离,首先想到的是iframe,自带数

微前端项目部署方案

本文旨在通过部署微前端项目的实践过程中沉淀出一套部署方案,针对项目分别部署在不同的服务器上的场景,就一些重点步骤、碰到的问题做了一些总结。