#!/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}`);