Electron 創(chuàng)建您的第一個應用程序

2023-02-16 17:14 更新

學習目標?

在本節(jié),您會學習如何創(chuàng)建您的 Electron 項目,并且編寫一個簡單的入門程序。 到了本節(jié)末尾,您應該能夠在終端開發(fā)環(huán)境運行一個 Electron 應用。

創(chuàng)建項目

避免使用 WSL

如果您用的是 Windows,在本教程中請不要使用 Windows Subsystem for Linux (WSL),否則您在運行應用時可能會遇到問題。

初始化 npm 項目

Electron 應用基于 npm 搭建,以 package.json 文件作為入口點。 首先創(chuàng)建一個文件夾,然后在其中執(zhí)行 npm init 初始化項目。

 npm Yarn 
mkdir my-electron-app && cd my-electron-app
npm init
mkdir my-electron-app && cd my-electron-app
yarn init

這條命令會幫您配置 package.json 中的一些字段。 為本教程的目的,有幾條規(guī)則需要遵循:

  • 入口點 應當是 main.js (您很快就會創(chuàng)建它)
  • author (作者)、license (開源許可證) 和 description (描述) 可以為任意內(nèi)容,不過在晚些的 打包應用程序 步驟中可能是需要的。

然后,將 Electron 安裝為您項目的 devDependencies,即僅在開發(fā)環(huán)境需要的額外依賴。

為什么 ELECTRON 是 DEVDEPENDENCY?

您的應用需要運行 Electron API,因此這聽上去可能有點反直覺。 實際上,打包后的應用本身會包含 Electron 的二進制文件,因此不需要將 Electron 作為生產(chǎn)環(huán)境依賴。

 npm Yarn 
npm install electron --save-dev
yarn add electron --dev

在初始化并且安裝完 Electron 之后,您的 package.json 應該長下面這樣。 文件夾中會出現(xiàn)一個 node_modules 文件夾,其中包含了 Electron 可執(zhí)行文件;還有一個 package-lock.json 文件,指定了各個依賴的確切版本。

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "Hello World!",
  "main": "main.js",
  "author": "Jane Doe",
  "license": "MIT",
  "devDependencies": {
    "electron": "19.0.0"
  }
}

高級安裝步驟

如果直接安裝 Electron 失敗,請參閱我們的 安裝指導 文檔,里面包含下載鏡像、代理和故障排除等信息。

添加 .gitignore 文件

.gitignore 指定了哪些文件不需要 Git 追蹤版本。 建議您復制一份 GitHub 的 Node.js gitignore 模板 到您項目的根目錄,以避免將 node_modules 文件夾提交到版本控制系統(tǒng)中。

運行 Electron 應用

:::延伸閱讀

參閱 流程模型 相關文檔來了解 Electron 的進程之間是如何協(xié)作的。

:::

您在 package.json 中指定的腳本文件 main 是所有 Electron 應用的入口點。 這個文件控制 主程序 (main process),它運行在 Node.js 環(huán)境里,負責控制您應用的生命周期、顯示原生界面、執(zhí)行特殊操作并管理渲染器進程 (renderer processes),稍后會詳細介紹。

在繼續(xù)編寫您的 Electron 應用之前,您將使用一個小小的腳本來確保主進程入口點已經(jīng)配置正確。 在根目錄的 main.js 文件中寫一行代碼:

console.log(`歡迎來到 Electron `)

因為 Electron 的主進程是一個 Node.js 運行時,您可以使用 electron 命令執(zhí)行任意 Node.js 代碼(甚至將其用作 REPL)。 要執(zhí)行這個腳本,在 package.json 的 scripts 字段中添加一個 start 命令,執(zhí)行內(nèi)容為 electron . 。 這個命令會告訴 Electron 在當前目錄下尋找主腳本,并以開發(fā)模式運行它。

{
  "name": "my-electron-app",
  "version": "1.0.0",
  "description": "Hello World!",
  "main": "main.js",
  "author": "Jane Doe",
  "license": "MIT",
  "scripts": {
    "start": "electron ."
  },
  "devDependencies": {
    "electron": "^19.0.0"
  }
}
 npm Yarn 
npm run start
yarn run start

您的終端應該會輸出 歡迎來到 Electron 。 恭喜,您已經(jīng)在 Electron 中執(zhí)行了您的第一行代碼! 接下來,您會學習如何用 HTML 創(chuàng)建用戶界面,并將它們裝載到原生窗口中。

將網(wǎng)頁裝載到 BrowserWindow

在 Electron 中,每個窗口展示一個頁面,后者可以來自本地的 HTML,也可以來自遠程 URL。 在本例中,您將會裝載本地的文件。 在您項目的根目錄中創(chuàng)建一個 index.html 文件,并寫入下面的內(nèi)容:

<!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>

現(xiàn)在您有了一個網(wǎng)頁,可以將它裝載到 Electron 的 BrowserWindow 上了。 將 main.js 中的內(nèi)容替換成下列代碼。 我們馬上會逐行解釋。

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

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
  })

  win.loadFile('index.html')
}

app.whenReady().then(() => {
  createWindow()
})

導入模塊

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

在第一行中,我們使用 CommonJS 語法導入了兩個 Electron 模塊:

  • app,它控制您的應用的事件生命周期。
  • BrowserWindow,它負責創(chuàng)建和管理應用的窗口。

大小寫慣例

您可能注意到了 app 和 BrowserWindow 兩個模塊名的大小寫差異。 Electron 遵循 JavaScript 傳統(tǒng)約定,以帕斯卡命名法 (PascalCase) 命名可實例化的類 (如 BrowserWindow, Tray 和 Notification),以駝峰命名法 (camelCase) 命名不可實例化的函數(shù)、變量等 (如 app, ipcRenderer, webContents) 。

在 ELECTRON 中使用 ES 語法

Electron 目前對 ECMAScript 語法 (如使用 import 來導入模塊) 的支持還不完善。 您可以在 electron/electron#21457 這個 issue 中查看 ESM 的適配進展。

將可復用的函數(shù)寫入實例化窗口

createWindow() 函數(shù)將您的頁面加載到新的 BrowserWindow 實例中:

const createWindow = () => {
  const win = new BrowserWindow({
    width: 800,
    height: 600,
  })

  win.loadFile('index.html')
}

在應用準備就緒時調(diào)用函數(shù)

app.whenReady().then(() => {
  createWindow()
})

Electron 的很多核心模組是 Node.js 事件觸發(fā)器,遵守 Node.js 的異步事件驅(qū)動架構。 app 模塊就是其中一個。

在 Electron 中,只有在 app 模組的 ?ready? 事件能觸發(fā)后才能創(chuàng)建 BrowserWindows 實例。 您可以借助 ?app.whenReady()? API 來等待此事件,并在該 API 的 promise 被 resolve 時調(diào)用 createWindow() 方法。

INFO

通常我們使用觸發(fā)器的 .on 函數(shù)來監(jiān)聽 Node.js 事件。

+ app.on('ready').then(() => {
- app.whenReady().then(() => {
  createWindow()
})

但是 Electron 暴露了 app.whenReady() 方法,作為其 ready 事件的專用監(jiān)聽器,這樣可以避免直接監(jiān)聽 .on 事件帶來的一些問題。 參見 electron/electron#21972 。

此時,運行 start 命令應該能成功地打開一個包含您網(wǎng)頁內(nèi)容的窗口!

您應用中的每個頁面都在一個單獨的進程中運行,我們稱這些進程為 渲染器 (renderer) 。 渲染器也能訪問前端開發(fā)常會用到的 API 和工具,例如用于打包并壓縮代碼的 webpack,還有用于構建用戶界面的 React 。

管理應用的窗口生命周期

應用窗口在不同操作系統(tǒng)中的行為也不同。 Electron 允許您自行實現(xiàn)這些行為來遵循操作系統(tǒng)的規(guī)范,而不是采用默認的強制執(zhí)行。 您可以通過監(jiān)聽 app 和 BrowserWindow 模組的事件,自行實現(xiàn)基礎的應用窗口規(guī)范。

針對特定進程的控制流

可以檢查 Node.js 的 process.platform 變量,幫助您在不同操作系統(tǒng)上運行特定代碼。 請注意,Electron 目前只支持三個平臺:win32 (Windows), linux (Linux) 和 darwin (macOS) 。

關閉所有窗口時退出應用 (Windows & Linux)

在 Windows 和 Linux 上,我們通常希望在關閉一個應用的所有窗口后讓它退出。 若要在 Electron 中實現(xiàn)這一點,您可以監(jiān)聽 ?window-all-closed? 事件,并調(diào)用 ?app.quit()? 來讓應用退出。這不適用于 macOS。

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

如果沒有窗口打開則打開一個窗口 (macOS)

與前二者相比,即使沒有打開任何窗口,macOS 應用通常也會繼續(xù)運行。 在沒有窗口可用時調(diào)用 app 會打開一個新窗口。

為了實現(xiàn)這一特性,可以監(jiān)聽模組的 ?activate? 事件,如果沒有任何活動的 BrowserWindow,調(diào)用 createWindow() 方法新建一個。

因為窗口無法在 ready 事件前創(chuàng)建,你應當在你的應用初始化后僅監(jiān)聽 activate 事件。 要實現(xiàn)這個,僅監(jiān)聽 whenReady() 回調(diào)即可。

app.whenReady().then(() => {
  createWindow()

  app.on('activate', () => {
    if (BrowserWindow.getAllWindows().length === 0) createWindow()
  })
})

完整實現(xiàn)代碼

 main.js  index.html
const { app, BrowserWindow } = require('electron');

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();
  }
});
<!DOCTYPE html>
<html>
  <head>
    <meta charset="UTF-8" />
    <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>
    <p id="info"></p>
  </body>
  <script src="./renderer.js"></script>
</html>

Open in Fiddle

DOCS/FIDDLES/TUTORIAL-FIRST-APP (22.0.2)

可選:使用 VS Code 調(diào)試

如果您希望使用 VS Code 調(diào)試您的程序,您需要讓 VS Code 監(jiān)聽主進程 (main process) 和渲染器進程 (renderer process) 。 下面為您提供了一個簡單的配置文件。 請在根目錄新建一個 .vscode 文件夾,然后在其中新建一個 launch.json 配置文件并填寫如下內(nèi)容。

{
  "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"
    }
  ]
}

保存后,當您選擇側邊欄的 “運行和調(diào)試”,將會出現(xiàn)一個 "Main + renderer" 選項。然后您便可設置斷點,并跟蹤主進程和渲染器進程中的所有變量。

上文中我們在 launch.json 所做的其實是創(chuàng)建三個配置項:

  • Main 用來運行主程序,并且暴露出 9222 端口用于遠程調(diào)試 (--remote-debugging-port=9222) 。 我們將把調(diào)試器綁定到那個端口來調(diào)試 renderer 。 因為主進程是 Node.js 進程,類型被設置為 node。
  • Renderer 用來調(diào)試渲染器進程。 因為后者是由主進程創(chuàng)建的,我們要把它 “綁定” 到主進程上 ()"request": "attach",而不是創(chuàng)建一個新的。 渲染器是 web 進程,因此要選擇 chrome 調(diào)試器。
  • Main + renderer 是一個 復合任務,可同時執(zhí)行前兩個任務。

注意事項

由于我們要將進程綁定到 Renderer 任務,您應用中的前幾行代碼可能會被跳過,因為調(diào)試器 (Debugger) 在執(zhí)行代碼之前沒有足夠的時間進行連接。 在開發(fā)環(huán)境中,您可以通過刷新頁面或者使用 setTimeout 延遲運行代碼,來避開這個問題。

延伸閱讀

如果您希望深挖調(diào)試步驟,可以查看以下指南:

  • 調(diào)試應用
  • 開發(fā)者工具擴展

摘要

Electron 程序是通過 npm 包創(chuàng)建的。 您應將 Electron 依賴安裝到 devDependencies ,然后在 package.json 中設置一個腳本來運行。

執(zhí)行命令后,Electron 程序會運行您在 package.json 文件的 main 字段設置的入口文件。 這個入口文件控制著 Electron 的主進程,后者運行于 Node.js 實例,負責應用的生命周期、展示原生窗口、執(zhí)行特殊操作和管理渲染進程。

渲染器進程(簡稱渲染器) 負責展示圖形內(nèi)容。 您可以將渲染的網(wǎng)頁指向 web 地址或本地 HTML 文件。 渲染器和常規(guī)的網(wǎng)頁行為很相似,訪問的 web API 也相同。

在教程下一節(jié),我們將會學習如何使用 API 給渲染器提權,以及如何在進程間通信。


以上內(nèi)容是否對您有幫助:
在線筆記
App下載
App下載

掃描二維碼

下載編程獅App

公眾號
微信公眾號

編程獅公眾號