快速入门

本指南将会通过使用Electron创建一个极简的 Hello World 应用一步步的带你了解,该应用与electron/electron-quick-start类似。

通过这个教程,你的app将会打开一个浏览器窗口,来展示包含当前正在运行的 Chromium, Node.js, and Electronweb等版本信息的web界面

前提条件

在使用Electron进行开发之前,您需要安装 Node.js。 我们建议您使用最新的LTS版本。

请使用为你平台预构建的 Node.js 安装器来进行安装, 否则,您可能会遇到与不同开发工具不兼容的问题。

要检查 Node.js 是否正确安装,请在您的终端输入以下命令:

  1. node -v
  2. npm -v

这两个命令应输出了 Node.js 和 npm 的版本信息。

注意 因为 Electron 将 Node.js 嵌入到其二进制文件中,你应用运行时的 Node.js 版本与你系统中运行的 Node.js 版本无关。

创建你的应用程序

使用脚手架创建

Electron 应用程序遵循与其他 Node.js 项目相同的结构。 首先创建一个文件夹并初始化 npm 包。

  1. mkdir my-electron-app && cd my-electron-app
  2. npm init

init初始化命令会提示您在项目初始化配置中设置一些值 为本教程的目的,有几条规则需要遵循:

  • entry point 应为 main.js.
  • authordescription 可为任意值,但对于应用打包是必填项。

你的 package.json 文件应该像这样:

  1. {
  2. "name": "my-electron-app",
  3. "version": "1.0.0",
  4. "description": "Hello World!",
  5. "main": "main.js",
  6. "author": "Jane Doe",
  7. "license": "MIT"
  8. }

然后,将 electron 包安装到应用的开发依赖中。

  1. $ npm install --save-dev electron

注意:如果您在安装 Electron 时遇到任何问题,请 参见 高级安装 指南。

最后,您希望能够执行 Electron 如下所示,在您的 package.json配置文件中的scripts字段下增加一条start命令:

  1. {
  2. "scripts": {
  3. "start": "electron ."
  4. }
  5. }

start命令能让您在开发模式下打开您的应用

  1. npm start

注意:此脚本将告诉 Electron 在您项目根目录运行 此时,您的应用将立即抛出一个错误提示您它无法找到要运行的应用

运行主进程

任何 Electron 应用程序的入口都是 main 文件。 这个文件控制了主进程,它运行在一个完整的Node.js环境中,负责控制您应用的生命周期,显示原生界面,执行特殊操作并管理渲染器进程(稍后详细介绍)。

执行期间,Electron 将依据应用中 package.json配置下main字段中配置的值查找此文件,您应该已在应用脚手架步骤中配置。

要初始化这个main文件,需要在您项目的根目录下创建一个名为main.js的空文件。

注意:如果您此时再次运行start命令,您的应用将不再抛出任何错误! 然而,它不会做任何事因为我们还没有在main.js中添加任何代码。

创建页面

在可以为我们的应用创建窗口前,我们需要先创建加载进该窗口的内容。 在 Electron 中,每个窗口中无论是本地的HTML文件还是远程URL都可以被加载显示。

此教程中,您将采用本地HTML的方式。 在您的项目根目录下创建一个名为index.html的文件:

  1. <!DOCTYPE html>
  2. <html>
  3. <head>
  4. <meta charset="UTF-8">
  5. <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
  6. <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
  7. <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
  8. <title>Hello World!</title>
  9. </head>
  10. <body>
  11. <h1>Hello World!</h1>
  12. We are using Node.js <span id="node-version"></span>,
  13. Chromium <span id="chrome-version"></span>,
  14. and Electron <span id="electron-version"></span>.
  15. </body>
  16. </html>

注意:在这个HTML文本中,您会发现主体文本中丢失了版本编号。 稍后我们将使用 JavaScript 动态插入它们。

在窗口中打开您的页面

现在您有了一个页面,将它加载进应用窗口中。 要做到这一点,你需要 两个Electron模块:

  • app 模块,它控制应用程序的事件生命周期。
  • BrowserWindow 模块,它创建和管理应用程序 窗口。

因为主进程运行着Node.js,您可以在文件头部将他们导入作为公共JS模块:

  1. const { app, BrowserWindow } = require('electron')

然后,添加一个createWindow()方法来将index.html加载进一个新的BrowserWindow实例。

  1. function createWindow () {
  2. const win = new BrowserWindow({
  3. width: 800,
  4. height: 600
  5. })
  6. win.loadFile('index.html')
  7. }

接着,调用createWindow()函数来打开您的窗口。

在 Electron 中,只有在 app 模块的 ready 事件被激发后才能创建浏览器窗口。 您可以通过使用 app.whenReady() API来监听此事件。 在whenReady()成功后调用createWindow()

  1. app.whenReady().then(() => {
  2. createWindow()
  3. })

注意:此时,您的电子应用程序应当成功 打开显示您页面的窗口!

管理窗口的生命周期

虽然你现在可以打开一个浏览器窗口,但你还需要一些额外的模板代码使其看起来更像是各平台原生的。 应用程序窗口在每个OS下有不同的行为,Electron将在app中实现这些约定的责任交给开发者们。

一般而言,你可以使用 进程 全局的 platform 属性来专门为某些操作系统运行代码。

关闭所有窗口时退出应用 (Windows & Linux)

在Windows和Linux上,关闭所有窗口通常会完全退出一个应用程序。

为了实现这一点,监听 app 模块的 'window-all-closed' 事件,并在用户不是在 macOS (darwin) 上运行时调用 [app.quit()][app-quit]

  1. app.on('window-all-closed', function () {
  2. if (process.platform !== 'darwin') app.quit()
  3. })

如果没有窗口打开则打开一个窗口 (macOS)

当 Linux 和 Windows 应用在没有窗口打开时退出了,macOS 应用通常即使在没有打开任何窗口的情况下也继续运行,并且在没有窗口可用的情况下激活应用时会打开新的窗口。

为了实现这一特性,监听 app 模块的 activate 事件,并在没有浏览器窗口打开的情况下调用你仅存的 createWindow() 方法。

因为窗口无法在 ready 事件前创建,你应当在你的应用初始化后仅监听 activate 事件。 通过在您现有的 whenReady() 回调中附上您的事件监听器来完成这个操作。

  1. app.whenReady().then(() => {
  2. createWindow()
  3. app.on('activate', function () {
  4. if (BrowserWindow.getAllWindows().length === 0) createWindow()
  5. })
  6. })

注意:此时,您的窗口控件应功能齐全!

通过预加载脚本从渲染器访问Node.js。

现在,最后要做的是输出Electron的版本号和它的依赖项到你的web页面上。

在主进程通过Node的全局 process 对象访问这个信息是微不足道的。 然而,你不能直接在主进程中编辑DOM,因为它无法访问渲染器 文档 上下文。 它们存在于完全不同的进程!

注意:如果您需要更深入地查看Electron进程,请参阅 进程模型 文档。

这是将 预加载 脚本连接到渲染器时派上用场的地方。 预加载脚本在渲染器进程加载之前加载,并有权访问两个 渲染器全局 (例如 windowdocument) 和 Node.js 环境。

创建一个名为 preload.js 的新脚本如下:

  1. window.addEventListener('DOMContentLoaded', () => {
  2. const replaceText = (selector, text) => {
  3. const element = document.getElementById(selector)
  4. if (element) element.innerText = text
  5. }
  6. for (const dependency of ['chrome', 'node', 'electron']) {
  7. replaceText(`${dependency}-version`, process.versions[dependency])
  8. }
  9. })

上面的代码访问 Node.js process.versions 对象,并运行一个基本的 replaceText 辅助函数将版本号插入到 HTML 文档中。

要将此脚本附加到渲染器流程,请在你现有的 BrowserWindow 构造器中将路径中的预加载脚本传入 webPreferences.preload 选项。

  1. // 在文件头部引入 Node.js 中的 path 模块
  2. const path = require('path')
  3. // 修改现有的 createWindow() 函数
  4. function createWindow () {
  5. const win = new BrowserWindow({
  6. width: 800,
  7. height: 600,
  8. webPreferences: {
  9. preload: path.join(__dirname, 'preload.js')
  10. }
  11. })
  12. win.loadFile('index.html')
  13. }
  14. // ...

这里使用了两个Node.js概念:

  • __dirname 字符串指向当前正在执行脚本的路径 (本例中,你的项目的根文件夹)。
  • path.join API 将多个路径段联结在一起,创建一个跨平台的组合路径字符串。

我们使用一个相对当前正在执行JavaScript文件的路径,这样您的相对路径将在开发模式和打包模式中都将有效。

额外:将功能添加到您的网页内容

此刻,您可能想知道如何为您的应用程序添加更多功能。

对于与您的网页内容的任何交互,您想要将脚本添加到您的渲染器进程中。 由于渲染器运行在正常的 Web 环境中,因此您可以在 index.html 文件关闭 </body> 标签之前添加一个 <script> 标签,来包括您想要的任意脚本:

  1. <script src="./renderer.js"></script>

renderer.js 中包含的代码接下来可以使用与前端开发相同的 JavaScript API 和工具,例如使用 webpack 打包并最小化您的代码或 React 来管理您的用户界面。

Recap

After following the above steps, you should have a fully functional Electron application that looks like this:

最简的 Electron 应用程序

The full code is available below:

  1. // main.js
  2. // Modules to control application life and create native browser window
  3. const { app, BrowserWindow } = require('electron')
  4. const path = require('path')
  5. function createWindow () {
  6. // Create the browser window.
  7. const mainWindow = new BrowserWindow({
  8. width: 800,
  9. height: 600,
  10. webPreferences: {
  11. preload: path.join(__dirname, 'preload.js')
  12. }
  13. })
  14. // and load the index.html of the app.
  15. mainWindow.loadFile('index.html')
  16. // Open the DevTools.
  17. // mainWindow.webContents.openDevTools()
  18. }
  19. // This method will be called when Electron has finished
  20. // initialization and is ready to create browser windows.
  21. // 部分 API 在 ready 事件触发后才能使用。
  22. app.whenReady().then(() => {
  23. createWindow()
  24. app.on('activate', function () {
  25. // On macOS it's common to re-create a window in the app when the
  26. // dock icon is clicked and there are no other windows open.
  27. if (BrowserWindow.getAllWindows().length === 0) createWindow()
  28. })
  29. })
  30. // Quit when all windows are closed, except on macOS. There, it's common
  31. // for applications and their menu bar to stay active until the user quits
  32. // explicitly with Cmd + Q.
  33. app.on('window-all-closed', function () {
  34. if (process.platform !== 'darwin') app.quit()
  35. })
  36. // In this file you can include the rest of your app's specific main process
  37. // code. 也可以拆分成几个文件,然后用 require 导入。
  1. // preload.js
  2. // All of the Node.js APIs are available in the preload process.
  3. // It has the same sandbox as a Chrome extension.
  4. window.addEventListener('DOMContentLoaded', () => {
  5. const replaceText = (selector, text) => {
  6. const element = document.getElementById(selector)
  7. if (element) element.innerText = text
  8. }
  9. for (const dependency of ['chrome', 'node', 'electron']) {
  10. replaceText(`${dependency}-version`, process.versions[dependency])
  11. }
  12. })
  1. <!--index.html-->
  2. <!DOCTYPE html>
  3. <html>
  4. <head>
  5. <meta charset="UTF-8">
  6. <!-- https://developer.mozilla.org/en-US/docs/Web/HTTP/CSP -->
  7. <meta http-equiv="Content-Security-Policy" content="default-src 'self'; script-src 'self'">
  8. <meta http-equiv="X-Content-Security-Policy" content="default-src 'self'; script-src 'self'">
  9. <title>Hello World!</title>
  10. </head>
  11. <body>
  12. <h1>Hello World!</h1>
  13. We are using Node.js <span id="node-version"></span>,
  14. Chromium <span id="chrome-version"></span>,
  15. and Electron <span id="electron-version"></span>.
  16. <!-- You can also require other files to run in this process -->
  17. <script src="./renderer.js"></script>
  18. </body>
  19. </html>

To summarize all the steps we’ve done:

  • We bootstrapped a Node.js application and added Electron as a dependency.

  • We created a main.js script that runs our main process, which controls our app and runs in a Node.js environment. In this script, we used Electron’s app and BrowserWindow modules to create a browser window that displays web content in a separate process (the renderer).

  • In order to access certain Node.js functionality in the renderer, we attached a preload script to our BrowserWindow constructor.

Package and distribute your application

The fastest way to distribute your newly created app is using Electron Forge.

  1. Add Electron Forge as a development dependency of your app, and use its import command to set up Forge’s scaffolding:

    1. ```sh npm2yarn
    2. npm install --save-dev @electron-forge/cli
    3. npx electron-forge import
    4. ✔ Checking your system
    5. ✔ Initializing Git Repository
    6. ✔ Writing modified package.json file
    7. ✔ Installing dependencies
    8. ✔ Writing modified package.json file
    9. ✔ Fixing .gitignore
    10. We have ATTEMPTED to convert your app to be in a format that electron-forge understands.
    11. Thanks for using "electron-forge"!!!
    12. ```
  2. Create a distributable using Forge’s make command:

    1. npm run make
    2. > my-electron-app@1.0.0 make /my-electron-app
    3. > electron-forge make
    4. Checking your system
    5. Resolving Forge Config
    6. We need to package your application before we can make it
    7. Preparing to Package Application for arch: x64
    8. Preparing native dependencies
    9. Packaging Application
    10. Making for the following targets: zip
    11. Making for target: zip - On platform: darwin - For arch: x64

    Electron Forge creates the out folder where your package will be located:

    1. // Example for macOS
    2. out/
    3. ├── out/make/zip/darwin/x64/my-electron-app-darwin-x64-1.0.0.zip
    4. ├── ...
    5. └── out/my-electron-app-darwin-x64/my-electron-app.app/Contents/MacOS/my-electron-app