single-spa框架分析

2021-09-05  本文已影响0人  我是小布丁

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之前,应用会被注册和加载,但不会被初始化、挂载、卸载

路由监听

window.addEventListener("hashchange", funcRef, false);
window.addEventListener("popstate", funcRef, false);
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存在一些问题:

4、参考文章

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

上一篇下一篇

猜你喜欢

热点阅读