feat(images): cache-bust /cms-images URLs by post._updated
Browser caches /cms-images responses immutably for a year. When the editor changes a focal point or alt text, the underlying transform output changes too, but the URL stays the same — so the browser keeps serving the previous bytes. Manual hard-reloads and /api/cache/clear help once but not for visitors who already have the file. - RustyImageTransformParams gains an optional `version` that serializes as `_v` in the /cms-images URL. - RustyImage.svelte takes a matching `version` prop and forwards it through `baseParams`, so every <picture> source carries the tag. - The post thumbnail passes `post._updated` (truncated to seconds) as version. Each save bumps `_updated`, the URL changes, browsers re-fetch. `_v` is intentionally not consumed by `/cms-images` — its sole job is to break the browser cache key. The server-side image-cache and the RustyCMS transform cache key both ignore it, so disk usage doesn't balloon when the version tag changes.
This commit is contained in:
@@ -37,6 +37,8 @@
|
|||||||
/** JPEG/AVIF/WebP-Qualität. Default 75. */
|
/** JPEG/AVIF/WebP-Qualität. Default 75. */
|
||||||
quality?: number;
|
quality?: number;
|
||||||
fit?: "cover" | "contain" | "fill";
|
fit?: "cover" | "contain" | "fill";
|
||||||
|
/** Cache-Bust-Tag (z.B. post._updated) → `_v`-Param, bricht Browser-HTTP-Cache. */
|
||||||
|
version?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
let {
|
let {
|
||||||
@@ -56,6 +58,7 @@
|
|||||||
formats = ["webp", "jpeg"],
|
formats = ["webp", "jpeg"],
|
||||||
quality = 75,
|
quality = 75,
|
||||||
fit = "cover",
|
fit = "cover",
|
||||||
|
version,
|
||||||
}: Props = $props();
|
}: Props = $props();
|
||||||
|
|
||||||
function parseAr(s: string | undefined): number | null {
|
function parseAr(s: string | undefined): number | null {
|
||||||
@@ -89,6 +92,7 @@
|
|||||||
...(arString && fit !== "contain"
|
...(arString && fit !== "contain"
|
||||||
? { height: Math.round(w / (arValue ?? 1)) }
|
? { height: Math.round(w / (arValue ?? 1)) }
|
||||||
: {}),
|
: {}),
|
||||||
|
...(version ? { version } : {}),
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -68,6 +68,13 @@ export interface RustyImageTransformParams {
|
|||||||
focalX?: number;
|
focalX?: number;
|
||||||
/** Focal-Y in [0,1] (Default 0.5). */
|
/** Focal-Y in [0,1] (Default 0.5). */
|
||||||
focalY?: number;
|
focalY?: number;
|
||||||
|
/**
|
||||||
|
* Cache-busting tag (e.g. post._updated). Serialized as `_v` and is the
|
||||||
|
* only param the cms-images endpoint deliberately ignores when forwarding
|
||||||
|
* to RustyCMS — its sole job is to invalidate the browser HTTP cache when
|
||||||
|
* the underlying entry (focal, alt, replacement) changes.
|
||||||
|
*/
|
||||||
|
version?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
function roundFocal(v: number): number {
|
function roundFocal(v: number): number {
|
||||||
@@ -89,6 +96,7 @@ export function getCmsImageUrl(src: string, params: RustyImageTransformParams =
|
|||||||
if (params.quality != null) searchParams.set('q', String(params.quality));
|
if (params.quality != null) searchParams.set('q', String(params.quality));
|
||||||
if (params.focalX != null) searchParams.set('fx', String(roundFocal(params.focalX)));
|
if (params.focalX != null) searchParams.set('fx', String(roundFocal(params.focalX)));
|
||||||
if (params.focalY != null) searchParams.set('fy', String(roundFocal(params.focalY)));
|
if (params.focalY != null) searchParams.set('fy', String(roundFocal(params.focalY)));
|
||||||
|
if (params.version) searchParams.set('_v', params.version);
|
||||||
return `/cms-images?${searchParams.toString()}`;
|
return `/cms-images?${searchParams.toString()}`;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -45,6 +45,7 @@
|
|||||||
class="block object-cover"
|
class="block object-cover"
|
||||||
loading="eager"
|
loading="eager"
|
||||||
fetchpriority="high"
|
fetchpriority="high"
|
||||||
|
version={(data.post as { _updated?: string })._updated?.slice(0, 19)}
|
||||||
/>
|
/>
|
||||||
</div>
|
</div>
|
||||||
{:else if data.postImageUrl}
|
{:else if data.postImageUrl}
|
||||||
|
|||||||
Reference in New Issue
Block a user