createBunAssetReader
Serves only build files listed in the asset manifest through Bun.file, with ETag, HEAD, 304 and Meeko's cache policy.
import { createBunAssetReader } from "@meekojs/meeko/bun";createBunAssetReader({ root, assets }) is Bun's public file reader. Like the Node reader, it only responds to paths in the build's asset manifest and returns null for all others, which are never looked up on disk; the difference is that it reads with Bun.file, which Bun sends without going through JavaScript.
Usage#
import { createServerApp } from "@meekojs/meeko/server";
import { createBunAssetReader } from "@meekojs/meeko/bun";
const app = await createServerApp({
manifest, load, runtime, production: true,
assets: createBunAssetReader({ root: new URL("./client/", import.meta.url), assets: manifest.assets ?? {} }),
});Type#
function createBunAssetReader(options: BunAssetReaderOptions): AssetReaderinterface BunAssetReaderOptions {
readonly root: string | URL
readonly assets: AssetManifest
}interface AssetReader {
get(pathname: string, request: Request): Promise<Response | null>
}Parameters#
| Option | Type | Description |
|---|---|---|
root |
string | URL |
Folder containing the manifest files, as a path or file: URL. In the Bun output, new URL("client/", import.meta.url). |
assets |
AssetManifest |
The public paths with their type, etag, size and immutable. |
Return value#
An AssetReader with get(pathname, request): null for a path not in assets or a method other than GET and HEAD; 304 if If-None-Match matches; 200 with content-type, ETag, content-length and cache-control (public, max-age=31536000, immutable for Vite's hashed files, public, max-age=0, must-revalidate for the rest).
Examples#
Test the reader in Bun#
// bun test assets.test.ts
import { expect, test } from "bun:test";
import { createBunAssetReader } from "@meekojs/meeko/bun";
test("only serves what is in the manifest", async () => {
const assets = createBunAssetReader({ root: new URL("./fixtures/client/", import.meta.url), assets: { "/robots.txt": { type: "text/plain", etag: '"r1"', size: 25 } } });
expect((await assets.get("/robots.txt", new Request("http://x/robots.txt")))?.status).toBe(200);
expect(await assets.get("/../package.json", new Request("http://x/../package.json"))).toBeNull();
});A cache in front of Bun#
GET /assets/entry-4f2a.js → 200, cache-control: public, max-age=31536000, immutable
GET /assets/entry-4f2a.js If-None-Match: "…" → 304 without reading the fileCommon mistakes#
Run it in Node#
// node server.mjs
await createBunAssetReader({ root, assets }).get("/robots.txt", request);The first read throws Error: The Meeko Bun adapter requires the Bun runtime. In Node, use createNodeAssetReader.
import { createNodeAssetReader } from "@meekojs/meeko/node";
const assets = createNodeAssetReader({ root: fileURLToPath(new URL("./client/", import.meta.url)), assets: manifest.assets ?? {} });A manifest file missing from the folder#
.meeko/output/bun/ copied without client/assets/A request for a listed file rejects with Error: Missing build asset /assets/entry-4f2a.js, which the application converts to 500 and sends to onError. Copy the complete output folder.
.meeko/output/bun/ complete: index.js, chunks/, client/ and prerender/Notes#
- Security. Paths are looked up in the manifest without decoding: no traversal matches.
HEADand304. They do not open the file.- Bun only. Importing
@meekojs/meeko/bunin Node does not fail; reading a file does.