导读:如果盘点2019年最火的前端技术,那么微前端肯定占有一席之地。但是大部分人对于微前端这个架构新贵的了解还是处于懵懵懂懂的状态,本文将会详细介绍微前端的前生今世,带大家了解微前端架构是如何一步步从实际需求中演化而来,以及小桔车服基于微前端所提炼的一套中后台体系建设实践。
1 . 什么是微前端 微前端这个概念最初是对应于微服务这个概念提出的,微服务的核心思想就是将一个大的单体应用基于业务能力拆分为一组小的服务,每个服务都是独立的进程且能独立部署,无需统一的技术栈进行集中化管理,只需要进行轻量级的通信就可以完成业务诉求。微前端就是这样一种类似于微服务的架构模式,它将微服务的核心思想应用于浏览器端,即将单个复杂(大规模)的前端应用转换成多个小型前端应用,每个小型前端应用都与技术栈无关,可以独立开发、独立部署,当然拆分还需要一套成熟的通信机制串联起所有的应用,既能保证应用自治又能保证应用联系,以更好的协同度共同提升开发效率。 总结来说,微前端就是在前端一体化的大背景下,利用技术手段达到业务层应用聚合、技术层应用自治的工程架构方案,实现一个功能丰富且强大的前端应用。 2. 为什么需要微前端 是不是还是感觉有些朦朦胧胧,没关系,基于任何技术都需要依托于业务的原则,我们举一个浅显易懂的例子来帮助你理解一下前端为什么需要微前端架构: 在很多年前,小红和小兰决定创业,开一家网上商城,两个人一拍即合,快速设计出原型1.0版本,使用最原始的Jquery以及Html产出了一套面向用户展现的购物网站以及面向运营展现的管理后台: 为了方便理解,我们先不管前台的购物系统,只专注后台管理系统,因为项目前期只需要满足最基本的购物需求,所以当时所有的管理需求都集中在一个管理系统,代码收拢在一个仓库,具体架构如下: 小红和小兰迅速将1.0版本的网上商城推向市场,由于抢占了先机,大家很喜欢这种足不出门就可以购物的感觉,两人迅速赚到了一笔钱。 后来随着业务越做越大,商品管理逐渐分成了精选商品管理和普通商品管理,库存管理分成了合作商库存和自营库存,订单管理和用户管理也愈发的庞大,成了这个样子: 可以明显看出,随着业务的繁杂,每个模块的管理变的愈发臃肿,所有团队都在一个系统中维护不同的功能变的越来越麻烦,因此小红和小兰决定了上线2.0版本,将整个后台管理系统解耦拆分,由不同的团队维护不同的模块,A团队只负责商品管理这块,B团队只负责库存管理这块,其余模块也类似,这样大家各自部署,各自开发,互不干涉。 在2.0模式下,当业务越做越大,小红和小兰决定再成立营销和渠道两个团队,分别开展一些营销活动和渠道活动时,后台管理系统也需要增加一个渠道管理和营销管理模块,沿用上面解耦的逻辑,这俩团队再新建一个渠道系统和营销系统分别管理,大家各自产出自己的代码,各自维护各自的系统,扩展性大大增强。 同时随着前端技术的发展,Jquery以及Html的框架逐步落后, Angular、 React、Vue等单页面应用异军突起成为主力,各个团队都逐渐开始重构各自的系统,商品管理系统用了React框架,订单管理系统用了Vue框架等等,大家各自朝着自己感兴趣的框架上发力,各自为政的状态让大家都互不干扰,这样做就满足了最开始代码解耦的需求。 2.0模式的一切看起来都挺完美,但是真的很完美么,很快问题就出来了: 首先,苦了真正使用后台系统的运营同学和产品同学,这些同学想要使用后台系统的各种功能,日常操作就变成了不断的切换、切换、再切换系统。例如他们想要上架一个新的商品,需要先去商品管理系统配置一系列信息,再去库存管理系统查询相应的商品库存,最后再去营销系统配置这个商品的营销活动,整个过程需要不断的切换系统,运营效率大大降低。 然后,开发效率也大大降低,比如所有的系统都是基于同一套登录权限模块,但由于部署在不同的域名环境,每个系统都重复开发一遍,类似的网关模块、日志模块等等也是如此。而且不同系统之间存在大量的耦合功能,单独的代码环境并不能复用一些其他系统已有的代码,就会造成各种重复造轮子的行为。 有什么样的方式既可以让各个系统既能单独开发部署,各自选择技术栈,又能紧密联系聚合成一个系统供运营同学和产品同学使用呢,微前端的架构思想应运而生。 微前端的核心思想就是将一个完整的前端应用分解成一些更小的、微粒化的、能够独立开发测试部署的子应用,子应用之间通过弱通信机制互相联系,在用户看来仍然是内聚的单个产品。 那么整个电子商城的后台管理系统可以使用微前端的思想重新架构一番,也就是3.0模式: 这样,从产品维度来看,所有的系统都内聚在一个基系统中,用户只需要一次登录就可以不刷新的切换各个系统,所有功能都内聚在一起,有效提高了运营效率;从技术维度来看,各个系统并不需要进行技术栈的重构,依然可以沿用原有技术栈,每个团队依然各自维护各自的代码库,独立部署独立上线,且可以共用一些通用的能力如登录、鉴权、打点、日志分析等,即保证了遗留系统的迁移,又聚合了前端应用,完美解决应用臃肿情况下如何各自治理的问题。 相信通过上面例子,在一个虚拟电子商务后台系统架构的逐渐演化中,你应该了解了前端为什么需要微前端架构,总结来说,微前端具备下面优势:这是最古老的微前端技术实现方式之一,也是最容易的实现方式,通过HTTP的反向代理功能,经过路由判断将请求转发到响应的服务上去,优点就是几乎不需要做任何改造,配置一下nginx服务即可,缺点也很明显,完全没有性能优化,切换系统仍需刷新页面重新加载资源文件,只是从表层将不同应用拼凑到一起。
▍iframe容器这是最古老的微前端技术实现方式之二,虽然简单但是确实有效,iframe一直是浏览器规范之一,除了某些化石级别的版本,几乎所有的浏览器都可以完全兼容。Iframe的页面与父页面分开,完全不受父页面css或者全局的javascript 影响,在一定程度上类似于“沙箱隔离”,但一个系统如果加载过多的iframe体验会很不友好,重复加载相同的依赖,影响网页加载速度。
▍微件式服务 微件化是指某个应用由开发人员提前将完整的、闭环的所有功能提前编译好,其他应用可以直接嵌入到网页中而不需要做任何的修改或者编译就可以直接运行展示。早期很多应用的引入都是这样做的,将本身应用封装成sdk包,使用者远程加载javascipt代码就能生成对应的组件嵌入到页面,后续随着npm的流行,逐渐发展成将应用以NPM包的形式发布源码,这样做的优势是发布灵活单独部署打包,缺点就是如果引入多个应用微件,可能存在互相干扰的问题,且应用间通信困难,对遗留应用需要做过多改造。 ▍Web ComponentsWeb Components是一个Web组件标准,它提供了浏览器底层的支持,不依赖各种框架的支持和webpack的编译,让人们也可以使用组件。Web Components通过一种标准化的非侵入的方式封装一个组件,每个组件能组织好它自身的HTML、CSS、JavaScript,并且不会干扰页面上的其他代码。使用方式与frame比较类似,组件拥有自己独立的 Scripts 和 Styles,以及对应的用于单独部署组件的域名,内部资源高内聚,作用域独立,加载由自身控制。看上去Web Components确实是一种比较好的微前端架构选型,但遗憾的是目前浏览器的支持程度尚不完善,在Safari、ie和火狐上支持并不理想,如果不考虑多浏览器的兼容,Web Components是一个不错的选择。
▍自制框架的微应用式服务微应用式服务是指系统在开始都是以单一微小应用的形式存在,只有当运行时才由系统框架将这些应用加载合并,组合成一个完整系统。无论是基于虚拟树的react和vue框架,还是基于Web Components的Angular框架,所有框架的原型都离不开在html里加载元素,那么,我们只需要提前将单个系统打包编译成一个微应用,在页面合适的地方引入或者创建 DOM,这样当用户操作时触发应用的启动,并能在用户切换时卸载应用,所以这个微应用式服务的核心在于加载器的设计,既能实时加载切换不同应用,又能有效隔离应用防止互相干扰。Single-SPA是现在较为成熟的一个开源框架,可以实现在一个页面将多个不同的框架整合,甚至在切换的时候都不需要刷新页面,已支持 React、Vue、Angular 1、Angular 2、Ember 等等,如果想要简单的将工程微应用化,可以考虑使用这个框架。
当然,没有银弹可言,微前端并不是万金油,无论是哪一种实现方式,我们在考虑采用微前端架构之前,除了考虑它带来的好处,还要考量存在的大量风险和技术挑战,例如:
使用之后如何区分开发环境和线上环境
registerApplication
方法注册微应用,支持传入异步函数
loadApp
(返回 Promise 即可)及非函数类型值。如果是非函数类型,它会主动转换,在钩子返回前后及返回的钩子做了一些功能建设:
beforeUnmount
、 afterUnmount
、 beforeMount
、 afterMount
、 beforeLoad
钩子,方便在应用mount及load前后做一些处理工作。template
和 execScripts
,用来执行 entry.js 获取钩子的方法。execScripts
获取 entry.js 的钩子函数,最后 loadApp
返回加工后的钩子函数。应用的预加载方案我们之前讨论了不少时间,考虑到以后管理的微应用规模及性能影响,我们决定采用预加载配置方案。需要手动配置哪些应用需要提前加载静态资源,主要我们来详细说说背后的处理及思考:
single-spa:first-mount
。因此,我们监听此事件,当第一个微应用 mount 后,我们就可以开始预加载任务了。 window.requestIdleCallback
API 在浏览器空闲时间预加载应用资源, 在 mobile 设备和弱网环境下,我们不会开启预加载任务。在不支持 window.requestIdleCallback
API 的浏览器里,我们使用 setTimeout
来模拟。▍样式隔离
劫持 HTMLHeadElement.prototype.appendChild 方法,接管 appendChild,在应用 mount、unmount 时做样式快照生成与恢复操作。后续考虑使用 shadow dom 方案做样式隔离,更彻底安全。
▍资源缓存 本地缓存资源,能有效减少资源请求加载的时间,加快应用渲染,减少页面空白时间。对比过浏览支持的各种本地数据存储方案,最终选择 IndexedDB 来做存储静态资源解决方案,为什么选择它,这里就不做过多赘述了。详细处理有以下几点:cacheAssets
、 getCacheAssets
、 clearExpiredAssets
如果郭德纲是个互联网人
外国网红靠财富密码年入百万!
加班吧!后浪
写给小白的入门级Java语法!