diff --git a/src/core/AssetUrls.ts b/src/core/AssetUrls.ts index ae43a8caf..951cf325e 100644 --- a/src/core/AssetUrls.ts +++ b/src/core/AssetUrls.ts @@ -30,7 +30,21 @@ export function buildAssetUrl( assetManifest: AssetManifest = {}, ): string { const normalizedPath = normalizeAssetPath(path); - return assetManifest[normalizedPath] ?? `/${encodeAssetPath(normalizedPath)}`; + + const directUrl = assetManifest[normalizedPath]; + if (directUrl) { + return directUrl; + } + + const directoryPrefix = `${normalizedPath}/`; + const hasNestedAssets = Object.keys(assetManifest).some((manifestPath) => + manifestPath.startsWith(directoryPrefix), + ); + if (hasNestedAssets) { + return `/_assets/${encodeAssetPath(normalizedPath)}`; + } + + return `/${encodeAssetPath(normalizedPath)}`; } declare global { diff --git a/tests/AssetUrls.test.ts b/tests/AssetUrls.test.ts new file mode 100644 index 000000000..70f5bc581 --- /dev/null +++ b/tests/AssetUrls.test.ts @@ -0,0 +1,30 @@ +import { describe, expect, test } from "vitest"; +import { buildAssetUrl } from "../src/core/AssetUrls"; + +describe("AssetUrls", () => { + test("returns hashed URLs for direct asset matches", () => { + expect( + buildAssetUrl("images/Favicon.svg", { + "images/Favicon.svg": "/_assets/images/Favicon.hash.svg", + }), + ).toBe("/_assets/images/Favicon.hash.svg"); + }); + + test("maps directory prefixes into the hashed asset namespace", () => { + const manifest = { + "maps/britanniaclassic/manifest.json": + "/_assets/maps/britanniaclassic/manifest.hash.json", + "maps/britanniaclassic/map.bin": + "/_assets/maps/britanniaclassic/map.hash.bin", + }; + + expect(buildAssetUrl("maps", manifest)).toBe("/_assets/maps"); + expect(buildAssetUrl("maps/britanniaclassic", manifest)).toBe( + "/_assets/maps/britanniaclassic", + ); + }); + + test("falls back to the unversioned path when manifest has no match", () => { + expect(buildAssetUrl("images/unknown.svg", {})).toBe("/images/unknown.svg"); + }); +});