UNPKG

vibescript

Version:

The ultimate prompt-driven, component-based, AI-powered, vibe-oriented programming language.

153 lines (135 loc) 4.92 kB
import chokidar from "chokidar"; import { compileVibeScript } from "./compiler.js"; import express from "express"; import { WebSocketServer } from "ws"; import path from "path"; import fs from "fs"; export async function watchVibeScript(file, config = {}) { console.log("👀 Watching for changes with live reload..."); console.log("🔨 Building initial pages..."); // Start dev server const app = express(); const distPath = path.resolve("dist"); // Ensure 'dist' directory exists before serving static files or reading from it if (!fs.existsSync(distPath)) { fs.mkdirSync(distPath, { recursive: true }); } // Serve static files from 'dist' app.use(express.static(distPath)); // Handle the root path ("/") to serve a default HTML file app.get("/", (req, res) => { // Get all HTML files in the dist directory const htmlFiles = fs .readdirSync(distPath) .filter((f) => f.endsWith(".html")); let targetFile = null; // Prioritize 'index.html' if it exists if (htmlFiles.includes("index.html")) { targetFile = "index.html"; } else if (htmlFiles.length > 0) { // Otherwise, pick the first HTML file found in the directory targetFile = htmlFiles[0]; } if (targetFile) { console.log(`Serving default page: ${targetFile}`); res.sendFile(path.join(distPath, targetFile)); } else { // If no HTML files are found, send a helpful message res.status(404).send( "<h1>No HTML pages found in 'dist' directory.</h1>" + "<p>Please ensure your VibeScript file generates at least one page.</p>" ); } }); const port = Number(config.port || 3000); let server; let wss; // WebSocket for reload events function broadcast(msg) { if (wss) { wss.clients.forEach((client) => { if (client.readyState === 1) { client.send(msg); } }); } } // Inject live reload script into HTML files function injectLiveReload() { const script = ` <script id="vibe-live-reload"> const ws = new WebSocket("ws://" + location.host); ws.onmessage = (event) => { if (event.data === "reload") { location.reload(); } if (event.data === "building") { const overlay = document.createElement("div"); overlay.id = "vibe-overlay"; overlay.style.position = "fixed"; overlay.style.top = 0; overlay.style.left = 0; overlay.style.width = "100%"; overlay.style.height = "100%"; overlay.style.background = "rgba(0,0,0,0.7)"; overlay.style.color = "white"; overlay.style.fontSize = "2rem"; overlay.style.display = "flex"; overlay.style.alignItems = "center"; overlay.style.justifyContent = "center"; overlay.innerText = "✨ Building vibes..."; document.body.appendChild(overlay); } if (event.data === "done") { const overlay = document.getElementById("vibe-overlay"); if (overlay) overlay.remove(); } }; </script> `; fs.readdirSync(distPath).forEach((file) => { if (file.endsWith(".html")) { const filePath = path.join(distPath, file); let html = fs.readFileSync(filePath, "utf8"); // Only inject the script if it's not already present in the HTML if (!html.includes('id="vibe-live-reload"')) { html = html.replace("</body>", `${script}</body>`); fs.writeFileSync(filePath, html); } } }); } // Initial build - do this BEFORE starting the server try { await compileVibeScript(file, config); console.log("✅ Initial build complete!"); // Now start the server after build is done server = app.listen(port, () => { console.log(`🌐 Dev server running at http://localhost:${port}`); console.log("🚀 Ready for development! Open the link above in your browser."); }); // Initialize WebSocket after server is running wss = new WebSocketServer({ server }); // Inject live reload and notify clients injectLiveReload(); broadcast("done"); } catch (error) { console.error("❌ Build failed:", error.message); process.exit(1); } // Watch for changes chokidar.watch(file).on("change", async () => { console.log("♻️ File changed, rebuilding..."); broadcast("building"); try { await compileVibeScript(file, config); console.log("✅ Rebuild complete!"); injectLiveReload(); // Re-inject live reload script if files were re-generated broadcast("done"); broadcast("reload"); } catch (error) { console.error("❌ Rebuild failed:", error.message); broadcast("done"); // Remove building overlay even on failure } }); }