first commit

This commit is contained in:
2026-07-12 15:55:18 +05:30
commit ee98026cc5
404 changed files with 44522 additions and 0 deletions
+75
View File
@@ -0,0 +1,75 @@
/**
* In-process file watcher (dev). Classifies each change and chooses the
* cheapest update that still shows the latest page:
*
* *.css / styles/ -> invalidate CSS cache, push { type: "css" } (instant swap)
* anything else -> a server module changed (pages, components, api, …):
* it can't be re-imported in process, so request a
* restart (the supervisor respawns us; the browser then
* morphs in the new HTML).
*/
import { watch, type FSWatcher } from "node:fs";
import type { HmrHub } from "./hmr.ts";
import type { DevAssetServer } from "./assets.ts";
export interface WatchOptions {
appDir: string;
hub: HmrHub;
assets: DevAssetServer;
/** Called when a change requires a fresh process. */
onServerChange: () => void;
}
function isIgnored(rel: string): boolean {
return (
rel.includes("node_modules/") ||
rel.includes(".wrnexus/") ||
rel.startsWith("dist/") ||
rel.includes("/dist/")
);
}
type Kind = "css" | "server";
function classify(rel: string): Kind {
if (rel.endsWith(".css") || rel.startsWith("styles/") || rel.includes("/styles/")) return "css";
return "server";
}
/** Returns the watcher so the caller can close it before a restart (important on
* Windows, where a live recursive fs.watch handle can block `process.exit`). */
export function startWatcher(opts: WatchOptions): FSWatcher | undefined {
const { appDir, hub, assets, onServerChange } = opts;
const pending = new Set<Kind>();
let timer: ReturnType<typeof setTimeout> | null = null;
const flush = (): void => {
timer = null;
// A server change always wins (needs a restart).
if (pending.has("server")) {
pending.clear();
onServerChange();
return;
}
if (pending.has("css")) {
assets.invalidateCss();
hub.css();
}
pending.clear();
};
try {
return watch(appDir, { recursive: true }, (_event, filename) => {
if (!filename) return;
const rel = filename.toString().replace(/\\/g, "/");
if (isIgnored(rel)) return;
pending.add(classify(rel));
if (timer) clearTimeout(timer);
timer = setTimeout(flush, 60); // debounce editor write bursts
});
} catch (err) {
console.warn("[wrnexus] file watching unavailable; HMR disabled", err);
return undefined;
}
}