Roll out client-side image compression to market + profile #59

Closed
opened 2026-05-20 14:54:41 +00:00 by padreug · 1 comment
Owner

Background

ImageUploadService now supports client-side resize + re-encode before the pict-rs POST, gated behind an opt-in compress option / <ImageUpload :compress="true"> prop. Events adopted it for banner uploads in commit [TODO: link once pushed].

Defaults when enabled (in src/modules/base/services/ImageUploadService.ts):

  • maxWidthOrHeight: 1920
  • maxSizeMB: 1 (target output, not validation cap)
  • fileType: 'image/webp'
  • initialQuality: 0.85
  • useWebWorker: true

EXIF orientation is handled by browser-image-compression; WebP encoding falls back to original-on-failure.

Gap

The existing consumers still upload originals untouched:

  • src/modules/market/components/CreateProductDialog.vue — up to 5 images per product, each potentially a 5–8 MB phone photo. The hot path on a busy marketplace.
  • src/modules/base/components/ProfileSettings.vue — profile avatar.

Pict-rs at img.ariege.io stores every original at full resolution forever; process.webp?resize=… URLs only affect delivery. So the disk hit is real.

Proposal

Two options, pick one:

  1. Flip the default in ImageUploadService so compress defaults to true and consumers opt out if they have a reason. Minimal surface — one-line change in the service; no consumer churn.
  2. Audit per-consumer and add :compress="true" (or tuned options) to each <ImageUpload> site. More explicit at the call site, slightly more code.

Suggested split for option 2:

  • Market product images: :compress="true" with default knobs (banner-like, posters and product shots in the same size class).
  • Profile avatars: :compress="{ maxWidthOrHeight: 512, maxSizeMB: 0.2 }" — avatars don't need 1920 px.

I lean (1) since it shrinks the trap surface — a future consumer that forgets the prop still gets compressed uploads.

Out of scope

  • Server-side preprocessing in pict-rs config (separate concern, infra repo).
  • Backfilling already-uploaded originals (no clear win — they're already on disk).

Sources

Reasoning + format choice (WebP over AVIF, resize-first-then-quality, EXIF orientation footgun) — see the events PR description / commit body.

## Background `ImageUploadService` now supports client-side resize + re-encode before the pict-rs POST, gated behind an opt-in `compress` option / `<ImageUpload :compress="true">` prop. Events adopted it for banner uploads in commit [TODO: link once pushed]. Defaults when enabled (in `src/modules/base/services/ImageUploadService.ts`): - `maxWidthOrHeight: 1920` - `maxSizeMB: 1` (target output, not validation cap) - `fileType: 'image/webp'` - `initialQuality: 0.85` - `useWebWorker: true` EXIF orientation is handled by `browser-image-compression`; WebP encoding falls back to original-on-failure. ## Gap The existing consumers still upload originals untouched: - `src/modules/market/components/CreateProductDialog.vue` — up to 5 images per product, each potentially a 5–8 MB phone photo. The hot path on a busy marketplace. - `src/modules/base/components/ProfileSettings.vue` — profile avatar. Pict-rs at img.ariege.io stores every original at full resolution forever; `process.webp?resize=…` URLs only affect *delivery*. So the disk hit is real. ## Proposal Two options, pick one: 1. **Flip the default in `ImageUploadService`** so `compress` defaults to `true` and consumers opt *out* if they have a reason. Minimal surface — one-line change in the service; no consumer churn. 2. **Audit per-consumer** and add `:compress="true"` (or tuned options) to each `<ImageUpload>` site. More explicit at the call site, slightly more code. Suggested split for option 2: - Market product images: `:compress="true"` with default knobs (banner-like, posters and product shots in the same size class). - Profile avatars: `:compress="{ maxWidthOrHeight: 512, maxSizeMB: 0.2 }"` — avatars don't need 1920 px. I lean (1) since it shrinks the trap surface — a future consumer that forgets the prop still gets compressed uploads. ## Out of scope - Server-side preprocessing in pict-rs config (separate concern, infra repo). - Backfilling already-uploaded originals (no clear win — they're already on disk). ## Sources Reasoning + format choice (WebP over AVIF, resize-first-then-quality, EXIF orientation footgun) — see the events PR description / commit body.
Author
Owner

Both consumers rolled out — went with option 2 (per-consumer opt-in) since profile wants different knobs than market:

  • c1194da feat(market): client-side compress product image uploads — default knobs (1920px / WebP / q=0.85), matches the events banner case
  • a815442 feat(base/profile): compress avatar uploads with tight 512px cap — { maxWidthOrHeight: 512, maxSizeMB: 0.2 } since avatars don't need 1920px

compress stays opt-in in the service. Default-on is still on the table for a future change once we're confident no consumer wants raw originals.

Both consumers rolled out — went with option 2 (per-consumer opt-in) since profile wants different knobs than market: - `c1194da` feat(market): client-side compress product image uploads — default knobs (1920px / WebP / q=0.85), matches the events banner case - `a815442` feat(base/profile): compress avatar uploads with tight 512px cap — `{ maxWidthOrHeight: 512, maxSizeMB: 0.2 }` since avatars don't need 1920px `compress` stays opt-in in the service. Default-on is still on the table for a future change once we're confident no consumer wants raw originals.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
aiolabs/webapp#59
No description provided.