diff --git a/src/runtime/api/filesystem_router.classes.ts b/src/runtime/api/filesystem_router.classes.ts index 99ec5c56c467..ac367fecf57f 100644 --- a/src/runtime/api/filesystem_router.classes.ts +++ b/src/runtime/api/filesystem_router.classes.ts @@ -28,6 +28,10 @@ export default [ getter: "getStyle", cache: true, }, + assetPrefix: { + getter: "getAssetPrefix", + cache: true, + }, }, klass: {}, }), diff --git a/src/runtime/api/filesystem_router.rs b/src/runtime/api/filesystem_router.rs index d39d6d12d922..fabda9c5d892 100644 --- a/src/runtime/api/filesystem_router.rs +++ b/src/runtime/api/filesystem_router.rs @@ -698,11 +698,14 @@ impl FileSystemRouter { #[bun_jsc::host_fn(getter)] pub fn get_asset_prefix(this: &Self, global_this: &JSGlobalObject) -> JsResult { - if let Some(ref asset_prefix) = this.asset_prefix { - return Ok(zs_to_js(asset_prefix.leak(), global_this)); - } + // An omitted `assetPrefix` and `assetPrefix: ""` both store no prefix, so report + // the empty string the router actually applies rather than null. + let prefix = match this.asset_prefix { + Some(ref asset_prefix) => asset_prefix.leak(), + None => b"", + }; - Ok(JSValue::NULL) + Ok(zs_to_js(prefix, global_this)) } // Codegen's `host_fn_finalize` calls this via `|b| FileSystemRouter::finalize(b)` diff --git a/test/js/bun/util/filesystem_router.test.ts b/test/js/bun/util/filesystem_router.test.ts index 51248c37db71..851f48754a21 100644 --- a/test/js/bun/util/filesystem_router.test.ts +++ b/test/js/bun/util/filesystem_router.test.ts @@ -314,6 +314,40 @@ it("assetPrefix, src, and origin", async () => { } }); +it("assetPrefix is readable from the router", () => { + const { dir } = make(["index.tsx"]); + + const router = new Bun.FileSystemRouter({ + dir, + style: "nextjs", + assetPrefix: "/_next/static/", + origin: "https://nextjs.org", + }); + + const descriptor = Object.getOwnPropertyDescriptor(Object.getPrototypeOf(router), "assetPrefix"); + expect(typeof descriptor?.get).toBe("function"); + expect(descriptor?.set).toBeUndefined(); + expect(Object.hasOwn(router, "assetPrefix")).toBe(false); + + expect(router.assetPrefix).toBe("/_next/static/"); + + // the prefix the router reports is the one it applies to `src` + expect(router.match("/")!.src).toBe(`${router.origin}${router.assetPrefix}index.tsx`); + + router.reload(); + expect(router.assetPrefix).toBe("/_next/static/"); +}); + +it("assetPrefix is an empty string when unset", () => { + const { dir } = make(["index.tsx"]); + + for (const assetPrefix of [undefined, ""]) { + const router = new Bun.FileSystemRouter({ dir, style: "nextjs", assetPrefix }); + expect(router.assetPrefix).toBe(""); + expect(router.match("/")!.src).toBe("index.tsx"); + } +}); + it(".query works", () => { // set up the test const { dir } = make(["posts.tsx"]);