微前端之四 • Single SPA 的源码实现

深入了解一个库最好的办法是直接去看源代码,学习作者的设计模式、运行原理、代码风格等。并且动手跑起来,碰到不懂的地方打断点或者打印关键信息,一步一步去琢磨。

很多流行库发展多年后,优化工作越做越好,但同时会变得比较臃肿,代码量大且文件分散,直接看最新版本的源代码可能无从下手。我是这么实践的,先去看它的第一个发行版,一般来说首次发行版的代码简洁,设计模式和原理与后面的版本不会有太大的变化。

Single SPA 的1.0.0 版本是7年前发布的,只有一个文件,一共不到400行代码,非常方便阅读。Github 选择 branch 的地方有一个 tags 的选项,点开可以看到每个版本对应的源码。我克隆了一份放在自己的 Github,加上了注释,并且添加了更容易理解的接入样例,地址:https://github.com/WinjayYu/the-single-spa

根目录下面的 index.html 相当于基座应用,这里作了简化处理。首先需要引入 System.js 模块加载器,它支持动态引入 js 模块。

我们平时使用 webpack 开发的时候,所有的组件在打包后就已经变成了非模块化的 js ,所以无论浏览器是否支持模块加载都可以顺利执行。随着 ES6 的普及,越来越多的浏览器开始支持 ES Module,但是兼容性还不好,SystemJS 是现阶段下(浏览器尚未正式支持importMap)原生 ES Module 的替代品。

随后引入 Single SPA 库,然后就可以调用 declareChildApplication 注册子应用了。注册方法需要两个参数,第一个是子应用暴露给基座的配置文件,主要包括了生命周期函数;第二个是触发条件,检测当前路由是否和子应用匹配。

上图中 src/index.js 是 Single SPA 的源码,实现细节请参考 Github 仓库。下面是通过源码逻辑画的流程图,直观地展示子应用从加载到销毁的过程:

其中比较关键的是劫持 window 的 popstate 和 hashchange 监听方法 。保证 Single SPA 先感知到路由的变化,根据路由挂载指定的子应用,待子应用挂载完整后,再执行 popstate 和 hashchange 原来的监听方法。

可以看到,微前端的原理并不复杂,它其实是一种约定的架构风格。做好一件事情往往并不依赖多么前沿的技术,但需要大家的互相协作,按照统一的约定风格开发。

posted @ 2022-11-19 11:27  WinjayYu  阅读(65)  评论(0编辑  收藏  举报