Responsive images (WebP/AVIF renditions) + media usage tracking
Responsive images (WebP/AVIF renditions) + media usage tracking
#19 in tonybierman/dx-blog — merged 2026-05-30
What & why
WordPress-style image handling: every uploaded image now gets a set of resized renditions served via <picture>/srcset, so the browser fetches the smallest file and best format that fits each slot instead of one full-size original. Plus media usage tracking ("which posts use this image").
Changes
- Renditions on upload —
thumb320 /small640 /medium1024 /large1600 (only widths below the original — never upscaling) + a full-size re-encode, in WebP. Pipeline insrc/server/images.rs(decode → Lanczos resize → encode), run on a blocking thread. Best-effort: animated GIFs / undecodable uploads keep only the original and never fail the upload. - Schema — new
media_variantstable (CREATE TABLE IF NOT EXISTS, idempotent). Originals stay the canonicalmedia.url. - Responsive rendering — featured images (post detail + feed cards) and inline
/uploadsbody images render as<picture>with format-switchingsrcset(AVIF→WebP→<img>fallback). SharedResponsiveImgcomponent; inline rewrite happens at read time inget_post. External URLs stay a plain<img>. - Usage tracking — media library shows "Used in N posts" and a delete confirm listing the posts (cover vs. body). Derived from featured-URL +
body_mdmatch, so it can't drift — hence nofeatured_media_idcolumn. - AVIF — behind the optional
avifcargo feature (off by default; heavy build/encode).--features avifalso emits.avifand prepends an<source type="image/avif">. - Backfill —
DX_BACKFILL_IMAGES=1at startup regenerates renditions for pre-existing uploads (idempotent).
With AVIF off (default), images render to WebP
<picture>
<source type="image/webp" srcset="…-thumb.webp 320w, …-large.webp 1600w" sizes="…">
<img src="/uploads/3_photo.jpg" loading="lazy" decoding="async">
</picture>
Verification
All gates pass: cargo fmt --check; clippy on server + wasm targets with -D warnings; cargo test (incl. 5 new server::images tests); and cargo check --features …,avif. Manual E2E steps in TODO_VERIFICATION.md.
🤖 Generated with Claude Code
Last updated 2026-05-31
Links to this note
Credits
Merged pull requests, newest first.