前言
single-spa
是一个用于前端微服务化的JavaScript
前端解决方案。single-spa
的核心就是定义了一套协议。协议包含主应用的配置信息和子应用的生命周期,通过这套协议,主应用可以方便的知道在什么情况下激活哪个子应用。
配置信息
1. 主应用配置
在single-spa
中的配置信息也称为:Root Config
,如下就是具体的配置项。需要配置子应用的名称,加载方式以及加载时机。
1 | { |
single-spa
提供registerApplication
将子应用的信息注册到主应用中。
1 | singleSpa.registerApplication( |
在上面的代码中System.import
让人比较在意,这是什么呢?
这个问题要从主应用如何加载子应用说起,在single-spa
中子应用要实现生命周期函数,然后导出给主应用使用。关键就是这个“导出”的实现,这涉及到JavaScript的模块化问题,即需要把子应用打包成一个包含生命周期的模块,让主应用引入。
2. JavaScript的模块化,如何在页面中引入模块?
JavaScript的模块化就是将JavaScript程序拆分为可按需导入的单独模块的机制。Node.js已经提供这个能力很长时间了,还有很多的Javascript库和框架已经开始了模块的使用(例如CommonJS和基于AMD的其他模块系统 如RequireJS,以及最新的Webpack和Babel)。目前最新的浏览器也开始原生支持模块功能。
(1)在<script>
标签上添加type=“module”
来实现导入导出
1 | <!doctype html> |
(2)实现import axios from ‘axios’
还需要借助于importmap
第一点虽然可以实现导入,但是每次import都要写入固定的地址,或者在不同的script中多次引入时就要重复书写,这样造成代码的冗余,所以这里可以使用importmap,使变量名和其相应的地址一一映射,允许控制js的import语句或import()表达式获取的库的url,并允许在非导入上下文中重用这个映射,这样就不用重复书写地址了。
1 | <script type="importmap"> |
(3)SystemJS
import maps
的兼容性不好,所以想在生产环境下使用还是需要一些兼容实现方案,SystemJS
就是解决这个问题的。
systemjs
是一个模块加载器,和requirejs
类似,systemjs
参考import maps
规范实现了自己的alias(类似requirejs-paths
或者webpack alias
)。具体用法在下面的demo中。
1 | <script src="https://cdn.bootcss.com/systemjs/6.2.6/system.js"></script> |
3. 总结一下single-spa
是如何通过以上方法加载子应用的:
在主应用中注册子应用的配置信息,主应用运行时根据配置信息去请求子应用的manifest.json
配置文件,这个文件中是子应用打包出的入口js和js文件的依赖关系,主应用通过动态的构造script标签去加载这些js文件,这里就完成了其注册过程。
这样在主应用检测路由命中子应用的规则之后就会触发其渲染函数,把子应用挂载到相应的dom下。
生命周期
single-spa
的另一个关键点就是生命周期,子应用生命周期包含bootstrap,mount,unmount
三个回调函数。主应用在管理子应用的时候,通过子应用暴露的生命周期函数来实现子应用的启动和卸载。
load:当应用匹配路由时就会加载脚本(非函数,只是一种状态)。
bootstrap:应用内容首次挂载到页面前调用。
Mount:当主应用判定需要激活这个子应用时会调用, 实现子应用的挂载、页面渲染等逻辑。
unmount:当主应用判定需要卸载这个子应用时会调用, 实现组件卸载、清理事件监听等逻辑。
unload:非必要函数,一般不使用。unload之后会重新启动bootstrap流程。
缺陷
通过以上两点的分析,大致了解了一下sing-spa的主要思想,但是single-spa毕竟是第一个微前端框架,他也有一定的缺点。
single-spa的文档略显凌乱,概念也比较多,在初次学习时上手难度较高。
single-spa是通过js文件去加载子应用,当文件名是乱码名时,每次子应用更新,父应用要更新引入配置文件,更新多项目时比较麻烦。
single-spa本身缺少js隔离和css隔离,虽然现在已经可以引入其他的包去解决,但是并没有做到开箱即用的程度。
所以在基本了解其思路之后,我们可以不妨看一下其他的方案比如qiankun都是如何实现和优化的。