2023-02-09 23:38:45 +08:00

286 lines
14 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

---
title: 谈谈微前端
createTime: 2019/08/31 05:13:33
author: pengzhanbo
permalink: /article/vpqgx0t7/
---
微前端 是最近比较新兴的一个话题,它不具体指某个库某个框架,而是一个思想,一种概念,运用这种思想,
根据自身的需求,从而实现适用于自身的 微前端 。
<!-- more -->
> 本文根据最近我在公司内部举行的 微前端技术解决方案 分享而写。
> 提供的 微前端方案 也应用于公司内部的项目,并取得了良好的反馈,获得广泛好评。
> 本文不具体谈如何实现微前端,仅讲述微前端的概念,期望能够通过本文理解微前端。
## 前言
微前端 目前在行业内是一个新兴的思想。
诞生这个思想的背景是,在公司内部,常常会有一类项目,这类项目很大、很重,
涉及的业务内容多而杂,还涉及了跨部门共同维护,积累的庞大的技术债 等各种问题。
这类项目在维护成本上、部署成本上等,都会花费巨大的开销,前端开发人员对于维护这类项目,苦不堪言,
急需找到解决这类问题的方案。
基于这样的背景下,开始探讨 解决方案的可行性, 微前端 正是基于此 开始慢慢 出现在人们的视野中。
## 现状
### 发展历程
在 Web 的发展初期,还没有所谓的前端的概念,网页的内容也相对简单,大多仅涉及文字图片信息的展示和表单内容,
这些工作可能网站负责人自己就包办了。
然后微软推出了 **Ajax** 技术,引起了网页的技术变革,从此网站开始具备了动态交互性,
能够在网页发起请求动态获取服务器的内容这丰富了网页的可交互性网页的开发也从UI界面和表单交互进一步增加了
数据和逻辑的开发,前端也慢慢的被划分一个相对独立的职能。
而伴随着 nodejs 的出现,以及 angular 的出现,还包括 vue/react 等库,以及建立在 nodejs 上的生态,
包括grunt、gulp、webpack 等工具的诞生,前端进入了一个喷井式爆发的时期,也是我们所处的时期。前端越来越专业化,
包含的技术内容越来越丰富依托于nodejs 以及众多的技术框架等,向着工程化进一步的发展,前端项目也越来越大。
### 浮现的问题
你是否维护过一个可能有着四五年以上历史的项目?是否维护过一个糅杂了各种各样的库的项目?
是否维护过一个多个公司部门参与的跨团队联合开发的项目?
对于很多人来说,入职的某个公司,最怕被安排去维护一个这样的项目。因为每一次维护迭代,就如同开盲盒一样,
永远不知道有什么惊喜在等着自己。
对于这类项目,可能存在的问题包括:
- 跨部门,夸团队联合开发,如何沟通?如何协作?
- 业务线多,页面多,如何管理?
- 如何进行代码管理?
- 如何进行分支管理?
- 多部门进行迭代,如何把控版本?
- 存在发布冲突,如何解决?
- 如何进行测试?
- 如何管理公共代码?
- ...
可能改动某一行代码,都会带来意想不到的结果,种种问题的积累,技术债的、业务债的,使得项目越来越臃肿,越来越难以维护。
亟需寻找一种方案,能够解决这些问题。
### iframe嵌入
于是,在大多数时候,我们不得不去选择通过 iframe嵌入 的方式,先把臃肿的项目一点一点的拆开给回各个部门或者团队自行维护,
再提供一个 系统门户应用,用 iframe嵌入 的方式,加上维护一个菜单列表与其他项目入口链接的映射,来糅合成一个 网站应用。
![iframe嵌入](//assets.processon.com/chart_image/630f92445653bb0c5d1040ab.png)
通过 iframe嵌入在一定程度上满足了 各部门各团队各业务线 独立开发独立部署的需求,只需要提供对应的页面链接就可以接入到
整个系统中。但也存在着一些问题
**安全问题**
然而,我们知道, iframe是存在安全问题的如果攻击者使用 iframe访问一个 未知来源的链接,有可能被注入恶意脚本,从而盗取
系统的隐私信息,这需要我们去严格配置 SCP以及配置 sandbox尽可能的保证 iframe 的安全性。
**资源加载过多**
而由于仅需要提供链接就可以嵌入,那么对于各自的项目来说,灵活度就很高,各个项目可以随意的选择各种技术框架来实现自己的业务,
又或者即使使用了相同的技术框架,但各项目的资源相对独立,对于整个系统而言,需要加载的资源量会十分庞大,
从而导致了页面访问速度变慢,经常会出现页面部分区域白屏等待时间过长等,这也带来了体验问题。
**访问地图丢失**
由于 iframe 嵌入的站点,独享访问历史记录,与外部的历史记录是相互独立的,即通过浏览器的 前进/回退 按钮来访问历史记录并
不能得到预期的结果,这在一定程度上影响了用户的操作。
## 寻找解决方案
有没有什么其他的方案,来进一步解决这些问题呢?
首先我们明确的知道,单项目管理目前来看不是一个可行的方案,需要在多项目管理上寻求解决方案。
### 多项目公共业务组件
对于多数的大型系统项目而言,大体上都采用以下布局结构:
![微前端-2](//assets.processon.com/chart_image/6311781d079129320755bec5.png)
主体布局结构包括:
- 导航栏 (可选)
- 左侧菜单栏 (可选)
- 内容区域
- 页脚 (可选)
在这种布局结构下,各个业务板块通常通过 导航栏 或者 左侧菜单栏 进行 导航切换,在 内容区域 展示 业务板块。
即,总体上看,对于业务来说,导航栏、左侧菜单栏、页脚,这几个都是可能 共同的,主要的不同点在于 内容区域。
那么我们可以把 共同的部分,如 导航栏、左侧菜单栏、页脚 这几个部分,抽离为公共业务组件,
对于每个业务板块,独立为单独的项目进行开发维护,并在项目中引入这些 公共业务组件。
公共业务组件其中主要负责之一是提供 链接到各个业务板块。
![微前端-3](//assets.processon.com/chart_image/631301e65653bb40f833b613.png)
这种方案具有如下的优点:
- 整体系统根据业务板块拆分为了多个项目;
- 实现了项目的独立性,可独立进行开发、发布;
- 通过在主项目重载渲染,实现类似 **SPA应用** 的访问体验;
但同样也带来了新的问题:
- 公共业务组件
- 公共业务组件 如何进行管理;
- 公共业务组件 如何在业务板块项目之间保持同步更新;
以及没有解决的问题:
- 资源加载过多;
 各个业务板块项目重复加载公共业务组件,重复加载各种库资源。
- 项目无法实现统一管理;
### 主项目重载业务项目资源
在上一个方案中,公共业务组件的引入解决了一部分问题,也带来了一部分问题,如何把公共业务组件进行统一管理,并保持一致性?
我们回到 iframe方案在这个 iframe方案中有一个主项目用于管理这些 菜单栏、导航栏等。 同样的,可以借鉴这个思路,
也抽象一个主项目,用于管理这些 公共业务组件,然后寻找另一种方式来加载渲染其他的业务板块项目。
我们知道,业务板块的项目,也是通过链接去访问的,而每个链接都对应着一个 html 资源文件通过加载这个资源以及HTML内的 css资源、js资源等来渲染页面。那么我们可以通过解析这个 html资源然后将得到的 html内容、css文件、js文件在主项目中加载后渲染到特定的区域
那么就可以做到在主项目中加载业务板块项目。
![微前端-4](//assets.processon.com/chart_image/6314ea9cf346fb55d89d4e77.png)
在主项目中,实现一个 资源加载器与解析器,通过业务板块项目的访问链接,获取 html资源文件并解析 html 的内容,包括:
- `<head>` 标签中的 `<title>`, `<link>`, `<script>` 等;
- `<body>` 标签中的 html 内容,`<script>`
然后加载 解析得到的 CSS资源、JS资源将 html内容 插入到 特定的区域中,并进行渲染。
从而呈现完整的网页内容。
这种方案,进一步解决了如下的问题:
- 公共业务组件交由 主项目进行统一管理,直接避免了同步问题;
- 业务板块均在主项目中渲染,提高了用户体验;
然而,也引入了新的问题:
- 业务板块都运行在同一个环境中,多个板块之间切换,加载的资源容易对环境产生污染,
如污染了某个全局变量、polyfill相互污染等。
- 可能存在 加载资源跨域问题。
但是也拥有了如下的优点:
- 拆分项目,可独立开发和部署;
- 主项目统一管理 公共业务组件,更易于维护;
- 项目间的切换得到体验优化;
当方案思考到了这里,发现,主项目是通过 解析 **链接** 来加载业务板块项目,
**链接** 对于现代前端来说,更多的意义是可能是 **路由**。那么我们顺着这个思路,继续优化,
## 新的方案
说起路由,我们很容易想到,像如今的 `react`, `vue`, `angular` 等主流的库/框架, 通过 路由 来实现 `SPA` 应用,
或者说, 通过 **路由分发页面**
那么,我们可以进一步的扩展这个思路,是否可以通过 **路由分发应用**
### 路由
在前端的范畴中,路由指 随着浏览器的地址栏变化,而呈现不同的内容给用户。
通常使用 **hash** 或者 **history API** 实现前端路由。
``` js
// hash
`https://pengzhanbo.com/#route`
// history API
`https://pengzhanbo.com/route`
```
路由进一步细化,通过 `/` ,又可以 划分为 一级路由、二级路由、三级路由... 等多级路由。
在现代的前端框架如 `React` / `Vue` / `Angular` 等,均有通过 路由 实现 SPA应用 的技术方案。
而 SPA应用 就是 **路由分发页面** 。
### 路由分发应用
与 **路由分发页面** 类似,我们也可以通过 **路由分发应用** 。
类似于 主项目重载业务项目资源,通过 实现 路由与业务板块项目的映射关系,
在主项目中通过路由寻找业务板块项目,加载相关资源并渲染在相关区域。
### 主应用与子应用
从这里开始, 我们将 主项目 定位为 主应用, 将各个 业务板块项目 定义为 子应用。
在主应用中实现 子应用加载器,加载器通过 解析路由来获取加载对应的子应用。
**主应用:** 作为独立的项目,整个系统的入口应用,负责统一管理公共业务组件(如 菜单栏、导航栏、页脚等),负责实现子应用加载器,负责实现渲染子应用的容器。
**子应用:** 作为独立的项目,系统的各个业务板块分别独立为单独的项目,单独开发维护与部署。
### 注册子应用
主应用需要通过路由发现子应用,需要建议起 路由与子应用的映射关系,所以需要有一套机制,用于向主应用注册子应用,
并关联相关资源文件等。
``` json
[
{
"AppName": "Sub Application",
"route": "/sub-app-route",
"resource": {
"js": [
"https://example.com/index.js"
],
"css": [
"https://example.com/style.css"
]
}
},
// more ...
]
```
## 微前端
通过将整个系统拆分为一个个小型的项目,小型项目即为子应用,通过细化,将整个系统细化为一个个微小的应用,
从而实现了降低整个系统的复杂性。
一个小型项目可以是某个部门的业务项目,可以是某个业务项目中的某个板块,也可以是一个单独的页面。
这也是为什么将新的方案称之为 **微前端**
微前端是指,通过将一个系统,拆分为一个个 微小的独立的子应用,通过主应用聚合为一个完整的系统。
微前端是一个与框架无强关联的概念,可以类比于服务端的微服务,是浏览器端的微服务。
![](//assets.processon.com/chart_image/6318b7297d9c0833ec81b2cd.png)
由于子应用是独立的,理论上是支持使用任意的技术框架进行开发,无论是使用 jQuery开发还是使用 Vue、React、Angular等。
然而在实际中,对于整个系统而言,技术框架的选择应该保持统一性,以保证整个系统的可维护性。
## 微前端的局限性
微前端的技术方案,更适合于 中大型的项目中使用,而对于小型项目而言,由于本身体量不大,没有必要对整个系统进行进一步的细化,
细化反而增加了项目的复杂度。
而对于中大型项目而言,如果是老系统迁移到微前端的方案,那么不可避免的,还需考虑新旧方案之间的迁移过渡的方案以及规划。
如果老系统中存在应用了多种不同的技术框架,或者同框架的不同版本,由于主应用、所有子应用均运行在同一个浏览器环境中,
不可避免的存在环境污染问题如全局环境污染polyfill对于原生对象的多次污染等还包括CSS的命名污染等问题。
所以如何保证子应用的正确渲染,如何避免环境污染问题,也是亟需解决的问题。
## 微前端的未来
目前来看,微前端主要分为 主应用 和 子应用,在 **微** 上,也仅细化到页面级别,然而,对于微前端而已,还可以进一步的细化,
如,细化到页面的某一个区块,细化到某一个逻辑功能,均可以通过微前端的技术方案,共享到主应用以及子应用中使用。
整个系统愈加化整为零,将复杂度进一步的拆解,细化,令每一块功能、逻辑等都能使用通过某个项目提供,甚至独立的项目进行维护和部署。
微前端是一个与框架无关的概念,但在实现微前端时,如果允许多技术框架共存,所带来的问题的,反而比不使用微前端时所存在的问题,要更难以预料,难以解决。在实际的场景中,最好还是限定在统一的技术框架范畴中,避免由于共存不同的技术框架,而引入更为复杂的问题,
## 结语
微前端是一个相对新兴的技术概念,适用于一些前端场景,但最好是你已经考虑清楚了,微前端是解决你的场景问题的最好方案,否则,除非必要,
无需选择微前端方案。