staticHost

tcmts.cli.test.e2e.examples.staticHost · #njbphsxn · term · runs on the server

uses node:http

Serve a directory as a static host does: its files, and nothing else. Resolves with its URL and a way to stop it; on port, if given (a site that comes back where it was, as after a deploy).

import fs from "node:fs";
import http from "node:http";
import path from "node:path";

export function staticHost(
  root: string,
  port = 0,
): Promise<{ url: string; port: number; close: () => Promise<void> }> {
  const types: Record<string, string> = {
    ".html": "text/html",
    ".js": "text/javascript",
    ".css": "text/css",
    ".svg": "image/svg+xml",
    ".png": "image/png",
    ".webmanifest": "application/manifest+json",
  };
  const server = http.createServer((req, res) => {
    let file = path.join(root, decodeURIComponent(new URL(req.url ?? "/", "http://x").pathname));
    // (`/today` is today.html, as static hosts have it)
    if (!fs.existsSync(file) && fs.existsSync(`${file}.html`)) file = `${file}.html`;
    if (fs.existsSync(file) && fs.statSync(file).isDirectory())
      file = path.join(file, "index.html");
    if (!file.startsWith(root) || !fs.existsSync(file))
      return void res.writeHead(404).end("not found");
    res.writeHead(200, { "content-type": types[path.extname(file)] ?? "application/octet-stream" });
    res.end(fs.readFileSync(file));
  });
  return new Promise((resolve) =>
    server.listen(port, "127.0.0.1", () => {
      const at = (server.address() as { port: number }).port;
      resolve({
        url: `http://127.0.0.1:${at}`,
        port: at,
        close: () => {
          server.closeAllConnections();
          return new Promise((r) => server.close(() => r()));
        },
      });
    }),
  );
}

used by