Skip to content

fix: support electron development window#356

Open
vinayak302004 wants to merge 1 commit into
AOSSIE-Org:mainfrom
vinayak302004:Electron
Open

fix: support electron development window#356
vinayak302004 wants to merge 1 commit into
AOSSIE-Org:mainfrom
vinayak302004:Electron

Conversation

@vinayak302004

@vinayak302004 vinayak302004 commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Addressed Issues:

Fixes #284

Description

Screenshots/Recordings:

image

Functional Verification

Use "npm run electron-dev" for development
Use "npm run build" and "npm run dist" for production

Screen Mirror

  • Screen MIrror works.

Authentication

  • Connection doesn't work without a valid token.

Basic Gestures

  • One-finger tap: Verified as Left Click.

  • Two-finger tap: Verified as Right Click.

  • Click and drag: Verified selection behavior.

  • Pinch to zoom: Verified zoom functionality (if applicable).

Modes & Settings

  • Cursor mode: Cursor moves smoothly and accurately.

  • Scroll mode: Page scrolls as expected.

  • Sensitivity: Verified changes in cursor speed/sensitivity settings.

  • Copy and Paste: Verified both Copy and Paste functionality.

  • Invert Scrolling: Verified scroll direction toggles correctly.

Advanced Input

  • Key combinations: Verified "hold" behavior for modifiers (e.g., Ctrl+C) and held keys are shown in buffer.

  • Keyboard input: Verified Space, Backspace, and Enter keys work correctly.

  • Glide typing: Verified path drawing and text output.

  • Voice input: Verified speech-to-text functionality for full sentences.

  • Backspace doesn't send the previous input.

Any other gesture or input behavior introduced:

  • New Gestures: Verified any other gesture or input behavior introduced in this PR.

Additional Notes:

Checklist

  • [ X ] My PR addresses a single issue, fixes a single bug or makes a single improvement.

  • [ X ] My code follows the project's code style and conventions

  • [ X ] I have performed a self-review of my own code

  • [ X ] I have commented my code, particularly in hard-to-understand areas

  • If applicable, I have made corresponding changes or additions to the documentation

  • If applicable, I have made corresponding changes or additions to tests

  • [ X ] My changes generate no new warnings or errors

  • [ X ] I have joined the and I will share a link to this PR with the project maintainers there

  • [ X ] I have read the

  • [ X ] Once I submit my PR, CodeRabbit AI will automatically review it and I will address CodeRabbit's comments.

  • [ X ] Incase of UI change I've added a demo video.

⚠️ AI Notice - Important!
We encourage contributors to use AI tools responsibly when creating Pull Requests. While AI can be a valuable aid, it is essential to ensure that your contributions meet the task requirements, build successfully, include relevant tests, and pass all linters. Submissions that do not meet these standards may be closed without warning to maintain the quality and integrity of the project. Please take the time to understand the changes you are proposing and their impact.

Summary by CodeRabbit

  • Chores
    • Refactored server startup flow with improved separation of development and production environments.
    • Enhanced error handling and logging for better debugging during development.
    • Improved cross-platform compatibility for development scripts and environment variable configuration.

@coderabbitai

coderabbitai Bot commented Jun 4, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

Walkthrough

This PR refactors Electron's main process to enable reliable development builds by distinguishing dev and production server startup paths. It removes configuration file loading, introduces environment-driven routing via isDev and DEV_URL, adds production server spawning with fixed ports, and updates window loading with branching logic and improved error logging. The electron-dev script is updated to use cross-env for cross-platform environment variable handling.

Changes

Electron dev/prod server flow

Layer / File(s) Summary
Dev/prod environment setup
electron/main.cjs
Core state variables (mainWindow, serverProcess) and environment-driven routing via isDev and DEV_URL (from VITE_DEV_SERVER_URL or fallback http://localhost:3000); waitForServer(url) HTTP polling helper retained.
Production server spawning
electron/main.cjs
startProductionServer() spawns packaged Nitro server from .output/server/index.mjs with fixed HOST=0.0.0.0 and PORT=3000, inherits stdio, and polls HTTP endpoint before returning.
Window creation and URL loading
electron/main.cjs
createWindow() always shows immediately with DevTools, branches dev/prod load flows (dev waits for server; prod starts server then loads), wraps load in try/catch with structured logging, and adds webContents diagnostics for did-fail-load and render-process-gone.
App lifecycle wiring
electron/main.cjs
App lifecycle directly calls createWindow() after app.whenReady(), retains server process termination and macOS-specific quit behavior on window-all-closed.
Development script and cross-platform support
package.json
electron-dev script uses cross-env VITE_DEV_SERVER_URL=... for environment variable setting; cross-env added to devDependencies.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~20 minutes

Possibly related PRs

  • AOSSIE-Org/Rein#237: Both PRs modify Electron startup in electron/main.cjs with Nitro server spawn and HTTP wait-for logic, plus differing single-instance and host/port configuration.
  • AOSSIE-Org/Rein#240: Both PRs add cross-env to devDependencies to support cross-platform environment variable handling in the electron-dev script.
  • AOSSIE-Org/Rein#283: Both PRs refactor electron/main.cjs server startup by changing how host/port are sourced (retrieved PR reads from server-config.json; this PR hardcodes 0.0.0.0:3000).

Suggested labels

Typescript Lang

Poem

A rabbit hops through dev and prod with glee,
One path per build, both running merrily!
The window shows, the server waits in time,
Cross-platform scripts in perfect rhyme—
No more broken Electron, bugs set free! 🐰✨

🚥 Pre-merge checks | ✅ 3 | ❌ 1

❌ Failed checks (1 inconclusive)

Check name Status Explanation Resolution
Description check ❓ Inconclusive The PR description addresses the linked issue (#284) and includes development/production instructions, though the 'Description' section is empty and most verification checkboxes are not marked. Add a detailed description of the changes made to fix the electron development window issue, explaining the key modifications to main.cjs and package.json.
✅ Passed checks (3 passed)
Check name Status Explanation
Title check ✅ Passed The title 'fix: support electron development window' is specific and directly related to the main change of enabling the electron development workflow, which addresses the core issue (#284) that 'npm run electron' was not working.
Linked Issues check ✅ Passed The code changes directly address issue #284 by fixing the electron development flow: electron/main.cjs now properly handles dev vs production modes with correct URL loading, and package.json adds cross-env for environment variable configuration needed for the electron-dev script.
Out of Scope Changes check ✅ Passed All code changes are scoped to fixing the electron development window issue: modifications to electron/main.cjs handle dev/prod server logic and electron/window creation, and package.json adds only the necessary cross-env dependency.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 8

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Inline comments:
In `@electron/main.cjs`:
- Around line 26-48: startProductionServer currently spawns the server but has
no error/exit handling or cleanup, so add robust spawn failure monitoring: when
calling spawn in startProductionServer attach 'error' and 'exit' listeners on
serverProcess to log the error/exit code and reject/throw so the caller can
handle it, and ensure you kill/cleanup the process on failure; also wrap the
spawn+waitForServer sequence so if waitForServer times out or rejects you
terminate serverProcess and propagate the error. Reference:
startProductionServer, serverProcess, spawn, and waitForServer.
- Around line 59-62: The current BrowserWindow webPreferences dangerously enable
nodeIntegration and disable contextIsolation (webPreferences: { nodeIntegration:
true, contextIsolation: false }), creating a critical security risk; change
these to safe defaults (nodeIntegration: false, contextIsolation: true), add a
preload script (pass preload path in webPreferences.preload) and move any
required Node APIs into a limited contextBridge API inside that preload so
renderer access is explicit and minimal; update any renderer code that relied on
global Node APIs to use the new exposed preload methods instead.
- Around line 13-23: The waitForServer function currently polls forever; update
waitForServer to accept an optional timeoutMs (default e.g. 30_000) and return a
Promise that rejects with a clear Error if the server hasn't responded within
that timeout. Implement a timer (setTimeout) that rejects after timeoutMs and
ensure you clear that timer and any pending retries when http.get succeeds
(resolve) or when rejecting; keep the existing retry logic (check and
setTimeout(check, 500)) but stop retries on reject/resolve. Reference
waitForServer and the inner http.get/.on('error') handler so you replace the
infinite polling with a timeout-aware implementation that provides a descriptive
error (including the URL and timeout) when it fails.
- Around line 67-85: The catch block for the window load sequence only logs
errors to console, leaving users with a blank window; update the error handling
in the try/catch around waitForServer/startProductionServer and
mainWindow.loadURL to show a user-facing error dialog and/or load a local error
HTML page: use Electron's dialog (e.g., dialog.showErrorBox or
dialog.showMessageBox) to display a clear message containing the error and a
friendly title, and as a fallback call mainWindow.loadFile or mainWindow.loadURL
to display an embedded error page; reference the existing symbols mainWindow,
waitForServer, startProductionServer, DEV_URL and mainWindow.loadURL when
implementing the dialog and fallback load.
- Line 65: The call to mainWindow.webContents.openDevTools() should only run in
development; update the code around where mainWindow is created so that
openDevTools() is invoked conditionally (e.g., guard it with a development check
such as process.env.NODE_ENV === 'development' or an isDev/isElectronDev flag or
using electron-is-dev) and ensure no DevTools are opened when running production
builds; locate the call to mainWindow.webContents.openDevTools() and wrap it in
that dev-only conditional (or replace it with a helper like isDev &&
mainWindow.webContents.openDevTools()).
- Around line 40-44: Replace the hardcoded env values HOST and PORT in the
spawned process env (the object that currently spreads ...process.env and sets
HOST: '0.0.0.0' and PORT: '3000') so they are read from the shared server
configuration file (src/server-config.json) instead; load/require the JSON (or
import) at top of the module, pull host and port values (e.g., config.host and
config.port) and use those to set the env.HOST and env.PORT before spawning the
production server, and apply the same replacement for the other occurrence
referenced near line 79 so both spawn sites use the single source of truth
config.
- Around line 27-33: The current construction of serverPath always assumes an
ASAR-unpacked layout (serverPath built from process.resourcesPath +
'app.asar.unpacked' + '.output/server/index.mjs'); update it to check for the
presence of the ASAR-unpacked path and fall back to the non-ASAR layout (e.g.,
process.resourcesPath + '.output/server/index.mjs') when app.asar.unpacked is
absent or the file doesn't exist. Modify the code that sets serverPath
(referencing serverPath and process.resourcesPath and the 'app.asar.unpacked'
segment) to attempt the unpacked path first and then a fallback path, using a
synchronous existence check or try/catch to select the correct path at runtime.

In `@package.json`:
- Line 13: The electron-dev npm script hardcodes port 3000 which couples it to
src/server-config.json; update the script to read the frontend port dynamically
(or at minimum document the dependency). Replace the current "electron-dev"
entry with a tiny Node helper (e.g., scripts/run-electron-dev.js) that requires
../src/server-config.json, builds the URL from config.frontendPort, and spawns
the concurrently command using that URL (or add a clear comment by the
electron-dev script referencing src/server-config.json frontendPort and noting
the required port if you prefer the simpler change). Ensure the helper is
referenced from package.json as "electron-dev": "node
scripts/run-electron-dev.js" and that the helper uses the built URL for both
wait-on and VITE_DEV_SERVER_URL.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Path: .coderabbit.yaml

Review profile: ASSERTIVE

Plan: Pro

Run ID: 2ad2e5dc-f80d-4757-8723-5d06bac6b6a2

📥 Commits

Reviewing files that changed from the base of the PR and between 4932b6f and 32e8638.

📒 Files selected for processing (2)
  • electron/main.cjs
  • package.json

Comment thread electron/main.cjs
Comment on lines 13 to 23
function waitForServer(url) {
return new Promise((resolve) => {
const check = () => {
http
.get(url, () => resolve())
.on('error', () => setTimeout(check, 500));
};

check();
});
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add timeout to prevent indefinite hang.

The waitForServer function polls indefinitely without a timeout. If the server fails to start (e.g., port already in use, server crash, misconfiguration), the Electron app will hang forever without feedback to the user.

⏱️ Add configurable timeout with clear error
-function waitForServer(url) {
+function waitForServer(url, timeoutMs = 30000) {
   return new Promise((resolve, reject) => {
+    const startTime = Date.now();
     const check = () => {
+      if (Date.now() - startTime > timeoutMs) {
+        return reject(new Error(`Server at ${url} did not start within ${timeoutMs}ms`));
+      }
       http
         .get(url, () => resolve())
         .on('error', () => setTimeout(check, 500));
     };
 
     check();
   });
 }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` around lines 13 - 23, The waitForServer function currently
polls forever; update waitForServer to accept an optional timeoutMs (default
e.g. 30_000) and return a Promise that rejects with a clear Error if the server
hasn't responded within that timeout. Implement a timer (setTimeout) that
rejects after timeoutMs and ensure you clear that timer and any pending retries
when http.get succeeds (resolve) or when rejecting; keep the existing retry
logic (check and setTimeout(check, 500)) but stop retries on reject/resolve.
Reference waitForServer and the inner http.get/.on('error') handler so you
replace the infinite polling with a timeout-aware implementation that provides a
descriptive error (including the URL and timeout) when it fails.

Comment thread electron/main.cjs
Comment on lines +26 to +48
async function startProductionServer() {
const serverPath = path.join(
process.resourcesPath,
'app.asar.unpacked',
'.output',
'server',
'index.mjs'
);

console.log('Starting production server:', serverPath);

serverProcess = spawn('node', [serverPath], {
stdio: 'inherit',
windowsHide: true,
env: {
...process.env,
HOST: '0.0.0.0',
PORT: '3000',
},
});
}

// Create window
function createWindow() {
if (mainWindow) return;
await waitForServer('http://localhost:3000');
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

Add error handling for production server spawn failures.

The startProductionServer function spawns the Node.js server process but does not handle spawn errors or server crashes. If the server executable is missing, Node.js is unavailable, or the server exits immediately due to an error, the function will either hang (waiting for a server that never starts) or silently fail, leaving the user with a non-functional app.

🛡️ Add spawn error handling and process monitoring
 async function startProductionServer() {
   const serverPath = path.join(
     process.resourcesPath,
     'app.asar.unpacked',
     '.output',
     'server',
     'index.mjs'
   );
 
   console.log('Starting production server:', serverPath);
 
   serverProcess = spawn('node', [serverPath], {
     stdio: 'inherit',
     windowsHide: true,
     env: {
       ...process.env,
       HOST: '0.0.0.0',
       PORT: '3000',
     },
   });
+
+  serverProcess.on('error', (err) => {
+    console.error('Failed to start server process:', err);
+    throw err;
+  });
+
+  serverProcess.on('exit', (code, signal) => {
+    if (code !== null && code !== 0) {
+      console.error(`Server process exited with code ${code}`);
+    }
+    if (signal) {
+      console.error(`Server process killed by signal ${signal}`);
+    }
+  });
 
   await waitForServer('http://localhost:3000');
 }
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
async function startProductionServer() {
const serverPath = path.join(
process.resourcesPath,
'app.asar.unpacked',
'.output',
'server',
'index.mjs'
);
console.log('Starting production server:', serverPath);
serverProcess = spawn('node', [serverPath], {
stdio: 'inherit',
windowsHide: true,
env: {
...process.env,
HOST: '0.0.0.0',
PORT: '3000',
},
});
}
// Create window
function createWindow() {
if (mainWindow) return;
await waitForServer('http://localhost:3000');
}
async function startProductionServer() {
const serverPath = path.join(
process.resourcesPath,
'app.asar.unpacked',
'.output',
'server',
'index.mjs'
);
console.log('Starting production server:', serverPath);
serverProcess = spawn('node', [serverPath], {
stdio: 'inherit',
windowsHide: true,
env: {
...process.env,
HOST: '0.0.0.0',
PORT: '3000',
},
});
serverProcess.on('error', (err) => {
console.error('Failed to start server process:', err);
throw err;
});
serverProcess.on('exit', (code, signal) => {
if (code !== null && code !== 0) {
console.error(`Server process exited with code ${code}`);
}
if (signal) {
console.error(`Server process killed by signal ${signal}`);
}
});
await waitForServer('http://localhost:3000');
}
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` around lines 26 - 48, startProductionServer currently
spawns the server but has no error/exit handling or cleanup, so add robust spawn
failure monitoring: when calling spawn in startProductionServer attach 'error'
and 'exit' listeners on serverProcess to log the error/exit code and
reject/throw so the caller can handle it, and ensure you kill/cleanup the
process on failure; also wrap the spawn+waitForServer sequence so if
waitForServer times out or rejects you terminate serverProcess and propagate the
error. Reference: startProductionServer, serverProcess, spawn, and
waitForServer.

Comment thread electron/main.cjs
Comment on lines +27 to +33
const serverPath = path.join(
process.resourcesPath,
'app.asar.unpacked',
'.output',
'server',
'index.mjs'
);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial

🧩 Analysis chain

🏁 Script executed:

#!/bin/bash
# Verify that electron-builder config correctly unpacks .output for the production server path

# Check that .output is in asarUnpack array
jq -e '.build.asarUnpack | any(. == ".output/**/*")' package.json

if [ $? -eq 0 ]; then
  echo "✓ .output is configured for ASAR unpacking"
else
  echo "✗ WARNING: .output is not in asarUnpack - production server path will fail"
fi

# Also check extraResources
jq -e '.build.extraResources | any(.from == ".output")' package.json

if [ $? -eq 0 ]; then
  echo "✓ .output is in extraResources"
else
  echo "✗ .output is not in extraResources"
fi

Repository: AOSSIE-Org/Rein

Length of output: 143


Server path matches current electron-builder ASAR-unpack config for .output

package.json configures build.asarUnpack to include .output/**/* and also ships .output via build.extraResources, which makes process.resourcesPath/app.asar.unpacked/.output/server/index.mjs in electron/main.cjs consistent with the current packaging setup.
Optional: add a fallback/guard for non-ASAR or layout changes (e.g., process.resourcesPath/.output/... when app.asar.unpacked is absent).

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` around lines 27 - 33, The current construction of
serverPath always assumes an ASAR-unpacked layout (serverPath built from
process.resourcesPath + 'app.asar.unpacked' + '.output/server/index.mjs');
update it to check for the presence of the ASAR-unpacked path and fall back to
the non-ASAR layout (e.g., process.resourcesPath + '.output/server/index.mjs')
when app.asar.unpacked is absent or the file doesn't exist. Modify the code that
sets serverPath (referencing serverPath and process.resourcesPath and the
'app.asar.unpacked' segment) to attempt the unpacked path first and then a
fallback path, using a synchronous existence check or try/catch to select the
correct path at runtime.

Comment thread electron/main.cjs
Comment on lines +40 to +44
env: {
...process.env,
HOST: '0.0.0.0',
PORT: '3000',
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🛠️ Refactor suggestion | 🟠 Major | ⚡ Quick win

Hardcoded HOST and PORT create maintenance risk.

The production server spawn hardcodes HOST: '0.0.0.0' and PORT: '3000', while the actual server configuration is defined in src/server-config.json. This duplication creates a maintenance risk: if the port or host in server-config.json is changed, the Electron app will attempt to connect to the wrong endpoint and fail to load.

♻️ Load configuration from server-config.json
+const serverConfig = require('../src/server-config.json');
+
 async function startProductionServer() {
   const serverPath = path.join(
     process.resourcesPath,
     'app.asar.unpacked',
     '.output',
     'server',
     'index.mjs'
   );
 
   console.log('Starting production server:', serverPath);
 
   serverProcess = spawn('node', [serverPath], {
     stdio: 'inherit',
     windowsHide: true,
     env: {
       ...process.env,
-      HOST: '0.0.0.0',
-      PORT: '3000',
+      HOST: serverConfig.host,
+      PORT: String(serverConfig.frontendPort),
     },
   });
 
-  await waitForServer('http://localhost:3000');
+  await waitForServer(`http://localhost:${serverConfig.frontendPort}`);
 }

Then update line 79 as well:

-      await mainWindow.loadURL("http://localhost:3000");
+      await mainWindow.loadURL(`http://localhost:${serverConfig.frontendPort}`);
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
env: {
...process.env,
HOST: '0.0.0.0',
PORT: '3000',
},
const serverConfig = require('../src/server-config.json');
async function startProductionServer() {
const serverPath = path.join(
process.resourcesPath,
'app.asar.unpacked',
'.output',
'server',
'index.mjs'
);
console.log('Starting production server:', serverPath);
serverProcess = spawn('node', [serverPath], {
stdio: 'inherit',
windowsHide: true,
env: {
...process.env,
HOST: serverConfig.host,
PORT: String(serverConfig.frontendPort),
},
});
await waitForServer(`http://localhost:${serverConfig.frontendPort}`);
}
Suggested change
env: {
...process.env,
HOST: '0.0.0.0',
PORT: '3000',
},
await mainWindow.loadURL(`http://localhost:${serverConfig.frontendPort}`);
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` around lines 40 - 44, Replace the hardcoded env values
HOST and PORT in the spawned process env (the object that currently spreads
...process.env and sets HOST: '0.0.0.0' and PORT: '3000') so they are read from
the shared server configuration file (src/server-config.json) instead;
load/require the JSON (or import) at top of the module, pull host and port
values (e.g., config.host and config.port) and use those to set the env.HOST and
env.PORT before spawning the production server, and apply the same replacement
for the other occurrence referenced near line 79 so both spawn sites use the
single source of truth config.

Comment thread electron/main.cjs
Comment on lines +59 to +62
webPreferences: {
nodeIntegration: true,
contextIsolation: false,
},

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

⚠️ Potential issue | 🔴 Critical | 🏗️ Heavy lift

Critical security risk: nodeIntegration enabled with contextIsolation disabled.

Enabling nodeIntegration: true and disabling contextIsolation: false allows the renderer process (which loads web content) to directly access Node.js APIs and Electron internals. This creates a severe security vulnerability: any XSS attack or malicious code execution in the web content can gain full system access. If the app loads any external content, user-generated content, or has any XSS vulnerability, an attacker can execute arbitrary code with full Node.js privileges.

Recommended mitigation:

  • Set nodeIntegration: false and contextIsolation: true (secure defaults)
  • If you need Node.js functionality in the renderer, use a preload script with contextBridge to expose only the specific APIs needed
  • Review Electron's security guidelines: https://www.electronjs.org/docs/latest/tutorial/security
🔒 Secure webPreferences configuration
     webPreferences: {
-      nodeIntegration: true,
-      contextIsolation: false,
+      nodeIntegration: false,
+      contextIsolation: true,
+      preload: path.join(__dirname, 'preload.cjs'), // Create preload script if needed
     },
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` around lines 59 - 62, The current BrowserWindow
webPreferences dangerously enable nodeIntegration and disable contextIsolation
(webPreferences: { nodeIntegration: true, contextIsolation: false }), creating a
critical security risk; change these to safe defaults (nodeIntegration: false,
contextIsolation: true), add a preload script (pass preload path in
webPreferences.preload) and move any required Node APIs into a limited
contextBridge API inside that preload so renderer access is explicit and
minimal; update any renderer code that relied on global Node APIs to use the new
exposed preload methods instead.

Comment thread electron/main.cjs
// Debug only if needed
mainWindow.webContents.on('did-fail-load', (e, code, desc) => {
console.log("LOAD FAILED:", code, desc);
mainWindow.webContents.openDevTools();

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Remove automatic DevTools in production builds.

Opening DevTools automatically (mainWindow.webContents.openDevTools()) is useful for development but should not be enabled in production builds. This exposes internal application details to end users and creates a poor user experience.

🔧 Conditionally open DevTools only in dev mode
-  mainWindow.webContents.openDevTools();
+  if (isDev) {
+    mainWindow.webContents.openDevTools();
+  }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` at line 65, The call to
mainWindow.webContents.openDevTools() should only run in development; update the
code around where mainWindow is created so that openDevTools() is invoked
conditionally (e.g., guard it with a development check such as
process.env.NODE_ENV === 'development' or an isDev/isElectronDev flag or using
electron-is-dev) and ensure no DevTools are opened when running production
builds; locate the call to mainWindow.webContents.openDevTools() and wrap it in
that dev-only conditional (or replace it with a helper like isDev &&
mainWindow.webContents.openDevTools()).

Comment thread electron/main.cjs
Comment on lines +67 to +85
try {
if (isDev) {
console.log("Loading DEV URL:", DEV_URL);

await waitForServer(DEV_URL);

await mainWindow.loadURL(DEV_URL);
} else {
console.log("Loading PROD URL");

await startProductionServer();

await mainWindow.loadURL("http://localhost:3000");
}

console.log("WINDOW LOADED");
} catch (err) {
console.error("LOAD ERROR:", err);
}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Improve error handling with user-facing feedback.

The current error handling logs to console but provides no feedback to the user when the window fails to load. If the server fails to start or the URL fails to load, the user sees a blank window with no indication of what went wrong.

📢 Show error dialog on load failure
+  const { dialog } = require('electron');
+
   try {
     if (isDev) {
       console.log("Loading DEV URL:", DEV_URL);
 
       await waitForServer(DEV_URL);
 
       await mainWindow.loadURL(DEV_URL);
     } else {
       console.log("Loading PROD URL");
 
       await startProductionServer();
 
       await mainWindow.loadURL("http://localhost:3000");
     }
 
     console.log("WINDOW LOADED");
   } catch (err) {
     console.error("LOAD ERROR:", err);
+    dialog.showErrorBox(
+      'Failed to Start Application',
+      `The application failed to start: ${err.message}\n\nPlease check the logs for details.`
+    );
+    app.quit();
   }
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@electron/main.cjs` around lines 67 - 85, The catch block for the window load
sequence only logs errors to console, leaving users with a blank window; update
the error handling in the try/catch around waitForServer/startProductionServer
and mainWindow.loadURL to show a user-facing error dialog and/or load a local
error HTML page: use Electron's dialog (e.g., dialog.showErrorBox or
dialog.showMessageBox) to display a clear message containing the error and a
friendly title, and as a fallback call mainWindow.loadFile or mainWindow.loadURL
to display an embedded error page; reference the existing symbols mainWindow,
waitForServer, startProductionServer, DEV_URL and mainWindow.loadURL when
implementing the dialog and fallback load.

Comment thread package.json
"build": "vite build",
"electron": "npx electron .",
"electron-dev": "concurrently \"vite\" \"wait-on http://localhost:3000 && VITE_DEV_SERVER_URL=http://localhost:3000 electron .\"",
"electron-dev": "concurrently \"vite\" \"wait-on http://localhost:3000 && cross-env VITE_DEV_SERVER_URL=http://localhost:3000 electron .\"",

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick | 🔵 Trivial | ⚡ Quick win

Script synchronization assumes Vite dev server URL matches hardcoded value.

The electron-dev script waits for http://localhost:3000, then sets VITE_DEV_SERVER_URL=http://localhost:3000 when launching Electron. However, if the Vite dev server is configured to run on a different port (e.g., via vite.config.ts or command-line flags), the script will wait for the wrong URL and potentially hang or connect to an incorrect server.

This is currently correct based on src/server-config.json (frontendPort: 3000), but creates a maintenance coupling between the script and the config file.

Consider reading the port from server-config.json dynamically, or at minimum, add a comment documenting the port dependency:

📝 Document port dependency
-		"electron-dev": "concurrently \"vite\" \"wait-on http://localhost:3000 && cross-env VITE_DEV_SERVER_URL=http://localhost:3000 electron .\"",
+		"electron-dev": "concurrently \"vite\" \"wait-on http://localhost:3000 && cross-env VITE_DEV_SERVER_URL=http://localhost:3000 electron .\"",
+		"_comment_electron-dev": "Port 3000 must match frontendPort in src/server-config.json",

Or for a more robust solution, use a small helper script to read the port:

"electron-dev": "node scripts/run-electron-dev.js"
// scripts/run-electron-dev.js
const { spawn } = require('child_process');
const config = require('../src/server-config.json');
const port = config.frontendPort;
const url = `http://localhost:${port}`;

spawn('concurrently', [
  '"vite"',
  `"wait-on ${url} && cross-env VITE_DEV_SERVER_URL=${url} electron ."`
], { stdio: 'inherit', shell: true });
📝 Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.

Suggested change
"electron-dev": "concurrently \"vite\" \"wait-on http://localhost:3000 && cross-env VITE_DEV_SERVER_URL=http://localhost:3000 electron .\"",
"electron-dev": "concurrently \"vite\" \"wait-on http://localhost:3000 && cross-env VITE_DEV_SERVER_URL=http://localhost:3000 electron .\"",
"_comment_electron-dev": "Port 3000 must match frontendPort in src/server-config.json",
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@package.json` at line 13, The electron-dev npm script hardcodes port 3000
which couples it to src/server-config.json; update the script to read the
frontend port dynamically (or at minimum document the dependency). Replace the
current "electron-dev" entry with a tiny Node helper (e.g.,
scripts/run-electron-dev.js) that requires ../src/server-config.json, builds the
URL from config.frontendPort, and spawns the concurrently command using that URL
(or add a clear comment by the electron-dev script referencing
src/server-config.json frontendPort and noting the required port if you prefer
the simpler change). Ensure the helper is referenced from package.json as
"electron-dev": "node scripts/run-electron-dev.js" and that the helper uses the
built URL for both wait-on and VITE_DEV_SERVER_URL.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[Bug]: npm run electron not working

1 participant