gale/scripts/dev_server.ts

74 lines
2.1 KiB
TypeScript

import { contentType } from "jsr:@std/media-types";
import {HTML} from "./assemble_files.ts";
// Parse the port from the command-line arguments, defaulting to 8000
const port = parseInt(Deno.args[0] || "8000", 10);
const sockets: WebSocket[] = [];
const devinc = await fetch(import.meta.resolve("../src/dev.js")).then(r=>r.text());
let html: string;
try {
html = Deno.readTextFileSync("./index.html");
} catch (_) {
html = HTML;
}
html = html.replace("</head>", `<script>${devinc}</script></head>`);
function extension(path: string): string {
// Remove trailing slash if it exists
const normalizedPath = path.endsWith("/") ? path.slice(0, -1) : path;
// Get the last part of the path
const lastPart = normalizedPath.split("/").pop() || "";
// Check if the last part contains a "."
return lastPart.split(".")[1] || "";
}
// Start the HTTP server using Deno.serve
Deno.serve({ port }, async (req: Request) => {
const url = new URL(req.url);
// Handle WebSocket connections
if (url.pathname === "/ws") {
const { socket, response } = Deno.upgradeWebSocket(req);
sockets.push(socket);
return response;
}
// Serve static files or the predefined HTML for non-file routes
const path = new URL(req.url).pathname;
const ext = extension(path);
// Serve the predefined HTML for non-file routes
if (!ext) {
return new Response(html, {
headers: { "Content-Type": "text/html" },
});
}
try {
const file = await Deno.open("." + path, { read: true });
return new Response(file.readable, {
headers: { "Content-Type": contentType(ext) || "application/javascript" },
});
} catch (err) {
if (err instanceof Deno.errors.NotFound) {
return new Response("File not found", { status: 404 });
} else {
return new Response("Internal server error", { status: 500 });
}
}
});
// Start watching for file changes
const watcher = Deno.watchFs(".");
for await (const event of watcher) {
if (event.kind === "modify") {
for (const ws of sockets) {
if (ws.readyState === WebSocket.OPEN) {
ws.send("reload");
continue;
}
}
}
}