Skip to content

ChadScript.embed

Compile-time file embedding. Reads files from disk during compilation and bakes their contents directly into the native binary as string constants. At runtime, accessing embedded files is instant — no file I/O, no filesystem dependency.

This is useful for bundling HTML, CSS, templates, config files, or any static assets into a single self-contained binary.

ChadScript.embedFile(path)

Embed a single file at compile time. Returns the file contents as a string.

typescript
const html = ChadScript.embedFile("./index.html");
console.log(html); // contents of index.html, baked into the binary

The path must be a string literal (not a variable). It is resolved relative to the entry file being compiled.

ChadScript.embedDir(path)

Recursively embed all files in a directory at compile time. Each file is stored as a string constant keyed by its relative path within the directory.

typescript
ChadScript.embedDir("./public");

This walks the directory tree and embeds every file it finds. Use getEmbeddedFile() to retrieve them at runtime.

ChadScript.getEmbeddedFile(key)

Retrieve a previously embedded file by its key. For embedFile(), the key is the filename. For embedDir(), the key is the relative path within the embedded directory.

typescript
ChadScript.embedDir("./public");

const html = ChadScript.getEmbeddedFile("index.html");
const css = ChadScript.getEmbeddedFile("style.css");
const nested = ChadScript.getEmbeddedFile("images/logo.txt");

Returns an empty string if the key is not found.

ChadScript.getEmbeddedFileAsUint8Array(key)

Retrieve a previously embedded file as a Uint8Array. Useful for working with binary data programmatically (e.g., hashing, transforming, or writing to disk).

typescript
ChadScript.embedDir("./assets");

const imageData: Uint8Array = ChadScript.getEmbeddedFileAsUint8Array("logo.png");
console.log(imageData.length); // exact byte count
fs.writeFileSync("/tmp/logo.png", imageData); // binary-safe write

Returns a zero-length Uint8Array if the key is not found.

ChadScript.serveEmbedded(path)

Return an HttpResponse for an embedded file. Strips the leading / from the path, looks up the file in the embedded table, and returns { status: 200, body: content, headers: "" } if found or { status: 404, body: "Not Found", headers: "" } if not.

The HTTP server automatically sets Content-Type based on the file extension, so .css, .js, .png, .wasm, etc. all get the correct header with no extra work.

This eliminates per-file route boilerplate for serving static assets:

typescript
ChadScript.embedDir("./public");

function handleRequest(req: HttpRequest): HttpResponse {
  if (req.path.startsWith("/api/")) return handleApi(req);
  return ChadScript.serveEmbedded(req.path);
}

httpServe(3000, handleRequest);

Example: HTTP Server with Embedded Files

A common pattern is embedding HTML/CSS for a web server so the entire app is a single binary with no external file dependencies:

my-server/
  app.ts
  public/
    index.html
    style.css
typescript
// Compile time: walks ./public/ and bakes every file into the binary as a string constant.
// The directory itself is not needed at runtime — files live in memory.
ChadScript.embedDir("./public");

function handleRequest(req: HttpRequest): HttpResponse {
  // serveEmbedded strips the leading '/', looks up the file in the embedded
  // table, and returns 200 + body if found, or 404 if not.
  // Content-Type is inferred from the file extension (.css, .png, .js, etc.)
  return ChadScript.serveEmbedded(req.path);
}

// Starts listening on port 3000; blocks forever
httpServe(3000, handleRequest);

Or with manual routing for more control:

typescript
ChadScript.embedDir("./public");

function handleRequest(req: HttpRequest): HttpResponse {
  if (req.path == "/") {
    return { status: 200, body: ChadScript.getEmbeddedFile("index.html"), headers: "" };
  }
  if (req.path == "/style.css") {
    return { status: 200, body: ChadScript.getEmbeddedFile("style.css"), headers: "Content-Type: text/css" };
  }
  return { status: 404, body: "Not Found", headers: "" };
}

httpServe(3000, handleRequest);
bash
$ chad build my-server/app.ts -o server
$ ./server
# HTML and CSS are served from memory — no files needed at runtime

See examples/hackernews/ for a full working example with embedDir().

How It Works

At compile time, the compiler reads the file(s) from disk and emits them as LLVM IR global string constants. At runtime, getEmbeddedFile() does a simple string comparison lookup across all embedded keys — no file system access occurs.

APIWhenWhat
embedFile(path)Compile timeReads file, returns contents as string
embedDir(path)Compile timeRecursively reads all files in directory
getEmbeddedFile(key)RuntimeLooks up embedded content by filename/path
getEmbeddedFileAsUint8Array(key)RuntimeSame as above, returns Uint8Array (binary-safe)
serveEmbedded(path)RuntimeReturns HttpResponse for embedded file (200 or 404, binary-safe via bodyLen)

Notes

  • All paths are resolved relative to the entry file (the .ts file passed to chad build)
  • embedFile() and embedDir() arguments must be string literals — they are evaluated at compile time
  • embedDir() embeds all files recursively; keys are relative paths from the embedded directory (e.g. subdir/page.html), so files with the same name in different subdirectories won't collide
  • embedFile() keys by filename only (basename), so avoid embedding two files with the same name via separate embedFile() calls — use embedDir() instead when you have nested structures
  • Binary files (images, fonts, wasm, etc.) are fully supported — they are embedded using Latin-1 encoding which preserves all byte values 0x00–0xFF