perf(web): generate avatar thumbnails automatically #122

Merged
eleith merged 1 commits from perf/right-size-avatar into main 2026-11-03 14:34:53 +00:00

Summary

Automatically optimize web avatars using the existing avatar_path and Takumi renderer. This replaces the earlier manual-thumbnail proposal: there is no new configuration field and no additional resizing package.

For avatar_path: /public/photo.webp:

  • /avatar/public/photo.webp serves the original.
  • /avatar/public/photo.webp?thumbnail=true serves the optimized avatar.
  • thumbnail=false also serves the original; other selector values return 400.
  • The requested path only validates that it matches configuration. It never selects a filesystem path or arbitrary source URL. Mismatches return 404.

Homepage, mobile booking banner, and desktop booking/rescheduling sidebar use the thumbnail URL. Paths stay in paths; there is no v parameter. Generated share cards retain the original source.

Image behavior and caching

  • Resize supported static raster images to at most 216×216 pixels; encode WebP only when it is smaller.
  • Preserve SVGs, animations, small images, and originals when conversion is unsupported or would increase bytes.
  • Never overwrite source files. Thumbnail processing caps input at 8 MiB; oversized sources fall back to the original.
  • Retain one completed derivative, revalidate source ETags/content hashes, and coalesce concurrent source fetching and resizing. Failed in-flight requests are cleared so later calls retry.
  • Preserve full-image validators and stream originals. Ask for identity encoding; if a source ignores that request, redirect to the original rather than forward decoded bytes with compressed-response headers.
  • Infer missing MIME metadata from the configured filename for SvelteKit's dev asset reader, without overriding explicit source types.

Takumi is upgraded to 2.19.0. EXIF orientation remains an accepted, documented upstream limitation; no orientation fix is claimed.

A local sample shrank from 18,470 to 4,830 bytes (~74%) at 216×216 on Takumi 2.19.0. This is an asset-size measurement, not a measured PageSpeed score improvement.

Readability and reviews

Independent code and readability reviews completed. Follow-up changes:

  • Separate original forwarding and thumbnail response construction from route orchestration.
  • Use resize guard returns and separate byte selection from response packaging.
  • Make cached results and in-flight work explicit.
  • Split E2E coverage into four named scenarios, with shared setup/restore helpers.
  • Use named request-fixture options.

The code review's compression-header issue is fixed and covered by a real gzip-upstream regression for both servers that honor identity encoding and servers that ignore it. Follow-up review found no actionable correctness issues; readability feedback was applied.

Validation

  • Full web unit suite: 1,165 tests passed.
  • Targeted Chromium suite: 18 tests passed, covering avatars, critical CSS, fonts, security headers/CSP, hydration, themes, and navigation.
  • Avatar tests cover formats, animation preservation, source changes, conditional responses, concurrency/failure cleanup, source size bounds, MIME fallback, and compressed forwarding.
  • Browser checks cover original and thumbnail responses, decoded thumbnail dimensions, unchanged original bytes, no-JavaScript homepage/booking/rescheduling at mobile and desktop sizes, an existing decoy image, and encoded recursive-source rejection.
  • Type checking, formatting, ESLint, and diff checks pass.
  • Includes patch changesets for the avatar feature and Takumi upgrade.

No image assets or deployment configuration are changed. Rebuild the Docker dev image to pick up the dependency upgrade; source mounts alone do not update container dependencies.

Branch history

Amended the original branch commit and updated it with an explicit --force-with-lease, replacing the rejected optional-thumbnail configuration approach. Ready for review; not merged or deployed.

## Summary Automatically optimize web avatars using the existing `avatar_path` and Takumi renderer. This replaces the earlier manual-thumbnail proposal: there is **no new configuration field and no additional resizing package**. For `avatar_path: /public/photo.webp`: - `/avatar/public/photo.webp` serves the original. - `/avatar/public/photo.webp?thumbnail=true` serves the optimized avatar. - `thumbnail=false` also serves the original; other selector values return 400. - The requested path only validates that it matches configuration. It never selects a filesystem path or arbitrary source URL. Mismatches return 404. Homepage, mobile booking banner, and desktop booking/rescheduling sidebar use the thumbnail URL. Paths stay in paths; there is no `v` parameter. Generated share cards retain the original source. ## Image behavior and caching - Resize supported static raster images to at most 216×216 pixels; encode WebP only when it is smaller. - Preserve SVGs, animations, small images, and originals when conversion is unsupported or would increase bytes. - Never overwrite source files. Thumbnail processing caps input at 8 MiB; oversized sources fall back to the original. - Retain one completed derivative, revalidate source ETags/content hashes, and coalesce concurrent source fetching and resizing. Failed in-flight requests are cleared so later calls retry. - Preserve full-image validators and stream originals. Ask for identity encoding; if a source ignores that request, redirect to the original rather than forward decoded bytes with compressed-response headers. - Infer missing MIME metadata from the configured filename for SvelteKit's dev asset reader, without overriding explicit source types. Takumi is upgraded to 2.19.0. EXIF orientation remains an accepted, documented upstream limitation; no orientation fix is claimed. A local sample shrank from 18,470 to 4,830 bytes (~74%) at 216×216 on Takumi 2.19.0. This is an asset-size measurement, **not a measured PageSpeed score improvement**. ## Readability and reviews Independent code and readability reviews completed. Follow-up changes: - Separate original forwarding and thumbnail response construction from route orchestration. - Use resize guard returns and separate byte selection from response packaging. - Make cached results and in-flight work explicit. - Split E2E coverage into four named scenarios, with shared setup/restore helpers. - Use named request-fixture options. The code review's compression-header issue is fixed and covered by a real gzip-upstream regression for both servers that honor identity encoding and servers that ignore it. Follow-up review found no actionable correctness issues; readability feedback was applied. ## Validation - Full web unit suite: **1,165 tests passed**. - Targeted Chromium suite: **18 tests passed**, covering avatars, critical CSS, fonts, security headers/CSP, hydration, themes, and navigation. - Avatar tests cover formats, animation preservation, source changes, conditional responses, concurrency/failure cleanup, source size bounds, MIME fallback, and compressed forwarding. - Browser checks cover original and thumbnail responses, decoded thumbnail dimensions, unchanged original bytes, no-JavaScript homepage/booking/rescheduling at mobile and desktop sizes, an existing decoy image, and encoded recursive-source rejection. - Type checking, formatting, ESLint, and diff checks pass. - Includes patch changesets for the avatar feature and Takumi upgrade. No image assets or deployment configuration are changed. Rebuild the Docker dev image to pick up the dependency upgrade; source mounts alone do not update container dependencies. ## Branch history Amended the original branch commit and updated it with an explicit `--force-with-lease`, replacing the rejected optional-thumbnail configuration approach. Ready for review; not merged or deployed.
eleith-gitea-agent Bot marked the pull request as work in progress 2026-11-02 23:40:39 +00:00
eleith added 1 commit 2026-11-03 14:29:25 +00:00
perf(web): generate avatar thumbnails automatically
ci/woodpecker/pr/calendar Pipeline was successful
ci/woodpecker/pr/cli Pipeline was successful
ci/woodpecker/pr/config Pipeline was successful
ci/woodpecker/pr/db Pipeline was successful
ci/woodpecker/pr/jobs Pipeline was successful
ci/woodpecker/pr/video-chat Pipeline was successful
ci/woodpecker/pr/web Pipeline was successful
ci/woodpecker/pr/worker Pipeline was successful
ci/woodpecker/push/calendar Pipeline was successful
ci/woodpecker/push/cli Pipeline was successful
ci/woodpecker/push/config Pipeline was successful
ci/woodpecker/push/db Pipeline was successful
ci/woodpecker/push/jobs Pipeline was successful
ci/woodpecker/push/video-chat Pipeline was successful
ci/woodpecker/push/web Pipeline was successful
ci/woodpecker/push/worker Pipeline was successful
9691ea7bce
eleith force-pushed perf/right-size-avatar from a4d6253654 to 9691ea7bce 2026-11-03 14:29:25 +00:00 Compare
eleith-gitea-agent Bot changed title from WIP: perf(web): support a smaller web avatar to perf(web): generate avatar thumbnails automatically 2026-11-03 14:30:22 +00:00
eleith merged commit 9691ea7bce into main 2026-11-03 14:34:53 +00:00
eleith deleted branch perf/right-size-avatar 2026-11-03 14:34:53 +00:00
Sign in to join this conversation.
No Reviewers
2 Participants
Notifications
Due Date
No due date set.
Dependencies

No dependencies set.

Reference: eleith/when#122