搭建好开发环境之后,写一个能跑起来的 Electron 应用其实只需要三个文件:package.json、main.js 和一个 HTML 页面。这一节会手把手带你创建它们,让你真正看到 Electron 是如何把一个网页变成桌面程序的。
2.4.1 项目初始化与 package.json
首先,新建一个项目文件夹,并用 npm 初始化:
mkdir my-first-electron-app
cd my-first-electron-app
npm init -y
这时会生成一个默认的 package.json。你需要告诉 Electron 主进程的入口文件在哪里,同时添加启动脚本:
{
"name": "my-first-electron-app",
"version": "1.0.0",
"main": "main.js",
"scripts": {
"start": "electron ."
},
"devDependencies": {
"electron": "^28.0.0"
}
}
这里有几个关键点:
"main": "main.js":这是一个隐式的约定,告诉 Electron 应用程序应该从哪个文件启动主进程。"start": "electron .":执行npm start时,会运行当前目录下的 Electron,它自动读取package.json中的main字段作为入口。
接着安装 Electron(因为前面搭建环境时已经在全局装过,但项目依赖里仍需要声明):
npm install --save-dev electron
2.4.2 主进程入口:main.js
主进程是整个应用的“心脏”。它的核心职责是创建窗口、管理应用状态以及处理系统级的交互。一个最精简的 main.js 代码如下:
// main.js
const { app, BrowserWindow } = require('electron');
const path = require('path');
function createWindow() {
// 创建一个窗口实例
const win = new BrowserWindow({
width: 800,
height: 600,
webPreferences: {
preload: path.join(__dirname, 'preload.js'), // 安全桥接
nodeIntegration: false, // 禁止渲染进程直接使用 Node.js
contextIsolation: true, // 开启上下文隔离
},
});
// 加载 HTML 页面
win.loadFile('index.html');
}
// Electron 初始化完成后调用 createWindow
app.whenReady().then(() => {
createWindow();
// macOS 特性:当点击 dock 图标且没有窗口时,重新创建窗口
app.on('activate', () => {
if (BrowserWindow.getAllWindows().length === 0) {
createWindow();
}
});
});
// 所有窗口关闭时退出应用(macOS 除外)
app.on('window-all-closed', () => {
if (process.platform !== 'darwin') {
app.quit();
}
});
这段代码展示了几个重要的设计模式:
app.whenReady():Electron 需要时间完成底层初始化(例如设置内部协议、加载扩展等)。必须等这个 Promise 完成之后才能安全地创建窗口。BrowserWindow:这是所有 UI 的载体。它的webPreferences配置决定了渲染进程的安全策略。现代 Electron 应用几乎都要开启contextIsolation并关闭nodeIntegration,再通过preload脚本暴露有限的 API。- 窗口加载:
win.loadFile('index.html')直接加载本地 HTML 文件。你也可以使用win.loadURL加载一个远程地址(如开发时的localhost:3000)。 - 生命周期处理:
window-all-closed和activate事件是为了遵守不同操作系统的约定。在 Windows/Linux 上关闭所有窗口通常意味着退出应用;而 macOS 上应用即使没有窗口也仍然保持活动状态,点击 Dock 图标应重新创建窗口。
2.4.3 一个简单的 HTML 页面
在项目根目录新建 index.html,内容非常简单:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
<title>我的第一个 Electron 应用</title>
<style>
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
margin: 0;
background: #f5f5f5;
}
h1 {
color: #333;
}
</style>
</head>
<body>
<h1>🎉 Hello Electron!</h1>
</body>
</html>
2.4.4 预加载脚本(preload.js)
虽然目前还没用到主进程的特殊能力,但既然在 main.js 里指定了 preload,我们应当创建一个占位的 preload.js 文件,否则启动时会报错:
// preload.js
// 目前为空,后续会在这里安全地暴露主进程的 API
preload.js 是连接安全世界(渲染进程)和特权世界(主进程)的桥梁,我们会在后续章节详细展开。
2.4.5 启动应用
一切就绪后,在终端执行:
npm start
你会看到一个干净的桌面窗口,中央显示着“🎉 Hello Electron!”,它的样式完全由 CSS 控制,窗口可以拖拽、最大化、关闭——行为就是一个标准的桌面程序。
这个窗口的背后:
- 主进程
main.js运行在 Node.js 环境,拥有对系统的完整访问权。 - 渲染进程(就是
index.html所在的环境)被严格隔离,默认不能直接碰触 Node.js 或 Electron 的原生模块,保证了前端代码的安全性。
如果你用的是 Chromium 内核,甚至可以按下 Ctrl+Shift+I(Windows/Linux)或 Cmd+Option+I(macOS)打开 DevTools,像调试普通网页一样检查元素、查看控制台输出。开发体验与 Web 开发完全一致。
至此,你已经完成了一个从零到一的 Electron 应用。它虽然简单,但已经包含了 Electron 最核心的骨架:package.json 定义入口、main.js 驱动主进程并创建窗口、index.html 提供界面、preload.js 预留安全通道。下一节我们会让这个应用“活”起来,添加 IPC 通信,真正感受前端与后端协作的魅力。