Spaces:
Running
Running
#!/usr/bin/env bun | |
// Simple static file server for Svelte build output | |
import { join } from "path"; | |
const PORT = process.env.PORT || 8000; | |
const BUILD_DIR = "./build"; | |
// MIME types for common web assets | |
const MIME_TYPES = { | |
".html": "text/html", | |
".css": "text/css", | |
".js": "application/javascript", | |
".json": "application/json", | |
".png": "image/png", | |
".jpg": "image/jpeg", | |
".jpeg": "image/jpeg", | |
".gif": "image/gif", | |
".svg": "image/svg+xml", | |
".ico": "image/x-icon", | |
".woff": "font/woff", | |
".woff2": "font/woff2", | |
".ttf": "font/ttf", | |
".eot": "application/vnd.ms-fontobject", | |
".webp": "image/webp", | |
".avif": "image/avif", | |
".mp4": "video/mp4", | |
".webm": "video/webm" | |
}; | |
function getMimeType(filename) { | |
const ext = filename.substring(filename.lastIndexOf(".")); | |
return MIME_TYPES[ext] || "application/octet-stream"; | |
} | |
const server = Bun.serve({ | |
port: PORT, | |
hostname: "0.0.0.0", | |
async fetch(req) { | |
const url = new URL(req.url); | |
let pathname = url.pathname; | |
// Remove leading slash and default to index.html for root | |
if (pathname === "/") { | |
pathname = "index.html"; | |
} else { | |
pathname = pathname.substring(1); // Remove leading slash | |
} | |
try { | |
// Try to serve the requested file | |
const filePath = join(BUILD_DIR, pathname); | |
const file = Bun.file(filePath); | |
if (await file.exists()) { | |
const mimeType = getMimeType(pathname); | |
const headers = { | |
"Content-Type": mimeType | |
}; | |
// Set cache headers | |
if (pathname.includes("/_app/immutable/")) { | |
// Long-term cache for immutable assets | |
headers["Cache-Control"] = "public, max-age=31536000, immutable"; | |
} else if (pathname.endsWith(".html")) { | |
// No cache for HTML files | |
headers["Cache-Control"] = "public, max-age=0, must-revalidate"; | |
} else { | |
// Short cache for other assets | |
headers["Cache-Control"] = "public, max-age=3600"; | |
} | |
return new Response(file, { headers }); | |
} | |
// If file not found and no extension, serve index.html for SPA routing | |
if (!pathname.includes(".")) { | |
const indexFile = Bun.file(join(BUILD_DIR, "index.html")); | |
if (await indexFile.exists()) { | |
return new Response(indexFile, { | |
headers: { | |
"Content-Type": "text/html", | |
"Cache-Control": "public, max-age=0, must-revalidate" | |
} | |
}); | |
} | |
} | |
return new Response("Not Found", { | |
status: 404, | |
headers: { "Content-Type": "text/plain" } | |
}); | |
} catch (error) { | |
console.error("Server error:", error); | |
return new Response("Internal Server Error", { | |
status: 500, | |
headers: { "Content-Type": "text/plain" } | |
}); | |
} | |
} | |
}); | |
console.log(`π Static server running on http://localhost:${server.port}`); | |
console.log(`π Serving files from: ${BUILD_DIR}`); | |