feat: Implement new settings pages and refactor application layout and navigation with new components and hooks.
This commit is contained in:
83
web/build.ts
83
web/build.ts
@@ -135,6 +135,7 @@ const build = async () => {
|
||||
minify: true,
|
||||
target: "browser",
|
||||
sourcemap: "linked",
|
||||
publicPath: "/", // Use absolute paths for SPA routing compatibility
|
||||
define: {
|
||||
"process.env.NODE_ENV": JSON.stringify((cliConfig as any).watch ? "development" : "production"),
|
||||
},
|
||||
@@ -159,14 +160,86 @@ console.log(`\n✅ Build completed in ${buildTime}ms\n`);
|
||||
|
||||
if ((cliConfig as any).watch) {
|
||||
console.log("👀 Watching for changes...\n");
|
||||
// Keep the process alive for watch mode
|
||||
// Bun.build with watch:true handles the watching,
|
||||
// we just need to make sure the script doesn't exit.
|
||||
process.stdin.resume();
|
||||
|
||||
// Also, handle manual exit
|
||||
// Polling-based file watcher for Docker compatibility
|
||||
// Docker volumes don't propagate filesystem events (inotify) reliably
|
||||
const srcDir = path.join(process.cwd(), "src");
|
||||
const POLL_INTERVAL_MS = 1000;
|
||||
let lastMtimes = new Map<string, number>();
|
||||
let isRebuilding = false;
|
||||
|
||||
// Collect all file mtimes in src directory
|
||||
const collectMtimes = async (): Promise<Map<string, number>> => {
|
||||
const mtimes = new Map<string, number>();
|
||||
const glob = new Bun.Glob("**/*.{ts,tsx,js,jsx,css,html}");
|
||||
|
||||
for await (const file of glob.scan({ cwd: srcDir, absolute: true })) {
|
||||
try {
|
||||
const stat = await Bun.file(file).stat();
|
||||
if (stat) {
|
||||
mtimes.set(file, stat.mtime.getTime());
|
||||
}
|
||||
} catch {
|
||||
// File may have been deleted, skip
|
||||
}
|
||||
}
|
||||
return mtimes;
|
||||
};
|
||||
|
||||
// Initial collection
|
||||
lastMtimes = await collectMtimes();
|
||||
|
||||
// Polling loop
|
||||
const poll = async () => {
|
||||
if (isRebuilding) return;
|
||||
|
||||
const currentMtimes = await collectMtimes();
|
||||
const changedFiles: string[] = [];
|
||||
|
||||
// Check for new or modified files
|
||||
for (const [file, mtime] of currentMtimes) {
|
||||
const lastMtime = lastMtimes.get(file);
|
||||
if (lastMtime === undefined || lastMtime < mtime) {
|
||||
changedFiles.push(path.relative(srcDir, file));
|
||||
}
|
||||
}
|
||||
|
||||
// Check for deleted files
|
||||
for (const file of lastMtimes.keys()) {
|
||||
if (!currentMtimes.has(file)) {
|
||||
changedFiles.push(path.relative(srcDir, file) + " (deleted)");
|
||||
}
|
||||
}
|
||||
|
||||
if (changedFiles.length > 0) {
|
||||
isRebuilding = true;
|
||||
console.log(`\n🔄 Changes detected:`);
|
||||
changedFiles.forEach(f => console.log(` • ${f}`));
|
||||
console.log("");
|
||||
|
||||
try {
|
||||
const rebuildStart = performance.now();
|
||||
await build();
|
||||
const rebuildEnd = performance.now();
|
||||
console.log(`\n✅ Rebuild completed in ${(rebuildEnd - rebuildStart).toFixed(2)}ms\n`);
|
||||
} catch (err) {
|
||||
console.error("❌ Rebuild failed:", err);
|
||||
}
|
||||
|
||||
lastMtimes = currentMtimes;
|
||||
isRebuilding = false;
|
||||
}
|
||||
};
|
||||
|
||||
const interval = setInterval(poll, POLL_INTERVAL_MS);
|
||||
|
||||
// Handle manual exit
|
||||
process.on("SIGINT", () => {
|
||||
clearInterval(interval);
|
||||
console.log("\n👋 Stopping build watcher...");
|
||||
process.exit(0);
|
||||
});
|
||||
|
||||
// Keep process alive
|
||||
process.stdin.resume();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user