Imagini: 215 MB → 77 MB, WebP servit prin <picture>, lazy-loading corectat
Închide #7 (closed) pe partea de fișiere și de livrare. Cele patru puncte din issue, în ordine.
Ce s-a schimbat
Unealtă nouă: tools/image-optimizer. Rulează la cerere peste frontend/public,
nu la fiecare build — sharp stă în propriul package.json, deci nici pipeline-ul,
nici imaginea de frontend nu-l instalează. npm run check verifică invariantul.
Conversia. 214,8 MB de rastere au devenit 47,5 MB de rastere + 29,2 MB de WebP.
Latura lungă e plafonată la 1600 px (nimic pe site nu se afișează peste 960 px CSS,
măsurat la 1920 și la 430). 147 de fișiere .png care nu aveau nicio transparență
reală au devenit .jpg; cele 164 cu transparență adevărată au rămas .png. Fiecare
raster are acum un frate .webp mai mic decât el.
Livrarea. frontend/src/components/Picture.tsx randează <picture> cu sursa
WebP înaintea rasterului. Se aplică doar căilor locale: o imagine încărcată din
panou, un URL absolut sau un SVG rămân exact ce erau, pentru că <picture> nu are
a doua șansă — o sursă acceptată și negăsită înseamnă imagine ruptă, nu una mai lentă.
Lazy-loading. loading="lazy" era pus pe două imagini vizibile fără scroll
(hero-ul de colecție și cardul cadou) și lipsea de pe șaptesprezece care nu sunt.
Ambele sensuri corectate.
Bază de date. backend/prisma/rename-image-extensions.ts duce redenumirea în
bazele deja populate: seed.ts face upsert(..., update: {}) pe produse, deci un
hoverImage stocat ar rămâne pentru totdeauna pe un fișier care nu mai există.
Rescrie doar potriviri exacte din tabelul de 147, deci un upload făcut între timp
de admin supraviețuiește. Idempotent.
Verificare
-
npx tsc -p tsconfig.app.json --noEmitcurat,oxlintcu singurul avertisment preexistent (src/App.tsx:69), 181 de teste frontend, 417 teste backend, ambele build-uri trec. -
find frontend/public -size +1000k→ 0.-size +300k→ 0. - Test nou,
publicAssets.test.ts: fiecare cale de imagine scrisă în cod are fișier pe disc, fiecare raster are frate.webp, nimic peste 300 KB. Nimic altceva din proiect nu observa o cale ruptă. - Randat local la 1920 și 430 pe 13 pagini: 816 imagini comparate cu producția, 0 diferențe de geometrie, 0 imagini rupte, 0 răspunsuri 4xx.
- Scriptul de redenumire rulat pe o copie a bazei: 63 de valori în 63 de rânduri (Product 32, ProductDetail 29, ContentListItem 2), a doua rulare nu mai găsește nimic, iar după el nicio cale din bază nu mai lipsește de pe disc.
Ordinea de livrare — obligatorie
- Merge → deploy (imaginile noi ajung pe disc).
- Abia apoi
rename-image-extensions.tspe bază. Invers, baza ar spune.jpgîn timp ce containerul are încă.png, și pozele produselor ar dispărea.
Înscrierea scriptului în cele două joburi manuale vine într-un MR separat: orice
diff care atinge .gitlab-ci.yml lasă MR-ul fără pipeline, deci fără build și fără
deploy.
Rămâne în afara acestui MR
- Punctul patru din issue, Cloudflare Polish, nu se mai justifică: era o măsură de avarie până intra conversia, iar acum ar recomprima fișiere deja optimizate.
- Imaginile încărcate din panou nu trec prin nimic —
backend/src/lib/uploads.tsle scrie așa cum vin. Hero-ul paginii principale, elementul LCP, e chiar un astfel de fișier. Primește issue propriu.