From 2f6152539c540697290ec73a7c1b50b9f2db88c6 Mon Sep 17 00:00:00 2001 From: Alan Pearce Date: Tue, 12 Sep 2023 16:54:29 +0200 Subject: Use own logic for static file serving --- bun.lockb | Bin 2386 -> 3923 bytes package.json | 3 ++- src/index.ts | 71 ++++++++++++++++++++++++++++++++++++++++++++++++----- test/index.test.ts | 12 ++++----- 4 files changed, 72 insertions(+), 14 deletions(-) diff --git a/bun.lockb b/bun.lockb index c8b2651..e8b79d3 100755 Binary files a/bun.lockb and b/bun.lockb differ diff --git a/package.json b/package.json index 27f95e0..0eb65a3 100644 --- a/package.json +++ b/package.json @@ -2,6 +2,7 @@ "name": "homestead", "module": "src/index.ts", "devDependencies": { + "@types/contains-path": "^1.0.2", "bun-html-live-reload": "^0.1.1", "bun-types": "latest" }, @@ -10,7 +11,7 @@ }, "type": "module", "dependencies": { - "serve-static-bun": "^0.5.3", + "contains-path": "^1.0.0", "toml": "^3.0.0" } } \ No newline at end of file diff --git a/src/index.ts b/src/index.ts index d8c9bf1..ec1c296 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,16 +1,75 @@ import path from "node:path"; +import fs, { Stats } from "node:fs"; +import fsp from "node:fs/promises"; +import util from "node:util"; + import { withHtmlLiveReload } from "bun-html-live-reload"; -import serveStatic from "serve-static-bun"; +import containsPath from "contains-path"; import readConfig from "./config"; -const base = Bun.argv.length > 2 ? Bun.argv[Bun.argv.length - 1] : "."; +const base = "../website/"; +const publicDir = path.resolve(base, "public") + path.sep; const config = readConfig(base); +const defaultHeaders = config.extra.headers; + +function getFilename(name: string): string { + return path.join(publicDir, `${name}`); +} + +let files: Map = new Map(); + +function registerFile(pathname: string, absPath: string, stat: Stats): void { + pathname = "/" + (pathname === "." || pathname === "./" ? "" : pathname); + + if (files.get(pathname) !== undefined) { + console.warn("File already registered:", pathname); + } + files.set(pathname, { + filename: absPath, + size: stat.size, + mtime: stat.mtime.toUTCString(), + }); +} + +function walkDirectory(root: string, dir: string) { + const absDir = path.join(root, dir); + for (let pathname of fs.readdirSync(absDir)) { + const relPath = path.join(dir, pathname); + const absPath = path.join(absDir, pathname); + const stat = fs.statSync(absPath); + if (stat.isDirectory()) { + walkDirectory(root, relPath + path.sep); + } else if (stat.isFile()) { + if (pathname === "index.html") { + registerFile(path.dirname(relPath), absPath, stat); + registerFile(path.dirname(relPath) + path.sep, absPath, stat); + } + registerFile(relPath, absPath, stat); + } + } +} + +walkDirectory(publicDir, ""); export default withHtmlLiveReload({ - fetch: serveStatic(path.join(base, "public"), { - headers: config.extra.headers, - dotfiles: "allow", - }), + fetch: async function (request) { + const pathname = new URL(request.url).pathname; + if (files.has(pathname)) { + const file = files.get(pathname); + console.info("filename", file.filename); + return new Response(Bun.file(file.filename), { + headers: defaultHeaders, + status: 200, + }); + } + return new Response(Bun.file(getFilename("404.html")), { + headers: Object.assign({}, defaultHeaders, { + "cache-control": "max-age=5, no-cache", + }), + status: 404, + statusText: "Not Found", + }); + }, }); diff --git a/test/index.test.ts b/test/index.test.ts index 234bd1e..c1f5f64 100644 --- a/test/index.test.ts +++ b/test/index.test.ts @@ -15,14 +15,12 @@ afterAll(function () { server.stop(); }); -test("/status returns 200 OK", async function () { - const res = await fetch(new URL("/status", base)); +test("/ returns 200", async function () { + const res = await fetch(base); expect(res.status).toBe(200); - expect(await res.text()).toBe("OK"); }); -test("/ returns 200 and says Hello world", async function () { - const res = await fetch(base); - expect(res.status).toBe(200); - expect(await res.text()).toBe("Hello world"); +test("/asdf returns 404", async function () { + const res = await fetch(`${base}asdf`); + expect(res.status).toBe(404); }); -- cgit 1.4.1