一、微前端的架构设计
1. 构建基础设施
在基础设施上,微前端架构与单体应用架构有相当大的差异。在单体应用里,共享层往往只有一个。而在微前端架构里,共享层则往往存在多个,有的是应用间公用的共享层,有的是应用内共用的 共享层。在微前端设计初期,构建基础设施要做如下几件事情:
- 组件与模式库。在应用之间提供通用的 UI 组件、共享的业务组件,以及相应的通用函数功能模块,如日期转换等。
- 应用通信机制。设计应用间的通信机制,并提供相应的底层库支持。
- 数据共享机制。对于通用的数据,采取一定的策略来缓存数据,而不是每个应用单独获取自己的数据。
- 专用的构建系统(可选)。在某些微前端实现里,如微件化,构建系统用于构建出每个单独的应用,又可以构建出最后的整个应用。
2. 提取组件与模式库
系统内有多个应用采用同一个框架的前端架构,模式库作为微前端架构的核心基础,可以用于共享代码。
样式 在实施微前端的过程中经常会遇到一个头疼的问题:样式冲突。如果在一个页面里同时多个前端应用,那么就会存在以下形式的样式:
组件级样式:只能用于某一特定组件的样式。
应用级样式:在某一个前端应用中使用的样式。
系统级样式:可在该页面中使用的样式,往往会影响多个应用。
对于组件级样式来说,有些框架可以从底层上直接支持组件模式隔离,如 Angular。此外组件库来说,也会创建对应的 CSS 前缀来保证唯一性,只要在开发的过程中多加注意即可。
对于应用级样式而言,则需要制定一个统一的规范,可以根据应用名加前缀,如 dashboard-, 也可以根据路由来增加相应的前缀,以确保应用本身的样式不会影响到其他应用。此外 往往也会为这些应用,创建一个统一的样式库,以提供一致的用户体验。
对于系统级样式而言,大抵只存在于基座模式设计的微前端架构里。在这种方案里,由基座应用来控制其他应用,也存在部分的样式。在编写这些样式的时候,需要注意其他应用的影响。 此外,它也可以作为统一的样式库承载的应用来使用。
业务组件及共享库
对于在多个应用中使用的业务组件和共享函数,既可以提供 NPM 包方式,又可以提供 git submodule 的方式,引入其他应用中。
对于通用的组件,它在开发的前期需要频繁地改动,这时可以将其抽取成为子模块(Submodule)的形式在项目中使用。当需要的时候,可以轻松地修改,并在其他应用中更新。当这些组件 趋于稳定的时候,可以尝试将其作为 NPM 包发布。如果一开始就有该打算,则需要在这个子模块中使用 package.json 和 NPM 包的管理方式,方便后期直接扩展。
此外,不得不提及的是,这种类型的修改应当是兼容式修改。在难以兼容的情况下,需要对系统中使用到的部分,逐一进行排查,直到确认已更新下游 API。然后,还要进行相应的部分测试, 以确保组件修改带来的影响都已经被修复。
3. 应用通信机制
解决了应用间共享代码的问题,还需要设计出一个应用间通信的机制,在微前端架构里,从应用间的关系来看,存在如下两种类型的通信:
- 同级通信,即挂载在同一个 HTML Document 下的应用间的通信。
- 父子级通信,即采用iframe 形式来加载其他应用。
前者往往通过全局的自定义事件(CustomEvent)便可以实现,值得一是的是,在 IE 浏览器上需要使用 Polyfill兼容库。此外,由于应用之间共享一个Window,所以还可以开发自己的 发布—订阅模式组件。与自定义事件相比,它拥有更高的可定制度。
如果采用父子级通信机制,则稍显麻烦一些。普通的父子级通信可以做到以下几方面:
- 通过PostMessage在父子窗口之间进行通信。
- 透过parent.window寻找到父窗口,再发出全局的自定义事件。
- 当其他应用加载时,将消息发送给父窗口,由父窗口发出自定义事件。
- 当其他应用未加载时,先将消息传递给父窗口,再由父窗口进行存储,提供一个获取通信的机制。
在实施过程中,具体采用哪种或哪几种方式,取决于在设计的时候有哪些需要。也可以在前期设计出所有的机制,方便后期使用。
值得注意的是,在实现的过程中往往会出现两种结果:
- 嵌入业务的特定通信机制。
- 剥离业务的通用通信机制。 后者是一个通用的通信机制,开发成本相对较高。前者则是一个业务绑定的模式,一旦添加新功能,便需要进行修改。
4. 数据管理
单页面应用是指对于业务状态的管理及处理。过去往往是由后端来实现的,即由 Session 来维持一个用户的状态,现在这个状态转交给了前端。 前端在与后端进行交互时,需要传递大量的状态,这时的状态主要由两个部分来组成: URI (GET的传参数会转换到URI中) + 请求body。 由于一个应用持有这些状态,所以为了实现方便、要在应用间共享这些数据。
应用的数据管理可以分为两部分,一部分是状态,另一部分则是应用数据。 只是从某种意义上来说,状态是一种特殊的应用数据,它更加显式地展示数据。 通过上部分的应用通信机制,可以解决部分数据共享问题,通用部分的数据,则可以选择一个合适的数据管理策略。 为此,需要一个去中心化的管理数据,或者基于基座应用的数据管理机制。
常见的数据交互方式,有以下几种:
- URI 参数传递。
- 使用 Localstorage 共享数据。
- 其他客户端存储, 如 IndexedDB、 Web SQL 等。
- 服务端存储客户端状态,可以采用JSON格式存储。
在这方面,很难通过实施一套有效的方案来管理,往往是通过规范来保持一致,如在某些情况下使用URI传递参数,在某些情况下应用自身从 Localstorage 获取。当然,如果设计了 安全存储策略,就另当别论了。
5. 专用的构建系统
首先需要声明一下,并非所有的微前端架构都需要一个专用的构建系统。只有那些依赖于构建及构建工具创建出来的微前端应用,才需要设计出一个专用的构建系统,以支撑系统的开发。
如果采用了微应用化、微件化的架构方案,就需要设计自己的构建流程、构建系统,每种方式在具体实现上各有差异。 微件化需要修改构建工具,如添加对应的构建插件,党它能支持构建出组件包; 微应用化则依赖于设计构建流程,而不需要对构建工具进行修改;