diff --git a/src/runtime/renderBundleMesh.ts b/src/runtime/renderBundleMesh.ts index 70e1368..1c76919 100644 --- a/src/runtime/renderBundleMesh.ts +++ b/src/runtime/renderBundleMesh.ts @@ -1280,10 +1280,12 @@ function firstQuakeRenderBundleBackgroundLayerValue(value: string): string { return value.split(",")[0]?.trim() ?? ""; } -function quakeRenderBundleUrlPath(url: string | undefined): string | undefined { +export function quakeRenderBundleUrlPath(url: string | undefined): string | undefined { if (!url) return undefined; try { - return new URL(url, window.location.href).pathname; + const resolvedUrl = resolveQuakeAssetUrl(url); + const baseUrl = typeof window !== "undefined" ? window.location.href : "http://cssquake.local/"; + return new URL(resolvedUrl, baseUrl).pathname; } catch { return undefined; } diff --git a/test/importTsModule.mjs b/test/importTsModule.mjs index a6dfcf1..49fed5b 100644 --- a/test/importTsModule.mjs +++ b/test/importTsModule.mjs @@ -5,10 +5,11 @@ import { build } from "esbuild"; const projectRoot = path.resolve(path.dirname(fileURLToPath(import.meta.url)), ".."); -export async function importTsModule(specifier) { +export async function importTsModule(specifier, options = {}) { const entryPoint = path.resolve(projectRoot, specifier); const result = await build({ bundle: true, + define: options.define, entryPoints: [entryPoint], format: "esm", logLevel: "silent", diff --git a/test/runtime/renderBundlePreloadUrls.test.mjs b/test/runtime/renderBundlePreloadUrls.test.mjs index 9dcf546..8ef7b42 100644 --- a/test/runtime/renderBundlePreloadUrls.test.mjs +++ b/test/runtime/renderBundlePreloadUrls.test.mjs @@ -49,6 +49,36 @@ test("render bundles without complete asset URLs fail before runtime preload", ( ); }); +test("render bundle URL paths resolve the deployed versioned asset root before matching", async () => { + const { quakeRenderBundleUrlPath: deployedRenderBundleUrlPath } = await importTsModule( + "src/runtime/renderBundleMesh.ts", + { + define: { + "import.meta.env": JSON.stringify({ + VITE_QUAKE_ASSET_ROOT: "https://assets.lowpoly.cc/q/live-sha", + }), + }, + }, + ); + const previousWindow = globalThis.window; + globalThis.window = new Window({ url: "https://cssquake.com/?map=e1m1" }); + try { + const bundlePath = deployedRenderBundleUrlPath("/q/285/b/e1m1/a5.avif"); + const computedPath = deployedRenderBundleUrlPath( + "https://assets.lowpoly.cc/q/live-sha/285/b/e1m1/a5.avif", + ); + + assert.equal(bundlePath, "/q/live-sha/285/b/e1m1/a5.avif"); + assert.equal(bundlePath, computedPath); + } finally { + if (previousWindow === undefined) { + delete globalThis.window; + } else { + globalThis.window = previousWindow; + } + } +}); + test("map floor preloads select only direct floor component assets", () => { const urls = quakeRenderBundleFloorAssetUrls(renderBundle({ assetUrls: [