Skip to content

Instantly share code, notes, and snippets.

@thehappycheese
Created December 15, 2024 08:06
Show Gist options
  • Save thehappycheese/c2500bd9c601bb10e2777a20b55c2786 to your computer and use it in GitHub Desktop.
Save thehappycheese/c2500bd9c601bb10e2777a20b55c2786 to your computer and use it in GitHub Desktop.

Automates reloading a website during development; served using vanilla Deno server using a websocket.

export function createHotReloadMiddleware(watchPath: string, script_route = "/hmr.js", socket_route="/hmrws") {
const clients = new Set<WebSocket>();
// File watcher for HMR
const watcher = Deno.watchFs(watchPath);
const debounceTime = 100; // Debounce time in milliseconds
let lastEventTime = 0;
(async (clients) => {
for await (const event of watcher) {
const currentTime = Date.now();
if (currentTime - lastEventTime < debounceTime) {
continue; // Debounce the events
}
lastEventTime = currentTime;
if (event.kind === "modify") {
console.log("File modified:", event.paths);
for (const client of clients) {
client.send("reload");
}
}
}
})(clients);
return function hmrMiddleware(request: Request): Response | null {
const { pathname } = new URL(request.url);
// WebSocket connection
if (pathname === socket_route) {
const { socket, response } = Deno.upgradeWebSocket(request);
socket.onopen = () => clients.add(socket);
socket.onclose = () => clients.delete(socket);
socket.onerror = () => clients.delete(socket);
return response;
}
// HMR client script
if (pathname === `${script_route}`) {
return new Response(
`const ws = new WebSocket("ws:/"+location.host+"${socket_route}");
ws.onmessage = (event) => {
if (event.data === "reload") {
location.reload();
}
};`,
{
headers: { "content-type": "application/javascript" },
}
);
}
// Not handled by HMR
return null;
};
}
<html>
<head>
<titleHt Reload Test</title>
<script src="hmr.js" defer></script>
</head>
<body>
<h1>Edit and save to see reload</h1>
</body>
</html>
import { createHotReloadMiddleware } from "./hot_reload.ts";
const hrm = createHotReloadMiddleware("./index.html")
async function server(request: Request): Promise<Response> {
// HOT RELOAD MIDDLEWARE
const hrm_response = hrm(request);
if (hrm_response) return hrm_response;
// Serve the HTML file with the injected HMR client script
return new Response(
await Deno.readTextFile("./index.html"),
{
headers: {
"content-type": "text/html; charset=utf-8",
},
},
);
}
Deno.serve(server);
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment