feat(images): responsive <picture> srcset for posts/blocks, drop AVIF for build speed
Deploy to Firebase Hosting / deploy (push) Failing after 2m4s

## Responsive sources

Wire `ensureResponsiveImage` (multi-width × multi-format srcset) into the three
remaining single-`<img>` components:

- ImageBlock (body): widths 600 + 1200, fit follows transform params
- ImageGalleryBlock (single-image branch): widths 600 + 1280, fit=contain
- PostCard (post-list cards): widths 400 + 800, fit=cover, ar=3:2

`resolveContentImages` now sets `block.resolvedResponsive` alongside the legacy
`resolvedImageSrc`, so every Svelte block component renders `<picture>` if
the responsive shape is present and falls back to a plain `<img>` otherwise.

Posts list pages (`/posts`, `/posts/page/N`, `/posts/tag/.../page/N`) call a
new `resolvePostCardResponsive` helper instead of one-shot `ensureTransformedImage`.

## Drop AVIF from defaults

Server-side AVIF encoding on the CMS is 5-10× slower than WebP. The bandwidth
win is marginal for this site and the build time hit is severe (multi-minute
hangs on each new variant). Default formats are now `["webp", "jpeg"]` for
`ensureResponsiveImage`, in `Layout.astro`'s TopBanner hero, and in the
post-card helper. Callers can still opt back into AVIF per-call.

## Module split for client-safe types

`ResponsiveImage` is now defined in a tiny `rusty-image-types.ts` and
duplicated in `rusty-image.ts` so Svelte components can `import type` the
shape without dragging `rusty-image.ts` (and its `node:crypto`/`node:fs`
imports) into the browser bundle.

`resolvePostCardResponsive` lives in a new `server-image.ts` for the same
reason — `blog-utils.ts` is imported by Svelte islands, so its server-only
helpers move out.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
Peter Meier
2026-04-27 18:41:22 +02:00
parent e8bdb9e987
commit e28230bcef
19 changed files with 1193 additions and 14745 deletions
+5
View File
@@ -1933,6 +1933,11 @@ balanced-match@^1.0.0:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-1.0.2.tgz#e83e3a7e3f300b34cb9d87f615fa0cbf357690ee"
integrity sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==
blurhash@^2.0.5:
version "2.0.5"
resolved "https://registry.yarnpkg.com/blurhash/-/blurhash-2.0.5.tgz#efde729fc14a2f03571a6aa91b49cba80d1abe4b"
integrity sha512-cRygWd7kGBQO3VEhPiTgq4Wc43ctsM+o46urrmPOiuAe+07fzlSB9OJVdpgDL0jPqXUVQ9ht7aq7kxOeJHRK+w==
boolbase@^1.0.0:
version "1.0.0"
resolved "https://registry.yarnpkg.com/boolbase/-/boolbase-1.0.0.tgz#68dff5fbe60c51eb37725ea9e3ed310dcc1e776e"