探索微前端架构:多种实现方式与实践思考

在当今的前端开发领域,微前端架构正逐渐成为热门话题。它借鉴了微服务的理念,将原本庞大的单体前端应用拆解为多个小型前端应用,并能让它们协同工作,就如同一个完整的应用一样。今天,咱们就一起来深入探讨微前端架构的几种常见实现方式以及在实际应用中需要考虑的方方面面。

一、微前端架构概述

微前端架构的核心思想,就是把 Web 应用从单一的单体应用转变成多个小型前端应用聚合而成的形态。这些小型前端应用具备独立运行、独立开发以及独立部署的能力,而且还能共享组件,实现并行开发。这里所说的前端应用是基于前后端分离的单应用页面,这是谈论微前端的基础前提。

二、微前端的几种实现方式

(一)路由分发式微前端

通过路由将不同的业务分发到不同的、独立前端应用上,这就是路由分发式微前端。实现它通常可以借助 HTTP 服务器的反向代理,或者利用应用框架自带的路由功能。目前来看,这种方式是采用最多、最容易上手的 “微前端” 方案。

但它也有个小缺点,那就是看起来更像是把多个前端应用简单拼凑在一起,每次用户从 A 应用切换到 B 应用的时候,往往需要刷新一下页面,用户体验上稍打折扣。

给大家举个实际项目里的例子吧,之前在进行遗留系统重写的项目中,我们制定了这样的迁移计划:

1.先用静态网站生成动态生成首页。

2.接着使用 React 技术栈重构详情页。

3.最后替换搜索结果页。

整个系统不是一次性迁移完成的,每完成一个步骤就得上线相应功能,这时就用到了 Nginx 来进行路由分发啦。下面就是一个基于路由分发的 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://172.31.25.29/web/admin;
}
location /web/notifications {
proxy_pass http://172.31.25.27/web/notifications;
}
location / {
proxy_pass /;
}
}
}

在这个配置里,不同页面的请求就被精准地分发到了不同的服务器上呢。

这种路由分发式微前端适用于以下几种场景:

  • 不同技术栈之间差异比较大,难以兼容、迁移、改造的时候。

  • 项目不想花费大量时间在系统改造上。

  • 现有的系统在未来将会被取代。

  • 系统功能已经很完善,基本不会有新需求。

要是想在这种情况下提升用户体验,还可以考虑结合 iframe 的方式来解决。

(二)使用 iFrame 创建容器

iFrame 虽然是个很古老、看似普通的技术,但它一直都挺管用的。<iframe>元素可以将另一个 HTML 页面嵌入到当前页面中,相当于创建了一个全新的独立宿主环境,能让前端应用之间相互独立运行。

不过采用 iframe 也是有前提条件的,要是网站不需要 SEO 支持,并且拥有相应的应用管理机制,那它就是个不错的选择。比如说在做应用平台,需要集成第三方系统或者多个不同部门团队下的系统时,就很适用。

但使用 iframe 也不是光把它嵌入就完事,还得设计管理应用机制、应用通讯机制以及加载机制。比如说通讯机制,直接在每个应用里创建 postMessage 事件并监听不太友好,因为对应用的侵入性太强,更好的做法是通过 iframeEl.contentWindow 去获取 iFrame 元素的 Window 对象。定义一套通讯规范,如事件名采用什么格式、什么时候开始监听事件等等。

(三)自制框架兼容应用

现有的前端框架不管是基于 Web Components 的 Angular,还是基于 VirtualDOM 的 React 等,都离不开基本的 HTML 元素 DOM。那就是在页面合适的地方引入或者创建 DOM,然后在用户操作时,加载对应的应用(触发应用的启动),并且能卸载应用。

在前端开发领域,DOM 操作的复杂性不容小觑。创建 DOM 或许相对易于处理,然而移除 DOM 及其相关应用的监听事件却颇具挑战性,特别是在涉及多种技术栈的情况下,往往需要精心设计一套专用逻辑。例如 Single-SPA,尽管它能够处理包括 React、Angular、Vue 等多数框架的启动与卸载流程,但就生产环境而言,其仍存在局限性。此前,在依托 Single-SPA 并针对 Vue 框架开展微前端架构应用搭建的实践进程中,历经全面综合的考量与权衡,我最终选定了一款在网上开源且名为 Mooa 的框架。借其之力,得以更精准地契合项目的特定需求,为项目的顺利推进提供了有力支撑与保障。以更好地满足项目需求。

这种方式上手难度相对高些,不过后期订制和可维护性比较方便。当然它也有风险,比如可能会遇到第三方库不兼容的问题,而且对于流量大的 toC 应用来说,首次加载时会多出大量请求。

(四)组合式集成:将应用微件化

组合式集成就是通过软件工程的方式,在构建前、构建时、构建后等步骤中对应用进一步拆分,然后再重新组合。它其实满足了微前端的独立运行、独立开发、独立部署这三个要素,再配合前端框架的组件 Lazyload 功能(也就是需要的时候才加载对应的业务组件或应用),看上去就妥妥的是个微前端应用。

常见的组合式集成方式有这么几种:

1.独立构建组件和应用,生成 chunk 文件,构建后再归类生成的 chunk 文件。不过这种方式成本相对高些,有点类似微服务的做法。

2.开发时独立开发组件或应用,集成时合并组件和应用,最后生成单体的应用。

3.在运行时,加载应用的 Runtime,随后加载对应的应用代码和模板。

但是这种方式也有一些限制:

  • 必须使用同一个框架,不过对于多数团队来说,这倒不算啥大问题。

  • 规范要求特别严格!比如要统一依赖,统一依赖的版本,引入新依赖时得一个个加进去;还要规范应用的组件及路由,避免不同应用之间因为组件名称啥的发生冲突;构建过程也可能会复杂些,有的方案里要修改构建系统,有的则需要复杂的架构脚本;另外共享通用代码也是个得经常面对的问题,还得制定代码规范。

(五)纯 Web Components 技术构建

Web Components 是一套很特别的技术,它允许创建可重用的定制元素,功能封装在代码之外,还能在 Web 应用里使用它们。它主要由 Custom elements(能创建自定义元素)、Shadow DOM(影子 DOM,可附加到主文档 DOM 中并控制关联功能,且不能直接被主文档 DOM 控制)、HTML templates(用于编写不在页面中显示的标记模板)以及 HTML Imports(用于引入自定义组件)这四项技术组件构成。

使用的时候,每个组件可以通过 标签引入,像这样:

1
2
<link rel="import" href="components/di-li.html">
<link rel="import" href="components/d-header.html">

然后在各自的 HTML 文件里创建相应的组件元素,编写组件逻辑。不过,用纯 Web Components 构建前端应用也有难度:

  • 得重写现有的前端应用,把整个系统功能用 Web Components 来实现。

  • 上下游生态系统不完善,缺乏一些第三方控件支持,不像 jQuery 那样有很多现成好用的控件。

  • 系统架构复杂,应用拆分成一个个组件后,组件间的通讯就成了一个麻烦事。

  • 而且不是所有浏览器都能完全支持 Web Components ,这也是个缺陷。

(六)结合 Web Components 构建

Web Components 虽然目前离我们有点距离,但结合它来构建前端应用可是一种面向未来演进的架构,现在已经有框架在探索这种可能性。

目前有两种结合的方式:

1.使用 Web Components 构建独立于框架的组件,随后在对应的框架中引入这些组件。这是一种组件式的做法。

2.在 Web Components 中引入现有的框架,有点类似于 iframe 的形式,感觉就像是把 “遗留系统” 往未来架构上迁移。

比如说 Angular 支持的 createCustomElement 就能实现一个 Web Components 形式的组件

1
2
3
4
5
6
platformBrowser()   
.bootstrapModuleFactory(MyPopupModuleNgFactory)
.then(({injector}) => {
const MyPopupElement = createCustomElement(MyPopup, {injector});
customElements.define(‘my-popup’, MyPopupElement);
});

还有像 Stencil 这种形式,可以将组件直接构建成 Web Components 形式的组件,然后在 React 或者 Angular 等框架里直接引用,下面是在 React 中引用 Stencil 生成的 Web Components 的示例代码:

1
2
3
4
5
6
7
8
9
10
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
import registerServiceWorker from './registerServiceWorker';
import 'test-components/testcomponents';

ReactDOM.render(<App />, document.getElementById('root'));

registerServiceWorker();

不过要注意,像 Stencil 目前也只是支持部分较新的浏览器,比如 Chrome、Safari、Firefox、Edge 和 IE11 等。

三、复合型方案

在微前端的技术领域中,各类实现方式均呈现出其独特的优势与不足。事实上,我们完全具备这样的灵活性:挑选若干适宜的方式加以组合运用,进而形成复合型方案。依据不同项目的特定需求以及多样化的应用场景,巧妙且灵活地对这些方式进行搭配整合。如此一来,便极有可能构建出与实际状况契合度更高、功能更为强劲的微前端架构应用。

综上所述,微前端架构无疑为前端应用的开发与维护工作开辟了更为广阔的可能性空间,并提供了新颖的思路与方法。然而,无论采用何种方式,均要求我们基于具体的实际情况,深入细致地权衡其中的利弊得失,以审慎严谨的态度作出抉择。

作者

hujinbin

发布于

2025-01-05

更新于

2025-02-14

许可协议

评论

:D 一言句子获取中...