Bannerul paginii de start vine odată cu documentul
Imaginea principală se descărca deja din prima după #21 (closed), dar slide-ul căruia îi aparține sosea tot separat: măsurat pe producție, fișierul era complet la 636 ms, iar /api/banners răspundea la 1.262 ms. Imaginea stătea gata în memorie o jumătate de secundă, cu nimic în care să fie pusă — iar acea așteptare e chiar ce măsoară LCP-ul.
Ce s-a schimbat
Randarea citea deja bannerele, ca să numească prima imagine pentru preload. Acum le și scrie în document, în limba paginii, exact în forma pe care o întoarce GET /api/banners — deci hero-ul citește un singur format, nu două.
Un <script type="application/json">, nu o atribuire pe window: browserul îl parsează ca date și nu îl execută niciodată, deci nu are nevoie de nimic din politica de scripturi a paginii și nu poate deveni o poartă de injecție. Stă în <head>, în afara lui #root, pentru că React își golește containerul la prima randare.
Blocul poartă data-locale. Adresa decide limba de ambele părți (frontend/src/main.tsx schimbă limba aplicației pe cea din adresă înainte să randeze), deci cele două coincid azi; atributul e ce permite hero-ului să observe dacă vreodată nu mai coincid, în loc să arate text în română cuiva care citește în rusă.
Cererea către API rămâne și tot ea are ultimul cuvânt, deci un banner editat din panou se vede la următoarea încărcare exact ca înainte.
Mărimea
Blocul are 1.305 octeți pentru cele trei slide-uri de azi, adăugat la un document de circa 3,5 KB. În schimb dispar două drumuri dus-întors de pe calea critică (permisiunea CORS și cererea în sine).
Verificare
- Pagina randată local: bloc prezent pe pagina de start în toate trei limbile, cu textele în limba corectă; absent pe pagina de produs; absent când niciun banner nu e publicat
-
backend:npm run build,npm test— 459 de teste trec, șapte noi întests/banner-data.test.ts, între care unul care scrie</script><script>alert(1)</script>în titlul unui banner și verifică că nu poate închide blocul mai devreme -
frontend:npm run lint,npm run build,npm test— 201 de teste trec, cinci noi însrc/test/HeroBanner.test.tsx: slide-ul e desenat sincron, la prima randare, cu cererea încă nerezolvată; răspunsul de la server îl înlocuiește când sosește; un bloc scris pentru altă limbă e ignorat; un bloc invalid nu aruncă
Closes #36 (closed)