From fbdbd7e05c097cc83e550d64c6299f993159e8fb Mon Sep 17 00:00:00 2001 From: "kevinguevaradevia@gmail.com" Date: Tue, 2 Jun 2026 04:18:34 -0500 Subject: [PATCH] fix: port conflicts and API proxy for Electron dev mode MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Vite proxy: /api/* requests from renderer (5173) → Express (3000) - Add dynamic port finding: if 3000 is taken, auto-pick next available - Import net module for port checking - Use dynamic expressPort in production URL loading --- electron.vite.config.ts | 7 +++++++ src/electron/main.ts | 43 ++++++++++++++++++++++++++++++++++------- 2 files changed, 43 insertions(+), 7 deletions(-) diff --git a/electron.vite.config.ts b/electron.vite.config.ts index 3be4b85..7e55be3 100644 --- a/electron.vite.config.ts +++ b/electron.vite.config.ts @@ -67,6 +67,13 @@ export default defineConfig({ server: { hmr: process.env.DISABLE_HMR !== 'true', watch: process.env.DISABLE_HMR === 'true' ? null : {}, + // Proxy API calls to the embedded Express server + proxy: { + '/api': { + target: 'http://127.0.0.1:3000', + changeOrigin: true, + }, + }, }, }, }); diff --git a/src/electron/main.ts b/src/electron/main.ts index 6d2c90c..60446e7 100644 --- a/src/electron/main.ts +++ b/src/electron/main.ts @@ -10,13 +10,36 @@ import { app, BrowserWindow, ipcMain, dialog } from 'electron'; import path from 'path'; import fs from 'fs'; +import net from 'net'; // Signal to server.ts / renderQueue.ts that we're in Electron process.env.BRADLY_ELECTRON = 'true'; -const EXPRESS_PORT = 3000; +const PREFERRED_PORT = 3000; +let expressPort = PREFERRED_PORT; let mainWindow: BrowserWindow | null = null; +// ═══ Port Utilities ═══ + +/** Find an available port, starting from the preferred one */ +function getAvailablePort(startPort: number): Promise { + return new Promise((resolve, reject) => { + const server = net.createServer(); + server.listen(startPort, '127.0.0.1', () => { + const port = (server.address() as net.AddressInfo).port; + server.close(() => resolve(port)); + }); + server.on('error', () => { + // Port in use, try the next one + if (startPort < 65535) { + resolve(getAvailablePort(startPort + 1)); + } else { + reject(new Error('No available ports found')); + } + }); + }); +} + // ═══ Path Setup for Electron ═══ function setupPaths() { @@ -72,7 +95,10 @@ function setupPaths() { // ═══ Express Server ═══ -async function startExpressServer(): Promise { +async function startExpressServer(): Promise { + // Find an available port + expressPort = await getAvailablePort(PREFERRED_PORT); + const { createExpressApp } = await import('../../server'); const expressApp = await createExpressApp(); @@ -96,10 +122,13 @@ async function startExpressServer(): Promise { } } - return new Promise((resolve, reject) => { - const server = expressApp.listen(EXPRESS_PORT, '127.0.0.1', () => { - console.log(`🚀 Express server on http://127.0.0.1:${EXPRESS_PORT}`); - resolve(); + return new Promise((resolve, reject) => { + const server = expressApp.listen(expressPort, '127.0.0.1', () => { + console.log(`🚀 Express server on http://127.0.0.1:${expressPort}`); + if (expressPort !== PREFERRED_PORT) { + console.warn(`⚠️ Port ${PREFERRED_PORT} was in use, using ${expressPort} instead`); + } + resolve(expressPort); }); server.on('error', reject); }); @@ -140,7 +169,7 @@ function createWindow() { } else { // In production, load from the embedded Express server // which serves the built renderer assets - mainWindow.loadURL(`http://127.0.0.1:${EXPRESS_PORT}`); + mainWindow.loadURL(`http://127.0.0.1:${expressPort}`); } mainWindow.on('closed', () => {