From 6cdd103c3d10fef38858380c1f835cf3726831bd Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Sat, 21 Jun 2025 11:33:59 -0700 Subject: [PATCH] chore(dev): improve bulk change handling (#2234) Fixed abandoned build processes sometimes still triggering a start (causing double-starts) made it more robust in regards to webui changes being intermixed: making the fetch a fire-and-forget to avoid errors, and waiting for the websocket connection to be re-established to avoid the browser attempting to reload when the server may not be up for a few seconds. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2234 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- scripts/dev.js | 12 +++++++++--- .../webuiFileChangeDetectedController.ts | 3 +-- src/services/webService.ts | 1 + static/webui/script.js | 19 ++++++++++++++----- 4 files changed, 25 insertions(+), 10 deletions(-) diff --git a/scripts/dev.js b/scripts/dev.js index 1852a131..10d6ac36 100644 --- a/scripts/dev.js +++ b/scripts/dev.js @@ -28,8 +28,12 @@ function run(changedFile) { runproc = undefined; } - buildproc = spawn("npm", ["run", "build:dev"], { stdio: "inherit", shell: true }); + const thisbuildproc = spawn("npm", ["run", "build:dev"], { stdio: "inherit", shell: true }); + buildproc = thisbuildproc; buildproc.on("exit", code => { + if (buildproc !== thisbuildproc) { + return; + } buildproc = undefined; if (code === 0) { runproc = spawn("npm", ["run", "start", "--", ...args], { stdio: "inherit", shell: true }); @@ -44,6 +48,8 @@ run(); chokidar.watch("src").on("change", run); chokidar.watch("static/fixed_responses").on("change", run); -chokidar.watch("static/webui").on("change", () => { - fetch("http://localhost/custom/webuiFileChangeDetected?secret=" + secret); +chokidar.watch("static/webui").on("change", async () => { + try { + await fetch("http://localhost/custom/webuiFileChangeDetected?secret=" + secret); + } catch (e) {} }); diff --git a/src/controllers/custom/webuiFileChangeDetectedController.ts b/src/controllers/custom/webuiFileChangeDetectedController.ts index 3ec52a48..aa6af978 100644 --- a/src/controllers/custom/webuiFileChangeDetectedController.ts +++ b/src/controllers/custom/webuiFileChangeDetectedController.ts @@ -1,11 +1,10 @@ import { args } from "@/src/helpers/commandLineArguments"; -import { config } from "@/src/services/configService"; import { sendWsBroadcast } from "@/src/services/webService"; import { RequestHandler } from "express"; export const webuiFileChangeDetectedController: RequestHandler = (req, res) => { if (args.dev && args.secret && req.query.secret == args.secret) { - sendWsBroadcast({ ports: { http: config.httpPort, https: config.httpsPort } }); + sendWsBroadcast({ reload: true }); } res.end(); }; diff --git a/src/services/webService.ts b/src/services/webService.ts index 8beda45c..5a9251d2 100644 --- a/src/services/webService.ts +++ b/src/services/webService.ts @@ -110,6 +110,7 @@ interface IWsMsgFromClient { } interface IWsMsgToClient { + reload?: boolean; ports?: { http: number | undefined; https: number | undefined; diff --git a/static/webui/script.js b/static/webui/script.js index d61a7cb5..44f7ade0 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -9,9 +9,10 @@ /* eslint-disable @typescript-eslint/explicit-function-return-type */ let auth_pending = false, - did_initial_auth = false; + did_initial_auth = false, + ws_is_open = false; const sendAuth = isRegister => { - if (localStorage.getItem("email") && localStorage.getItem("password")) { + if (ws_is_open && localStorage.getItem("email") && localStorage.getItem("password")) { auth_pending = true; window.ws.send( JSON.stringify({ @@ -28,10 +29,18 @@ const sendAuth = isRegister => { function openWebSocket() { window.ws = new WebSocket("/custom/ws"); window.ws.onopen = () => { + ws_is_open = true; sendAuth(false); }; window.ws.onmessage = e => { const msg = JSON.parse(e.data); + if ("reload" in msg) { + setTimeout(() => { + getWebSocket().then(() => { + location.reload(); + }); + }, 100); + } if ("ports" in msg) { location.port = location.protocol == "https:" ? msg.ports.https : msg.ports.http; } @@ -72,7 +81,7 @@ function openWebSocket() { } }; window.ws.onclose = function () { - window.ws = undefined; + ws_is_open = false; setTimeout(openWebSocket, 3000); }; } @@ -82,7 +91,7 @@ function getWebSocket() { return new Promise(resolve => { let interval; interval = setInterval(() => { - if (window.ws) { + if (ws_is_open) { clearInterval(interval); resolve(window.ws); } @@ -117,7 +126,7 @@ function logout() { function doLogout() { logout(); - if (window.ws) { + if (ws_is_open) { // Unsubscribe from notifications about nonce invalidation window.ws.send(JSON.stringify({ logout: true })); }