single-spa框架分析

single-spa的原理其实很简单,它就是一个子应用加载器 + 状态机的结合体,而且具体怎么加载子应用还是基座应用提供的;框架里面维护了各个子应用的状态,以及在适当的时候负责更改子应用的状态、执行相应的生命周期函数

1、single-spa的状态

注册、加载、初始化、挂载、卸载、移除、错误


image.png

LOAD_ERROR,这通常是由于下载应用程序的js包时出现网络错误造成的。Single-spa将在用户从当前路由导航并返回后重试加载应
SKIP_BECAUSE_BROKEN,应用在加载、初始化、挂载或卸载过程中抛出错误,由于行为不当而被跳过,因此被隔离。其他应用将正常运行

2、single-spa 源码分析

源码的 rollup.config.js 中可以看出,入口文件为 /src/single-spa.js,这个文件导出很多方法和状态值

registerApplication 注册子应用

single-spa/src/applications/apps.js

  1. sanitizeArguments(appNameOrConfig, appOrLoadApp, activeWhen,customProps),格式化用户传递的应用配置参数
  2. getAppNames() ,去重判断
  3. apps.push(app),将新的应用最加到apps中,并添加一些内置属性status、loadErrorTime、parcels、devtools
  4. ensureJQuerySupport() jQuery打补丁
  5. reroute(),更改app.status和执行生命周期函数

reroute 更改app.status和执行生命周期函数

single-spa/src/navigation/reroute.js

  1. 将apps分为4类,需要被移除的、需要被卸载的、需要被加载的、需要被挂载的
  2. 已经start(),将4类合在一起,执行performAppChanges()
  3. 没有start(),执行loadApps(),把需要被加载的执行toLoadPromise

performAppChanges()

  1. dispatch事件
  2. 取消导航,执行finishUpAndReturn(),并且导航到旧的地址上
  3. 没有取消导航,
    需要被移除的,直接执行toUnloadPromise;
    需要被卸载的,先执行toUnmountPromise,再执行toUnloadPromise;
    需要被加载的,先执行toLoadPromise,执行toBootstrapPromise,等到移除和卸载完成再执行toMountPromise
    需要被挂载的,先执行toBootstrapPromise,等到移除和卸载完成后再执行toMountPromise
    最后把移除和卸载的完成后,把loadThenMountPromises + mountPromises合一起,完成后执行finishUpAndReturn()

toLoadPromise(app)

  1. 如果已经存在app.loadPromise,说明已经被加载过,直接返回
  2. 只有状态为NOT_LOADED和LOAD_ERROR的app才可以被加载,其他状态直接返回
  3. 设置app.status = LOADING_SOURCE_CODE;
  4. 执行app.loadApp(props),返回一个promise。这个promise.then得到用户定义的生命周期方法:bootstrap、mount、unmount、unload、timeouts
  5. 设置app.status = NOT_BOOTSTRAPPED;
  6. 把得到的生命周期方法挂到app中,然后删除app.loadPromise

toBootstrapPromise(appOrParcel, hardFail)

  1. 只有NOT_BOOTSTRAPPED状态可以被初始化,其他状态直接返回
  2. 设置appOrParcel.status = BOOTSTRAPPING
  3. 执行生命周期方法bootstrap
  4. 设置appOrParcel.status = NOT_MOUNTED

toMountPromise(appOrParcel, hardFail)

  1. 只有NOT_MOUNTED状态可以被挂载,其他状态直接返回
  2. 执行生命周期方法mount
  3. 设置appOrParcel.status = MOUNTED

toUnmountPromise(appOrParcel, hardFail)

  1. 只有MOUNTED状态可以被卸载
  2. 设置appOrParcel.status = UNMOUNTING
  3. 执行生命周期函数unmount
  4. appOrParcel.status = NOT_MOUNTED

toUnloadPromise(app)

  1. 维护自己的移除队列appsToUnload
  2. NOT_LOADED状态,直接执行finishUnloadingApp(app, unloadInfo),清除工作,设置app.status = NOT_LOADED
  3. UNLOADING状态,等待移除完成
  4. 非NOT_MOUNTED和非LOAD_ERROR,需要等到挂载完成,再进行移除
  5. 执行生命周期函数unload
  6. 设置app.status = UNLOADING
  7. 移除完成,执行finishUnloadingApp(app, unloadInfo),完成清除工作,设置app.status = NOT_LOADED

start(opts)

调用start之前,应用会被注册和加载,但不会被初始化、挂载、卸载

路由监听

  • hashchange:当URL中的片段标识发生改变时,会触发此事件
  • popstate:当活动历史条目更改时,触发popstate事件。需要注意的是调用history.pushState()或history.replaceState()不会触发popstate事件。只有在做出浏览器动作时,才会触发该事件,如用户点击浏览器的回退按钮(或者在JS代码中调用history.back()或者history.forward()方法)
window.addEventListener("hashchange", funcRef, false);
window.addEventListener("popstate", funcRef, false);
  • history.pushState(state, title, url) 向当前浏览器会话的历史堆栈中添加一个状态
  • history.replaceState(state, title, url) 修改当前历史记录实体
history.pushState({foo: "bar"}, "", "bar.html");
history.replaceState({foo: "bar"}, "", "bar2.html");

3、single-spa的缺点

single-spa 就做了两件事,加载微应用(加载方法还是用户自己提供的)、维护微应用状态(初始化、挂载、卸载)。
single-spa 采用 JS Entry 的方式接入微应用。将整个微应用打包成一个JS文件,发布静态资源服务器,然后在主应用中配置该 JS 文件的地址告诉 single-spa 去这个地址加载微应用。

single-spa存在一些问题:

  • 1、对微应用的侵入性太强
    将整个微应用打包成一个 JS 文件,常见的打包优化基本上都没了,比如:按需加载、首屏资源加载优化、css 独立打包等优化措施
  • 2、样式隔离问题
    single-spa中没有做这部分的工作。如果保证一个大型项目中,主应用和微应用之间,微应用和微应用之间的样式隔离。比如应用样式以自己的应用名称开头
  • 3、JS隔离问题
    single-spa中没有做这部分的工作。JS全局对象污染,没有保证微应用A和微应用B的window互相没有影响
  • 4、资源预加载
    single-spa中没有做这部分的工作。
  • 5、应用间通信
    single-spa中没有做这部分的工作。它只在注册微应用时给微应用注入一些状态信息,后续就不管了,没有任何通信的手段,只能用户自己去实现

4、参考文章

微前端框架 之 single-spa 从入门到精通
微前端框架 之 qiankun 从入门到源码分析

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 201,681评论 5 474
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,710评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 148,623评论 0 334
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,202评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,232评论 5 363
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,368评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,795评论 3 393
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,461评论 0 256
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,647评论 1 295
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,476评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,525评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,226评论 3 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,785评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,857评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,090评论 1 258
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,647评论 2 348
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,215评论 2 341

推荐阅读更多精彩内容