@zeix/ui-element
Version:
UIElement - minimal reactive framework based on Web Components
125 lines (113 loc) ⢠3.58 kB
text/typescript
import { watch } from "fs/promises";
import { exec } from "child_process";
import { promisify } from "util";
import { ServerWebSocket } from "bun";
const execAsync = promisify(exec);
const sockets = new Set<ServerWebSocket>();
// Function to rebuild docs and notify clients
async function rebuildDocs() {
console.log("\nš Rebuilding docs...");
const startTime = performance.now();
try {
await execAsync("bun run build:docs-html");
const duration = (performance.now() - startTime).toFixed(2);
console.log(`⨠Docs rebuilt successfully in ${duration}ms!`);
// Notify all connected clients to reload
sockets.forEach(socket => {
socket.send('reload');
});
} catch (error) {
console.error("ā Error rebuilding docs:", error);
}
}
// Watch for changes in markdown files
async function watchDocs() {
console.log("š Watching for changes in docs-src/pages...");
const watcher = watch("docs-src/pages", { recursive: true });
for await (const event of watcher) {
if (event.filename?.endsWith(".md")) {
console.log(`\nš Detected change in: ${event.filename}`);
await rebuildDocs();
}
}
}
// Start the watcher
watchDocs().catch(console.error);
const server = Bun.serve({
port: 3000,
websocket: {
open(ws: ServerWebSocket) {
console.log("š Client connected");
sockets.add(ws);
},
close(ws: ServerWebSocket) {
console.log("š Client disconnected");
sockets.delete(ws);
},
message(ws: ServerWebSocket, message: string) {
console.log("šØ Received message:", message);
},
},
async fetch(req) {
const url = new URL(req.url);
const path = url.pathname;
// Handle WebSocket upgrade
if (path === '/ws') {
const upgraded = server.upgrade(req);
if (!upgraded) {
return new Response('Upgrade failed', { status: 400 });
}
return new Response();
}
// Inject the reload script into HTML responses
if (path.endsWith('.html') || path === '/') {
try {
let content = await Bun.file(`./docs${path === '/' ? '/index.html' : path}`).text();
const reloadScript = `
<script>
const ws = new WebSocket('ws://' + window.location.host + '/ws');
ws.onmessage = (event) => {
if (event.data === 'reload') {
console.log('š Reloading page...');
window.location.reload();
}
};
</script>
`;
content = content.replace('</body>', `${reloadScript}</body>`);
return new Response(content, {
headers: { "Content-Type": "text/html; charset=UTF-8" },
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
console.warn(`ā ļø Not found: ${path}`);
return new Response("Fallback response");
}
}
// Handle other static files
const type = (path: string) => {
const ext = path.split(".").pop();
switch (ext) {
case "js": return "application/javascript; charset=UTF-8";
case "css": return "text/css; charset=UTF-8";
case "png": return "image/png";
default: return "text/html; charset=UTF-8";
}
}
try {
if (!path.match(/\.(js|css|png|ico)$/)) {
console.log(`š Serving: ${path}`);
}
return new Response(await Bun.file(`./docs${path}`).bytes(), {
headers: { "Content-Type": type(path) },
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
} catch (error) {
console.warn(`ā ļø Not found: ${path}`);
return new Response("Fallback response");
}
},
});
console.log(`\nš Server started at http://localhost:${server.port}`);
console.log("āØļø Hot Module Reloading is enabled\n");
export {};