Electron是一个使用 JavaScript、HTML 和 CSS 构建桌面应用程序的框架。 嵌入 Chromium 和 Node.js 到 二进制的 Electron 允许您保持一个 JavaScript 代码代码库并创建 在Windows上运行的跨平台应用 macOS和Linux——不需要本地开发 经验。
入门指南
Electron 是网页应用 (web apps) 的一个原生包装层,在 Node.js 环境中运行。确保您的电脑中有node,字数比较多,😄大家可以只看关键的部分,原理的部分可以后面再看。
初始化 npm 项目
Electron 应用基于 npm 搭建,以 package.json 文件作为入口点。 首先创建一个文件夹,然后在其中执行 npm init
初始化项目。
- npm
- Yarn
mkdir my-electron-app && cd my-electron-app
npm init
这条命令会帮您配置 package.json 中的一些字段。 为本教程的目的,有几条规则需要遵循:
- 入口点 应当是
main.js
(您很快就会创建它) - author、license 和 _description_可为任意值,但对于 应用打包 是必填项。
然后,将 Electron 安装为您项目的 devDependencies,即仅在开发环境需要的额外依赖。
为什么 ELECTRON 是 DEVDEPENDENCY?
您的应用需要运行 Electron API,因此这听上去可能有点反直觉。 实际上,打包后的应用本身会包含 Electron 的二进制文件,因此不需要将 Electron 作为生产环境依赖。
- npm
- Yarn
npm install electron --save-dev
在初始化并且安装完 Electron 之后,您的 package.json 应该长下面这样。 文件夹中会出现一个 node_modules
文件夹,其中包含了 Electron 可执行文件;还有一个 package-lock.json
文件,指定了各个依赖的确切版本。
package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
添加 .gitignore 文件
.gitignore 文件可以指定哪些文件和目录应该在Git中不被跟踪。 建议您复制一份 GitHub 的 Node.js gitignore 模板 到您项目的根目录,以避免将 node_modules
文件夹提交到版本控制系统中。
由于 Electron 的主进程是一个 Node.js 运行时,您可以使用 electron
命令执行任意的 Node.js 代码 (甚至可以将其作为 REPL 使用)。 要执行这个脚本,需要在 package.json 的 scripts 字段中添加一个 start
命令,内容为 electron .
。 这个命令会告诉 Electron 在当前目录下寻找主脚本,并以开发模式运行它。
package.json
{
"name": "my-electron-app",
"version": "1.0.0",
"description": "Hello World!",
"main": "main.js",
"scripts": {
"start": "electron .",
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "Jane Doe",
"license": "MIT",
"devDependencies": {
"electron": "23.1.3"
}
}
- npm
- Yarn
npm run start
您的终端应该会输出 欢迎来到 Electron 👋
。 恭喜,您已经在 Electron 中执行了您的第一行代码! 接下来,您会学习如何用 HTML 创建用户界面,并将它们装载到原生窗口中。
将网页装载到 BrowserWindow
在 Electron 中,每个窗口展示一个页面,后者可以来自本地的 HTML,也可以来自远程 URL。 在本例中,您将会装载本地的文件。 在您项目的根目录中创建一个 index.html
文件,并写入下面的内容:
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'"
/>
<meta
http-equiv="X-Content-Security-Policy"
content="default-src 'self'; script-src 'self'"
/>
<title>Hello from Electron renderer!</title>
</head>
<body>
<h1>Hello from Electron renderer!</h1>
<p>👋</p>
</body>
</html>
现在您有了一个网页,您可以将其加载到一个 Electron 的 BrowserWindow 上了。 将 main.js
中的内容替换成下列代码。 我们马上会逐行解释。
main.js
const { app, BrowserWindow } = require('electron')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
导入模块
main.js (Line 1)
const { app, BrowserWindow } = require('electron')
在第一行中,我们使用 CommonJS 语法导入了两个 Electron 模块:
- app,它着您应用程序的事件生命周期。
- BrowserWindow,它负责创建和管理应用窗口。
模块大小写规范
您可能注意到了 app 和 BrowserWindow 两个模块名的大小写差异。 Electron 遵循 JavaScript 传统约定,以帕斯卡命名法 (PascalCase) 命名可实例化的类 (如 BrowserWindow, Tray 和 Notification),以驼峰命名法 (camelCase) 命名不可实例化的函数、变量等 (如 app, ipcRenderer, webContents) 。
ELECTRON 中的 ES 模块
Electron 28 起,Electron 支持ECMAScript 模块(即使用 import
加载模块)。 您可以在我们的 ESM 指南 中找到有关 Electron 中 ESM 状态以及如何在我们的应用程序中使用它们的更多信息。
将可复用的函数写入实例化窗口
createWindow()
函数将您的页面加载到新的 BrowserWindow 实例中:
main.js (Lines 3-10)
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
在应用准备就绪时调用函数
main.js (Lines 12-14)
app.whenReady().then(() => {
createWindow()
})
Electron 的许多核心模块都是 Node.js 的事件触发器,遵循 Node.js 的异步事件驱动架构。 app 模块就是其中一个。
在 Electron 中,只有在 app 模块的 ready 事件触发后才能创建 BrowserWindows 实例。 您可以通过使用 app.whenReady() API 来监听此事件,并在其成功后调用 createWindow()
方法。
INFO
通常我们使用触发器的 .on
函数来监听 Node.js 事件。
+ app.on('ready', () => {
- app.whenReady().then(() => {
createWindow()
})
但是 Electron 暴露了 app.whenReady()
方法,作为其 ready
事件的专用监听器,这样可以避免直接监听 .on 事件带来的一些问题。 参见 electron/electron#21972 。
此时,运行 start
命令应该能成功地打开一个包含您网页内容的窗口!
您应用中的每个页面都在一个单独的进程中运行,我们称这些进程为 渲染器 (renderer) 。 渲染进程使用与常规Web开发相同的JavaScript API和工具,例如使用 webpack来打包和压缩您的代码,或使用 React 构建用户界面。
管理应用的窗口生命周期
应用窗口在不同操作系统中的行为也不同。 Electron 允许您自行实现这些行为来遵循操作系统的规范,而不是采用默认的强制执行。 您可以通过监听 app 和 BrowserWindow 模组的事件,自行实现基础的应用窗口规范。
针对特定进程的控制流
通过检查 Node.js 的 process.platform 变量,您可以针对特定平台运行特定代码。 请注意,Electron 目前只支持三个平台:win32
(Windows), linux
(Linux) 和 darwin
(macOS) 。
关闭所有窗口时退出应用 (Windows & Linux)
在 Windows 和 Linux 上,我们通常希望在关闭一个应用的所有窗口后让它退出。 要在您的Electron应用中实现这一点,您可以监听 app 模块的 window-all-closed 事件,并调用 app.quit() 来退出您的应用程序。此方法不适用于 macOS。
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
如果没有窗口打开则打开一个窗口 (macOS)
与前二者相比,即使没有打开任何窗口,macOS 应用通常也会继续运行。 在没有窗口可用时调用 app 会打开一个新窗口。
为了实现这一特性,可以监听模组的 activate 事件,如果没有任何活动的 BrowserWindow,调用 createWindow()
方法新建一个。
因为窗口无法在 ready
事件前创建,你应当在你的应用初始化后仅监听 activate
事件。 要实现这个,仅监听 whenReady()
回调即可。
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
完整实现代码
DOCS/FIDDLES/TUTORIAL-FIRST-APP (31.2.1)Open in Fiddle
- main.js
- index.html
const { app, BrowserWindow } = require('electron/main')
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow()
}
})
})
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit()
}
})
可选:使用 VS Code 调试
如果您希望使用 VS Code 调试您的程序,您需要让 VS Code 监听主进程 (main process) 和渲染器进程 (renderer process) 。 下面为您提供了一个简单的配置文件。 请在根目录新建一个 .vscode
文件夹,然后在其中新建一个 launch.json 配置文件并填写如下内容。
.vscode/launch.json
{
"version": "0.2.0",
"compounds": [
{
"name": "Main + renderer",
"configurations": ["Main", "Renderer"],
"stopAll": true
}
],
"configurations": [
{
"name": "Renderer",
"port": 9222,
"request": "attach",
"type": "chrome",
"webRoot": "${workspaceFolder}"
},
{
"name": "Main",
"type": "node",
"request": "launch",
"cwd": "${workspaceFolder}",
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron",
"windows": {
"runtimeExecutable": "${workspaceFolder}/node_modules/.bin/electron.cmd"
},
"args": [".", "--remote-debugging-port=9222"],
"outputCapture": "std",
"console": "integratedTerminal"
}
]
}
保存后,当您选择侧边栏的 “运行和调试”,将会出现一个 "Main + renderer" 选项。然后您便可设置断点,并跟踪主进程和渲染器进程中的所有变量。
上文中我们在 launch.json
所做的其实是创建三个配置项:
Main
用来运行主程序,并且暴露出 9222 端口用于远程调试 (--remote-debugging-port=9222
) 。 我们将把调试器绑定到那个端口来调试renderer
。 因为主进程是 Node.js 进程,类型被设置为node
。Renderer
用来调试渲染器进程。 因为后者是由主进程创建的,我们要把它 “绑定” 到主进程上 ()"request": "attach"
,而不是创建一个新的。 渲染器是 web 进程,因此要选择chrome
调试器。Main + renderer
是一个 复合任务,可以同时执行上述任务。
注意事项
由于我们要将进程绑定到 Renderer
任务,您应用中的前几行代码可能会被跳过,因为调试器 (Debugger) 在执行代码之前没有足够的时间进行连接。 在开发环境中,您可以通过刷新页面或者使用 setTimeout 延迟运行代码,来避开这个问题
Electron Fiddle 运行实例
Electron Fiddle 是由 Electron 开发并由其维护者支持的沙盒程序。 我们强烈建议将其作为一个学习工具来安装,以便在开发过程中对Electron的api进行实验或对特性进行原型化。
Fiddle 已经完美的集成到我们的帮助文档之中。 当你浏览我们教程中的例子,你会发现有个「Open In Electron Fiddle」按钮在代码示例中。 如果你已经安装了 Fiddle,「Open In Electron Fiddle」按钮会打开一个 fiddle.electronjs.org
链接并加载示例。 fiddle docs/latest/fiddles/quick-start
文档包含哪些内容?
所有官方文档都可以在侧边栏中查阅。 以下是几个类别,以及相应的介绍:
- 教程:如何创建并发布您的第一个 Electron 程序。
- Electron 进程:对 Electron 中的进程,以及如何使用它们的参考。
- 最佳实践:在开发 Electron 程序时需要留意的一些细节。
- 示例代码: 有了示例代码稍微改一下就可以放入 Electron 应用中.
- 开发:有关开发的其它一些指导。
- 分发:学习如何向终端用户分发您的程序。
- 检测和调试: 如何调试 JavaScript, 如何编写测试代码, 还有就是如何使用其它工具快速创建 Electron 应用.
- 引用: 版本信息相关说明
- 参与贡献: 编译 Electron 并尝试参与贡献. 我们正在尽力让这一步骤更加简单。
寻求帮助
还是有疑问? 请参考一下例子
- 开发过程中如果你需要帮助,我们的 Discord 英文社区 将是绝佳讨论的地方。或前往我们的 Discord 中文社区。
- 如果在开发过程中遇到
electron
package里的疑难杂症,你可以去 GitHub issue tracker 查看是否有人已经遇到相同的问题。 如果你很幸运的找到 bug,欢迎提交 issue 到 GitHub。