Skip to content

Electron - Hello World

让我们创建你的第一个现代 Electron 桌面应用。这个 “Hello World” 示例将展示基本的结构,包括主进程(Main Process)、渲染进程(Renderer Process)以及用于安全通信的预加载脚本(Preload Script),这是现代 Electron 开发的关键方面。

首先,确保你有一个 package.json 文件。如果没有,运行 npm init -y。然后安装 Electron:npm install --save-dev electron。

创建一个名为 main.js 的文件。这是你的 Electron 应用的入口点,运行在主进程中:

const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
// 创建浏览器窗口。
const mainWindow = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'),
contextIsolation: true, // 防范原型链污染 (Protect against prototype pollution)
nodeIntegration: false // 强制关注点分离 (Enforce separation of concerns)
}
});
// 加载应用的 index.html 文件。
mainWindow.loadFile('index.html');
// 打开开发者工具 (可选)
// mainWindow.webContents.openDevTools();
}
// Electron 完成初始化并准备创建浏览器窗口时调用此方法。
app.whenReady().then(() => {
createWindow();
app.on('activate', function () {
// 在 macOS 上,当 dock 图标被点击且没有其他窗口打开时,
// 通常会重新创建一个窗口。
if (BrowserWindow.getAllWindows().length === 0) createWindow();
});
});
// 当所有窗口都被关闭时退出,macOS 上除外。
app.on('window-all-closed', function () {
if (process.platform !== 'darwin') app.quit();
});

接下来,创建 preload.js。这个脚本在一个特权环境中运行,早于渲染器的网页加载。它可以访问 Node.js API,并通过 contextBridge 安全地向渲染进程暴露特定的功能。

const { contextBridge } = require('electron');
contextBridge.exposeInMainWorld('electronVersions', {
node: () => process.versions.node,
chrome: () => process.versions.chrome,
electron: () => process.versions.electron
// 我们也可以暴露变量,不只是函数 (We can also expose variables, not just functions)
});

现在,创建你的 index.html 文件。这是将在你的应用窗口中显示的网页(渲染进程):

<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>Hello World!</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<h1>Hello World!</h1>
<p>
We are using Node.js <span id="node-version"></span>,
Chromium <span id="chrome-version"></span>,
and Electron <span id="electron-version"></span>.
</p>
<script src="renderer.js"></script>
</body>
</html>

创建一个简单的 styles.css(可选):

body {
font-family: Arial, sans-serif;
padding: 20px;
background-color: #f4f4f4;
color: #333;
}
h1 {
color: #0056b3;
}
span {
font-weight: bold;
color: #28a745;
}

最后,创建 renderer.js。这个脚本运行在渲染进程中,并与 DOM 交互。它将使用 preload.js 暴露的 API:

renderer.js
document.addEventListener('DOMContentLoaded', () => {
const nodeVersionElement = document.getElementById('node-version');
const chromeVersionElement = document.getElementById('chrome-version');
const electronVersionElement = document.getElementById('electron-version');
if (window.electronVersions) {
nodeVersionElement.textContent = window.electronVersions.node();
chromeVersionElement.textContent = window.electronVersions.chrome();
electronVersionElement.textContent = window.electronVersions.electron();
} else {
console.error('electronVersions API not found. Check preload script.');
}
});

要运行你的应用,首先向 package.json 添加一个启动脚本:

"scripts": {
"start": "electron ."
}

然后,从你的终端运行应用:

npm start

一个窗口将会出现,显示 “Hello World!” 以及正在使用的 Node.js, Chromium 和 Electron 的版本。这些文本是由 renderer.js 动态插入的,它使用了 preload.js 安全地提供的信息。

  1. main.js(主进程): 管理应用的生命周期并创建浏览器窗口(BrowserWindow)。它通过配置 webPreferences 来使用 preload.js 脚本,启用 contextIsolation(上下文隔离),并禁用 nodeIntegration(Node 集成)以增强安全性。

  2. preload.js(预加载脚本): 作为 Node.js 环境(在此可访问)与渲染器的隔离 JavaScript 上下文之间的桥梁。它使用 contextBridge.exposeInMainWorld 选择性地将特定的 Node.js 功能(如 process.versions)暴露给渲染器,通过一个选定的 API 命名空间(例如 window.electronVersions)。

  3. index.html 和 renderer.js(渲染进程): index.html 定义了用户界面(UI)结构。renderer.js 运行在这个沙箱环境中。它不能直接访问 Node.js API。相反,它使用 preload.js 暴露的函数(例如 window.electronVersions.node())来获取所需信息并更新 DOM。

这种结构通过限制渲染进程访问强大的 Node.js API 来增强安全性,从而减少了应用加载远程或不受信任内容时的攻击面。