RobotHub-Frontend / static-server.js
blanchon's picture
Update
1fbccb3
#!/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}`);