From 9ddf960312d53052762474d592fe3af4b7c4b1ce Mon Sep 17 00:00:00 2001 From: dotta Date: Thu, 26 Mar 2026 12:27:17 -0500 Subject: [PATCH] Harden dev-watch excludes for nested UI outputs Co-Authored-By: Paperclip --- server/scripts/dev-watch.ts | 2 +- server/src/__tests__/dev-watch-ignore.test.ts | 8 +++++++ server/src/dev-watch-ignore.ts | 21 ++++++++++++++++--- 3 files changed, 27 insertions(+), 4 deletions(-) diff --git a/server/scripts/dev-watch.ts b/server/scripts/dev-watch.ts index 69a85245..cfcb7a71 100644 --- a/server/scripts/dev-watch.ts +++ b/server/scripts/dev-watch.ts @@ -7,7 +7,7 @@ import { resolveServerDevWatchIgnorePaths } from "../src/dev-watch-ignore.ts"; const require = createRequire(import.meta.url); const tsxCliPath = require.resolve("tsx/dist/cli.mjs"); const serverRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); -const ignoreArgs = resolveServerDevWatchIgnorePaths(serverRoot).flatMap((ignorePath) => ["--ignore", ignorePath]); +const ignoreArgs = resolveServerDevWatchIgnorePaths(serverRoot).flatMap((ignorePath) => ["--exclude", ignorePath]); const child = spawn( process.execPath, diff --git a/server/src/__tests__/dev-watch-ignore.test.ts b/server/src/__tests__/dev-watch-ignore.test.ts index 0331f61b..4f54e609 100644 --- a/server/src/__tests__/dev-watch-ignore.test.ts +++ b/server/src/__tests__/dev-watch-ignore.test.ts @@ -25,10 +25,18 @@ describe("resolveServerDevWatchIgnorePaths", () => { const ignorePaths = resolveServerDevWatchIgnorePaths(serverRoot); expect(ignorePaths).toContain(path.join(worktreeUiRoot, "node_modules")); + expect(ignorePaths).toContain(`${path.join(worktreeUiRoot, "node_modules").replaceAll(path.sep, "/")}/**`); expect(ignorePaths).toContain(fs.realpathSync(path.join(sharedUiRoot, "node_modules"))); + expect(ignorePaths).toContain(`${fs.realpathSync(path.join(sharedUiRoot, "node_modules")).replaceAll(path.sep, "/")}/**`); + expect(ignorePaths).toContain(path.join(worktreeUiRoot, "node_modules", ".vite-temp")); + expect(ignorePaths).toContain( + `${path.join(worktreeUiRoot, "node_modules", ".vite-temp").replaceAll(path.sep, "/")}/**`, + ); expect(ignorePaths).toContain(path.join(worktreeUiRoot, ".vite")); expect(ignorePaths).toContain(fs.realpathSync(path.join(sharedUiRoot, ".vite"))); expect(ignorePaths).toContain(path.join(worktreeUiRoot, "dist")); expect(ignorePaths).toContain(fs.realpathSync(path.join(sharedUiRoot, "dist"))); + expect(ignorePaths).toContain("**/{node_modules,bower_components,vendor}/**"); + expect(ignorePaths).toContain("**/.vite-temp/**"); }); }); diff --git a/server/src/dev-watch-ignore.ts b/server/src/dev-watch-ignore.ts index 6e7d90ce..cd618f73 100644 --- a/server/src/dev-watch-ignore.ts +++ b/server/src/dev-watch-ignore.ts @@ -1,19 +1,34 @@ import fs from "node:fs"; import path from "node:path"; +function toGlobstarPath(candidate: string): string { + return `${candidate.replaceAll(path.sep, "/")}/**`; +} + function addIgnorePath(target: Set, candidate: string): void { target.add(candidate); + target.add(toGlobstarPath(candidate)); try { - target.add(fs.realpathSync(candidate)); + const realPath = fs.realpathSync(candidate); + target.add(realPath); + target.add(toGlobstarPath(realPath)); } catch { // Ignore paths that do not exist in the current checkout. } } export function resolveServerDevWatchIgnorePaths(serverRoot: string): string[] { - const ignorePaths = new Set(); + const ignorePaths = new Set([ + "**/{node_modules,bower_components,vendor}/**", + "**/.vite-temp/**", + ]); - for (const relativePath of ["../ui/node_modules", "../ui/.vite", "../ui/dist"]) { + for (const relativePath of [ + "../ui/node_modules", + "../ui/node_modules/.vite-temp", + "../ui/.vite", + "../ui/dist", + ]) { addIgnorePath(ignorePaths, path.resolve(serverRoot, relativePath)); }