一、概念

说到微前端之前先提一下微服务。微服务是为了解决庞大的后端服务带来的变更与拓展方面的限制,而将一个大型的服务应用分割成若干个颗粒度较小的可独立开发、测试及部署的单个子应用。而越来越复杂的前端项目也面临同样的问题。于是有了微前端的诞生。

微前端与微服务类似,都是将一个复杂大型的应用程序拆解成颗粒度更小的可以独立开发、测试及部署的小模块,并通过一些策略方案来确定这些模块之间的依赖关系。

微前端概念诞生于 2016年,Micro Frontends 官网对微前端概念的定义是:

Techniques, strategies and recipes for building a modern web app with multiple teams that can ship features independently.

翻译成中文为:微前端是构建一个现代 Web 应用所需要的技术、策略和方法,并具备多个团队独立开发、部署的特性。

从以上概念可以看出微前端并不是一种新的技术,而是为了提高大型复杂应用的多团队协作,提升项目的可维护性、拓展性和灵活性,研究出的一种技术策略和方法,它是一种宏观上的架构模式。

二、特点

(一)代码库更小,可维护性更高
比起传统的一整个项目代码块,微前端架构下的代码块更小、更容易开发。还可以避免模块之间的隐式耦合。独立性更强,维护性更高。

(二) 渐进式升级与迭代
微前端架构可以让新旧代码和谐共存,在重构时,可以一边将旧的应用逐步翻新,一边继续提供新功能,直到整个重构完成。这种增量升级的能力意味着能够对产品功能进行低风险的局部替换,包括升级依赖项、更替架构、UI 改版等。另一方面,也带来了技术选型上的灵活性,有助于新技术、新交互模式的实验性试错。

(三) 独立部署
独立部署在微前端中非常重要,子模块之间只有部署,才能减轻依赖,降低耦合。独立部署能够缩小项目变更范围,降低生产风险。无论前端代码在何处托管,每个微前端都应该有连续交付通道,该通道可以构建、测试并将其一直部署到生产环境中。

三、实现方式

前面有介绍到微前端的概念和一些优点,但是微前端架构会面临如下问题:

(一) 打包之后的 Bundle 如何集成

在微前端架构中一般会有一个容器应用将各子应用集成起来。比如统一的 Header、Footer、Navigator 等。提供一些公共的方法。然后把各个子模块整合到一个页面上,并控制渲染区域和时机。

集成方式一般分为三种。

  1. 服务端集成
    每个子服务负责独立渲染对应的微前端应用,由主服务向各个子服务发起请求。

  2. 构建时集成
    常见的构建时集成是 NPM 包形式抽离和引用,可以将各个子应用发布成独立的 NPM 包,并作为主应用的依赖项,构建成一个可以直接部署的 Bundle。不过这种方式会在发布阶段造成应用之间的强耦合,任何一个子应用变更都要重新构建整个项目。

  3. 运行时集成
    将集成时机从构建时推迟到运行时,就能避免发布阶段的耦合。常见的运行时集成方式有:

  • iframe
    支持样式隔离及全局变量隔离。性能差,通信复杂,灵活性差。

  • JS:比如前端路由
    由每个子应用暴露出渲染函数,主应用在启动时加载各个子应用的独立 Bundle,之后根据路由规则渲染相应的子应用。目前看来,是最灵活的方式

  • Web Components
    将每个子应用封装成自定义 HTML 元素(而不是前端路由方案中的渲染函数),以获得Shadow DOM带来的样式隔离等好处。

(二) 子应用之间如何隔离
子应用之间,子应用和主应用之间的样式、作用域隔离是必须要考虑的问题。常用的解决方案如下:

  • 样式隔离:开发规范(如BEM)、CSS 预处理(如SASS)、模块定义(如CSS Module)、用 JS 来写(CSS-in-JS)、以及shadow DOM特性

  • 作用域隔离:各种模块定义(如ES Module、AMD、Common Module、UMD)

(三) 子应用之间如何通信

  1. 通过自定义事件间接通信
    该方式是一种避免直接耦合的常用方式。

  2. React 的单向数据流模型
    React 的单向数据流模型也能让依赖关系更加明确,对应到微前端中,从容器应用向子应用传递数据与回调函数。

  3. 路由参数
    路由参数除了能用于分享、书签等场景外,也可以作为一种通信手段

其实无论采用哪种方式,都应该尽可能减少子应用间的通信,以避免大量弱依赖造成的强耦合。

(四) 公共资源如何复用

公共资源可以大致分为以下三种:

  1. 基础资源
    项目中需要使用到的图片、图标、标签、按钮等。

  2. UI 组件
    含有一定逻辑的 UI组件。如搜索框(自动完成)、表格(如排序、筛选、分页)等。

  3. 业务组件
    含有业务逻辑的业务组件,不建议跨子应用复用业务组件,因为会造成高度耦合,增加变更成本。

资源复用对于呈现给用户的 UI 界面非常重要。但是组件复用并非项目一启动就能够完全确定。前期开发时可以有一些代码冗余,可以由各个子模块在代码中去创建自己的公共组件,等到业务模块已经完全确定再提取最终可供复用的公共组件。公共资源应当遵循统一规范,其归属和管理最好由专人负责。

Logo

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

更多推荐