Skip to content

Commit d2c38da

Browse files
committed
Fix automatic dependency installation on app startup
- Make installDependencies() function properly reject on failure instead of silently continuing - Add pre-startup dependency checks for both fullstack and single-server frontend apps - Verify vite package exists before attempting to start frontend server - Provide clear error messages when dependencies cannot be installed - Prevent server crashes due to missing packages like vite
1 parent 0d617d1 commit d2c38da

File tree

1 file changed

+98
-10
lines changed

1 file changed

+98
-10
lines changed

src/ipc/handlers/app_handlers.ts

Lines changed: 98 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -293,10 +293,38 @@ async function executeAppLocalNode({
293293
// Ensure frontend dependencies are installed
294294
try {
295295
logger.info(`Ensuring frontend dependencies are installed in ${frontendPath}`);
296-
await installDependencies(frontendPath, "nodejs");
296+
297+
// Check if node_modules exists and has basic packages
298+
const hasNodeModules = fs.existsSync(path.join(frontendPath, "node_modules"));
299+
const hasVite = hasNodeModules && fs.existsSync(path.join(frontendPath, "node_modules", "vite"));
300+
301+
if (!hasVite) {
302+
logger.info(`Frontend dependencies not found or incomplete, installing...`);
303+
await installDependencies(frontendPath, "nodejs");
304+
305+
// Double-check that vite was installed
306+
const viteInstalled = fs.existsSync(path.join(frontendPath, "node_modules", "vite"));
307+
if (!viteInstalled) {
308+
logger.error(`Failed to install vite dependency in ${frontendPath}`);
309+
safeSend(event.sender, "app:output", {
310+
type: "stdout",
311+
message: `❌ Failed to install frontend dependencies. Please run 'npm install' manually in the frontend directory.`,
312+
appId,
313+
});
314+
return;
315+
}
316+
logger.info(`Frontend dependencies installed successfully`);
317+
} else {
318+
logger.info(`Frontend dependencies already installed, skipping installation`);
319+
}
297320
} catch (error) {
298-
logger.warn(`Failed to install frontend dependencies: ${error}`);
299-
// Continue anyway - the dev server might still work
321+
logger.error(`Failed to install frontend dependencies: ${error}`);
322+
safeSend(event.sender, "app:output", {
323+
type: "stdout",
324+
message: `❌ Failed to install frontend dependencies: ${error instanceof Error ? error.message : String(error)}. Please run 'npm install' manually in the frontend directory.`,
325+
appId,
326+
});
327+
return;
300328
}
301329

302330
// Determine backend framework for proper server command
@@ -370,6 +398,17 @@ async function executeAppLocalNode({
370398

371399
// Start frontend server
372400
try {
401+
// Double-check that we have the necessary dependencies before starting
402+
const viteAvailable = fs.existsSync(path.join(frontendPath, "node_modules", "vite"));
403+
if (!viteAvailable) {
404+
safeSend(event.sender, "app:output", {
405+
type: "stdout",
406+
message: `❌ Cannot start frontend server: vite package not found. Please ensure dependencies are installed.`,
407+
appId,
408+
});
409+
return;
410+
}
411+
373412
const frontendCommand = `npx vite --port ${frontendPort} --host`;
374413
const frontendProcess = spawn(frontendCommand, [], {
375414
cwd: frontendPath,
@@ -435,6 +474,26 @@ async function executeAppLocalNode({
435474
workingDir = frontendPath;
436475
serverPort = await findAvailablePort(32100);
437476
modeMessage = `Running in frontend mode - Starting frontend server on port ${serverPort}...`;
477+
478+
// Ensure frontend dependencies are installed for frontend-only apps
479+
try {
480+
logger.info(`Ensuring frontend dependencies are installed in ${frontendPath}`);
481+
const hasNodeModules = fs.existsSync(path.join(frontendPath, "node_modules"));
482+
const hasVite = hasNodeModules && fs.existsSync(path.join(frontendPath, "node_modules", "vite"));
483+
484+
if (!hasVite) {
485+
logger.info(`Frontend dependencies not found or incomplete, installing...`);
486+
await installDependencies(frontendPath, "nodejs");
487+
}
488+
} catch (error) {
489+
logger.error(`Failed to install frontend dependencies: ${error}`);
490+
safeSend(event.sender, "app:output", {
491+
type: "stdout",
492+
message: `❌ Failed to install frontend dependencies: ${error instanceof Error ? error.message : String(error)}. Please run 'npm install' manually in the frontend directory.`,
493+
appId,
494+
});
495+
return;
496+
}
438497
} else if (hasBackend && !hasFrontend) {
439498
// Only backend exists (backend-only app)
440499
workingDir = backendPath;
@@ -448,6 +507,26 @@ async function executeAppLocalNode({
448507
workingDir = frontendPath;
449508
serverPort = await findAvailablePort(32100);
450509
modeMessage = `Running in frontend mode - Starting frontend server on port ${serverPort}...`;
510+
511+
// Ensure frontend dependencies are installed for frontend apps
512+
try {
513+
logger.info(`Ensuring frontend dependencies are installed in ${frontendPath}`);
514+
const hasNodeModules = fs.existsSync(path.join(frontendPath, "node_modules"));
515+
const hasVite = hasNodeModules && fs.existsSync(path.join(frontendPath, "node_modules", "vite"));
516+
517+
if (!hasVite) {
518+
logger.info(`Frontend dependencies not found or incomplete, installing...`);
519+
await installDependencies(frontendPath, "nodejs");
520+
}
521+
} catch (error) {
522+
logger.error(`Failed to install frontend dependencies: ${error}`);
523+
safeSend(event.sender, "app:output", {
524+
type: "stdout",
525+
message: `❌ Failed to install frontend dependencies: ${error instanceof Error ? error.message : String(error)}. Please run 'npm install' manually in the frontend directory.`,
526+
appId,
527+
});
528+
return;
529+
}
451530
} else if (hasBackend) {
452531
// Only backend exists
453532
workingDir = backendPath;
@@ -470,6 +549,16 @@ async function executeAppLocalNode({
470549

471550
// For frontend, override with dynamic port and host binding for proxy access
472551
if (workingDir === frontendPath && serverPort > 0) {
552+
// Double-check that we have the necessary dependencies before starting
553+
const viteAvailable = fs.existsSync(path.join(frontendPath, "node_modules", "vite"));
554+
if (!viteAvailable) {
555+
safeSend(event.sender, "app:output", {
556+
type: "stdout",
557+
message: `❌ Cannot start frontend server: vite package not found. Please ensure dependencies are installed.`,
558+
appId,
559+
});
560+
return;
561+
}
473562
command = `npx vite --port ${serverPort} --host`;
474563
}
475564

@@ -2301,17 +2390,16 @@ async function installDependencies(projectPath: string, framework: string) {
23012390
logger.info(`Successfully installed dependencies for ${framework}`);
23022391
resolve();
23032392
} else {
2304-
logger.warn(`Dependency installation failed for ${framework} (code: ${code}): ${installError}`);
2305-
// Don't reject here - we want to continue even if installation fails
2306-
// as the framework files are still created and user can install manually
2307-
resolve();
2393+
const errorMsg = `Dependency installation failed for ${framework} (code: ${code}): ${installError}`;
2394+
logger.error(errorMsg);
2395+
reject(new Error(errorMsg));
23082396
}
23092397
});
23102398

23112399
installProcess.on("error", (err) => {
2312-
logger.error(`Failed to start dependency installation for ${framework}:`, err);
2313-
// Don't reject here for the same reason as above
2314-
resolve();
2400+
const errorMsg = `Failed to start dependency installation for ${framework}: ${err.message}`;
2401+
logger.error(errorMsg);
2402+
reject(new Error(errorMsg));
23152403
});
23162404
});
23172405
}

0 commit comments

Comments
 (0)