微前端之一 • 什么是微前端?

随着前端的业务逻辑日益复杂,工程代码越来越庞大臃肿,导致开发效率低、版本发布困难、技术栈难升级等问题。前些年微前端概念的提出,正是为了解决这些疼点,目前在行业内得到了比较普遍的推广。

Airwallex(我的雇主)的前端应用在2020年遇到了这个瓶颈,当时面向客户的前端产品代码全部存放在一个 repository 里面,随着业务的快速扩张,海内外的前端工程师们全天候向它提交代码,很容易出现冲突,PR和版本发布均需要多位同事的 approve,加上时差的问题导致流程变得很长。

另一个头疼的问题是,项目最初使用的是 Angular 框架加上 Flow (静态类型解决方案),后来大家认为 React + TypeScript 的方案更佳,所以新页面就改用它们,老代码怎么办呢?大多是没人管的状态,特别是那些已经离职员工做的页面,所以在一段时间里这个 repository 同时存在这四个两两互斥的库,开发体验很糟糕。

痛定思痛,2020年前端团队一致决定将项目拆分,到2022年上半年,历经1年多的时间,终于整体完成了向微前端架构的转型。我将用几篇文章来介绍微前端的本质和应用,以及将我参与转型过程中的所见所得记录下来。

什么是微前端?

微前端是一种支持多个团队通过独立发布功能的方式来共同构建 web 应用的技术。

它有以下核心优点:

  1. 技术栈无关。 主框架不限制接入应用的技术栈,子应用具备完全自主权。

  2. 独立开发、独立部署。 子应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新 。

  3. 独立运行时。 每个子应用之间状态隔离,运行时状态不共享。

微前端概念发展的几个重要节点

  1. 2016年,Thought Works 公司在他们网站的技术雷达板块发表了微前端 https://www.thoughtworks.com/radar/techniques/micro-frontends 的概念,借鉴了微服务的架构理念,核心在于将一个庞大的前端应用拆分成多个独立灵活的小型应用。

  2. 2017年,Thought Works 公司推荐 Singla SPA 框架作为微前端的实现 https://www.thoughtworks.com/en-in/radar/languages-and-frameworks/single-spa

  3. 2019年,Cam Jackson 在 martinfowler 网站发表长文介绍微前端架构 https://martinfowler.com/articles/micro-frontends.html

  4. 2020年4月,Webpack 5 发布 module federation 功能, 为微前端的实现再提供一种方案。

  5. 2021年4月,Thought Works 公司开始推荐 module federation 作为微前端的实现 https://www.thoughtworks.com/radar/languages-and-frameworks/webpack-5-module-federation

实现微前端的方案

服务端集成

Nginx 路由转发。使用 Nginx 反向代理将不同的 URL 映射到不同的前端应用中去。优点是实现简单,应用之间完全隔离,前端几乎不用做任何额外配置。缺点是切换URL会触发浏览器刷新,出现白屏影响用户体验。

构建时集成

Npm package。将每个子应用作为一个 npm package,父应用匹配路由渲染不同的 package。这种方法虽然可以实现 micro front end ,但是缺点太多,比如不能实现独立发版,使用 npm link 开发体验比较差,强烈不建议这个方法。

运行时集成

Iframe。每个子应用作为iframe嵌套在父应用的页面里面。优点是实现简单,天生具备沙盒机制。缺点是父子页面通信不方便;子应用的弹窗无法覆盖到父应用;URL history 存在缺陷,刷新会回到首页。

JavaScript。这是一个很灵活的方法,每个子应用都使用

<div id="root"></div>

<script type="text/javascript">
  // 这些元素是由上面的 script 所定义
  const webComponentsByRoute = {
    '/a': 'micro-frontend-a',
    '/b': 'micro-frontend-b',
    '/c': 'micro-frontend-c',
  };
  // 在确定了子应用元素类型后
  // 现在创建一个它的实例,并将其附加到 DOM 上
  const webComponentType = webComponentsByRoute[window.location.pathname];
  const root = document.getElementById('root');
  const webComponent = document.createElement(webComponentType);
  root.appendChild(webComponent);
`

父应用通过路由匹配到指定的子应用,调用子应用的生命周期函数,然后子应用渲染 DOM 并挂载到元素上去。

可以看到无论哪种方法实现微前端,都不需要使用新的技术,所以微前端其实是一种架构风格,团队按照这种约定的风格开发,就可以将原来臃肿的巨应用改造成若干个轻装上阵的小应用。

下一章将会介绍目前流行的几个框架,以及微前端在使用中的一些特点。

posted @ 2022-09-23 10:52  WinjayYu  阅读(405)  评论(0编辑  收藏  举报