Electron:白话Electron开发桌面端应用

最近在公司分享了Electron的相关技术栈的应用,准备的还是挺充分的,下面将分享的内容大纲附上

1 为什么Electron这么火

1.1 Electron是什么?

Electron是Github开发的开源框架

它允许开发者使用web技术构建跨平台桌面,兼容 Mac、Windows(exclude XP) 和 Linux,可以构建同时支持三个平台的应用程序

跨平台构建应用,一直都是香饽饽,随着载体产商的丰富之后,已经不能满足于以前的android和ios两大阵营,同时还有各种小程序,从微信到抖音、百度、支付宝等,因此应运而生的就有各种岗位的需求,但是当这种需求达到一定波峰的时候,势必会走下坡路,更别说出现了各种的跨平台的技术加持,这种下坡速度就更快了。

Electron就是这种跨平台技术阵营的一员,虽然相比C++等以更接近底层和追求性能的技术相比,有一定的差距瓶颈,但是随着硬件的快速发展,这种跨平台技术的性能缺陷,完全可以忽略,同时因为其入门简单,社区活跃,发展迅速,反而占据了一定市场。

这边重点提下发展迅速的意思吧,举个例子我再11月5日中午的时候,版本还是27.0.2,到了晚上的时候就版本就更新到了27.0.3,到了11月16日的时候,版本已经升级到了27.0.10。迭代的频率够大了吧,但是这么快的频率背后也是有一些问题的,这边先不说!

1.2 什么时候用Electron

  • 快速试错场景

比如工期有限,需要快速出demo

  • 效率工具和开发者工具

说白了,就是提升我们工作效率的工具的开发,可以考虑用Electron;同时开发人员要用的工具都可以考虑用这个来开发,比如我最近在云内正在构建的知识库-桌面版,目前已经有知识库-web版并在项目组内部在用了,但是还是有诸多的场景感觉瓶颈很明显,比如对本地文件的处理。后续的多功能记事本案例就是对这个的说明。

  • 成本管控严格

就是说就这么多人力和财力预算,但是让你同时开发桌面应用、web应用,这个时候肯定不可能又招ui工程师、前端工程师、后端工程师、C++开发工程师等。那么这个时候就可以考虑Electron的引入了。

1.3粉丝应用有哪些?

Electron的发展其实很久了,在技术领域不算新秀了,最初被GitHub开发,2013年4月11日以Atom Shell为名起步,2014年5月16日开源,2015年4月17日改名为Electron。

我最早听到Electron是从听说vscode是用electron开发的,后面进一步了解,还有像美团大象、Atom等。难怪Vscode看起来跟其他的工具相比,总觉得好看多了。

2 白话Electron架构原理

2.1 最简单的Electron应用

一个最简单的Electron项目包括三个文件

  • package.json
  • index.html
    • 渲染进程页面
  • main.js
    • 主进程文件

2.2 Electron核心

2.2.1 Node.js

- 能力:底层能力,支持与底层OS交互
- 后台服务的能力,增强web技术
- 技术手段多,开源npm包丰富

Node.js作为可以替代Java开发服务的技术,在整个应用开发过程中,作用非常明显。并且曾经Node.js以其拥有最大的依赖包仓库而广为闻名,因此各种前卫的、流行的功能,有它的加成,实现都是轻而易举的,比如基于Puppeteer库,可以快速且低代码的完成截屏、海报等图片的生成。

2.2.2 内置Native API

- 跨平台
- 原生能力:比如窗口,进程监控等

2.2.3 Chromium

- 高效:通过WEB技术写UI
- 强大且通用
- 兼容性强

引入了chromium,可以简单的理解Electron应用其实就是一个简版的chromium浏览器应用。那么浏览器能做什么,它也就能做什么了。所以用Electron开发出来的桌面应用就可以有非常高的颜值了。

chromium是多进程架构,引入两个概念:主进程和渲染进程,Electron里头的主进程和渲染进程也是由此得到的。

2.2.3.1 主进程

就是用来创建窗口、创建顶部菜单、右键菜单等。一个应用只有一个主进程。(Browser)

2.2.3.2 渲染进程

每个具体的窗口页面,就是一个渲染进程(Render),一个应用可以有多个渲染进程的。

2.2.3.3 跨进程通信

包括主进程和渲染进程之间以及渲染进程和渲染进程之间的交互(IPC,Inter-Process Communication)

Electron的主进程和渲染进程与Chromium还有点不一样,Electron在各个进程里暴露了Native API,还引入了Node.js。因此Electron中可以使用Chromium和Node.js,支持在html页面上直接使用Node.js。

2.2.3.4 事件驱动整合

这块是一个难点,这边就不做分享了,有兴趣的可以去了解下,包括的Node事件轮询、libuv以及chromium的messageloop等。

3 基于Electron开发多功能记事本

3.1 背景介绍

多功能记事本,是我在云内发起的一个基于Electron开发的桌面记事本工具的雏形,主要的功能是记事本,其次是各种工具的整合,比如,我们收数的时候,都要通过上游的卸数标志flag文件来生成表的字段信息,其实这个过程,很多人采用的方式都是通过复制粘贴的方式,但是我一开始采用的方式就是Notepad++加上正则替换的方式来处理的,不管多少字段,就是一个命令一个按钮,问题就解决了。再比如需要将多行压缩成一行,说白了,就是去除换行符啦。上面这些只是日常工作中常见的两个小案例。多功能记事本支持提前将这些处理固化成本地命令,通过菜单一键完成处理。

3.2 环境安装

首先需要将Node的版本升级到最新版,因为最新版的Electron对Node的版本是有要求的,所以为了简单,建议直接升级Node到最新版本。

云内开发Electron应用,按照我的经验,我感觉最难的就是安装几个基础的包:

  • Electron
  • Electron-forge

云内的制品库Package有上面表面上的所有的依赖包,注意,我这边说的是表面上,因为Electron安装过程还有一个非常棘手的问题:二次安装

Electron的内部命令有一个自触发命令去处理二次安装:

node install.js

二次安装的时候会自行去下载一个Electron的zip压缩包,并解压。但是很不幸,虽然我尝试了先用–ignore-script的方式初步安装顺利结束,然后人工干预重构了install.js,并且自行下载了Electron的压缩包,但是结局是Electron的命令不可用。最后的解决方案是:云外安装Electron,并将整个node-module打包进云内使用。

其他的包安装,基本上就是在开发过程按需安装了。详细可以查看package.json

3.3 项目结构

目录结构如下,详见项目源码

先试用下多功能记事本的功能再讲解下面的内容。

3.4 功能和实现

3.4.1 菜单栏和菜单

最为简单的菜单栏和菜单的实现方式就是直接调用Electron提供的Menu菜单类。缺点如下:

  • 无法定制ui
  • 无法动态更新:比如动态增删菜单项
  • 替代方案:自定义菜单栏

3.4.2 打开和保存文件

依赖Node.js的fs包

  • 打开文件:读取文件,fs.readSync
  • 保存文件:写文件,fs.writeSync

3.4.2 打印

调用窗口的print的API

3.4.3 导出pdf

调用窗口的printToPDF的API

3.4.4 命令

通过new BrowserWindow来创建新的窗口以此来维护管理命令

因为Menu无法动态的更新,要更新只能重启应用,所以每次编辑命令后要想立马生效只能重启来看效果

  • 存储命令,依赖本地数据库,可以是一个本地的一个文件
    • node-little-db引入,内部已封装了json的CRUD的api
    • 命令的本地存储本质是一个个键值对
  • 运行命令,本质是动态创建API,并传递必要的实参
    • 命令:sqlldr的flag转表字段
    • 命令:去掉换行符
    • 本质都是通过JavaScript的replace(Regex, Str)来实现的

3.4.5 快捷键

沿用web的快捷键使用方式

3.4.6 总结

从上到下看过来,整个实现并没有什么难点,实际也是如此,只要您有一定的Node.js的服务端开发经验,又有一定的前端开发经验,入门Electron估计就只要一本《Electron从0到1开发实战》的工具书即可。基本上无任何的技术障碍。

4 Electron开发经验分享和闭坑小妙招

4.1 开发经验分享

  • Electron提供的能力已经很强了,但是仍然建议,以自定义为主,比如上面讲到的菜单,为项目的迭代升级铺垫基础,虽然自定义的话,会麻烦一点,但是长治久安。
  • 不用remote模块。刚入门的同学,看到main.js里头有用到像dialog等功能的时候,就想直接在渲染进程里头也使用,百度搜索,就发现可以通过remote来实现,但是如果用不好,实际上也很难用好,会让系统直接卡死乃至奔溃:
electron/remote 是一个 Electron 模块,它将 JavaScript 对象从主进程桥接到渲染器进程。 这使您可以访问仅主进程的对象,就好像它们在渲染器进程中可用一样。
注意:该模块的问题很多,@electron/remote 是 Electron 中内置远程(remote)模块的替代品,该模块已被弃用,最终将被删除。
    代替remote的方案就是将系统能力集中到main.js主进程中,通过ipcRender.send的方式调用主进程中的能力来实现功能,代码会复杂点,但是如果在项目初期,设计好进程间的通信,那么其实也就没那么复杂了。
  • ipc不用同步模式,即sync模式,因为会阻塞渲染进程从而造成卡顿。

4.2 闭坑

  • 因为Electron依赖chromium,所以当chromium发布新版本的时候,Electron都得发布版本去支持新版的chrominum。因此不要时刻保持项目的Electron版本最新,因为没有最新,只有更新。

  • Electron只维护三个大版本,每2个月发布一个大版本

  • 性能、CPU等表现比不上Native,因此对此有要求的,请绕道!

  • 包体积比较大,但是有部分解决的方案。