Add electron packaging for single exe server distribution

This commit is contained in:
2026-03-13 00:27:36 +08:00
parent decba25a08
commit 0d84793a48
2 changed files with 115 additions and 53 deletions

View File

@@ -1,68 +1,107 @@
const { app, BrowserWindow } = require('electron'); const { app, Tray, Menu, nativeImage } = require('electron');
const path = require('path'); const path = require('path');
const fs = require('fs');
const { spawn } = require('child_process'); const { spawn } = require('child_process');
let mainWindow = null; let tray = null;
let serverProcess = null;
function startServer() { function startServer() {
console.log('Starting OpenChamber server...'); console.log('Starting OpenChamber server...');
serverProcess = spawn('bun', ['run', 'start:web'], { let serverPath;
cwd: path.join(__dirname, '..'), let cwdPath;
let execPath;
if (app.isPackaged) {
serverPath = path.join(process.resourcesPath, 'server', 'index.js');
cwdPath = path.join(process.resourcesPath);
execPath = path.join(process.resourcesPath, 'nodejs', 'node.exe');
} else {
serverPath = path.join(__dirname, '..', 'server', 'index.js');
cwdPath = path.join(__dirname, '..');
execPath = 'node';
}
console.log('Server path:', serverPath);
console.log('CWD:', cwdPath);
console.log('Exec:', execPath);
const env = { ...process.env };
env.OPENCHAMBER_PORT = '3000';
env.OPENCODE_SKIP_START = 'true';
// 创建批处理脚本
const batContent = `"${execPath}" "${serverPath}"`;
const batPath = path.join(cwdPath, 'start-server.bat');
fs.writeFileSync(batPath, batContent);
console.log('Bat path:', batPath);
try {
const child = spawn('cmd.exe', ['/c', batPath], {
cwd: cwdPath,
stdio: 'inherit', stdio: 'inherit',
shell: true, env: env,
detached: false detached: false
}); });
serverProcess.on('error', (err) => { child.on('error', (err) => {
console.error('Server error:', err); console.error('Server error:', err);
}); });
serverProcess.on('exit', (code) => { child.on('exit', (code) => {
console.log('Server exited with code:', code); console.log('Server exited:', code);
}); });
} catch (e) {
console.error('Failed to start:', e);
}
} }
function createWindow() { function createTray() {
mainWindow = new BrowserWindow({ try {
width: 800, let iconPath;
height: 600, if (app.isPackaged) {
show: false, iconPath = path.join(process.resourcesPath, 'public', 'favicon.png');
webPreferences: { } else {
nodeIntegration: false, iconPath = path.join(__dirname, '..', 'public', 'favicon.png');
contextIsolation: true
} }
});
mainWindow.loadURL('http://localhost:3000'); let icon;
try {
icon = nativeImage.createFromPath(iconPath);
if (icon.isEmpty()) {
icon = nativeImage.createEmpty();
}
} catch (e) {
icon = nativeImage.createEmpty();
}
mainWindow.once('ready-to-show', () => { tray = new Tray(icon);
mainWindow.show();
});
mainWindow.on('closed', () => { const contextMenu = Menu.buildFromTemplate([
mainWindow = null; { label: 'OpenChamber Server', enabled: false },
}); { type: 'separator' },
{ label: 'Open http://localhost:3000', click: () => {
require('electron').shell.openExternal('http://localhost:3000');
}},
{ type: 'separator' },
{ label: 'Quit', click: () => {
app.quit();
}}
]);
tray.setToolTip('OpenChamber Server');
tray.setContextMenu(contextMenu);
} catch (e) {
console.error('Failed to create tray:', e);
}
} }
app.whenReady().then(() => { app.whenReady().then(() => {
startServer(); startServer();
createTray();
setTimeout(() => {
createWindow();
}, 3000);
}); });
app.on('window-all-closed', () => { app.on('window-all-closed', () => {
if (serverProcess) {
serverProcess.kill();
}
app.quit(); app.quit();
}); });
app.on('before-quit', () => {
if (serverProcess) {
serverProcess.kill();
}
});

View File

@@ -17,12 +17,35 @@
}, },
"files": [ "files": [
"main.js", "main.js",
"../dist/**/*",
"../server/**/*",
"../bin/**/*",
"../public/**/*",
"package.json" "package.json"
], ],
"extraResources": [
{
"from": "../dist",
"to": "dist",
"filter": ["**/*"]
},
{
"from": "../server",
"to": "server",
"filter": ["**/*"]
},
{
"from": "../bin",
"to": "bin",
"filter": ["**/*"]
},
{
"from": "../public",
"to": "public",
"filter": ["**/*"]
},
{
"from": "D:\\Program Files\\nodejs",
"to": "nodejs",
"filter": ["node.exe"]
}
],
"win": { "win": {
"target": "portable" "target": "portable"
}, },