微前端介绍

前提摘要:Jpunster 最近电脑最近在维修,所以不能及时更新公众号。
今天由我copper(Jpunster技术启蒙老师+好兄弟)来给大家分享一下微前端方面的知识。

最近几年,微服务架构在后端领域大行其道,大有一种不知道微服务都不好意思跟人打招呼的味道:happy:,多少小团队为了微服务而微服务,完全不顾开发以及后期的运维难度(打住,不是来吐槽的😏)。今天的主角微前端也是类似于微服务的一种前端架构。

什么是微前端

在介绍微前端前,我们先来看看在后端领域甚是流行的微服务带来了什么好处:

  • 复杂度可控: 体积小、复杂度低,每个微服务可由一个小规模开发团队完全掌控,易于保持高可维护性和开发效率。
  • 独立部署: 由于微服务具备独立的运行进程,所以每个微服务也可以独立部署。
  • 技术选型灵活: 微服务架构下,技术选型是去中心化的。每个团队可以根据自身服务的需求和行业发展的现状,自由选择最适合的技术栈。
  • 容错: 当某一组建发生故障时,在单一进程的传统架构下,故障很有可能在进程内扩散,形成应用全局性的不可用。
  • 扩展: 单块架构应用也可以实现横向扩展,就是将整个应用完整的复制到不同的节点。

回到今天的主题微前端,其实ThoughtWorks 早在2016年的技术雷达中就提到过微前端这一概念,并将其列入了组织应评估的技术之列。

thoughtworks

它是一种类似于微服务的前端架构,能够将不同语言开发的不同系统聚合为一个统一对外的系统,也可以在共享组件的同时并行开发。

如下图所示,假设我们有三个业务子系统,用户如果要使用三个系统中的不同功能,他就需要同时在三个系统中登录然后来回切换进行操作。

system

而实际上理想的状态是:A、B、C 三个子系统在同一个大平台上,通过菜单提供入口进入,用户可以自由访问任意一个子系统的页面。如下图所示:

one system

那应用了微前端会为我们带来什么好处呢:

  • 复杂度可控: 每一个UI业务模块由独立的前端团队开发,避免代码巨无霸,保持开发时的高速编译,保持较低的复杂度,便于维护与开发效率。
  • 独立部署: 每一个模块可单独部署,颗粒度可小到单个组件的UI独立部署,不对其他模块有任何影响。
  • 技术选型灵活: 也是最具吸引力的,在同一项目下可以使用如今市面上所有前端技术栈,也包括未来的前端技术栈。
  • 容错: 单个模块发生错误,不影响全局。
  • 扩展: 每一个服务可以独立横向扩展以满足业务伸缩性,与资源的不必要消耗。

从上面不难看出微前端能够带来的一些好处:独立开发独立部署、各个系统自治、单一职责、技术栈无关,甚至于能够解决遗留系统的迁移。防止一个普通应用演变为一个不可维护的巨石应用

需要明确得是微前端不是框架、不是工具/库,而是一套架构体系,它包括若干库、工具、中心化治理平台以及相关配套设施,主要包括已下3部分:

  • 微前端的基础设施。这是目前讨论得最多的,一个微应用如何通过一个组件基座加载进来、脚手架工具、怎么单独构建和部署、怎么联调。
  • 微前端配置中心:标准化的配置文件格式,支持灰度、回滚、红蓝、A/B 等发布策略。
  • 微前端的可观察性工具:对于任何分布式特点的架构,线上/线下治理都很重要。

微前端就是一把万能的钥匙吗?很明显不是的,作为类似微服务的一种架构,它同样拥有微服务所带来的一系列问题,比如服务拆分的粒度、基础设施引入所带来的维护问题等等。

解决方案

在这里采用FE萝卜头的对比角度对方案进行分类:硬/软隔离。服务端路由分发与 iFrame 是典型的基于浏览器的硬隔离方案,其天然支持多技术栈、多源的灵活组合,不过其在应用协调与治理方面需要投入较大的精力。软隔离更多地依赖于应用框架或者开发构建流程,来实现容错与样式、DOM 等隔离。

浏览器硬隔离
路由分发式

通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理(比如Nginx)来实现,又或者是应用框架自带的路由来解决。

这种方式实现起来非常简单,并且也能够做到独立开发独立部署,但这更像是多个前端应用的聚合,我们只是将这些不同的前端应用拼凑到一起,使他们看起来像是一个完整的整体。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-nfBvfehN-1585896951244)(https://i.loli.net/2020/03/21/8LKZrGNbQmCeiFp.jpg)]

非常凑巧的是在我调研微前端之前,我们组内已经有同事在实施这种方案,将多个不同的系统接入到一个统一的管理平台。但是无论从接入方式还是使用体验来讲,都不尽如人意。

IFrame

IFrame可以创建一个全新的独立的宿主环境,这意味着我们的前端应用之间可以相互独立运行。而且它得到了浏览器原生支持,能够天然的解决CSS、Js的污染问题。但是问题也很明显:每次都需要重新加载,占用额外的内存,使用体验欠佳、不支持SEO、需要我们自定义应用管理与应用通讯机制。

单体应用软隔离

软隔离可以从应用的组合时机与技术栈的支持情况这两个维度,划分不同的解决方案。对于需要支持不同技术栈(React, Angular, Vue.js, etc.)的场景,我们往往需要彻底的类后端微服务化,每个前端应用都是独立的服务化应用,而宿主应用则提供统一的应用管理和启动机制;此时若需要解决资源重复加载、冗余的问题,则需要依赖统一构建或者由宿主应用提供公共依赖库,子应用打包时仅打包自身或非公用库代码。如果是相同技术栈的场景,那么我们可以方便地利用框架本身的懒加载能力,在开发阶段以模块划分为微应用进行开发,构建时以单体应用的形式构建,在运行时是以应用模块的形式存在。

典型的应用组合方式分为构建时(Build Time)组合与运行时(Runtime)组合,如下图所示即是典型的构建时组合方案:

build

构建时组合的优势在于能够进行较好地依赖管理,抽取公共模块,减少最终的包体大小,不过其最终的产出仍是单体应用,各个应用模块无法进行独立部署。 与之相对的,运行时组合能够保障真正地独立开发与独立部署:

run

对于构建时组合来讲,这种方式表面看起来不错,但它打破了我们好不容易在开发和测试阶段实现的解耦和独立,相当于又绕回到之前的样子。

对于运行时组合业界已经有比较多的实现方案了,比如最为流行的Single-SPA。这种方式一般分为主应用和子应用,主应用的代码一般非常简单,仅作为加载容器,管理子应用的生命周期。主应用捕获全局的路由事件,基于当前路由判断需要加载哪一个子应用。比如路由为main/vue,我们就加载 /vue 子应用;当路由为 /main/react,则加载 /react 子应用。最后,当路由切走后,也要卸载该应用。

除了Single-SPA,还有很多基于或者类似它的产品,其中比较靠谱的有:

  • qiankun:意为统一,我们希望通过 qiankun 这种技术手段,让你能很方便的将一个巨石应用改造成一个基于微前端架构的系统,并且不再需要去关注各种过程中的技术细节,做到真正的开箱即用和生产可用。
  • icestark:面向大型系统的微前端解决方案。icestark 在保证一个系统的操作体验基础上,实现各个子应用的独立开发和发版,框架应用通过 icestark 管理子应用的注册和渲染,将整个系统彻底解耦。

结语

最后借用 Simon Brown 的一条 twitter 来结束这篇文章:

I’ll keep saying this … if people can’t build monoliths properly, microservices won’t help.

如果你连单体应用都写不好,微前端也帮不上什么忙

参考文章

Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐