1import { serveDir } from "@std/http/file-server";23const PORT = Number(Deno.env.get("PORT") ?? 8000);45// Dev live-reload: SSE clients get poked whenever the bundle or assets change.6const reloadClients = new Set<ReadableStreamDefaultController<Uint8Array>>();7const encoder = new TextEncoder();89async function watchForReload() {10 const targets = ["static", "assets"].filter((p) => {11 try {12 return Deno.statSync(p).isDirectory;13 } catch {14 return false;15 }16 });17 if (targets.length === 0) return;18 const watcher = Deno.watchFs(targets);19 let timer: ReturnType<typeof setTimeout> | undefined;20 for await (const _event of watcher) {21 clearTimeout(timer);22 timer = setTimeout(() => {23 for (const client of reloadClients) {24 try {25 client.enqueue(encoder.encode("data: reload\n\n"));26 } catch {27 reloadClients.delete(client);28 }29 }30 }, 80);31 }32}33watchForReload();3435Deno.serve({ port: PORT }, (req) => {36 const url = new URL(req.url);3738 if (url.pathname === "/_reload") {39 let ctrl: ReadableStreamDefaultController<Uint8Array>;40 const body = new ReadableStream<Uint8Array>({41 start(controller) {42 ctrl = controller;43 reloadClients.add(controller);44 controller.enqueue(encoder.encode(": connected\n\n"));45 },46 cancel() {47 reloadClients.delete(ctrl);48 },49 });50 return new Response(body, {51 headers: {52 "content-type": "text/event-stream",53 "cache-control": "no-store",54 },55 });56 }5758 if (url.pathname.startsWith("/assets/")) {59 return serveDir(req, { fsRoot: "assets", urlRoot: "assets" });60 }61 return serveDir(req, { fsRoot: "static" });62});