在本節(jié),您會學(xué)習(xí)如何創(chuàng)建您的 Electron 項目,并且編寫一個簡單的入門程序。 到了本節(jié)末尾,您應(yīng)該能夠在終端開發(fā)環(huán)境運行一個 Electron 應(yīng)用。
避免使用 WSL
如果您用的是 Windows,在本教程中請不要使用 Windows Subsystem for Linux (WSL),否則您在運行應(yīng)用時可能會遇到問題。
Electron 應(yīng)用基于 npm 搭建,以 package.json 文件作為入口點。 首先創(chuàng)建一個文件夾,然后在其中執(zhí)行 npm init
初始化項目。
npm | Yarn |
|
|
這條命令會幫您配置 package.json 中的一些字段。 為本教程的目的,有幾條規(guī)則需要遵循:
main.js
(您很快就會創(chuàng)建它)然后,將 Electron 安裝為您項目的 devDependencies,即僅在開發(fā)環(huán)境需要的額外依賴。
為什么 ELECTRON 是 DEVDEPENDENCY?
您的應(yīng)用需要運行 Electron API,因此這聽上去可能有點反直覺。 實際上,打包后的應(yīng)用本身會包含 Electron 的二進(jìn)制文件,因此不需要將 Electron 作為生產(chǎn)環(huán)境依賴。
npm | Yarn |
|
|
在初始化并且安裝完 Electron 之后,您的 package.json 應(yīng)該長下面這樣。 文件夾中會出現(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 失敗,請參閱我們的 安裝指導(dǎo) 文檔,里面包含下載鏡像、代理和故障排除等信息。
.gitignore
指定了哪些文件不需要 Git 追蹤版本。 建議您復(fù)制一份 GitHub 的 Node.js gitignore 模板 到您項目的根目錄,以避免將 node_modules
文件夾提交到版本控制系統(tǒng)中。
:::延伸閱讀
參閱 流程模型 相關(guān)文檔來了解 Electron 的進(jìn)程之間是如何協(xié)作的。
:::
您在 package.json 中指定的腳本文件 main
是所有 Electron 應(yīng)用的入口點。 這個文件控制 主程序 (main process),它運行在 Node.js 環(huán)境里,負(fù)責(zé)控制您應(yīng)用的生命周期、顯示原生界面、執(zhí)行特殊操作并管理渲染器進(jìn)程
(renderer processes),稍后會詳細(xì)介紹。
在繼續(xù)編寫您的 Electron 應(yīng)用之前,您將使用一個小小的腳本來確保主進(jìn)程入口點已經(jīng)配置正確。 在根目錄的 main.js
文件中寫一行代碼:
console.log(`歡迎來到 Electron `)
因為 Electron 的主進(jìn)程是一個 Node.js 運行時,您可以使用 electron
命令執(zhí)行任意 Node.js 代碼(甚至將其用作 REPL)。 要執(zhí)行這個腳本,在 package.json 的 scripts
字段中添加一個 start
命令,執(zhí)行內(nèi)容為 electron .
。
這個命令會告訴 Electron 在當(dāng)前目錄下尋找主腳本,并以開發(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 |
|
|
您的終端應(yīng)該會輸出 歡迎來到 Electron
。 恭喜,您已經(jīng)在 Electron 中執(zhí)行了您的第一行代碼! 接下來,您會學(xué)習(xí)如何用 HTML 創(chuàng)建用戶界面,并將它們裝載到原生窗口中。
在 Electron 中,每個窗口展示一個頁面,后者可以來自本地的 HTML,也可以來自遠(yuǎn)程 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 語法導(dǎo)入了兩個 Electron 模塊:
大小寫慣例
您可能注意到了 app 和 BrowserWindow 兩個模塊名的大小寫差異。 Electron 遵循 JavaScript 傳統(tǒng)約定,以帕斯卡命名法 (PascalCase) 命名可實例化的類 (如 BrowserWindow, Tray 和 Notification),以駝峰命名法 (camelCase) 命名不可實例化的函數(shù)、變量等 (如 app, ipcRenderer, webContents) 。
在 ELECTRON 中使用 ES 語法
Electron 目前對 ECMAScript 語法 (如使用
import
來導(dǎo)入模塊) 的支持還不完善。 您可以在 electron/electron#21457 這個 issue 中查看 ESM 的適配進(jìn)展。
createWindow()
函數(shù)將您的頁面加載到新的 BrowserWindow 實例中:
const createWindow = () => {
const win = new BrowserWindow({
width: 800,
height: 600,
})
win.loadFile('index.html')
}
app.whenReady().then(() => {
createWindow()
})
Electron 的很多核心模組是 Node.js 事件觸發(fā)器,遵守 Node.js 的異步事件驅(qū)動架構(gòu)。 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
命令應(yīng)該能成功地打開一個包含您網(wǎng)頁內(nèi)容的窗口!
您應(yīng)用中的每個頁面都在一個單獨的進(jìn)程中運行,我們稱這些進(jìn)程為 渲染器 (renderer) 。 渲染器也能訪問前端開發(fā)常會用到的 API 和工具,例如用于打包并壓縮代碼的 webpack,還有用于構(gòu)建用戶界面的 React 。
應(yīng)用窗口在不同操作系統(tǒng)中的行為也不同。 Electron 允許您自行實現(xiàn)這些行為來遵循操作系統(tǒng)的規(guī)范,而不是采用默認(rèn)的強制執(zhí)行。 您可以通過監(jiān)聽 app 和 BrowserWindow 模組的事件,自行實現(xiàn)基礎(chǔ)的應(yīng)用窗口規(guī)范。
針對特定進(jìn)程的控制流
可以檢查 Node.js 的
process.platform
變量,幫助您在不同操作系統(tǒng)上運行特定代碼。 請注意,Electron 目前只支持三個平臺:win32
(Windows),linux
(Linux) 和darwin
(macOS) 。
在 Windows 和 Linux 上,我們通常希望在關(guān)閉一個應(yīng)用的所有窗口后讓它退出。 若要在 Electron 中實現(xiàn)這一點,您可以監(jiān)聽 ?window-all-closed
? 事件,并調(diào)用 ?app.quit()
? 來讓應(yīng)用退出。這不適用于 macOS。
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') app.quit()
})
與前二者相比,即使沒有打開任何窗口,macOS 應(yīng)用通常也會繼續(xù)運行。 在沒有窗口可用時調(diào)用 app 會打開一個新窗口。
為了實現(xiàn)這一特性,可以監(jiān)聽模組的 ?activate
? 事件,如果沒有任何活動的 BrowserWindow,調(diào)用 createWindow()
方法新建一個。
因為窗口無法在 ready
事件前創(chuàng)建,你應(yīng)當(dāng)在你的應(yīng)用初始化后僅監(jiān)聽 activate
事件。 要實現(xiàn)這個,僅監(jiān)聽 whenReady()
回調(diào)即可。
app.whenReady().then(() => {
createWindow()
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) createWindow()
})
})
main.js | index.html |
|
|
DOCS/FIDDLES/TUTORIAL-FIRST-APP (22.0.2)
如果您希望使用 VS Code 調(diào)試您的程序,您需要讓 VS Code 監(jiān)聽主進(jìn)程 (main process) 和渲染器進(jìn)程 (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"
}
]
}
保存后,當(dāng)您選擇側(cè)邊欄的 “運行和調(diào)試”,將會出現(xiàn)一個 "Main + renderer" 選項。然后您便可設(shè)置斷點,并跟蹤主進(jìn)程和渲染器進(jìn)程中的所有變量。
上文中我們在 launch.json
所做的其實是創(chuàng)建三個配置項:
Main
用來運行主程序,并且暴露出 9222 端口用于遠(yuǎn)程調(diào)試 (--remote-debugging-port=9222
) 。 我們將把調(diào)試器綁定到那個端口來調(diào)試 renderer
。 因為主進(jìn)程是 Node.js 進(jìn)程,類型被設(shè)置為 node
。Renderer
用來調(diào)試渲染器進(jìn)程。 因為后者是由主進(jìn)程創(chuàng)建的,我們要把它 “綁定” 到主進(jìn)程上 ()"request": "attach"
,而不是創(chuàng)建一個新的。 渲染器是 web 進(jìn)程,因此要選擇 chrome
調(diào)試器。Main + renderer
是一個 復(fù)合任務(wù),可同時執(zhí)行前兩個任務(wù)。注意事項
由于我們要將進(jìn)程綁定到
Renderer
任務(wù),您應(yīng)用中的前幾行代碼可能會被跳過,因為調(diào)試器 (Debugger) 在執(zhí)行代碼之前沒有足夠的時間進(jìn)行連接。 在開發(fā)環(huán)境中,您可以通過刷新頁面或者使用 setTimeout 延遲運行代碼,來避開這個問題。
延伸閱讀
如果您希望深挖調(diào)試步驟,可以查看以下指南:
開發(fā)者工具擴(kuò)展
Electron 程序是通過 npm 包創(chuàng)建的。 您應(yīng)將 Electron 依賴安裝到 devDependencies
,然后在 package.json 中設(shè)置一個腳本來運行。
執(zhí)行命令后,Electron 程序會運行您在 package.json 文件的 main
字段設(shè)置的入口文件。 這個入口文件控制著 Electron 的主進(jìn)程,后者運行于 Node.js 實例,負(fù)責(zé)應(yīng)用的生命周期、展示原生窗口、執(zhí)行特殊操作和管理渲染進(jìn)程。
渲染器進(jìn)程(簡稱渲染器) 負(fù)責(zé)展示圖形內(nèi)容。 您可以將渲染的網(wǎng)頁指向 web 地址或本地 HTML 文件。 渲染器和常規(guī)的網(wǎng)頁行為很相似,訪問的 web API 也相同。
在教程下一節(jié),我們將會學(xué)習(xí)如何使用 API 給渲染器提權(quán),以及如何在進(jìn)程間通信。
更多建議: