mirror of
https://github.com/Pandipipas/scoreko-dev.git
synced 2026-06-06 03:32:06 +00:00
feat(electron): build compressed Windows installer with Electron 40.6.1
This commit is contained in:
@@ -0,0 +1,118 @@
|
||||
import { app, BrowserWindow } from 'electron';
|
||||
import path from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
import { spawn } from 'node:child_process';
|
||||
|
||||
const __filename = fileURLToPath(import.meta.url);
|
||||
const __dirname = path.dirname(__filename);
|
||||
|
||||
const BUNDLE_ROOT = app.isPackaged
|
||||
? path.join(process.resourcesPath, 'bundle')
|
||||
: path.resolve(__dirname, '..');
|
||||
|
||||
const NODECG_PORT = Number.parseInt(process.env.NODECG_PORT ?? '9090', 10);
|
||||
const NODECG_HOST = process.env.NODECG_HOST ?? '127.0.0.1';
|
||||
const NODECG_URL = `http://${NODECG_HOST}:${NODECG_PORT}`;
|
||||
|
||||
let nodecgProcess;
|
||||
|
||||
function getNodecgCliPath() {
|
||||
return app.isPackaged
|
||||
? path.join(process.resourcesPath, 'app.asar.unpacked', 'node_modules', 'nodecg', 'bin', 'nodecg.js')
|
||||
: path.join(__dirname, 'node_modules', 'nodecg', 'bin', 'nodecg.js');
|
||||
}
|
||||
|
||||
function startNodecg() {
|
||||
const nodecgCli = getNodecgCliPath();
|
||||
|
||||
nodecgProcess = spawn(process.execPath, [nodecgCli, 'start'], {
|
||||
cwd: BUNDLE_ROOT,
|
||||
env: {
|
||||
...process.env,
|
||||
ELECTRON_RUN_AS_NODE: '1',
|
||||
NODECG_PORT: String(NODECG_PORT),
|
||||
},
|
||||
stdio: 'inherit',
|
||||
});
|
||||
|
||||
nodecgProcess.on('exit', (code) => {
|
||||
if (code !== 0) {
|
||||
console.error(`[electron] NodeCG process exited with code ${code}`);
|
||||
}
|
||||
|
||||
if (!app.isQuitting) {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
function stopNodecg() {
|
||||
if (!nodecgProcess || nodecgProcess.killed) {
|
||||
return;
|
||||
}
|
||||
|
||||
app.isQuitting = true;
|
||||
nodecgProcess.kill();
|
||||
}
|
||||
|
||||
async function waitForNodecg(retries = 80, delayMs = 250) {
|
||||
for (let attempt = 0; attempt < retries; attempt += 1) {
|
||||
try {
|
||||
const response = await fetch(NODECG_URL, { method: 'HEAD' });
|
||||
if (response.ok || response.status >= 300) {
|
||||
return;
|
||||
}
|
||||
} catch {
|
||||
// Ignore connection errors while NodeCG boots.
|
||||
}
|
||||
|
||||
await new Promise((resolve) => {
|
||||
setTimeout(resolve, delayMs);
|
||||
});
|
||||
}
|
||||
|
||||
throw new Error(`NodeCG did not start in time at ${NODECG_URL}`);
|
||||
}
|
||||
|
||||
async function createWindow() {
|
||||
const mainWindow = new BrowserWindow({
|
||||
width: 1366,
|
||||
height: 768,
|
||||
autoHideMenuBar: true,
|
||||
webPreferences: {
|
||||
contextIsolation: true,
|
||||
sandbox: true,
|
||||
},
|
||||
});
|
||||
|
||||
await mainWindow.loadURL(NODECG_URL);
|
||||
}
|
||||
|
||||
app.whenReady().then(async () => {
|
||||
startNodecg();
|
||||
|
||||
try {
|
||||
await waitForNodecg();
|
||||
await createWindow();
|
||||
} catch (error) {
|
||||
console.error('[electron] Failed to start wrapper:', error);
|
||||
app.quit();
|
||||
}
|
||||
|
||||
app.on('activate', async () => {
|
||||
if (BrowserWindow.getAllWindows().length === 0) {
|
||||
await createWindow();
|
||||
}
|
||||
});
|
||||
});
|
||||
|
||||
app.on('before-quit', () => {
|
||||
app.isQuitting = true;
|
||||
stopNodecg();
|
||||
});
|
||||
|
||||
app.on('window-all-closed', () => {
|
||||
if (process.platform !== 'darwin') {
|
||||
app.quit();
|
||||
}
|
||||
});
|
||||
Reference in New Issue
Block a user