electron 是谁
Electron 是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架,底层借助浏览器壳子支持了跨平台,然后可以借助 Node.js 操作进程逻辑和调用系统能力,最后再渲染网页内容,整体组成如下:
Electron = Chromium + Node.js + Native API
快速开始
用脚手架 electron-quick-start
快速搭建项目
git clone https://github.com/electron/electron-quick-start
cd electron-quick-start
yarn
yarn start
项目结构比较简单
electron-quick-start
├─ LICENSE.md
├─ README.md
├─ index.html # html网页
├─ main.js # 主进程脚本
├─ package-lock.json
├─ package.json
├─ preload.js # 预执行脚本
├─ renderer.js # 页面js脚本
└─ styles.css
main.js
:启动应用程序并创建一个浏览器窗口来呈现 HTMLpreload.js
:在渲染器进程加载之前运行的脚本,可以将 Electron 的不同类型的进程桥接在一起
// main.js
// ...
function createWindow() {
// 创建window对象
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
// 加载preload脚本
preload: path.join(__dirname, "preload.js"),
},
});
// 加载网页
mainWindow.loadFile("index.html");
}
preload.js 应用示例
// preload.js
const { contextBridge } = require("electron");
// exposeInMainWorld 将 API 注入到 window 对象,之后渲染进程可通过 window[apiKey] 访问
contextBridge.exposeInMainWorld("versions", {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron,
});
现在渲染器能够全局访问 versions 了,让我们快快将里边的信息显示在窗口中
// renderer.js
const information = document.getElementById("info");
information.innerText = `本应用正在使用 Chrome (v${versions.chrome()}), Node.js (v${versions.node()}), 和 Electron (v${versions.electron()})`;
调整 index.html
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8" />
<!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
<meta
http-equiv="Content-Security-Policy"
content="default-src 'self'; script-src 'self'; style-src 'self' 'unsafe-inline'"
/>
<link href="./styles.css" rel="stylesheet" />
<title>Hello World!</title>
</head>
<body>
<h1>Hello World!</h1>
<!-- We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>. -->
<p id="info"></p>
<!-- You can also require other files to run in this process -->
<script src="./renderer.js"></script>
</body>
</html>
当然脚手架本身的示例也是类似的效果,不过并不是用 contextBridge.exposeInMainWorld
的方式,而是在获取到进程信息后直接操作 dom 节点,殊途同归~
打包
借助 Electron-forge
可以打包 electron 应用,用法如下:
yarn add --dev @electron-forge/cli
npx electron-forge import
yarn make
Electron-forge
会创建 out 文件夹,在那里找到生成的软件包,直接运行试试!
当然也可以用 Electron Builder
,它集成了许多插件,如自动更新、发布、代码签名等,感兴趣可以自行探究~
实际项目可能还要用到 typescript、react、代码工具等,所以建议用基于构建工具(比如 webpack)的脚手架,比如 electron-react-boilerplate,是个比较出名的 electron-react 脚手架。vue 也有对应的脚手架 electron-vue
调试
其实就跟浏览器调试一样了,devtools 全家桶
多进程架构
参考 https://chend0316.github.io/frontend/electron/#electron%E7%9A%84%E6%8A%80%E6%9C%AF%E6%9E%B6%E6%9E%84
每个 Electron 应用有且只有一个主进程(Main Process
)、以及 n 个渲染进程(Renderer Process
), 对应多个网页,除此之外还有 GPU 进程、扩展进程等
主要介绍下两个进程:主进程和渲染进程
主进程
- 主进程使用
BrowserWindow
实例创建页面,主进程可以创建多个渲染进程 - 响应应用(app)的生命周期事件
- 负责与原生操作系统 API 进行通信,可以使用 Node.js 所有模块
- 执行诸如注册全局快捷方式、创建菜单和对话框等操作
这里有俩个关键模块
app
控制应用程序的事件生命周期BrowserWindow
创建和管理应用程序窗口
渲染进程
可以操作部分 Node.js api,比如 fs、cypto、path
等,参考下图
- 当 BrowserWindow 实例销毁时,对应的渲染进程也会终止。渲染进程可以加载 Web 页面
- 在窗口中包含 webContents 实例之前,实际上不会创建渲染器进程。一个窗口可以托管多个 webview,每个 webview 都有自己的 webContents 实例和渲染器进程
- 渲染进程中可以使用所有 DOM API、
Node.js API
和Electron API
的子集 - 渲染进程之间相互隔离,并且不允许它们直接访问操作系统级别的 API。当渲染进程需要访问系统级别 api,可以与主进程通信,由主进程实现其功能
preload 脚本
搭建渲染进程和主进程的桥梁,通过 contextBridge.exposeInMainWorld()
将 electron 或者 Node.js 的 api 或者自定义函数暴露到 window 上,使得网页代码中可以使用额外的 api,跟主进程进行通信
从 Electron 20 开始,预加载脚本默认沙盒化,不再拥有完整 Node.js 环境的访问权。可用 api 参考 https://www.electronjs.org/zh/docs/latest/tutorial/tutorial-preload
进程间通信
IPC 实现中使用结构化克隆算法序列化进程之间传递的对象,分为 ipcmain
(主进程 IPC 协议)和 ipcRenderer
(渲染进程 IPC 协议) ,这两个都是 EventEmitter
类的实例
- 渲染进程向主进程(单向)
on/send
- 渲染进程向主进程(双向)
handle/invoke
- 主进程向渲染进程(单向)
webContents
- 渲染进程之间,主进程做消息代理或基于
MessagePort
代码示例参考 https://www.electronjs.org/zh/docs/latest/tutorial/ipc
其他桌面开发方式
Native(C++/C#/Objective-C)
不管从原生体验、包体积、性能方面来说都是最佳的选择,但是开发门槛和成本都比较高- Web 的代表
Electron
和NW.js
,相比后者,Electron 有更活跃的社区,像 Atom、vscode 这样的大型应用都是基于 Electron 开发的,性能相比于 Native 是肯定要差 QT
是基于 C++的跨平台开发框架,跨平台应用很广泛,比如 WPS 就是用 QT 开发的。性能很好,可以媲美 Native,但是开发门槛还是比较高的Flutter
渲染性能优于 web,但稳定性和生态相对差一些
进阶方向
主要是以下几个大方向可以深入探究
- 构建工具与 electron 配套的结合,进一步提高构建效率。这块可以学习下优秀的脚手架项目的实现
- 深化与操作系统和 Node.js 的集成,以及可以试着写写 c++插件
- 应用性能优化,比如减少包体积和白屏现象等