全面敏捷模式下的微前端方案——设计篇

这里是突然勤奋的 Zhuo,持续更新文档中。
本文只涉及到 module-federation 微前端方案的设计层面分享,关于具体实现,可以参考写的简单例子;所有的设计图自取,如果对你有一些启发,请点个 star
背景 团队从瀑布流模式转变为敏捷模式,将整个项目团队划分为多个小组并行开发,多小组同时升级的分支处理和代码冲突之类的问题频繁出现。于是接到了组内一个技术需求:《模块支持单独升级和部署》。目前,我们开发和维护代码的现状:
全面敏捷模式下的微前端方案——设计篇
文章图片

  • 一个仓库包含了所有的业务组的前端代码
  • 只能一起打包出一个整包,也无法单独部署
  • 后端已完成微服务的拆分
如上所述,虽然一般场景通过 git 多分支管理能解决【独立开发】和【发布】的问题,但是一遇到【多团队同时发布】的场景就让人头疼了:
  • 需要拉上各个团队的负责人,反复确认当天能否正常上线
  • 上线分支排列组合(release-a、release-b、release-ab )预防某一个团队突发问题不上线
  • 测试工作量增加:原本只要验收一个代码包,现在还要验证多个代码包功能(> 1)
看一眼分支模型:
全面敏捷模式下的微前端方案——设计篇
文章图片

既然提出了已有问题,为了解决这些问题,我们意识到和后端一样将整个项目拆分成若干的子应用,将它们也变成微服务,不就可以解决目前的困境了吗?自然而然我们就想到了“微前端”的概念。有目标,就好发力了,我们参考了业务优秀方案,同时结合了自身实际情况,最终决定用webpack5 module federation 特性来进行微前端的实践与落地。
需求分析 外部需求
  1. 拆分解耦
  2. 单独打包,独立部署
  3. 不影响现在的用户体验
内部需求
  1. 不影响开发体验
  2. 方案对原业务代码侵入性最低
  3. 学习成本低
  4. 统一技术栈
  5. 前端灰度发布
方案选择 方案:
  1. 应用微服务化,诸如 qiankun2
    • 存在性能问题,且沙箱逃逸问题难解决,放弃
  2. 微件化:通过组合多个独立应用、组件来构建一个单体应用,例如 Module Federation
    • 在接入第三方应用上存在的问题比较大,但是对于我们想要达到【独立升级】的效果来说,此短板可以接受
  3. 结合 Web Components 构建,例如 micro-app
    • 在处理沙箱的性能问题和逃逸问题上虽然比方案1更优秀,但这两个问题出现还是难解决,且目前官方维护的频率及未有稳定版本,放弃
  4. MPA+路由分发
    • 相当将原本的一个系统拆成多个系统,体验上无法接受,放弃
  5. MPA + iframe
    • iframe 在性能和用户体验上的问题也是无法接受,放弃
  6. 【全面敏捷模式下的微前端方案——设计篇】纯 Web Component 进行构建应用
    • 需要用一个新的基础方案将整个项目的代码重构,工作量上无法接受,放弃
最终采用方案2:module federation
全面敏捷模式下的微前端方案——设计篇
文章图片

微前端实践 通过方案的分析以及项目实际情况的梳理,我们确定了微前端的整体方案,输出组件图,如下图所示:
全面敏捷模式下的微前端方案——设计篇
文章图片

可以看到,整个方案非常简单:按照开发小组进行路由级别的拆分,整个系统可分为两个部分:
  • 基座应用:用于管理子应用的路由切换、注册子应用的路由和全局 Store 层、提供全局库和复用层
  • 子应用:用于开发子应用业务代码,一个子应用对应一个开发小组,并且管理自己的路由、语言包、埋点、Store
基座应用和子应用联系起来的桥梁则是入口文件:remoteEntry.js。这可以让基座应用准确地发现子应用资源的路径从而进行加载。
因为依赖了remoteEntry.js进行关联,所以这个文件不会加 hash 后缀,这就要求对该命名的文件全部设置协商缓存,不再是强缓存。
微前端下的架构变化 在整个方案的改造之后,我们的项目整体的架构变成了如下图展示的样子:
全面敏捷模式下的微前端方案——设计篇
文章图片

前端侧的代码按照小组特性拆分成若干个子应用:
  • 每个子应用只拥有自己相关的代码,基座应用可以看成比较特殊的子应用,它提供工程能力,最好不要有业务代码
  • 将应用代码划分到 packages/apps文件下, 通过 monorepo + pnpm 进行管理依赖
  • 所有的文件夹进行单独的打包构建,搭配 Docker + Kubernetes 构建成单独的容器(红色部分内所有的子应用都是单独的容器)变成真正的微服务
  • 通过 ingressroute + nginx 加载不同容器之间的子应用资源
以上的变化,让拆分出来的子应用能够独立开发 - 维护 - 发布之外,还使得我们前端应用升级时的 灰度 - 部署 - 回滚 操作变得更加简单、快速。
部署方案 在达成独立部署上线的目标之后,所有的子应用都是独立的,发布不需要依赖于任何应用。只需要确认开发修改了哪些子应用的代码,那么就升级对应的子应用即可。
全面敏捷模式下的微前端方案——设计篇
文章图片

具体流程:
  1. 开发修改了 A 应用的代码,上库
  2. 打包平台(千流,公司自建)识别到具体变更的代码路径,对 A 应用进行打包,生成镜像容器、版本号等,推送到镜像平台
  3. 升级对应服务
虽然步骤是这些,但是在开发人员这里,他只需要提供本次升级的版本号(1.0.xxx)即可,背后流程不需要深入了解。
回滚方案 得益于 Docker + Kubernets ,前端的回滚只需要执行一条 helm 命令即可。除此没有其他的内容。
总结 总的来说,我们完成了以下的目标:
  • [x] 代码拆分解耦
  • [x] 单独打包,独立部署
  • [x] 不影响现在的用户体验:没有引入其他类库,也没有使用 iframe
  • [x] 不影响开发体验:支持热更新
  • [x] 方案对原业务代码侵入性最低:核心工作量在代码拆分,webpack的配置并没有多少工作量
  • [x] 学习成本低:基本没有学习成本
  • [x] 统一技术栈:本来就是一个项目
  • [x] 前端灰度发布
学习链接 感谢以下文章的作者/团队分享的文章,提供了很好的思路。
  1. Module federation 原理研究
  2. Revolutionizing Micro Frontends with Webpack 5, Module Federation and Bit
  3. How to Build a Micro Frontend with Webpack's Module Federation Plugin
  4. Webpack Module Federation
  5. Module Federation Examples
  6. https://medium.com/@A__G__B/i...
  7. EMP-面向未来微前端方案正式开源了!
  8. micro-app 介绍
  9. 可能是你见过最完善的微前端解决方案
  10. 字节跳动是如何落地微前端的
  11. 微前端在美团外卖的实践
都看到这里了,帮忙点个赞呗~

    推荐阅读