Implement watch command

Add command that watches the source files for changes and (re)spawns the
serve local server whenever a change is detected.  This skips having to
manually restart the serve server every time a change is made.
This commit is contained in:
Hornwitser 2025-02-02 21:27:11 +01:00
parent 5eef85727e
commit 03d8872895

View file

@ -1,3 +1,4 @@
import { type ChildProcess, fork } from "node:child_process";
import * as fs from "node:fs"; import * as fs from "node:fs";
import * as posix from "node:path/posix"; import * as posix from "node:path/posix";
import { prettify, htmlDocument } from "antihtml"; import { prettify, htmlDocument } from "antihtml";
@ -6,6 +7,9 @@ import type { Page } from "./types.js";
import { resolveRefs } from "./utils/resolve-refs.js"; import { resolveRefs } from "./utils/resolve-refs.js";
import { createServer } from "./utils/http-server.js"; import { createServer } from "./utils/http-server.js";
const srcDir = "build/node";
const webDir = "web";
function pageToHtml(page: Page) { function pageToHtml(page: Page) {
if (!page.ref.startsWith("/")) { if (!page.ref.startsWith("/")) {
throw new Error(`ref "${page.ref}" for "${page.title}" is not absolute.`); throw new Error(`ref "${page.ref}" for "${page.title}" is not absolute.`);
@ -21,7 +25,6 @@ function pageToHtml(page: Page) {
} }
function assembleResources() { function assembleResources() {
const webDir = "web";
const resources = new Map<string, string | Page>(); const resources = new Map<string, string | Page>();
for (const entry of fs.readdirSync(webDir, { recursive: true, withFileTypes: true })) { for (const entry of fs.readdirSync(webDir, { recursive: true, withFileTypes: true })) {
if (!entry.isFile()) if (!entry.isFile())
@ -77,10 +80,34 @@ function serve() {
console.log("Listening on http://localhost:8080"); console.log("Listening on http://localhost:8080");
} }
function watch(script: string) {
let child: ChildProcess;
function start() {
child = fork(script, ["serve"]);
}
function restart() {
if (child.exitCode === null) {
child.kill();
child.once("close", start);
} else {
start();
}
}
let restartTimeout: ReturnType<typeof setTimeout>;
function onChange() {
clearTimeout(restartTimeout);
restartTimeout = setTimeout(restart, 100)
}
fs.watch(webDir, { recursive: true }, onChange);
fs.watch(srcDir, { recursive: true }, onChange);
start();
}
function printUsage() { function printUsage() {
console.log("Usage: cli.js <cmd>"); console.log("Usage: cli.js <cmd>");
console.log(" build - Copy resources and generated pages to build directory."); console.log(" build - Copy resources and generated pages to build directory.");
console.log(" serve - Host website on localhost:8080 for development purposes."); console.log(" serve - Host website on localhost:8080 for development purposes.");
console.log(" watch - Run serve and automatically restart it on changes.");
} }
function main(runtime: string, script: string, args: string[]) { function main(runtime: string, script: string, args: string[]) {
@ -95,6 +122,8 @@ function main(runtime: string, script: string, args: string[]) {
build(); build();
} else if (command === "serve") { } else if (command === "serve") {
serve(); serve();
} else if (command === "watch") {
watch(script);
} else { } else {
console.log(`Error: Unkown sub-command ${command}`); console.log(`Error: Unkown sub-command ${command}`);
printUsage(); printUsage();