Skip to content

Instantly share code, notes, and snippets.

@colorincode
Created February 20, 2025 22:50
Show Gist options
  • Save colorincode/ea64ab7cea51a4afee38c90a410ccb30 to your computer and use it in GitHub Desktop.
Save colorincode/ea64ab7cea51a4afee38c90a410ccb30 to your computer and use it in GitHub Desktop.
serve ts
import { serve, HTMLBundle, Server } from "bun";
import { watch } from "fs";
import { join } from "path";
import { buildProject, runBuild} from "./bun_build";
import { URL } from "url";
// const clients = new Set<new WebSocket("ws://localhost:8080")>;
let hostname = "localhost";
const initial = performance.now();
const clients = new Set<WebSocket>();
let isBuilding = false;
type DisposableTimer = Timer & { [Symbol.dispose](): void };
let buildTimeout: DisposableTimer | null = null;
async function findAvailablePort(startPort: number = 1234): Promise<number> {
for (let port = startPort; port < 65536; port++) {
try {
const testServer = Bun.serve({
port,
fetch() {
return new Response("Port check");
},
});
if (typeof testServer.stop === "function") {
testServer.stop();
}
return port;
} catch (error: any) {
if (error.code !== "EADDRINUSE") {
throw error;
}
// If the error indicates the port is in use, continue checking.
}
}
throw new Error("No available ports found");
}
// const port = await findAvailablePort() ; //call this outside of scope
export async function startServer() {
const port = await findAvailablePort();
const server = Bun.serve({
port: 0,
async fetch(req, server) {
// If the request can be upgraded for websockets, do so:
const upgradeSuccessful = server.upgrade(req);
const url = new URL(req.url);
let filePath = join("./dist", url.pathname);
if (url.pathname === "/" || url.pathname === "/index.html") {
filePath = join("./dist", "index.html");
}
const file = Bun.file(filePath);
if (await file.exists() || upgradeSuccessful) {
return new Response(file);
} else {
return new Response("Not Found", { status: 404 });
}
},
websocket: {
message(ws, message) {
console.log(`Received message: ${message}`);
ws.send(`Echo: ${message}`);
},
open(ws) {
clients.add(ws);
},
close(ws) {
clients.delete(ws);
},
},
});
console.log(`Server running at http://localhost:${port}`);
return server;
}
function debounce(func: Function, delay: number) {
let timeoutId: ReturnType<typeof setTimeout> | null = null;
return (...args: any[]) => {
if (timeoutId) {
clearTimeout(timeoutId);
}
timeoutId = setTimeout(() => func(...args), delay);
};
}
// function debounce(func: Function, delay: number) {
// let timeoutId: Timer | null = null;
// return (...args: any[]) => {
// if (timeoutId) {
// clearTimeout(timeoutId);
// }
// timeoutId = setTimeout(() => {
// func(...args);
// }, delay);
// };
// }
const debouncedBuild = debounce(async () => {
if (!isBuilding) {
isBuilding = true;
console.log("Starting build...");
await buildProject();
isBuilding = false;
clients.forEach(client => client.send("reload"));
}
}, 1000);
function watchAndRebuild() {
const srcDir = join(process.cwd(), "src");
watch(srcDir, { recursive: true }, (event, filename) => {
console.log(`File changed: ${filename}`);
debouncedBuild();
});
}
async function main() {
await buildProject();
await startServer();
watchAndRebuild();
}
main().catch(console.error);
console.log("Buns are in the oven.");
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment