不知不觉在阿里已经入职满一年时间了,在这一年时间里主要接触了低代码(Low Code)、小程序、移动端 H5、监控以及 PC 桌面端(CEF & Electron)等开发技术。在这些技术中, PC 桌面端混合开发技术相对沉淀多一些,接下来会跟大家分享一些桌面端开发的思考,希望对大家的日常开发有所启迪。
本文所讲解的桌面端开发主要采用了 Hybrid 混合的开发模式(一种在原生应用容器中嵌入 Web 浏览器的开发模式),这种模式混合了 Natiive 和 Web 开发的优点。在某些高性能的业务场景中(例如 IM 聊天、音视频、直播等)可以采用 Native 进行开发,而在一些功能迭代相对频繁的业务场景中则可以采用 Web 进行开发(开发成本低)。除此之外, Web 开发在跨平台、动画、动态化、富文本编排等方面能力相对出色。
需要注意上述所说的 CEF 容器可以简单理解为在原生应用环境中嵌入 Google Chromium 浏览器。除此之外,桌面端的应用可以做到多窗口的开发模式,每一个窗口至少可以承载一个 Web 前端应用(简称子应用)。多个子应用之间如果想进行通信则可以利用 URL 的 query 参数(实时性要求低)或者 Native 桥接技术中的发布订阅机制(实时性要求高)。
温馨提示:很多同学对于 Google Chromium 和 Google Chrome 的差异相对迷惑,值得 Goolge 一下。
JSBridge & Native API
前端开发的环境受限于浏览器的沙箱隔离,操作系统中一些涉及到安全问题的系统能力会被限制使用。在桌面端的混合开发中难免需要使用 Web 前端去调起特定的系统能力,此时就需要一种桥接 Web 和 Native 的技术,这种技术被称为 Bridge,具体如下图所示:
温馨提示:图片由同事提供,没有找到具体出处。
可以把上图的左侧部分(自绘引擎开发框架)简单当作 Native 开发,右侧部分(泛 Web 容器框架)当作 Hybrid 混合开发。可以发现 Web 前端如果想绕过沙箱限制调起原生视图组件和系统能力,需要通过 Native 提供的 Bridge 技术。 在 CEF 容器中原生应用可以侵入 JavaScript 语法环境,因此可以通过向 JavaScript 环境(例如 window 全局对象)注射 API 的形式进行桥接,这里的 API 简称 Native API。
温馨提示:除了桌面端的混合开发模型,移动端也存在类似的混合模型,其中的 Web 前端通常被称作 H5 技术。除此之外,桥接技术是 Web 前端间接通过 Native 去调用系统能力,因此会存在一些性能损耗。
JS API
阿里的桌面端除了开发自己的应用以外,也会提供服务平台供外部的 ISV 进行三方应用扩展。此时需要将 Native API 进行能力开放(会涉及到一些调用的版本和鉴权匹配处理),这些开放的 API 简称 JS API,相对 Native API 而言在能力上会更加抽象,除此之外,也需要做到跨平台、跨应用等,具体如下图所示:
不知不觉在阿里已经入职满一年时间了,在这一年时间里主要接触了低代码(Low Code)、小程序、移动端 H5、监控以及 PC 桌面端(CEF & Electron)等开发技术。在这些技术中, PC 桌面端混合开发技术相对沉淀多一些,接下来会跟大家分享一些桌面端开发的思考,希望对大家的日常开发有所启迪。
基本概念
首先讲解一些桌面端开发的基础概念,这里有些说明并不会贯穿全文,其中一些说明会有助于理解后续的框架说明。
Hybrid 混合开发
本文所讲解的桌面端开发主要采用了 Hybrid 混合的开发模式(一种在原生应用容器中嵌入 Web 浏览器的开发模式),这种模式混合了 Natiive 和 Web 开发的优点。在某些高性能的业务场景中(例如 IM 聊天、音视频、直播等)可以采用 Native 进行开发,而在一些功能迭代相对频繁的业务场景中则可以采用 Web 进行开发(开发成本低)。除此之外, Web 开发在跨平台、动画、动态化、富文本编排等方面能力相对出色。
CEF 容器
本文所讲解的 Hybrid 混合开发主要采用了 CEF(Chromium Embedded Framework) 技术,它主要的特点如下:
需要注意上述所说的 CEF 容器可以简单理解为在原生应用环境中嵌入 Google Chromium 浏览器。除此之外,桌面端的应用可以做到多窗口的开发模式,每一个窗口至少可以承载一个 Web 前端应用(简称子应用)。多个子应用之间如果想进行通信则可以利用 URL 的
query
参数(实时性要求低)或者 Native 桥接技术中的发布订阅机制(实时性要求高)。JSBridge & Native API
前端开发的环境受限于浏览器的沙箱隔离,操作系统中一些涉及到安全问题的系统能力会被限制使用。在桌面端的混合开发中难免需要使用 Web 前端去调起特定的系统能力,此时就需要一种桥接 Web 和 Native 的技术,这种技术被称为 Bridge,具体如下图所示:
可以把上图的左侧部分(自绘引擎开发框架)简单当作 Native 开发,右侧部分(泛 Web 容器框架)当作 Hybrid 混合开发。可以发现 Web 前端如果想绕过沙箱限制调起原生视图组件和系统能力,需要通过 Native 提供的 Bridge 技术。 在 CEF 容器中原生应用可以侵入 JavaScript 语法环境,因此可以通过向 JavaScript 环境(例如
window
全局对象)注射 API 的形式进行桥接,这里的 API 简称 Native API。JS API
阿里的桌面端除了开发自己的应用以外,也会提供服务平台供外部的 ISV 进行三方应用扩展。此时需要将 Native API 进行能力开放(会涉及到一些调用的版本和鉴权匹配处理),这些开放的 API 简称 JS API,相对 Native API 而言在能力上会更加抽象,除此之外,也需要做到跨平台、跨应用等,具体如下图所示:
HotFix
在原生应用的桌面端技术中,想要修复线上版本的 Bug 或进行新功能迭代往往需要伴随着新版本的发布。HotFix 是在不发布应用版本的前提下修复线上 Bug 且可以做到用户无感知(也可以通过提示用户手动更新补丁包的方式),大致实现流程如下:
在混合开发中如果想要修复 Web 前端应用的 Bug 会相对简单一些,至少可以省略桌面端的重启步骤。同时离线的 Web 前端资源可以通过资源下发的形式进行更新,而 CDN 形式的资源则只需要推送新的资源版本即可(通常做这些事情的时候会进行逐级灰度,确保更新的稳定性)。
桌面端开发
在阿里的一年时间里,对于桌面端的开发主要经历了一下几个阶段:
了解桌面端框架
在前期对桌面端技术进行了简单的科普之后,对于现有的桌面端框架进行了深入了解,大致如下图所示:
该框架主要包含了容器层、通用层和应用层三个层级,特性大致如下:
开发新的子应用
刚开始进行客户端子应用开发时虽然意识到了框架结构的复杂性,但是并没有想到在框架上可以做一些优化工作,只是在原有框架的基础上进行了应用层的局部优化处理。由于受到了框架的限制,无法采用 React Hook 以及 JavaScript 的一些新特性,代码的设计相对无法做到扁平化的结构方式。当时思考了一些子应用层面的代码结构层次优化,具体如下图所示:
业务层
从桌面端框架和以上思维导图可以看出,这里对原有的应用层做了一些简单的变动。原有业务层本身的功能没有层级划分,是一种没有层级思维模式的开发方式。在前期延续旧的子应用思维模式时发现代码的结构无法适应需求带来的频繁变化,因此思考了之后决定采用业务层分层的设计模式:
这样的层级结构设计带来的好处是需求一旦发生排布变化,只需要在布局层做出相应的调整即可。
MVC 约束
建设公共的数据层(Model),用于驱动业务层(View)更新,而业务层中的容器则担任了控制器(Controller)的作用。除此之外,当业务变得极其复杂之后,数据层会变得相对难以维护,这里采用了分类的控制方式:
需要注意视图数据会随着业务的复杂度增加而增加,当视图数据和视图的关联越来越复杂后容易导致重复渲染问题,此时可通过
immutability-helper
配合React.PureComponent
或shouldComponentUpdate
进行处理(更多关于 React 的优化建议可查看官方文档 Optimizing Performance )。桌面端框架优化探索
在开发子应用的过程中,逐渐体会到旧客户端框架的一些痛点:
大致设想了一些框架的局部优化处理:
从上图可以看出,在原有框架的基础上新增了 Monorepo 结构,该框架的特点如下:
当时考虑了一些通用能力的建设,但是子应用仍然无法做到真正的解耦。除此之外, Monorepo 本身并不能够减少应用的认知和维护成本,因此没有采用这套框架体系。该框架的设计思考奠定了解耦子应用的思维模式。
技术沉淀
桌面端框架优化实践
为了彻底做到子应用的解耦,新的子应用不在原有应用的仓库中进行开发和维护,而是采用了集团的工程化脚手架能力进行独立的开发和维护。除此之外,还在脚手架的基础上新增了桌面端子应用的通用模板能力,可通过 CLI 命令一键快速生成:
大致介绍一下该工程化的能力建设:
react-scripts
,可支持应用、组件以及小程序等多种开发模式其中子应用开发模板的结构大致如下所示:
这里主要讲解一下通用能力建设:
ErrorBoundary
:视图白屏处理(显示兜底的出错视图),并进行白屏的监控上报处理Hook
:多端通用的自定义Hook
能力Request
:多端通用的请求库,能处理缓存和 Loading 优化(特定请求时间内不产生 Loading,请求数据缓存等)Utils
:通用的工具函数需要注意这里的子应用开发模板并没有做到动态插件化的能力,而是相对固定的一个桌面端开发模板。
子应用解耦之后,桌面端混合开发优化后的框架如下图所示:
优化后的框架特性如下:
除此之外,在旧有框架的基础上新增了构建层。由于框架的优化解耦了各个子应用,因此需要将所有子应用的构建产物进行合并处理(成为客户端安装包中的 Web 前端离线产物),合并产物所包含的各个子应用还需要和客户端进行版本映射。因此增加构建层用于处理各个子应用的版本映射关系以及云构建协同处理,这里采用了 Jenkins、 Node 以及 Shell 进行各个子应用的在线构建和产物合并处理。
未来规划
桌面端框架的优化实践虽然做了一些工作,开发效率也得到了极大的提升,但同时也增加了认知和开发协同成本。除此之外,在构建层做的太薄,除了构建本身以外还有很多可发挥的空间,这里就客户端的未来建设做出一些粗略的规划。
文档中心
建立桌面端开发的文档中心,可以更好的帮助开发者在一无所知的情况下快速了解当前桌面端的技术和业务背景,文档中心未来大致会分为以下几个内容:
其中开发指南是重点,大概会包含以下一些内容:
构建优化
构建层除了云构建本身以外,还可以做到子应用开发规范的收口处理,具体如下图所示:
其中会新增在线检测能力,主要包含:
流程协同主要是提升构建的效率,在一些研发流程相关的闭环中可以快速进行构建处理。比如在 Gitlab 中提交特定
commit
信息的代码或者publish
特定分支即可触发构建(这一块和 Github Actions 类似),当然这里的触发层不仅仅涉及 Gitlab,还会涉及到很多阿里内部的研发协同平台。研发服务
研发服务是可以打通整个研发链路的工具服务平台。例如构建优化框架中最顶层的虚线框就是其中非常重要的一个环节,除此之外也可以接入工程化能力、研发效能数据大盘、业务监控数据大盘、流程协同以及 HotFixed 能力等。
研发服务是未来打通桌面端(也可以包括小程序、H5 等应用)整个研发链路的基础服务。在工程化层面可以集成类似于
vue ui
的能力,将现有的子应用模板进行灵活的插件化集成,从而可以快速适应各个业务场景的研发诉求。除此之外,从创建应用、需求评审关联、需求变更、分支管理、需求开发、云构建、缺陷关联、灰度以及发布等整体的研发链路都可以在研发服务平台完成,从而做到工程体系、流程协同、构建等一体化。参考文献