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