摘要
时间过得真快,在忙碌的工作中,2020
年就已经过去了。
虽然到了 2021
年,年龄增加了一岁,白头发多了很多,技术学了很多,但是工资却没有见涨。
那能如何呢?难道 xxx
不再剥削了,打工人就能自由了?
“打工人,打工魂,打工才是人上人”,透露出小人物在平凡生活中的不懈追求,
有着更积极的乐观主义色彩。
这是一种自嘲,也是一直激励。同为打工人,那就一起来学习一直很火的 electron
吧。
阅读本文需要一定的 node
基础知识。知道 electron
是开发桌面应用程序的技术。
本文主要介绍了桌面应用程序的历史和 electron
的历史,分析了 electron
原理和 electron-vue
项目架构,快速上手了 electron-vue
项目。
关键词
Electron Electron-vue
正文
一、 背景
在开发 xxx
项目的时候,需要用到 electron
技术,为了让更多同学了解和喜欢 electron
,我想通过本文分享这些年的实战经验。
二、 桌面应用程序的历史
桌面应用程序,又称为 GUI
程序。
从古到今,开发桌面应用程序有很多种技术,每种技术的优劣,大家可能耳熟能详了:
- VB
上古程序员的开发工具,曾经全球第一的开发语言,拖拽式的图形化开发让它成为极佳的桌面开发工具。微软依靠其操作系统的优势,一直压制同时期的竞争对手delphi
。 - C++的win32API
其MFC
方案是基于窗口中组合控件和消息传递机制。这也是20
多年前的技术,所以API
设计的不是很友好。几年前微软已经停止维护,简单来说它已经过时了。 - Winform
但是从开发体验角度来说自定义、美化控件会比较麻烦。 - C#的.net framework
代表就是WPF
,它的原生特性是其他类库无法比拟的:High DPI
、Split Screen
以及对DirectX
的天然优势。但是并不开源,需要依赖.net
框架,还有就是启动会比较慢。 - Java的swing/javaFx
这是一类比较大的阵营,优势是跨平台和流行开发语言Java
的天然结合,但是界面不太美观。 - C++的Qt
这是很多客户端跨平台的首选,因为开源、UI
库和各种功能的类库非常丰富,但是学习成本比较高。 - C++的duilib
这是windows
下开源的directUI
(微软提出的分离UI
和逻辑的思想)库,它是迎合互联网桌面软件小而美的趋势发展起来的,可能大家对它的关注度比较少。但是用它开发出的产品大名鼎鼎,比如QQ
、微信、爱奇艺等很多知名度高的软件。 - Objective-c/swift cocoa
这是mac
平台下的方案。可以方便调用底层的API
,缺点是不跨平台,文档不友好,UI
库并不丰富。现在这种方式开发的越来越少了。
从 B/S
和 C/S
架构逐渐融合的角度来说,基于 Web
技术进行桌面程序的开发渐渐变成了主流。因为对界面的代码部分可以做到复用。
- 这类技术早期的方案是用
vb
内嵌webBrowser
控件,基于IE
内核,正好很多网页开发也有用activeX
的需求,但这种方式具有明显的缺陷,就是非常依赖于用户的环境,会因为组件缺失导致程序各种崩溃。 - 嵌入式网页框架,这类技术主要是基于浏览器引擎实现
UI
渲染。比较典型的就是appkit
上面UIWebView
和CEF
(chro-mium embeded framework
)。这种方法可以使用网页HTML5+CSS
实现各种酷炫的效果,但是缺点也比较明显,就是桌面程序里面嵌入了一个类似Chrome
的浏览器,内存的开销会比较大。
后面出现了 nwjs
和 electron
,electron
相比 CEF
有了单独执行 js
的 v8
引擎,可以运行 Node.js
来完成服务器端功能,通过和内部浏览器的 v8
引擎交互可以实现一个独立的客户端,这不同于 CEF
需要寄宿在其他程序内部。
三、 Electron的历史
Electron
(最初名为 Atom Shell
)是 GitHub
开发的一个开源框架。它允许使用 Node.js
(作为后端)和 Chromium
(作为前端)完成桌面 GUI
应用程序的开发。Electron
现已被多个开源 Web
应用程序用于前端与后端的开发,著名项目包括 GitHub
的 Atom
和微软的 Visual Studio Code
。
图 1 ATM编辑器
图 2 vscode编辑器
官网上第一段话就是:Electron
是一个框架,可以让您使用 JavaScript
,HTML
和 CSS
创建桌面应用程序。 然后这些应用程序可以打包在 macOS
、Windows
和 Linux
上直接运行,或者通过 Mac App Store
或微软商店分发。通常,您使用每个操作系统特定的本地应用程序框架为操作系统 (OS
)创建一个桌面应用程序。 Electron
可以在使用您已经知道的技术后写入您的应用程序。由此看出,它是框架,而不是库,前端开发者可以像开发 web
应用一样开发桌面应用程序。当然在各大应用商店都可以上架,这个需要各自的认证,这个之后文章讲述。
图 3 electron图标
其优势如下图:
图 4 electron的优势
用 Electron
来做桌面程序开发的优势明显,相当于是完全的网页编程,有 Web
开发经验的前端开发上手非常容易。Web
开发生态广泛,开发成本低,可扩展性强,一些流行的前端框架例如 React
、Angular
、Vue
都可以和 electron
结合进行开发。另外它也具备和 Qt
一样跨平台的优良特性。对性能要求不高的桌面版程序来说,一份代码同时得到网页版和各个平台的桌面版,开发的效率是其他方案无法比的。可以说,这是大部分人看好的趋势。
四、 Electron的入门
(一) 应用程序结构
图 5 electron的架构
Electron
由三个主要部分组成:
- Chromium 用于显示网页内容。
- Node.js 用于本地文件系统和操作系统。
- 自定义 APIs 用于使用经常需要的 OS 本机函数。
Electron
开发应用程序就像构建一个带有网页界面的 Node.js
应用程序,想一想 vscode
就瞬间明了。
主进程和渲染器进程
Electron
有两种进程 :Main
进程和Rendererer
进程。
Main
进程,又叫主进程,通常是名为 main.js
的文件,是每个 Electron
应用的入口文件。它控制着整个 App
的生命周期,从打开到关闭。 它也管理着系统原生元素比如菜单、菜单栏、Dock
栏(软件启动后,在屏幕下方生成的一条栏)和托盘等。主进程负责创建 APP
的每个渲染进程。而且整个 Node API
都集成在里面。
每个应用程序的主进程文件都在 package.json
中的 main
属性中指定。这就是程序知道在启动时执行什么文件。
Rendererer
进程,又叫渲染进程。在 Chromium
中,此进程被称为“浏览器进程”。 它在 Electron
中重新命名,以避免与渲染器过程混淆。与主进程不同的是,它可以有多个,每个都是在一个单独的进程中运行的。它们也可以被掩盖。
在通常的浏览器内,网页通常运行在一个沙盒的环境中,并且不能够使用原生的资源。然而 Electron
的用户在 Node.js
的 API
支持下可以在页面中和操作系统进行一些低级别的交互。
- 主进程通过创建
BrowserWindow
实例来创建网页。 每一个BrowserWindow
实例在其渲染过程中运行网页。当一个BrowserWindow
实例被摧毁时,对应的渲染过程也被终止。 - 主进程管理所有网页及其对应的渲染进程。
- 渲染进程只能管理每个相应的网页。在一个渲染过程中崩溃不会影响其他渲染过程。
- 渲染进程通过
IPC
与主进程通信在网页上执行GUI
操作。由于安全考虑和可能的资源泄漏,直接从渲染器过程中调用与本地GUI
有关的API
受到限制。
谈到两个进程,那必须要涉及进程间通信。可以通过进程间通信模块进行: ipcMain
和 ipcRenderer
。
ipcMain
从主进程到渲染进程的异步通信。
可以从主进程向渲染进程发送消息。
- 发送消息时,事件名称为
channel
。 - 回复同步信息时,需要设置
event.returnValue
。 - 可以使用
event.reply(...)
将异步消息发送回发送者。
ipcRenderer
从渲染器进程到主进程的异步通信。
下面是一个渲染进程向主进程通信的例子:
同步:
//在渲染进程中
const {
ipcRenderer } = require('electron')
ipcRenderer.on('main-reply', (event, arg) => {
console.log(arg) // "main的回复消息"
})
ipcRenderer.send('render-main-message', '来自render的消息')
// 在主进程中
const {
ipcMain } = require('electron')
ipcMain.on('render-main-message', (event, arg) => {
console.log(arg) // "来自render的消息"
event.reply('main-reply', 'main的回复消息')
})
异步:
//在渲染进程中
const {
ipcRenderer } = require('electron')
console.log(ipcRenderer.sendSync('render-main-message', '来自render的消息')) // 来自render的消息
// 在主进程中
const {
ipcMain } = require('electron&