微前端初探

引言

当一个项目代码越来越庞大,团队间协作不是那么容易的时候,大家就会希望可以通过分割成多个小项目,降低维护难度,我们期望有一种团队间、不同业务间单独维护的架构;当公司有一个技术栈老旧的项目,功能运行还算稳定,对于这种遗留系统来说,我们不想再花时间优化老旧系统,期望能跟上技术潮流,挑战新技术。我们期望有更好维护性、业务拆分更细粒度、多个技术栈共同嵌入一个应用中的架构模式,于是,微前端理念呼之欲出。

一、什么是微前端

微前端是一种新模式,其中 Web 应用程序 UI(前端)由一些半独立的片段组成,可以由不同的团队使用不同的技术来构建。微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。各个前端应用还可以独立运行、独立开发、独立部署。

二、微前端的作用

微前端的作用是为了解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用后,随之而来的应用不可维护的问题。其带来的核心作用有一下几点:

  • 技术栈无关 主框架、子应用可以使用不同的技术栈,子应用具备完全自主权
  • 独立开发、独立部署 子应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
  • 独立运行时 每个子应用之间状态隔离,运行时状态不共享

三、实现微前端架构的 6 种方式

一个大型的应用,通常需要由多个项目组成,那么就涉及到多应用拆分。
技术方式
从技术实践上,微前端架构可以采用以下的几种方式进行:

1、路由分发式

路由分发式微前端,即通过路由将不同的业务分发到不同的、独立前端应用上。其通常可以通过 HTTP 服务器的反向代理来实现,又或者是应用框架自带的路由来解决。但是这种方式看上去更像是多个前端应用的聚合,即我们只是将这些不同的前端应用拼凑到一起,使他们看起来像是一个完整的整体。但是它们并不是,每次用户从 A 应用到 B 应用的时候,往往需要刷新一下页面。一个页面只有唯一一个应用。目前这种方式是最常用的微前端方案,我们团队目前也是采用这种方案。

适用性:

  • 不同技术栈之间差异比较大,难以兼容、迁移、改造
  • 项目不想花费大量的时间在这个系统的改造上
  • 现有的系统在未来将会被取代
  • 系统功能已经很完善,基本不会有新需求

路由分发式微前端示意如下:

以下是基于路由分发的 Nginx 配置示例:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
http {
server {
listen 80;
server_name www.phodal.com;
location /api/ {
proxy_pass http://http://172.31.25.15:8000/api;
}
location /web/admin {
proxy_pass http://serverA/web/admin;
}
location /web/notifications {
proxy_pass http://serverB/web/notifications;
}
location / {
proxy_pass /;
}
}
}

2、前端容器化:iFrame

iFrame 是一种古老的实现微前端的方式,它能有效地将另一个网页/单页面应用嵌入到当前页面中,两个页面间的 CSS 和 JavaScript 是相互隔离的——除去 iframe 父子通信部分的代码,它们之间的代码是完全不相互干扰的。iframe 便相当于是创建了一个全新的独立的宿主环境,类似于沙箱隔离,它意味着前端应用之间可以相互独立运行。

采用 iframe 有几个重要的前提:

  • 网站不需要 SEO 支持
  • 拥有相应的应用管理机制。

采用 iframe 时,我们同时需要考虑:

  • 设计管理应用机制:
    在什么情况下,我们会去加载、卸载这些应用;在这个过程中,采用怎样的动画过渡,让用户看起来更加自然。
  • 设计应用通讯机制:
    直接在每个应用中创建 postMessage 事件并监听,并不是一个友好的事情。其本身对于应用的侵入性太强,因此通过 iframeEl.contentWindow 去获取 iFrame 元素的 Window 对象是一个更简化的做法。随后,就需要定义一套通讯规范:事件名采用什么格式、什么时候开始监听事件等等。

3、自制框架兼容应用

在页面合适的地方引入或者创建 DOM,用户操作时,加载对应的应用(触发应用的启动),并能卸载应用。这种方式的上手难度相对比较高,但是后期订制及可维护性比较方便。在不考虑每次加载应用带来的用户体验问题,其唯一存在的风险可能是:第三方库不兼容。

4、组合式集成:将应用微件化

通过软件工程的方式在构建前、构建时、构建后等步骤中,对应用进行一步的拆分,并重新组合。其前提是必须使用同一个框架,并且要制定规范,用来统一依赖、规范应用的组件及路由、共享 tong y 哦功能代码等。
这种方式常见的实现:

  • 独立构建组件和应用,生成 chunk 文件,构建后再归类生成的 chunk 文件。(这种方式更类似于微服务,但是成本更高)
  • 开发时独立开发组件或应用,集成时合并组件和应用,最后生成单体的应用。
  • 在运行时,加载应用的 Runtime,随后加载对应的应用代码和模板。

5、纯 Web Components 技术构建

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

它主要由四项技术组件:

  • Custom elements,允许开发者创建自定义的元素。
  • Shadow DOM,即影子 DOM,通常是将 Shadow DOM 附加到主文档 DOM 中,并可以控制其关联的功能。而这个 Shadow DOM 则是不能直接用其它主文档 DOM 来控制的。
  • HTML templates,即
  • HTML Imports,用于引入自定义组件。

Web Components 中的 ShadowDOM 更像是新一代的前端 DOM 容器。而遗憾的是并不是所有的浏览器,都可以完全支持 Web Components。

6、结合 Web Components 构建

Web Components 离现在的我们太远,但是我们可以开始采用这种方式来构建我们的应用。
集成在现有框架中的 Web Components,类似于 Stencil 的形式,将组件直接构建成 Web Components 形式的组件。 Stencil 仍然也只是支持最近的一些浏览器,比如:Chrome、Safari、Firefox、Edge 和 IE11。

参考文章: