浅谈微前端在滴滴车服中的应用实践

简介: 云栖号资讯:【点击查看更多行业资讯】在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来! 导读:如果盘点2019年最火的前端技术,那么微前端肯定占有一席之地。但是大部分人对于微前端这个架构新贵的了解还是处于懵懵懂懂的状态,本文将会详细介绍微前端的前生今世,带大家了解微前端架构是如何一步步从实际需求中演化而来,以及小桔车服基于微前端所提炼的一套中后台体系建设实践。

云栖号资讯:【点击查看更多行业资讯
在这里您可以找到不同行业的第一手的上云资讯,还在等什么,快来!


导读:如果盘点2019年最火的前端技术,那么微前端肯定占有一席之地。但是大部分人对于微前端这个架构新贵的了解还是处于懵懵懂懂的状态,本文将会详细介绍微前端的前生今世,带大家了解微前端架构是如何一步步从实际需求中演化而来,以及小桔车服基于微前端所提炼的一套中后台体系建设实践。

1. 什么是微前端

微前端这个概念最初是对应于微服务这个概念提出的,微服务的核心思想就是将一个大的单体应用基于业务能力拆分为一组小的服务,每个服务都是独立的进程且能独立部署,无需统一的技术栈进行集中化管理,只需要进行轻量级的通信就可以完成业务诉求。微前端就是这样一种类似于微服务的架构模式,它将微服务的核心思想应用于浏览器端,即将单个复杂(大规模)的前端应用转换成多个小型前端应用,每个小型前端应用都与技术栈无关,可以独立开发、独立部署,当然拆分还需要一套成熟的通信机制串联起所有的应用,既能保证应用自治又能保证应用联系,以更好的协同度共同提升开发效率。

总结来说,微前端就是在前端一体化的大背景下,利用技术手段达到业务层应用聚合、技术层应用自治的工程架构方案,实现一个功能丰富且强大的前端应用。

2. 为什么需要微前端

是不是还是感觉有些朦朦胧胧,没关系,基于任何技术都需要依托于业务的原则,我们举一个浅显易懂的例子来帮助你理解一下前端为什么需要微前端架构:

在很多年前,小红和小兰决定创业,开一家网上商城,两个人一拍即合,快速设计出原型1.0版本,使用最原始的Jquery以及Html产出了一套面向用户展现的购物网站以及面向运营展现的管理后台:

1

为了方便理解,我们先不管前台的购物系统,只专注后台管理系统,因为项目前期只需要满足最基本的购物需求,所以当时所有的管理需求都集中在一个管理系统,代码收拢在一个仓库,具体架构如下:

2

小红和小兰迅速将1.0版本的网上商城推向市场,由于抢占了先机,大家很喜欢这种足不出门就可以购物的感觉,两人迅速赚到了一笔钱。

后来随着业务越做越大,商品管理逐渐分成了精选商品管理和普通商品管理,库存管理分成了合作商库存和自营库存,订单管理和用户管理也愈发的庞大,成了这个样子:

3

可以明显看出,随着业务的繁杂,每个模块的管理变的愈发臃肿,所有团队都在一个系统中维护不同的功能变的越来越麻烦,因此小红和小兰决定了上线2.0版本,将整个后台管理系统解耦拆分,由不同的团队维护不同的模块,A团队只负责商品管理这块,B团队只负责库存管理这块,其余模块也类似,这样大家各自部署,各自开发,互不干涉。

在2.0模式下,当业务越做越大,小红和小兰决定再成立营销和渠道两个团队,分别开展一些营销活动和渠道活动时,后台管理系统也需要增加一个渠道管理和营销管理模块,沿用上面解耦的逻辑,这俩团队再新建一个渠道系统和营销系统分别管理,大家各自产出自己的代码,各自维护各自的系统,扩展性大大增强。

同时随着前端技术的发展,Jquery以及Html的框架逐步落后, Angular、 React、Vue等单页面应用异军突起成为主力,各个团队都逐渐开始重构各自的系统,商品管理系统用了React框架,订单管理系统用了Vue框架等等,大家各自朝着自己感兴趣的框架上发力,各自为政的状态让大家都互不干扰,这样做就满足了最开始代码解耦的需求。

4

2.0模式的一切看起来都挺完美,但是真的很完美么,很快问题就出来了:

首先,苦了真正使用后台系统的运营同学和产品同学,这些同学想要使用后台系统的各种功能,日常操作就变成了不断的切换、切换、再切换系统。例如他们想要上架一个新的商品,需要先去商品管理系统配置一系列信息,再去库存管理系统查询相应的商品库存,最后再去营销系统配置这个商品的营销活动,整个过程需要不断的切换系统,运营效率大大降低。

然后,开发效率也大大降低,比如所有的系统都是基于同一套登录权限模块,但由于部署在不同的域名环境,每个系统都重复开发一遍,类似的网关模块、日志模块等等也是如此。而且不同系统之间存在大量的耦合功能,单独的代码环境并不能复用一些其他系统已有的代码,就会造成各种重复造轮子的行为。

有什么样的方式既可以让各个系统既能单独开发部署,各自选择技术栈,又能紧密联系聚合成一个系统供运营同学和产品同学使用呢,微前端的架构思想应运而生。

微前端的核心思想就是将一个完整的前端应用分解成一些更小的、微粒化的、能够独立开发测试部署的子应用,子应用之间通过弱通信机制互相联系,在用户看来仍然是内聚的单个产品。

那么整个电子商城的后台管理系统可以使用微前端的思想重新架构一番,也就是3.0模式:

5

这样,从产品维度来看,所有的系统都内聚在一个基系统中,用户只需要一次登录就可以不刷新的切换各个系统,所有功能都内聚在一起,有效提高了运营效率;从技术维度来看,各个系统并不需要进行技术栈的重构,依然可以沿用原有技术栈,每个团队依然各自维护各自的代码库,独立部署独立上线,且可以共用一些通用的能力如登录、鉴权、打点、日志分析等,即保证了遗留系统的迁移,又聚合了前端应用,完美解决应用臃肿情况下如何各自治理的问题。

相信通过上面例子,在一个虚拟电子商务后台系统架构的逐渐演化中,你应该了解了前端为什么需要微前端架构,总结来说,微前端具备下面优势:

  • 灵活聚合业务成系统:产品功能耦合,面向用户时多个不同的业务功能耦合成一个业务系统。
  • 兼容多技术栈:无论技术栈是Vue,还是React,或者Angular,都可以完美的在一个系统中运行。
  • 独立开发部署:子应用之间仓库独立,可以各自开发,部署后容器层会完成自动的同步更新。
  • 依赖资源复用:抽离不同应用中所依赖的公共资源,一次性加载多方复用,从而提升性能。

3. 微前端的技术选型

前面介绍了为什么需要微前端架构,那么接下来介绍一下技术选型,首先需要明确一个概念,微前端是一种架构思想,并不具体指某个技术,它是当前端业务在发展到一定规模之后,一种用来分解复杂度的架构模式,具体可以考虑以下几种选型:

路由式分发

这是最古老的微前端技术实现方式之一,也是最容易的实现方式,通过HTTP的反向代理功能,经过路由判断将请求转发到响应的服务上去,优点就是几乎不需要做任何改造,配置一下nginx服务即可,缺点也很明显,完全没有性能优化,切换系统仍需刷新页面重新加载资源文件,只是从表层将不同应用拼凑到一起。

iframe容器

这是最古老的微前端技术实现方式之二,虽然简单但是确实有效,iframe一直是浏览器规范之一,除了某些化石级别的版本,几乎所有的浏览器都可以完全兼容。Iframe的页面与父页面分开,完全不受父页面css或者全局的javascript 影响,在一定程度上类似于“沙箱隔离”,但一个系统如果加载过多的iframe体验会很不友好,重复加载相同的依赖,影响网页加载速度。

微件式服务

微件化是指某个应用由开发人员提前将完整的、闭环的所有功能提前编译好,其他应用可以直接嵌入到网页中而不需要做任何的修改或者编译就可以直接运行展示。早期很多应用的引入都是这样做的,将本身应用封装成sdk包,使用者远程加载javascipt代码就能生成对应的组件嵌入到页面,后续随着npm的流行,逐渐发展成将应用以NPM包的形式发布源码,这样做的优势是发布灵活单独部署打包,缺点就是如果引入多个应用微件,可能存在互相干扰的问题,且应用间通信困难,对遗留应用需要做过多改造。

Web Components

Web 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 等等,如果想要简单的将工程微应用化,可以考虑使用这个框架。

当然,没有银弹可言,微前端并不是万金油,无论是哪一种实现方式,我们在考虑采用微前端架构之前,除了考虑它带来的好处,还要考量存在的大量风险和技术挑战,例如:

  • 使用之后如何区分开发环境和线上环境
  • 如何隔离 JS,避免 CSS 冲突
  • 应用间共享公共资源的机制
  • 第三方模块重叠
  • 处理数据获取并考虑用户的初始化加载状态
  • 权限如何接入
  • 如何减少初始 Loading 时间
  • 如何有效测试

所以,微前端与微服务一样,要真正进入实践,还需要做好一系列的技术储备。目前小桔车服结合实际业务形态,构建出一套全链路的的产品接入平台,解决了上述微前端中的技术卡点,为中后台体系建设提供了一套通用的解决方案。

4. 微前端在车服中的实践

先介绍下背景,车服租车业务线有非常高的业务复杂度,并经历了多次商业模式探索整合优化。在业务不断探索调整的过程中,租车商用和MIS系统形成了多个系统分治的局面,同时林林总总的诸如采购、营销、企业车队等独立系统也都因业务侧的诉求纷纷进行了新建,且有更多的新的独立系统在业务侧筹划构建的路上,这极大加剧了开发和维护这些中后台系统的成本。

为此,团队决定以整合当前集团和车服环境内LASS能力为基点,提供一套微前端的架构体系,从页面资源到微应用再到系统级的搭建和管理的统一能力,即Midway平台。

6

如上,Midway平台以微前端架构思想为基础,采用基座模式,提供一个主应用即基座作为系统的统一入口,管理子应用的生命周期以及应用间的通信,提供核心部分的业务功能如用户登录、统一鉴权、导航菜单、路由管理等功能,并将对应的请求指向对应的服务,子应用则是具体负责子模块的业务实现,无视技术栈,由各个团队独立开发部署。

Midway 底层以single-spa为基础,隔离子应用间的样式与作用域,通过应用注册、钩子引用等方法,对接入的应用进行完整的生命周期控制,同时提供了应用通讯、公共资源加载、应用按需加载、应用预加载、日志监控等多种底层功能,下面捡重点介绍一下:

应用注册

Midway 调用 single-spa 的 registerApplication方法注册微应用,支持传入异步函数 loadApp(返回 Promise 即可)及非函数类型值。如果是非函数类型,它会主动转换,在钩子返回前后及返回的钩子做了一些功能建设:

  • 新增 beforeUnmount、 afterUnmount、 beforeMount、 afterMount、 beforeLoad 钩子,方便在应用mount及load前后做一些处理工作。
  • 根据单页面构架器(飞马)获取静态资源,为飞马页面entry.js添加钩子及相关配置等。
  • 根据应用注册时传入的entry类型,分析处理获取当前应用的 html、scripts、styles、id(飞马页面) 等信息。
  • 根据 entry 配置,异步拉取相关静态资源,最终返回用来渲染的模板代码 template和 execScripts,用来执行 entry.js 获取钩子的方法。
  • 为当前应用创建沙箱环境(proxy),并在沙箱环境下执行 execScripts获取 entry.js 的钩子函数,最后 loadApp返回加工后的钩子函数。

应用预加载

应用的预加载方案我们之前讨论了不少时间,考虑到以后管理的微应用规模及性能影响,我们决定采用预加载配置方案。需要手动配置哪些应用需要提前加载静态资源,主要我们来详细说说背后的处理及思考:

过滤已经 mount 过的应用,已经 mount 过的应用资源肯定加载过了,所以不需要预加载了。

注册的微应用中的第一个应用 mount 后,才会对配置的其它预加载应用做预加载,single-spa 做了一些自定义事件,其中有一个就是在第一个微应用 mount 后触发的事件 single-spa:first-mount。因此,我们监听此事件,当第一个微应用 mount 后,我们就可以开始预加载任务了。

利用 window.requestIdleCallback API 在浏览器空闲时间预加载应用资源, 在 mobile 设备和弱网环境下,我们不会开启预加载任务。在不支持 window.requestIdleCallbackAPI 的浏览器里,我们使用 setTimeout 来模拟。

JS沙箱

“沙箱”这个词听起来高大上,但是其实我们很早就已经接触过了。具体的概念及细节这里不再赘述,大家可以自行搜索。简单的说,当你要解析或执行不可信的 js 的时候,当你要隔离被执行代码的执行环境的时候,当你要对执行代码中可访问对象进行限制的时候,沙箱就派上用场了。

样式隔离

劫持 HTMLHeadElement.prototype.appendChild 方法,接管 appendChild,在应用 mount、unmount 时做样式快照生成与恢复操作。后续考虑使用 shadow dom 方案做样式隔离,更彻底安全。

资源缓存

本地缓存资源,能有效减少资源请求加载的时间,加快应用渲染,减少页面空白时间。对比过浏览支持的各种本地数据存储方案,最终选择 IndexedDB 来做存储静态资源解决方案,为什么选择它,这里就不做过多赘述了。详细处理有以下几点:

  • 使用 Dexie.js 来管理 IndexedDB 数据库
  • 设置缓存周期为 7 天,过期资源会被清理
  • 核心 API 有 cacheAssets、 getCacheAssets、 clearExpiredAssets

5. 总结

总结来说,Midway 整体设计理念以高内聚、低耦合为标准,秉承微前端的理念,实现了一套前台渲染、后台管理的平台化服务体系,用户不必再去关注应用聚合时的技术细节,开箱即可用。

目前,租车业务线的多系统分治的情况已开始使用Midway平台着手治理,各问题域模块也在相继按照微应用的粒度进行拆分以实现多系统间复用,同时新立系统也已有多个接入,极大降低了系统搭建的门槛和业务模块开发的重复性。我们未来围绕Midway微前端核心能力建设的同时,将持续把工程化、安全监控、性能体验、数据可视化等方向的能力逐步融入到Midway中,力求使该平台成为基于微前端的中后台系统一站式搭建解决方案的最佳实践。

【云栖号在线课堂】每天都有产品技术专家分享!
课程地址:https://yqh.aliyun.com/live

立即加入社群,与专家面对面,及时了解课程最新动态!
【云栖号在线课堂 社群】https://c.tb.cn/F3.Z8gvnK

原文发布时间:2020-05-28
本文作者:滴滴技术
本文来自:“掘金”,了解相关信息可以关注“掘金”

相关文章
|
15天前
|
前端开发 JavaScript 安全
前端性能调优:HTTP/2与HTTPS在Web加速中的应用
【10月更文挑战第27天】本文介绍了HTTP/2和HTTPS在前端性能调优中的应用。通过多路复用、服务器推送和头部压缩等特性,HTTP/2显著提升了Web性能。同时,HTTPS确保了数据传输的安全性。文章提供了示例代码,展示了如何使用Node.js创建一个HTTP/2服务器。
29 3
|
10天前
|
编解码 前端开发 UED
探索无界:前端开发中的响应式设计深度解析与实践####
【10月更文挑战第29天】 本文深入探讨了响应式设计的核心理念,即通过灵活的布局、媒体查询及弹性图片等技术手段,使网站能够在不同设备上提供一致且优质的用户体验。不同于传统摘要概述,本文将以一次具体项目实践为引,逐步剖析响应式设计的关键技术点,分享实战经验与避坑指南,旨在为前端开发者提供一套实用的响应式设计方法论。 ####
35 4
|
16天前
|
Rust 前端开发 JavaScript
前端性能革命:WebAssembly在高性能计算中的应用探索
【10月更文挑战第26天】随着Web应用功能的日益复杂,传统JavaScript解释执行模式逐渐成为性能瓶颈。WebAssembly(Wasm)应运而生,作为一种二进制代码格式,支持C/C++、Rust等语言编写的代码在浏览器中高效运行。Wasm不仅提升了应用的执行速度,还具备跨平台兼容性和安全性,显著改善了Web应用的响应速度和用户体验。
31 4
|
15天前
|
前端开发 数据管理 测试技术
前端自动化测试:Jest与Cypress的实战应用与最佳实践
【10月更文挑战第27天】本文介绍了前端自动化测试中Jest和Cypress的实战应用与最佳实践。Jest适合React应用的单元测试和快照测试,Cypress则擅长端到端测试,模拟用户交互。通过结合使用这两种工具,可以有效提升代码质量和开发效率。最佳实践包括单元测试与集成测试结合、快照测试、并行执行、代码覆盖率分析、测试环境管理和测试数据管理。
31 2
|
16天前
|
前端开发 安全 应用服务中间件
前端性能调优:HTTP/2与HTTPS在Web加速中的应用
【10月更文挑战第26天】随着互联网的快速发展,前端性能调优成为开发者的重要任务。本文探讨了HTTP/2与HTTPS在前端性能优化中的应用,介绍了二进制分帧、多路复用和服务器推送等特性,并通过Nginx配置示例展示了如何启用HTTP/2和HTTPS,以提升Web应用的性能和安全性。
17 3
|
16天前
|
前端开发 JavaScript 数据可视化
前端自动化测试:Jest与Cypress的实战应用与最佳实践
【10月更文挑战第26天】前端自动化测试在现代软件开发中至关重要,Jest和Cypress分别是单元测试和端到端测试的流行工具。本文通过解答一系列问题,介绍Jest与Cypress的实战应用与最佳实践,帮助开发者提高测试效率和代码质量。
27 2
|
16天前
|
前端开发 JavaScript API
前端框架新探索:Svelte在构建高性能Web应用中的优势
【10月更文挑战第26天】近年来,前端技术飞速发展,Svelte凭借独特的编译时优化和简洁的API设计,成为构建高性能Web应用的优选。本文介绍Svelte的特点和优势,包括编译而非虚拟DOM、组件化开发、状态管理及响应式更新机制,并通过示例代码展示其使用方法。
32 2
|
17天前
|
前端开发 JavaScript 开发者
“揭秘React Hooks的神秘面纱:如何掌握这些改变游戏规则的超能力以打造无敌前端应用”
【10月更文挑战第25天】React Hooks 自 2018 年推出以来,已成为 React 功能组件的重要组成部分。本文全面解析了 React Hooks 的核心概念,包括 `useState` 和 `useEffect` 的使用方法,并提供了最佳实践,如避免过度使用 Hooks、保持 Hooks 调用顺序一致、使用 `useReducer` 管理复杂状态逻辑、自定义 Hooks 封装复用逻辑等,帮助开发者更高效地使用 Hooks,构建健壮且易于维护的 React 应用。
28 2
|
22天前
|
JavaScript 前端开发 测试技术
前端全栈之路Deno篇(五):如何快速创建 WebSocket 服务端应用 + 客户端应用 - 可能是2025最佳的Websocket全栈实时应用框架
本文介绍了如何使用Deno 2.0快速构建WebSocket全栈应用,包括服务端和客户端的创建。通过一个简单的代码示例,展示了Deno在WebSocket实现中的便捷与强大,无需额外依赖,即可轻松搭建具备基本功能的WebSocket应用。Deno 2.0被认为是最佳的WebSocket全栈应用JS运行时,适合全栈开发者学习和使用。
|
18天前
|
前端开发 API UED
深入理解微前端架构:构建灵活、高效的前端应用
【10月更文挑战第23天】微前端架构是一种将前端应用分解为多个小型、独立、可复用的服务的方法。每个服务独立开发和部署,但共同提供一致的用户体验。本文探讨了微前端架构的核心概念、优势及实施方法,包括定义服务边界、建立通信机制、共享UI组件库和版本控制等。通过实际案例和职业心得,帮助读者更好地理解和应用微前端架构。