From 45a9555380560f436826aea04eed07152986c96f Mon Sep 17 00:00:00 2001 From: ErickHub192 Date: Tue, 4 Aug 2026 11:16:27 -0600 Subject: [PATCH] El preview no arranca en Windows y tumba el server Levantar Multi en Windows sin Docker truena con "spawn npm ENOENT" en cuanto una sala intenta arrancar su preview. En Windows el ejecutable se llama npm.cmd, no npm: sin shell, spawn busca un archivo llamado "npm", no lo encuentra y falla. Dentro del contenedor no pasaba porque ahi es Linux, pero el camino sin Docker corre en la maquina de quien levanto Multi, y esa puede ser Windows. Lo grave no era eso. Nadie escuchaba el evento 'error' del proceso, asi que Node lo trataba como excepcion no capturada y se llevaba el server COMPLETO. Una sala que no podia arrancar su preview tiraba a todas las demas y sacaba a la gente que estaba adentro. Ahora se registra el fallo y esa sala se queda sin preview, nada mas. Visto al levantarlo en PowerShell para compartir por tunel. --- server/src/engine/preview.ts | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/server/src/engine/preview.ts b/server/src/engine/preview.ts index 69a00d3..1ff6467 100644 --- a/server/src/engine/preview.ts +++ b/server/src/engine/preview.ts @@ -173,14 +173,28 @@ export async function startPreview( : spawn(command, args, { cwd: launch.cwd ?? workspace.dir, env: { ...process.env, ...(portEnv ? { [portEnv]: String(port) } : {}) }, - // stdout/stderr capturados para logs y para detectar arranque; sin shell. + // stdout/stderr capturados para logs y para detectar el arranque. stdio: ["ignore", "pipe", "pipe"], + // Con shell porque en Windows el ejecutable es npm.cmd, no npm: sin esto + // spawn busca un archivo llamado "npm", no lo encuentra y truena con + // ENOENT. Dentro del contenedor da igual (es Linux), pero el camino sin + // Docker corre en la máquina de quien levantó Multi, y esa puede ser + // Windows. + shell: process.platform === "win32", }); const tag = `[preview ${workspace.roomId}:${port}]`; child.stdout?.on("data", (d) => process.stdout.write(`${tag} ${d}`)); child.stderr?.on("data", (d) => process.stderr.write(`${tag} ${d}`)); + // Un fallo al LANZAR el proceso (comando inexistente, permisos) llega como + // evento 'error'. Sin este listener Node lo trata como excepción no capturada + // y se lleva el server entero: una sala que no puede arrancar su preview + // tiraba a todas las demás y a la gente que estaba adentro. + child.on("error", (err) => { + console.error(`${tag} no se pudo arrancar el dev server:`, err.message); + }); + const url = `http://localhost:${port}`; const stop = async (): Promise => {