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 (您很快就会创建它)
  • authorlicense 和 _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。

点赞(0) 打赏

评论列表 共有 0 条评论

暂无评论

微信公众账号

微信扫一扫加关注

发表
评论
返回
顶部