微前端探索,将前端微服务化

微前端探索
背景 前段时间开发了一个业务管理系统项目,项目中包含一系列功能,包括人员管理、机构部门、权限、功能维护等基本功能。于是乎,打算将这些基本的功能独立出来供其他业务系统使用。那么这个基础的项目应该具备以下特点:独立的代码库、便于更新迭代、完善的文档等。
于是便有了微前端的想法,尽管可能实现方式诸多。


什么是微前端 微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。



独立开发
微前端的每一部分必然有各自独立的代码库

独立部署
既然是服务化,独立部署也是需要满足的。

技术无关
微服务化,必然避免不了对不同技术栈的整合

分包与微前端 关于这方面@sorrycc的文档笔记中也有提到https://www.yuque.com/f2e-growth/notes/op1wkk
但是个人觉得分包还是不同于微前端,分包可能会更加大,而微前端可能粒度更小,那么可不可以认为更细粒度的分包即是微前端?
前面阐述了微前端的3个特点,那么如何实现?
假设,我们有30+个不同技术栈的前端组件,要如何将它们整合为一个可用的项目?
下面是我搜集到的一些可用框架:

微前端的几种实现框架
Single-SPA
https://single-spa.js.org/
优点:跨技术栈、
缺点:粒度不够小,与其叫它微前端不如称其为微应用,因为它针对的是页面级的,通过管理路由整合其它应用;
每个子应用需要满足约定好的方式进行开发,不便对原有项目进行改造

Project Mosaic
https://www.mosaic9.org/
优点:完全细粒度到组件
缺点:整体非常复杂

Open-Components
https://opencomponents.github.io/
优点:细粒度到组件
缺点:需要部署registy库
通过约定方式发布组件到registry中,客户端直接使用发布的组件地址调用;
个人认为这种方式与发布到npm,然后加载umd包的方式没有太大区别,前者在发布时貌似处理了umd包依赖冗余的问题。

最终的选择方案(伪微前端?>_<)
NPM包、Lerna进行多包管理
为什么叫它伪微前端呢,因为这种方式仅仅只实现了独立开发。但是好在上手简便,即没有微前端框架的那些特殊约定也无需对现有项目进行太多的改造,可以说是无痛迁移。
对比上面的几种微前端实现方式,npm最大的区别就是,整个项目在构建时依然是捆绑在一起的,尽管如此,在项目开发中并无影响,而且使用npm包的方式更易于版本管理。
之前由于对npm打包并不熟系,导致还是走了很多弯路,但是umi的生态解决了大部分问题,再次感谢云谦大大,哈哈哈,现在我的前端之路,已经是跟着umi前行了。
接下来,阐述一下最终的实现方式,以及遇到的一些问题:

使用umi-library的babel方式进行打包
期间恰逢umi-library发布,一路摸爬滚打终于成功,此处简单记录一下:

  1. umi-library可以使用rollup、babel两种方式打包,rollup会进行文件合并,所有依赖文件被打包成一个文件,babel方式打包是文件到文件的编译,使用此种方式可保证发布到npm后的包文件路径与开发时一致。
  2. 可以打包成es、cjs以及umd,如果不想每次更新npm包,可以发布umd包到npm,然后使用unpkg cdn加载umd文件。
  3. umi-lib dev --watch 监听文件变化,并自动更新打包文件。本地开发时,使用此方式配合lerna,可实现页面的热更新。

Lerna进行多包管理,发布
  1. 当对项目进行拆分后,发现拆分出了3个包,这三个包都需要发布到npm,而且如何在本地进行开发、调试?Lerna是最好的选择,而且能保证在开发和调用npm包的时候保持有一致的开发方式。umi有很多库,也是使用lerna进管理的。
  2. lerna bootstrap 安装所有包的依赖,lerna publish from-package仅发布npm包,不提交到git
是不是很简单?只要会bootstrap、publish两个命令,你就能完成多包管理。

使用umi进行项目构建
  1. 使用umi-plugin-react更新路由,将npm包中配置好的路由注册到项目中
  2. 使用chainwebpack重新处理css module的问题,由于打包的npm包中存在使用了css module的组件,但是umi是不处理node_modules下的组件的css module的,于是乎使用通过chainwebpack的api对配置进行了改写:
config.module.rule('less-in-node_modules').use('css-loader').loader('css-loader').options({importLoaders: 1,sourceMap: true,modules: true})

另外,此处赞一下,在控制台中打印出chainwebpack的参数config.toString(),你会发现每一条规则都写好了注释,指明了配置改写的规则。当时没看到这个注释的时候,可费了老大劲了。。。

总结 对于微前端方案选型,前期折腾了不少时间,主要是想在兼容目前项目的同时进行改造,能否兼容项目中不同的使用场景都是一个疑问,比如Single Spa能否结合redux,如何避免现有项目的改造,是否稳定,种种因素让人放弃了采用目前已有的一些微前端框架。

相关资源 https://micro-frontends.org/
https://microfrontend.cn
https://github.com/ChristianUlbrich/awesome-microfrontends
https://micro-frontends.zeef.com/elisabeth.engel?ref=elisabeth.engel&share=ee53d51a914b4951a e5c94ece97642fc

思考,是否有更好的微前端实现方式? 【微前端探索,将前端微服务化】在探索微前端的这段时间,搜集到的一些框架,都各有劣势,约定太强并且实现复杂。能否有更好的方式?

    推荐阅读