一文带你进入微前端世界

更新日期: 2022-05-31阅读: 964标签: 微前端

什么是微前端

微前端(Micro-Frontends)是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。微前端(micro-frontends)术语在 2016 年在 TECHNOLOGY RADAR 中被提及。

微前端架构具备以下的特点:

  • 技术栈无关。主框架不限制接入应用的技术栈,微应用具备完全自主权
  • 独立开发、独立部署。微应用仓库独立,前后端可独立开发,部署完成后主框架自动完成同步更新
  • 增量升级。在面对各种复杂场景时,我们通常很难对一个已经存在的系统做全量的技术栈升级或重构,而微前端是一种非常好的实施渐进式重构的手段和策略
  • 独立运行时。每个微应用之间状态隔离,运行时状态不共享

微前端解决了什么问题?

微前端架构旨在解决单体应用在一个相对长的时间跨度下,由于参与的人员、团队的增多、变迁,从一个普通应用演变成一个巨石应用(Frontend Monolith)后,随之而来的应用不可维护的问题。比如:

  • 原本一个团队管理的项目,后面多个团队进行管理
  • 随着项目的体积变大,编译的速度变长,研发效率降低
  • 项目变大,系统的复杂度也会随之变大,可维护性越来越低,重构成本越来越大
  • ...

通过微前端拆分成一个容器应用和多个子应用之后,各个应用能够独立部署,相互之间隔离,从而做到:

  • 研发效率提升:多业务线并行开发,团队自治,独立迭代
  • 运维风险降级:变更范围缩小
  • 技术选择增多:各个应用可以选择更加适合自身的技术栈
  • 重构风险降低:低风险局部替换,渐进式完成大规模重构
  • ...

微前端实现方案

对比Nginx路由转发

通过Nginx配置反向代理来实现不同路径映射到不同应用,例如www.abc.com/app1对应app1,www.abc.com/app2对应app2,这种方案本身并不属于前端层面的改造,更多的是运维的配置。

优点:

  1. 简单,快速,易配置

缺点:

  1. 在切换应用时会触发浏览器刷新,影响体验

iframe嵌套

父应用单独是一个页面,每个子应用嵌套一个iframe,父子通信可采用postMessage或者contentWindow方式。

优点:

  • 实现简单,子应用之间自带沙箱,天然隔离,互不影响

缺点:

  • url 不同步。浏览器刷新 iframe url 状态丢失、后退前进按钮无法使用。
  • UI 不同步,dom 结构不共享。想象一下屏幕右下角 1/4 的 iframe 里来一个带遮罩层的弹框,同时我们要求这个弹框要浏览器居中显示,还要浏览器 resize 时自动居中..
  • 全局上下文完全隔离,内存变量不共享。iframe 内外系统的通信、数据同步等需求,主应用的 cookie 要透传到根域名都不同的子应用中实现免登效果。
  • 慢。每次子应用进入都是一次浏览器上下文重建、资源重新加载的过程。

Web Components

每个子应用需要采用纯Web Components技术编写组件,是一套全新的开发模式

优点:

  • 每个子应用拥有独立的script和css,也可单独部署

缺点:

  • 对于历史系统改造成本高,子应用通信较为复杂易踩坑

webpack5 的 Module Federation

使用 Module Federation,我们可以在一个应用中动态加载并执行另一个应用的代码,且与技术栈无关,并且能够共享模块,从而减小编译时间以及降低包体积。

优点:

  • 能够共享模块,减小编译时间以及降低包体积

缺点:

  • 需要升级 webpack5,构建工具受限

组合式应用路由分发

每个子应用独立构建和部署,运行时由父应用来进行路由管理,应用加载,启动,卸载,以及通信机制。

优点:

  • 纯前端改造,体验良好,可无感知切换,子应用相互隔离

缺点:

  • 需要设计和开发,由于父子应用处于同一页面运行,需要解决子应用的样式冲突,变量对象污染,通信机制等技术点

组合式应用路由分发是目前业内普遍使用的一种方案,并且能够满足大部分需求,接下来我们详细来看看这种实现方式。

组合式应用路由分发的微前端实现思路

该方案使用的是基座模式,通过一个主应用(基座应用-Main APP),来管理其它应用(子应用-MicroAPP)。基座应用大多数是一个前端 SPA 项目,主要负责应用注册,路由映射,消息下发等,而微应用是独立前端项目,这些项目不限于采用 reactvueangular 或者 jquery 开发,每个微应用注册到基座应用中,由基座进行管理,但是如果脱离基座也是可以单独访问。

当整个微前端框架运行之后,给用户的体验就是类似下图所示:

简单描述下就是基座应用中有一些菜单项,点击每个菜单项可以展示对应的微应用,这些应用的切换是纯前端无感知的

上面的实现过程主要如下:

  • 获取注册表和进行初始化,这些都是在基座应用中进行的。
  • 路由分发。在浏览器路径发生变化后,基座应用会监听 hashchange 或者 popstate 事件,从而获取到路由切换的时机。通过查询注册信息可以获取到转发到那个微应用,经过一些逻辑处理后,采用修改hash方法或者pushState方法来路由信息推送给微应用的路由,微应用可以是手动监听hashchange或者popstate事件接收,或者采用React-router,vue-router接管路由,后面的逻辑就由微应用自己控制。
  • 远程拉取资源,加载应用。这里一般有通过 JavaScript Entry 或者 html Entry 作为渲染入口。

注意:子应用也可以将包打成多个,然后利用 webpack 的 webpack-manifest-plugin 插件打包出 manifest.json

文件,生成一份资源清单,然后主应用的 loadApp 远程读取每个子应用的清单文件,依次加载文件里面的资源;不过该方案也没办法享受子应用的按需加载能力。

  • HTML Entry。则更加灵活,直接将子应用打出来 HTML 作为入口,主框架可以通过 fetch html 的方式获取子应用的静态资源,同时将 HTML document 作为子节点塞到主框架的容器中。这样不仅可以极大的减少主应用的接入成本,子应用的开发方式及打包方式基本上也不需要调整,而且可以天然的解决子应用之间样式隔离的问题(后面提到)。这种方案可以通过 。
  • JavaScript Entry。通常是子应用将资源打成一个 entry script。但这个方案的限制也颇多,如要求子应用的所有资源打包到一个 js bundle 里,包括 css、图片等资源。除了打出来的包可能体积庞大之外的问题之外,资源的并行加载等特性也无法利用上。

微前端的应用隔离

CSS 隔离

当主应用和微应用同屏渲染时,就可能会有一些样式会相互污染,可以采取以下两种方案:

  • CSS Module
  • 命名空间,通过 webpack 的 postcss 插件,在打包时添加特定的前缀,即各个子应用使用特定的前缀来命名 class。但对于一些插入到 body 中的样式,比如 element UI 的 Popover 弹出框,这种就特殊处理。

而对于微应用与微应用之间的CSS隔离就非常简单,在每次应用加载时,将该应用所有的link和style 内容进行标记。在应用卸载后,同步卸载页面上对应的link和style即可。

JavaScript 隔离

每当微应用的 JavaScript 被加载并运行时,它的核心实际上是对全局对象 Window 的修改以及一些全局事件的改变,例如 jQuery 这个 js 运行后,会在 Window 上挂载一个 window.$ 对象,对于其他库 React,Vue 也不例外。为此,需要在加载和卸载每个微应用的同时,尽可能消除这种冲突和影响,最普遍的做法是采用沙箱机制(SandBox)。

沙箱机制的核心是让局部的 JavaScript 运行时,对外部对象的访问和修改处在可控的范围内,即无论内部怎么运行,都不会影响外部的对象。通常在 Node.js 端可以采用 vm 模块,而对于浏览器,则需要结合 with 关键字和 window.Proxy 对象来实现浏览器端的沙箱。

微前端的消息通信

微前端通常不会限制应用采用的框架,如何在不同的应用,框架之间进行通信是一个需要仔细考量的决定。应用间通信有很多种方式,当然,要让多个分离的微应用之间要做到通信,本质上仍离不开中间媒介或者说全局对象。

自定义事件

通过事件进行通信应该是最简单、通用的方案了。

// 监听事件
window.addEventListener('message', (event) => {
  // 处理事件
});

// 触发事件
window.dispatchEvent(new CustomEvent('message', { detail: input.value }))

发布-订阅

消息订阅(pub/sub)模式的通信机制是非常适用的,在基座应用中会定义事件中心Event,每个微应用分别来注册事件,当被触发事件时再有事件中心统一分发,这就构成了基本的通信机制。

import { Observable } from 'windowed-observable';

const observable = new Observable('konoha');
observable.subscribe((ninja) => {
  console.log(ninja)
})

observable.publish('Uchiha Shisui');

Web Workers

通过 Web Workers 进行事件通信。

import Worky from 'worky'
const worker = new Worky("some-worker.js");

worker.on("eventName", function (some, data) {
  // 处理
});
worker.emit("someEvent", and, some, data);

共享状态

主应用创建 state store,共享给子应用使用,适用于主、子应用技术栈相同的场景。

总结

微前端是一种将单个巨型应用转变为多个微型应用聚合为一的应用,能够解决“巨石应用”的维护性问题。实现微前端的方式有很多种,每种方案都需要考虑应用隔离和应用通信的问题,目前较为普遍使用的是组合式路由分发的方式。

来源: 前端杂货铺

链接: https://fly63.com/article/detial/11629

实施微前端的六种方式

微前端架构是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,即将 Web 应用由单一的单体应用转变为多个小型前端应用聚合为一的应用。由此带来的变化是,这些前端应用可以独立运行、独立开发、独立部署。

基于 React & TS & Webpack 的微前端应用模板

在 Web 开发导论/微前端与大前端一文中,笔者简述了微服务与微前端的设计理念以及微前端的潜在可行方案。微服务与微前端,都是希望将某个单一的单体应用,转化为多个可以独立运行、独立开发、独立部署、独立维护的服务或者应用的聚合

微前端的好处和缺陷

“微前端架构”是一种使用微服务模式构建前端应用的方法。微前端的理念是将你的前端拆分为一组可独立部署、松散耦合的应用。然后将这些应用组装在一起以创建面向用户的单个应用程序

微前端如何落地?

在过去的几星期里,随着 Martin Fowler 博客上,那篇 Cam Jackson 写的微前端的文章发布,到处都在讨论 Microfrontend。作为一个微前端 “专家”,我也分享一下:如何去落地微前端

微前端究竟好在哪?

微前端架构是一种设计方法,其中,前端应用被分解为多个松散而协同工作的半独立“微应用”。微前端的思想来源于微服务,其名称也遵循了微服务的命名方式。那么,微前端的优势和好处在哪?让我们一起通过这篇微前端教程来了解

从微前端聊聊架构演进

就目前来看,微前端已经不是一个新话题了。随着越来越多的公司的深入研究,当前也提出了很多的解决方案。不过本文不是想要来介绍微前端,更想介绍项目如何一步步到达微前端架构的实际需求

实现微前端需要了解的 Vue Genesis 渲染器

核心的就是渲染器,它提供了最基础渲染能力,有了它,你可以实现微前端、微服务、远程组件、首屏渲染,甚至可以和 React、EJS 等配合使用。

微前端开发常见问题汇总

微前端开发常见问题汇总,前端应用可以独立运行、独立开发、独立部署。微前端不是单纯的前端框架或者工具而是一套架构体系。其在开发中会有各种问题,今天小编整理了一下分享给大家!

用Single-spa 创建基于React和Vue的微前端

Single SPA 是一个用于前端微服务的 javascript 框架。它使你可以在单页应用中使用多个框架,这样就可以按功能拆分代码,并 能使 Angular、React、Vue.js 程序一起运行

5分钟带你了解微前端

不同于单纯的前端框架/工具,微前端是一套架构体系,这个概念最早在2016年底由 ThoughtWorks 提出。 微前端是一种类似于微服务的架构,它将微服务的理念应用于浏览器端,将 Web 应用从整个的「单体应用」转变为多个小型前端应用的「聚合体」。

点击更多...

内容以共享、参考、研究为目的,不存在任何商业目的。其版权属原作者所有,如有侵权或违规,请与小编联系!情况属实本人将予以删除!