本文由 vivo 技术团队 Yang Kun 分享,原题“electron 利用开发优良实际”,本文有订正。
1、引言
在上篇《Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)》的分享中,咱们曾经对 Electron 跨端框架的开发有了大略的理解。本篇将基于 vivo 技术团队的技术实际,具体论述了 vivo 在应用 Electron 进行跨端桌面开发时的技术栈选型考量,同时分享了在打包构建、版本更新、性能优化、品质保障、安全性等方面的实际计划和踩坑总结。
学习交换:- 挪动端 IM 开发入门文章:《新手入门一篇就够:从零开发挪动端 IM》-
开源 IM 框架源码:https://github.com/JackJiang2…(备用地址点此)
(本文已同步公布于:http://www.52im.net/thread-40…)
2、系列文章
本文是系列文章中的第 3 篇,本系列总目录如下:
- 《IM 跨平台技术学习(一):疾速理解新一代跨平台桌面技术——Electron》
- 《IM 跨平台技术学习(二):Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)》
- 《IM 跨平台技术学习(三):vivo 的 Electron 技术栈选型、全方位实际总结》(* 本文)
- 《IM 跨平台技术学习(四):蘑菇街基于 Electron 开发 IM 客户端的技术实际》(稍后公布..)
- 《IM 跨平台技术学习(五):融云基于 Electron 的 IM 跨平台 SDK 革新实际总结》(稍后公布..)
-
《IM 跨平台技术学习(六):网易云信基于 Electron 的 IM 音讯全文检索技术实际》(稍后公布..)
3、技术背景
因业务倒退,咱们须要用到桌面端技术,技术个性波及离线可用、调用桌面零碎能力等要求。那么什么是桌面端开发?一句话概括就是:以 Windows、MacOS 和 Linux 为操作系统的桌面软件开发。对此咱们做了具体的技术调研:桌面端的开发方式次要有 Native、QT、Flutter、NW、Electron、Tarui。这些技术各自优劣势如下表格所示:
咱们最终的桌面端技术选型是 Electron,Electron 是一个能够应用 Web 技术来开发跨平台桌面利用的开发框架。其技术组成如下:Electron = Chromium + Node.js + Native API 各技术能力如下图所示:
整体架构如下图所示:
Electron 是多过程架构,架构具备以下特点:1)由一个主过程和 N 个渲染过程组成;2)主过程承当主导作用,用于实现各种跨平台和原生交互;3)渲染过程能够是多个,应用 Web 技术开发,通过浏览器内核渲染页面;4)主过程和渲染过程通过过程间通信来实现各种性能。这里回顾一下 Electron 过程间通信技术原理。electron 应用 IPC(interprocess communication)在过程之间进行通信。如下图所示:
其提供了 IPC 通信模块,主过程的 ipcMain 和渲染过程的 ipcRenderer。从 electron 源码中能够看出,ipcMain 和 ipcRenderer 都是 EventEmitter 对象。源码如下图所示:
看到源码实现,是不是感觉 IPC 不难理解了。知其本质,方可熟能生巧。限于篇幅,这里对 Electron 的基础知识就不再开展,有趣味的读者可回顾一下本系列的前两篇《疾速理解新一代跨平台桌面技术——Electron》、《Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)》(这篇中的“5、过程详解”特地介绍了 Electron 过程间的关系以及通信原理)。
4、开发技术栈选型
4.1 编程语言选型
咱们最终抉择的是 Typescript,理由如下。
针对开发者:
1)Javascript 的超集(无缝反对所有的 es2020+ 所有的个性,学习老本小);
2)编译生成的 JavaScript 的代码放弃很好的可读性;
3)可维护性明显增强;
4)残缺的 OOP 的反对(extends, interface,private,protect,public 等);
5)类型即文档;
6)类型的束缚,更少的单元测试的笼罩;
7)更平安的代码。
针对工具:
1)更好的重构能力;
2)动态剖析主动导包;
3)代码谬误查看;
4)代码跳转;
5)代码提醒补齐。
社区反对:大量的社区的类型定义文件 晋升开发效率。
4.2 构建工具选型
咱们抉择的是 Electron-Forge。理由很充沛:Electron-Forge 简略而又弱小,目前 electron 利用最好的构建工具之一。这里提一下 electron-builder 其和 electron-forge 的介绍和区别。看下图所示:两者最大的区别在于自由度,两者在能力上根本没什么差别了,从官网组织中的排序看,无意优先举荐 electron-forge。
4.3Web 计划选型咱们采纳的是 Vue3,同时应用 Vite 作为构建工具,具体长处,大家能够查看官网介绍,这套组合是目前支流的 Web 开发计划。
4.4monorepo 计划选型目前的 monorepo 生态百花齐放,正确的实际办法应该是集大成法,也就是取各家之长,目前的趋势也是如此,各开源 monorepo 工具达成默契,专一本人善于的能力。如 pnpm 善于依赖治理,turbo 善于构建工作编排。遂在 monorepo 技术选型上,我抉择了 pnpm 和 turbo。以下是 pnpm 的官网:pnpm 理由如下:
1)目前最好的包管理工具(pnpm 排汇了 npm、yarn、lerna 等支流工具的精髓,并去其糟粕);2)生态、社区沉闷且弱小;
3)联合 workspace 能够实现 monorepo 最佳设计和实际;
4)在治理多我的项目的包依赖、代码格调、代码品质、组件库复用等场景下,表现出色;
5)在框架、库的开发、调试、保护方面,表现出色。相比于 vue 官网,在应用 pnpm 上,我加了 workspace。
turbo 理由如下:
1)它是一个高性能构建零碎(领有增量构建、云缓存、并行执行、运行时零开销、工作管道、精简子集等个性);
2)具备十分优良的工作编排能力(能够补救 pnpm 在工作编排上的短板)。
4.5 本地数据库选型
Electron 利用数据库有十分多的抉择如 lowdb、sqlite3、electron-store、pouchdb、dedb、rxdb、dexie、ImmortalDB 等。这些数据库都有一个个性,那就是无服务器。
Electron 本地数据库技术选型思考因素次要有:
1)生态(使用者数量、保护频率、版本稳定度);
2)能力;
3)性能;
4)其余(和使用者技术匹配度)。
咱们通过以下渠道进行了相干调研:
1)github 的 issues、commit、fork、star;
2)sourcegraph 关键字搜寻后果数;
3)npm 包下载量、版本公布;
4)官网和博客。给出四个最优抉择,别离是 lowdb、sqlite3、nedb、electron-store。
咱们的理由如下:
1)lowdb:生态、能力、性能三方面体现优良,json 模式的存储构造,反对 lodash、ramda 等 api 操作,利于备份和调用;
2)sqlite3:生态、能力、性能三方面体现优良,Nodejs 关系型数据库第一抉择计划;
3)nedb:能力、性能三方面体现优良,毛病是根本不保护了,但底子还在,尤其操作是 MongoDB 的子集,对于相熟 MongoDB 的使用者来说是绝佳抉择;
4)electron-store:生态体现优良,轻量级长久化计划,简略易用。咱们应用的数据库最终选型是 lowdb 计划。
PS:提一下 pouchdb,如果须要将本地数据同步到远端数据库,能够应用 pouchdb,其和 couchdb 能够轻松实现同步。
4.6 脚本工具选型软件开发过程中,将一些流程和操作通过脚本来实现,能够无效地进步开发效率和幸福度。依赖 node runtime 的优良抉择就两个:shelljs 和 zx。
抉择 zx 的理由如下:
1)自带 fetch、chalk 等罕用库,应用方便快捷;
2)多个子过程方便快捷(执行远端脚本、解析 md、xml 文件脚本、反对 ts),功能丰富且弱小;
3)谷歌出品、大厂背景,生态十分沉闷。至此,技术选型就介绍完了。5、打包构建实际
5.1 利用图标生成
不同尺寸图标的生成有以下办法。
Windows:
1)软件生成:icofx3;
2)网页生成:https://tool.520101.com/diann…。
MacOS:
1)软件生成:icofx3;
2)网页生成:https://tool.520101.com/diann…;
3)命令行生成:应用 sips 和 iconutil 生成。
5.2 二进制文件构建
本章节内容是基于 electron-forge 论述的,不过原理是一样的。在开发桌面端利用时,会有场景要用到第三方的二进制程序,比方 ffmpeg 这种。
在构建二进制程序时,要关注以下两个留神项。
1)二进制程序不能打包进 asar 中 能够在构建配置文件(forge.config.js)进行如下设置:const os = require(‘os’)const platform = os.platform()const config = { packagerConfig: { // 能够将 ffmpeg 目录打包到 asar 目录里面 extraResource: [./src/main/ffmpeg/
] }}
2)开发和生产环境,获取二进制程序门路办法是不一样的 能够采纳如下代码进行动静获取:import {app} from ‘electron’import os from ‘os’import path from ‘path’const platform = os.platform()const dir = app.getAppPath()let basePath = ”if(app.isPackaged) basePath = path.join(process.resourcesPath)elsebasePath = path.join(dir, ‘ffmpeg’)const isWin = platform === ‘win32’// ffmpeg 二进制程序门路 const ffmpegPath = path.join(basePath,${platform}
, `ffmpeg${isWin ? ‘.exe’:
5.3 按需构建如何对跨平台二进制文件进行按需构建呢?比方桌面利用中用到了 ffmpeg,它须要有 windows、mac 和 linux 的下载二进制。在打包的时候,如果不做按需构建,则会将 3 个二进制文件全部打到构建中,这样会让利用体积减少很多。能够在 forge.config.js 配置文件中进行如下配置,即可实现按需构建。代码如下:const platform = os.platform()const config = { packagerConfig: { extraResource: [./src/main/ffmpeg/${platform}
] },}通过 platform 变量来把对应零碎的二进制打到构建中,即可实现对二进制文件的按需构建。
5.4 性能优化次要是构建速度和构建体积优化,构建速度这块不好优化。这里重点说下构建体积优化,拿 mac 零碎举例说明,在 electron 利用打包后,查看利用包内容。如下图所示:能够看到有一个 app.asar 文件。
这个文件用 asar 解压后能够看到有以下内容:能够看出 asar 中的文件,就是咱们构建后的我的项目代码,从图中能够看到有 node_modules 目录,这是因为在 electron 构建机制中,会主动把 dependencies 的依赖全部打到 asar 中。
联合上述剖析,咱们的优化措施有以下 4 点:
1)将 web 端构建所需的依赖全副放到 devDependencies 中,只将在 electron 端须要的依赖放到 dependencies;
2)将和生产无关的代码和文件从构建中剔除;
3)对跨平台应用的二进制文件,如 ffmpeg 进行按需构建(上文按需构建已介绍);
4)对 node_modules 进行清理精简。
这里提下第 4)点,如何对 node_modules 进行清理精简呢?
如果是 yarn 装置的依赖:咱们能够在根目录应用上面命令进行精简:yarn autoclean -Iyarn autoclean - F 如果是 pnpm 装置的依赖:第 4)点应该不起作用了。我在我的项目中应用 yarn 装置依赖,而后执行上述命令后,发现打包体积缩小了 6M,尽管不多,但也还能够。6、版本更新实际
6.1 全量更新全量更新就是通过下载最新的包或者 zip 文件,进行软件更新,须要替换所有的文件。整体设计流程图如下:
依照流程图去实现,咱们须要做以下事件:
1)开发服务端接口,用来返回利用最新版本信息;
2)渲染过程应用 axios 等工具申请接口,获取最新版本信息;
3)封装更新逻辑,用来对接口返回的版本信息进行综合比拟,判断是否更新;
4)通过 ipc 通信将更新信息传递给主过程;
5)主过程通过 electron-updater 进行全量更新;
6)将更新信息通过 ipc 推送给渲染过程;
7)渲染过程向用户展现更新信息,若更新胜利,则弹出弹窗通知用户重启利用,实现软件更新。6.2 增量更新增量更新是通过拉取最新的渲染层打包文件,笼罩之前的渲染层代码,实现软件更新,此计划只需替换渲染层代码,无需替换所有文件。依照流程图去实现,咱们须要做以下事件:
1)渲染过程定时告诉主过程检测更新;
2)主过程检测更新;
3)须要更新,则拉取线上最新包;
4)删除旧版本包,复制线上最新包,实现增量更新;
5)告诉渲染过程,提醒用户重启利用实现更新。全量更新和增量更新各有劣势,少数状况下,采纳增量更新来进步用户更新体验,同时应用全量更新作为兜底更新计划。7、性能优化实际打包构建优化
在上节内容中曾经具体介绍过了,这里不再介绍,上面将介绍咱们对“启动时优化”和“运行时优化”的实际。
7.1 启动时优化次要从以下几个方面着手:
1)应用 v8-compile-cache 缓存编译代码;
2)优先加载外围性能,非核心性能动静加载;
3)应用多过程,多线程技术;
4)采纳 asar 打包:会放慢启动速度;
5)减少视觉过渡:loading + 骨架屏。
7.1.1)应用 v8-compile-cache 缓存编译代码:应用 V8 缓存数据,为什么要这么做呢?因为 electorn 应用 V8 引擎运行 js,V8 运行 js 时,须要先进行解析和编译,再执行代码。其中,解析和编译过程耗费工夫多,常常导致性能瓶颈。而 V8 缓存性能,能够将编译后的字节码缓存起来,省去下一次解析、编译的工夫。次要应用 v8-compile-cache 来缓存编译的代码,做法很简略:在须要缓存的中央加一行。1require(‘v8-compile-cache’)其余应用办法请查看此链接文档:https://www.npmjs.com/package…
7.1.2)优先加载外围性能,非核心性能动静加载:伪代码如下:export functionshare() { const kun = require(‘kun’) kun()}
7.2 运行时优化次要从以下几个方面着手:
1)对渲染过程 进行 Web 性能优化;
2)对主过程进行轻量瘦身。
7.2.1)对渲染过程 进行 Web 性能优化:用一个思维导图来残缺论述如何进行 Web 性能优化,如下图所示:上图根本蕴含了性能优化的外围关键点和内容,大家能够以此作为参考,去做性能优化。
7.2.2)对主过程进行轻量瘦身:外围计划就是将运行时耗时、计算量大的性能交给新开的 node 过程去执行解决。伪代码如下:
const {fork} = require(‘child_process’)let {app} = require(‘electron’) functioncreateProcess(socketName) {process = fork(xxxx/server.js
, [‘–subprocess’, app.getVersion(), socketName ])} const initApp = async () => { // 其余初始化代码 … let socket = await findSocket() createProcess(socket)} app.on(‘ready’, initApp)通过以上代码,将耗时、计算量大的性能,放在 server.js,而后再 fork 到新开 node 过程中进行解决。至此,性能优化实际就介绍完了。8、品质保障实际
8.1 概述品质保障的全流程措施如下图所示:
本节次要从以下 3 个方面分享:1)自动化测试;2)解体监控;3)解体治理。上面将会顺次介绍上述内容。
8.2 自动化测试自动化测试是什么?上图是做自动化测试一个残缺步骤,大家能够看图体会。自动化测试次要分为 单元测试、集成测试、端到端测试。三者关系如下图所示:
个别状况下:作为软件工程师,咱们做到肯定的单元测试就能够了。而且从我目前教训来说,如果是写业务性质的我的项目,基本上不会编写测试相干的代码。自动化测试次要是用来编写库、框架、组件等须要作为独自个体提供给别人应用的。electron 的测试工具举荐 vitest、spectron。具体用法参考官网文档即可,没什么特地的技巧。
8.3 解体监控对于 GUI 软件,尤其桌面端软件来说,解体率十分重要,因而须要对解体进行监控。解体监控原理如下图所示:解体监控技巧:
1)渲染过程解体后,提醒用户从新加载;
2)通过 preload 对立初始化解体监控;
3)主过程、渲染过程通过 process.crash() 进行模仿解体;
4)对解体日志进行收集剖析。解体监控做好后,如果产生解体,该如何治理解体呢?
8.4 解体治理解体治理难点:
1)定位出错栈艰难:Native 谬误栈,无操作上下文;
2)调试门槛高:C++、IIdb/GDB;
3)运行环境简单:机器型号、零碎、其他软件。
解体治理技巧:
1)及时降级 electron;
2)用户操作日志和零碎信息;
3)复现和定位问题比治理重要;
4)把问题交给社区解决,社区响应快;
5)长于用 devtool 剖析和治理内存问题。9、安全性实际
9.1 概述俗话说的好,平安大于天,保障 electron 利用的平安也是一项重要的事件。
本章节将平安分为以下 5 个方面:
1)源码透露;
2)asar;
3)源码爱护;
4)利用平安;
5)编码平安。上面将会顺次介绍上述内容。
9.2 源码透露目前 electron 在源码平安做的不好,官网只用 asar 做了一下很没用的源码爱护,到底有多没用呢?你只须要下载 asar 工具,而后对 asar 文件进行解压就能够失去外面的源码了。如下图所示:通过图中操作即可看到语雀利用的源码。下面提到的 asar 是什么呢?9.3asar 介绍 asar 是一种将多个文件合并成一个文件的类 tar 格调的归档格局。Electron 能够无需解压整个文件,即可从其中读取任意文件内容。能够间接看 electron 源码,都是 ts 代码,容易浏览,源码如下图所示:
9.4 源码爱护防止源码透露,依照从低到高的源码平安,能够分为几个水平。
具体如下:
1)asar;
2)代码混同;
3)WebAssembly;
4)Language bindings。
其中:Language bindings 是最高的源码安全措施,其实应用 C++ 或 Rust 代码来编写 electron 利用代码,通过将 C++ 或 Rust 代码编译成二进制代码后,破译的难度会变高。这里我说下如何应用 Rust 去编写 electron 利用代码。计划是:应用 napi-rs 作为工具去编写,如下图所示:咱们采纳 pnpm-workspace 去治理 Rust 代码,应用 napi-rs。比方咱们写一个 sum 函数,rs 代码如下:fn sum(a: f64, b: f64) -> f64 {a + b}此时咱们加上 napi 装璜代码,如下所示:use napi_derive::napi; #[napi]fn sum(a: f64, b: f64) -> f64 {a + b}在通过 napi-cli 将上述代码编译成 node 能够调用的二进制代码。编译后,在 electron 应用上述代码,如下所示:import {sum as rsSum} from ‘@rebebuca/native’// 输入 7console.log(rsSum(2, 5))napi-rs 的应用请浏览官网文档,地址是:https://napi.rs/ 至此,language bindings 的论述就实现了。咱们通过这种形式,能够实现对重要性能的源码爱护。
9.5 利用平安目前熟知的一个平安问题是克隆攻打,此问题的支流解决方案是将用户认证信息和利用设施指纹进行绑定。整体流程如如下图所示:如上图所示:
1)利用设施指纹生成:能够用上文论述的 napi-rs 计划去实现;
2)用户认证信息和设施指纹绑定:应用服务端去实现。
9.6 编码平安次要有以下措施:
1)罕用的 web 平安,比方防 xss、csrf;
2)设置 node 可执行环境;
3)窗体开启平安选项;
4)限度链接跳转。以上具体细节不再介绍,自行搜寻上述计划。
除此之外,还有个官网举荐的最佳平安实际,有空能够看看,地址如下:https://www.electronjs.org/do…。至此,安全性这块实际就介绍完了。10、本文小结
本文介绍了咱们对跨零碎桌面端技术的调研、确定技术选型,以及用 electron 开发过程中,总结的实践经验及踩坑填坑过程,如构建、性能优化、品质保障、平安等。心愿对读者在开发跨端桌面利用过程中有所帮忙,文章不免有有余和谬误的中央,欢送读者评论。
11、参考资料
[1] Electron 官网开发者手册
[2] 疾速理解新一代跨平台桌面技术——Electron》
[3] Electron 初体验(疾速开始、跨过程通信、打包、踩坑等)
[4] Electron 根底入门 简单明了,看完啥都懂了
[5] 网易云信 Web 端 IM 的聊天音讯全文检索技术实际
(本文已同步公布于:[http://www.52im.net/thread-40…])