3.7 KiB
3.7 KiB
Electron 单文件打包指南
概述
将 OpenChamber 打包成单个可执行文件 (exe),用户双击即可运行服务器。
核心挑战
Electron 打包后面临的最大问题:如何启动服务器?
- 开发环境:直接用
spawn('node', ...)即可,因为系统有 node - 打包后:electron 内置的是 chromium + node 融合体,没有独立的
node命令 - 解决:把 node.exe 打包进 resources,用批处理脚本启动
实现步骤
1. 目录结构
web/electron/
├── main.js # electron 入口
├── package.json # 打包配置
└── release/ # 输出目录
└── OpenChamber.exe
2. main.js 关键代码
const { app, Tray, Menu, nativeImage } = require('electron');
const path = require('path');
const fs = require('fs');
const { spawn } = require('child_process');
function startServer() {
// 打包后路径
const serverPath = path.join(process.resourcesPath, 'server', 'index.js');
const cwdPath = path.join(process.resourcesPath);
const execPath = path.join(process.resourcesPath, 'nodejs', 'node.exe');
// 创建批处理脚本
const batContent = `"${execPath}" "${serverPath}"`;
const batPath = path.join(cwdPath, 'start-server.bat');
fs.writeFileSync(batPath, batContent);
// 启动服务器
spawn('cmd.exe', ['/c', batPath], {
cwd: cwdPath,
stdio: 'inherit',
env: { ...process.env, OPENCHAMBER_PORT: '3000', OPENCODE_SKIP_START: 'true' }
});
}
function createTray() {
// 系统托盘图标
const iconPath = path.join(process.resourcesPath, 'public', 'favicon.png');
const tray = new Tray(nativeImage.createFromPath(iconPath));
tray.setContextMenu(Menu.buildFromTemplate([
{ label: 'Open http://localhost:3000', click: () => {
require('electron').shell.openExternal('http://localhost:3000');
}},
{ label: 'Quit', click: () => app.quit() }
]));
}
app.whenReady().then(() => {
startServer();
createTray();
});
3. package.json 打包配置
{
"name": "openchamber",
"main": "main.js",
"build": {
"appId": "com.openchamber.app",
"productName": "OpenChamber",
"directories": {
"output": "release"
},
"files": [
"main.js",
"package.json"
],
"extraResources": [
{ "from": "../dist", "to": "dist" },
{ "from": "../server", "to": "server" },
{ "from": "../bin", "to": "bin" },
{ "from": "../public", "to": "public" },
{ "from": "D:\\Program Files\\nodejs", "to": "nodejs", "filter": ["node.exe"] }
],
"win": { "target": "portable" },
"portable": { "artifactName": "OpenChamber.exe" },
"asar": true
}
}
关键点:
extraResources把 dist、server、bin、public、node.exe 打包进去win.target: portable生成单个 exe
4. 打包命令
cd web/electron
npx electron-builder --win --x64
输出:web/electron/release/OpenChamber.exe (~260MB)
原理图
OpenChamber.exe (便携版)
├── electron.exe (运行时)
├── resources/
│ ├── app.asar (electron 主代码)
│ ├── dist/ (静态页面)
│ ├── server/ (服务器代码)
│ ├── bin/ (CLI)
│ ├── public/ (静态资源)
│ └── nodejs/
│ └── node.exe (Node 运行时)
用户双击 exe:
- electron 启动
- main.js 执行
- 创建批处理脚本调用 node.exe 运行 server/index.js
- 服务器在 3000 端口启动
- 系统托盘显示图标
注意事项
- 路径问题:打包后用
process.resourcesPath获取资源目录 - node 路径:必须把系统 node.exe 复制到打包目录
- 托盘图标:需要 favicon.png,否则用空图标
- 端口占用:默认 3000 端口