67 lines
2.3 KiB
TypeScript
67 lines
2.3 KiB
TypeScript
import { serve } from "bun";
|
|
|
|
const port = Number(process.env.PORT ?? "3000");
|
|
|
|
function contentType(pathname: string): string | undefined {
|
|
if (pathname.endsWith(".html")) return "text/html; charset=utf-8";
|
|
if (pathname.endsWith(".css")) return "text/css; charset=utf-8";
|
|
if (pathname.endsWith(".js")) return "application/javascript; charset=utf-8";
|
|
if (pathname.endsWith(".mjs")) return "application/javascript; charset=utf-8";
|
|
if (pathname.endsWith(".json")) return "application/json; charset=utf-8";
|
|
if (pathname.endsWith(".svg")) return "image/svg+xml";
|
|
if (pathname.endsWith(".png")) return "image/png";
|
|
if (pathname.endsWith(".jpg") || pathname.endsWith(".jpeg")) return "image/jpeg";
|
|
if (pathname.endsWith(".webp")) return "image/webp";
|
|
if (pathname.endsWith(".ico")) return "image/x-icon";
|
|
if (pathname.endsWith(".woff")) return "font/woff";
|
|
if (pathname.endsWith(".woff2")) return "font/woff2";
|
|
if (pathname.endsWith(".txt")) return "text/plain; charset=utf-8";
|
|
return undefined;
|
|
}
|
|
|
|
const distDir = `${process.cwd()}/dist`;
|
|
|
|
serve({
|
|
port,
|
|
async fetch(req) {
|
|
const url = new URL(req.url);
|
|
|
|
// Normalize paths
|
|
let pathname = decodeURIComponent(url.pathname);
|
|
|
|
// Default document
|
|
if (pathname === "/") pathname = "/index.html";
|
|
|
|
const filePath = `${distDir}${pathname}`;
|
|
|
|
// Try direct file first
|
|
let file = Bun.file(filePath);
|
|
if (!(await file.exists())) {
|
|
// If request is for a "route", serve index.html (SPA-ish fallback)
|
|
// Astro static pages typically exist as real files, but this fallback helps
|
|
// if you add client-side routing later.
|
|
file = Bun.file(`${distDir}/index.html`);
|
|
if (!(await file.exists())) {
|
|
return new Response("Not Found", { status: 404 });
|
|
}
|
|
}
|
|
|
|
const headers = new Headers();
|
|
const ct = contentType(pathname);
|
|
if (ct) headers.set("Content-Type", ct);
|
|
|
|
// Cache policy:
|
|
// - HTML: no-cache (so updates show quickly)
|
|
// - assets: cache long (Astro fingerprints assets by default)
|
|
if (pathname.endsWith(".html")) {
|
|
headers.set("Cache-Control", "no-cache");
|
|
} else {
|
|
headers.set("Cache-Control", "public, max-age=31536000, immutable");
|
|
}
|
|
|
|
return new Response(file, { headers });
|
|
}
|
|
});
|
|
|
|
console.log(`Serving dist on http://0.0.0.0:${port}`);
|