feat: improve Windows cache management and enhance FastAPI/Next.js logging in the Electron app

This commit is contained in:
sudipnext 2026-03-06 19:08:28 +05:45
parent 52b37335ea
commit 047ddf284e
2 changed files with 67 additions and 13 deletions

View file

@ -1,6 +1,7 @@
require("dotenv").config();
import { app, BrowserWindow } from "electron";
import path from "path";
import fs from "fs";
import { findUnusedPorts, killProcess, setupEnv, setUserConfig } from "./utils";
import { startFastApiServer, startNextJsServer } from "./utils/servers";
import { ChildProcessByStdio } from "child_process";
@ -16,6 +17,30 @@ var nextjsProcess: any;
app.commandLine.appendSwitch('gtk-version', '3');
// Mitigate "Unable to move the cache: Access is denied" on Windows (Chromium disk cache).
// Use explicit cache paths and remove stale old_* dirs that cause move failures.
if (process.platform === "win32") {
const ud = app.getPath("userData");
const cacheBase = path.join(ud, "Cache");
const gpuCacheBase = path.join(ud, "GPUCache");
app.setPath("cache", cacheBase);
app.commandLine.appendSwitch("disk-cache-dir", cacheBase);
try {
[cacheBase, gpuCacheBase].forEach((dir) => {
if (fs.existsSync(dir)) {
const entries = fs.readdirSync(dir, { withFileTypes: true });
for (const e of entries) {
if (e.isDirectory() && e.name.startsWith("old_")) {
fs.rmSync(path.join(dir, e.name), { recursive: true, force: true });
}
}
}
});
} catch {
/* ignore cleanup errors */
}
}
const createWindow = () => {
win = new BrowserWindow({
width: 1280,

View file

@ -24,8 +24,22 @@ export async function startFastApiServer(
const binary = process.platform === "win32" ? "fastapi.exe" : "fastapi";
command = path.join(directory, binary);
args = ["--port", port.toString()];
if (!fs.existsSync(command)) {
throw new Error(
`FastAPI binary not found at ${command}. Rebuild the app for ${process.platform} or run in dev mode.`
);
}
}
const safeLog = (data: Buffer | string, logPath: string) => {
try {
fs.appendFileSync(logPath, data);
} catch {
/* ignore if logs dir not writable */
}
};
const fastapiLogPath = path.join(logsDir, "fastapi-server.log");
const fastApiProcess = spawn(
command,
args,
@ -36,13 +50,16 @@ export async function startFastApiServer(
}
);
fastApiProcess.stdout.on("data", (data: any) => {
fs.appendFileSync(path.join(logsDir, "fastapi-server.log"), data);
safeLog(data, fastapiLogPath);
console.log(`FastAPI: ${data}`);
});
fastApiProcess.stderr.on("data", (data: any) => {
fs.appendFileSync(path.join(logsDir, "fastapi-server.log"), data);
safeLog(data, fastapiLogPath);
console.error(`FastAPI: ${data}`);
});
fastApiProcess.on("error", (err) => {
safeLog(`Spawn error: ${err.message}\n`, fastapiLogPath);
});
// Wait for FastAPI server to start
await waitForServer(`${localhost}:${port}/docs`);
return fastApiProcess;
@ -67,17 +84,25 @@ export async function startNextJsServer(
env: { ...process.env, ...env },
}
);
const nextjsLogPath = path.join(logsDir, "nextjs-server.log");
const safeNextLog = (d: Buffer | string) => {
try {
fs.appendFileSync(nextjsLogPath, d);
} catch {
/* ignore */
}
};
nextjsProcess.stdout.on("data", (data: any) => {
fs.appendFileSync(path.join(logsDir, "nextjs-server.log"), data);
safeNextLog(data);
console.log(`NextJS: ${data}`);
});
nextjsProcess.stderr.on("data", (data: any) => {
fs.appendFileSync(path.join(logsDir, "nextjs-server.log"), data);
safeNextLog(data);
console.error(`NextJS: ${data}`);
});
} else {
// Start NextJS build server
nextjsProcess = startNextjsBuildServer(directory, port);
nextjsProcess = await startNextjsBuildServer(directory, port);
}
// Wait for NextJS server to start
@ -85,16 +110,20 @@ export async function startNextJsServer(
return nextjsProcess;
}
async function startNextjsBuildServer(directory: string, port: number) {
const server = http.createServer((req, res) => {
return handler(req, res, {
public: directory,
cleanUrls: true,
function startNextjsBuildServer(directory: string, port: number): Promise<http.Server> {
return new Promise((resolve, reject) => {
const server = http.createServer((req, res) => {
return handler(req, res, {
public: directory,
cleanUrls: true,
});
});
server.on("error", reject);
server.listen(port, () => {
server.off("error", reject);
resolve(server);
});
});
server.listen(port);
return server;
}