微前端如何落地?

在过去的几个星期里,随着 Martin Fowler 博客上那篇 Cam Jackson 写的微前端的文章发布,到处都在讨论 Microfrontend。作为一个微前端 “专家”,我也分享一下:如何去落地微前端。

微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将单页面前端应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立开发、独立部署。同时,它们也可以在共享组件的同时进行并行开发——这些组件可以通过 NPM 或者 Git Tag、Git Submodule 来管理。

为什么需要微前端?

微前端不是银弹,它和微服务一样会带来大量的挑战。

  • 遗留系统迁移。解决遗留系统,才是人们采用微前端方案最重要的原因
  • 聚合前端应用。微服务架构,可以解耦后端服务间依赖。而微前端,则关注于聚合前端应用。
  • 热闹驱动开发。新的技术,既然很热闹,那么就学吧。

微前端的实现,意味着对前端应用的拆分。拆分应用的目的,并不只是为了架构上好看,还为了提升开发效率。

为此,微前端带来这么一系列的好处:

1.应用自治。只需要遵循统一的接口规范或者框架,以便于系统集成到一起,相互之间是不存在依赖关系的。

2.单一职责。每个前端应用可以只关注于自己所需要完成的功能。

3.技术栈无关。你可以使用 Angular 的同时,又可以使用 React 和 Vue。

除此,它也有一系列的缺点:

  • 应用的拆分基础依赖于基础设施的构建,一旦大量应用依赖于同一基础设施,那么维护变成了一个挑战。
  • 拆分的粒度越小,便意味着架构变得复杂、维护成本变高。
  • 技术栈一旦多样化,便意味着技术栈混乱

毕竟没有银弹。

如何设计微前端架构?

就当前而言,要设计出一个微前端应用不是一件容易的事——还没有最佳实践。在不同的落地案例里,使用的都是不同的方案。出现这种情况的主要原因是,每个项目所面临的情况、所使用的技术都不尽相同。为此,我们需要了解一些基础的微前端模式。

架构模式

微前端应用间的关系来看,分为两种:基座模式(管理式)、自组织式。分别也对应了两者不同的架构模式:

  • 基座模式。通过一个主应用,来管理其它应用。设计难度小,方便实践,但是通用度低。
  • 自组织模式。应用之间是平等的,不存在相互管理的模式。设计难度大,不方便实施,但是通用度高。

就当前而言,基座模式实施起来比较方便,方案上便也是蛮多的。

而不论种方式,都需要提供一个查找应用的机制,在微前端中称为服务的注册表模式。和微服务架构相似,不论是哪种微前端方式,也都需要有一个应用注册表的服务,它可以是一个固定值的配置文件,如 JSON 文件,又或者是一个可动态更新的配置,又或者是一种动态的服务。它主要做这么一些内容:

  • 应用发现。让主应用可以寻找到其它应用。
  • 应用注册。即提供新的微前端应用,向应用注册表注册的功能。
  • 第三方应用注册。即让第三方应用,可以接入到系统中。
  • 访问权限等相关配置。

应用在部署的时候,便可以在注册表服务中注册。如果是基于注册表来管理应用,那么使用基座模式来开发比较方便。

设计理念

在笔者实践微前端的过程中,发现了以下几点是我们在设计的过程中,需要关注的内容:

  • 中心化:应用注册表。这个应用注册表拥有每个应用及对应的入口。在前端领域里,入口的直接表现形式可以是路由,又或者对应的应用映射。
  • 标识化应用。 我们需要一个标识符来标识不同的应用,以便于在安装、卸载的时候,能寻找到指定的应用。一个简单的模式,就是通过康威定律来命名应用。
  • 应用生命周期管理。
  • 高内聚,低耦合。

生命周期

前端微架构与后端微架构的最大不同之处,也在于此——生命周期。微前端应用作为一个客户端应用,每个应用都拥有自己的生命周期:

  • Load,决定加载哪个应用,并绑定生命周期
  • bootstrap,获取静态资源
  • Mount,安装应用,如创建 DOM 节点
  • Unload,删除应用的生命周期
  • Unmount,卸载应用,如删除 DOM 节点、取消事件绑定

这部分的内容事实上,也就是微前端的一个难点所在,如何以合适的方式来加载应用——毕竟每个前端框架都各自不同,其所需要的加载方式也是不同的。当我们决定支持多个框架的时候,便需要在这一部分进入更细致的研究。

如何拆分?

随后,我们要面临的一个挑战是:如何去拆分应用。

技术方式

从技术实践上,微前端架构可以采用以下的几种方式进行:

  • 路由分发式。通过 HTTP 服务器的反向代理功能,来将请求路由到对应的应用上。
  • 前端微服务化。在不同的框架之上设计通讯、加载机制,以在一个页面内加载对应的应用。
  • 微应用。通过软件工程的方式,在部署构建环境中,组合多个独立应用成一个单体应用。
  • 微件化。开发一个新的构建系统,将部分业务功能构建成一个独立的 chunk 代码,使用时只需要远程加载即可。
  • 前端容器化。通过将 iFrame 作为容器,来容纳其它前端应用。
  • 应用组件化。借助于 Web Components 技术,来构建跨框架的前端应用。

实施的方式虽然多,但是都是依据场景而采用的。有些场景下,可能没有合适的方式;有些场景下,则可以同时使用多种方案。

路由分发式

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

就当前而言,路由分发式的架构应该是采用最多、最容易的 “微前端” 方案。但是

前端微服务化

前端微服务化,是微服务架构在前端的实施,每个前端应用都是完全独立(技术栈、开发、部署、构建独立)、自主运行的,最后通过模块化的方式组合出完整的前端应用。其架构如下图所示:

采用这种方式意味着,一个页面上同时存在二个及以上的前端应用在运行。而路由分发式方案,则是一个页面只有唯一一个应用。

组合式集成:微应用化

微应用化,即在开发时,应用都是以单一、微小应用的形式存在,而在运行时,则通过构建系统合并这些应用,组合成一个新的应用。其架构如下图所示:

微应用化更多的是以软件工程的方式,来完成前端应用的开发,因此又可以称之为组合式集成。对于一个大型的前端应用来说,采用的架构方式,往往会是通过业务作为主目录,而后在业务目录中放置相关的组件,同时拥有一些通用的共享模板。

微件化

微件(widget),指的是一段可以直接嵌入在应用上运行的代码,它由开发人员预先编译好,在加载时不需要再做任何修改或者编译。而微前端下的微件化则指的是,每个业务团队编写自己的业务代码,并将编译好的代码部署(上传或者放置)到指定的服务器上,在运行时,我们只需要加载相应的业务模块即可。对应的,在更新代码的时候,我们只需要更新对应的模块即可。下图便是微件化的架构示意图:

在非单面应用时代,要实现微件化方案,是一件特别容易的事。从远程加载来对应的 JavaScript 代码,在浏览器上执行,生成对应的组件嵌入到页面的相应部分。对于业务组件也是类似的,提前编写好我们的业务组件,当需要对应的组件时再响应、执行。

前端容器化

前端容器:iframe

iframe 作为一个非常 “古老” 的,人人都觉得普通的技术,却一直很管用。它能有效地将另一个网页/单页面应用嵌入到当前页面中,两个页面间的 CSS 和 JavaScript 是相互隔离的——除去 iframe 父子通信部分的代码,它们之间的代码是完全不相互干扰的。iframe 便相当于是创建了一个全新的独立的宿主环境,类似于沙箱隔离,它意味着前端应用之间可以相互独立运行。

结合 Web Components 构建

Web Components 是一套不同的技术,允许开发者创建可重用的定制元素(它们的功能封装在代码之外),并且在 web 应用中使用它们。

目前困扰 Web Components 技术推广的主要因素,在于浏览器的支持程度。在 Chrome 和 Opera 浏览器上,对于 Web Components 支持良好,而对于 Safari、IE、Firefox 浏览器的支持程度,并没有那么理想。

业务拆分

与微服务类似,要划分不同的前端边界,不是一件容易的事。就当前而言,以下几种方式是常见的划分微前端的方式:

  • 按照业务拆分。
  • 按照权限拆分。
  • 按照变更的频率拆分。
  • 按照组织结构拆分。利用康威定律来进一步拆分前端应用。
  • 跟随后端微服务划分。实践证明, DDD 与事件风暴是一种颇为有效的后端微前端拆分模式,对于前端来说,它也颇有有效——直接跟踪后端服务。

每个项目都有自己特殊的背景,切分微前端的方式便不一样。即使项目的类型相似,也存在一些细微的差异。

微前端之外

如果微前端对于你们来说困境重重,还有一些不错的架构模式可以采用。

应用微化架构

应用微化架构,是一种开发时整体,构建时拆分,运行时分离的前端架构模式。即应用微化架构从一份代码中,构建出适用于不同环境的多套目标代码。实现上它是一种:

  • 构建时拆分架构。
  • 代码删除架构。笑,以删代码的方式,来形成每个前端应用。
  • 微前端准备式架构。即,随时可以拆分为多个前端应用。

由于它与微应用化的相似性,我们将它与微应用化做一个对比。它与微应用化不同的是,应用微化是在构建时对应用进行拆分,而非在本地模式下对应用拆分。相似的是,它也是基于构建系统的应用拆分方式。

即:微应用化,是一个随时可合并式架构。而应用微化,则是一个随时可拆分式架构。

它不仅仅是一个适合于前端的架构模式,也是一适用于后端的架构模式。

整洁前端架构

Clean Architecture 是由 Robert C. Martin 在 2012 年提出的架构模式。它具有这么一些特点:框架无关性、可被测试、UI 无关性、数据库无关性、外部机构(agency)无关性。

对于前端架构来说,Clean Architecure 实际上是:Clean Architecture + MVP + 组件化。如下图所示:

考虑到应用的规模,这里以 Angular + TypeScript 作为示例:

这种架构模式特别适合于:组织内即写前端又同后端的团队。它易于映射前后端 API,且可以使用 usecase 作为防腐层。

没有银弹。不得不提及的是,对于小规模的团队来说,它带来的弊端可能会远远大于好处——带来大量冗余的代码。尽管通过 Angular Schematics 可以通过参数来生成代码,但是这种分层架构地于简单的应用来说,还是过于复杂、难以上手。对于不写测试的项目来说 ,usecase 也不能带来它们所承诺的好处。

结论

微前端不是银弹,当前也没有最佳实践,但是这是一个非常好的学习机会。


文/ThoughtWorks黄峰达
更多精彩洞见,请关注微信公众号:ThoughtWorks洞见

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 214,588评论 6 496
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,456评论 3 389
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 160,146评论 0 350
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,387评论 1 288
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,481评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,510评论 1 293
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,522评论 3 414
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,296评论 0 270
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,745评论 1 307
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,039评论 2 330
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,202评论 1 343
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,901评论 5 338
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,538评论 3 322
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,165评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,415评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,081评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,085评论 2 352

推荐阅读更多精彩内容

  • 借用当下最流行的段子做个开场白。 “设计原则千万条,高内聚低耦合第一条,架构设计不规范,开发运维两行泪!”。 在分...
    为爱放弃一切阅读 1,437评论 1 48
  • 如何针对当前需求,选择合适的应用架构,如何面向未来,保证架构平滑过渡,这个是软件开发者,特别是架构师,都需要深入思...
    程序员技术圈阅读 972评论 1 5
  • 中台建设完成后,通过微服务实现了后端应用的解耦,提高了中台应用的弹性伸缩能力。但由于微服务拆分,也会导致项目团队和...
    梅西爱骑车阅读 2,057评论 2 8
  • 表情是什么,我认为表情就是表现出来的情绪。表情可以传达很多信息。高兴了当然就笑了,难过就哭了。两者是相互影响密不可...
    Persistenc_6aea阅读 124,716评论 2 7
  • 16宿命:用概率思维提高你的胜算 以前的我是风险厌恶者,不喜欢去冒险,但是人生放弃了冒险,也就放弃了无数的可能。 ...
    yichen大刀阅读 6,042评论 0 4