Három különböző dolgot szoktak „lassúságnak” hívni, és három különböző eszközzel kell javítani őket. Ez a modul szétválasztja a hármat, megmutatja a Nuxt késleltetett hidratálását — a legkonkrétabb kliensoldali nyereséget —, majd a Workers-specifikus részt: a bundle-limitet, a hidegindítást és a CPU-időt, valós számokkal és a méréshez tartozó parancsokkal.
A 2. modulból: minden komponens lefut a szerveren, majd újra a kliensen. A hydration az a fázis, amikor a böngésző „ráköti” a JS-t a már megjelenített HTML-re. Nagy oldalon ez a legdrágább kliensoldali tétel — és a felhasználó ezt úgy éli meg, hogy látszik az oldal, de nem reagál.
A Nuxt erre két, egymásra épülő eszközt ad:
Lazy prefix — a kód később töltődik<template>
<!-- csak akkor tölti le a komponens kódját, amikor tényleg kell -->
<LazyExportDialog v-if="dialogNyitva" />
</template>
Lazy a chunk-méretet szabályozza, nem a futásidőt: ha a komponens mégis renderelődik, ugyanúgy betöltődik és hidratálódik. A dokumentáció is figyelmeztet erre. A valódi nyereséghez a hidratálás idejét kell szabályozni — ez a következő.<template>
<!-- a hajtás alatti tartalom: csak amikor a nézetbe kerül -->
<LazyActivityFeed hydrate-on-visible />
<!-- másodlagos widget: amikor a böngésző ráér -->
<LazyUsageChart hydrate-on-idle />
<!-- nehéz szerkesztő: csak ha a felhasználó odamegy -->
<LazyRichTextEditor hydrate-on-interaction="mouseover" />
<!-- mobilon nem is kell -->
<LazySidePanel hydrate-on-media-query="(min-width: 1024px)" />
<!-- feltételhez kötve -->
<LazyAdminTools :hydrate-when="isAdmin" />
<!-- statikus tartalom: SOSEM hidratálódik — csak HTML marad -->
<LazyMarketingFooter hydrate-never />
</template>
hydrate-never a legalulértékeltebb. Rengeteg olyan komponens van egy oldalon, ami sosem lesz interaktív: lábléc, statikus fejléc, tartalmi blokk, jogi szöveg. Ezek SSR-ből megjelennek, aztán fölöslegesen hidratálódnak. A hydrate-never-rel kimaradnak a kliensoldali munkából — a HTML ugyanúgy ott van, csak nem fizetsz érte CPU-t. Ez a legolcsóbb teljesítmény-nyereség, amit egy meglévő oldalon elérhetsz.A stratégiák egymást kizárják (egy komponensre egy), és a komponens @hydrated eseményt bocsát ki, amikor aktiválódott — hasznos, ha mérni akarod.
<ClientOnly> fallbackkel (3. modul) — de emlékeztetőül: ez elveszi az SSR-t, tehát nem hydration-optimalizáció, hanem kompromisszum.ssr: false egész útvonalcsoportra (7. modul) — ahol nincs SEO-igény.shallowRef vagy sima adat is elég.Az 5. modulból tudjuk, mi ez: a szerveroldali lekérések eredménye a HTML-be ágyazva. Két szempontból számít — méret (hálózat) és tartalom (szivárgás). A méretet így nézd meg:
curl -s https://app.pelda.hu/dashboard | wc -c
curl -s https://app.pelda.hu/dashboard | grep -o '__NUXT_DATA__.*' | wc -c
| Ha a payload nagy | Mit tegyél |
|---|---|
| Teljes adatbázis-sorok utaznak | DTO a server route-ban (5. modul) — ez egyszerre méret- és biztonsági javítás |
| Több száz elemű lista az első képernyőn | Lapozás vagy virtualizálás; az első 20 elég |
| Személyre szabott blokkok | server: false — kliensre kerül, és a HTML cache-elhetővé válik (7. modul) |
| Ugyanaz az adat többször | Közös key — a Nuxt egyszer tárolja (5. modul) |
Itt jön a rész, ami Node-szerveren nem létezik. A Workernek mérethatára van, és a Nuxt-appok szerverkódja nem kicsi:
| Limit | Free | Paid |
|---|---|---|
| Worker-méret gzip után | 3 MB | 10 MB |
| Worker-méret tömörítés előtt | 64 MB | 64 MB |
| Indulási idő (globális scope kiértékelése) | 1 másodperc | 1 másodperc |
| CPU-idő kérésenként | 10 ms | 30 s alapból, 5 percig állítható |
| Memória | 128 MB | 128 MB |
| Statikus fájlok száma (verziónként) | 20 000 | 100 000 |
.output/public/ tartalma külön megy (static assets), és arra más — sokkal nagyobb — korlátok élnek. Vagyis a kliensoldali JS-bundle mérete nem számít bele a 10 MB-ba; a .output/server/ viszont igen. Ez fontos, mert a két méretet külön kell figyelni és külön eszközzel javítani.# ① gyors méret-ellenőrzés, deploy nélkül
npx wrangler deploy --outdir bundled/ --dry-run
# Total Upload: 4231.61 KiB / gzip: 1180.23 KiB
# ② méret ÉS hidegindítási profil egyben (a 11.3-as CI-kapu)
npx wrangler check startup --config .output/server/wrangler.json \
--outfile startup.cpuprofile
# ③ a KLIENS-bundle összetétele — mi hízott meg és miért
npx nuxi analyze
| Tétel | Nagyságrend | Mit tehetsz |
|---|---|---|
| ORM (TypeORM, Prisma) | Jelentős | Drizzle/Kysely kisebb (11.3); ha marad, mérd |
Node-polyfillek (nodejs_compat) | Közepes | Csak akkor kapcsold be, ha tényleg kell |
| i18n fordítások | Nyelvenként nő | Lusta betöltés nyelvenként, ne mindet a bundle-be |
| Nagy segédkönyvtárak (dátum, validáció, markdown) | Változó | await import() a hívás helyén (11.5) |
Barrel-fájlok (utils/index.ts) | Rejtett | Kilövik a tree-shakinget — ne csináld (3. modul) |
| Véletlenül becsomagolt séma vagy ORM a kliens felől | Nagy | import type, ne érték-import (11.2) |
--dry-run --outdir kimenete elemezhető: a legnagyobb modulok általában azonnal látszanak.A Worker indulásakor lefut a globális scope: minden top-level import, minden modul-szintű kifejezés. Erre 1 másodperc a keret (2025 októberétől — korábban 400 ms volt). Ha ezt átléped, a deploy nem megy át.
// ✗ ez indulási időt fogyaszt, minden izolátum-indításnál
const nagyTablazat = buildLookupTable() // modul-szinten fut le
const regexek = SZABALYOK.map(s => new RegExp(s))
// ✓ halaszd az első használatig
let _tabla: Lookup | null = null
function getTabla() { return _tabla ??= buildLookupTable() }
A wrangler check startup által kiírt .cpuprofile megnyitható a Chrome DevTools „Performance” fülén — ott látod, melyik modul kiértékelése mennyi időt vitt el. Ha az indulás gyanúsan magas, ez az egyetlen eszköz, ami megmondja, miért.
A kérésenkénti CPU-idő nem csak limit, hanem árazási tényező. Ami belefér:
| Mi fogyaszt CPU-t | Mit tehetsz |
|---|---|
| A komponensfa renderelése | Kevesebb komponens az első képernyőn; prerender ahol lehet (7. modul) |
| A payload szerializálása | Kisebb DTO — ugyanaz a javítás, mint a 15.3-nál |
| SQL-építés kérésenként | Prepared statements (11.2) |
| Jelszó-hashelés | Csak bejelentkezéskor, rate limit mögött (10. modul) |
| Nagy JSON parse/stringify | Streamelj, ahol lehet (8. modul) |
| Kriptográfia (aláírás-ellenőrzés) | Web Crypto natív — ne JS-implementációt használj |
ssr: false útvonal majdnem nullát. Mielőtt a renderelést gyorsítanád, kérdezd meg, kell-e egyáltalán rendereled — a legtöbb SaaS-ban az oldalak fele nem igényel kérésenkénti SSR-t.| Metrika | Cél | Mit befolyásol a Nuxt |
|---|---|---|
| LCP — a fő tartalom megjelenése | < 2,5 s | Sokat: az SSR ezt javítja, a nagy bundle rontja. Képméret és font-betöltés is ide tartozik |
| INP — reagálás az interakcióra | < 200 ms | Sokat: a hydration és a fölösleges reaktivitás rontja. Itt segít a késleltetett hidratálás |
| CLS — elmozduló elrendezés | < 0,1 | Közvetve: adj width/height-ot a képeknek, használj #fallback-et a <ClientOnly>-hoz, és @nuxt/fonts-ot a font-ugrás ellen |
| TTFB | < 800 ms | Sokat: SSR-idő + adatlekérés. Itt jön elő a 9. modul latency-paradoxona |
A számok akkor érnek valamit, ha a build elbukik, amikor átlépted őket. Kiindulási javaslat — igazítsd a saját appodhoz, de legyen:
| Mit | Küszöb | Miért ennyi |
|---|---|---|
| Worker-bundle (gzip) | a limit 80%-a | Legyen mozgástér, mielőtt a deploy bukna |
| Indulási profil | 800 ms (az 1 s 80%-a) | Ugyanaz az elv |
| Kliens-JS az első oldalon | ~250 KB gzip | Efölött mobilhálózaton érezhető |
| Payload egy oldalon | ~50 KB | Efölött általában DTO-hiba van mögötte |
| Lighthouse (mobil, throttled) | > 85 | Regressziófigyelésre, nem célnak |
# CI-lépés: méret + indulás + titok-keresés egyben (12.3)
npm run build
node scripts/verify-bundle.mjs # wrangler check startup + 80%-os guard
grep -ril "sk_live\|SESSION_PASSWORD" .output/public/ && exit 1
echo "OK"
@nuxt/test-utils és Vitest, mit érdemes tesztelni egy ilyen appon, a hydration mismatch szisztematikus felderítése, és a legnehezebb eset — a hiba, ami csak Workers-en jelentkezik.① Hálózat — mennyi bájt megy át (bundle, HTML+payload, képek); főleg LCP-t érint. ② Kliens-CPU — parse, execute, hydration, reaktivitás; főleg INP-t érint. ③ Szerver-CPU — SSR, szerializálás, hidegindítás; TTFB-t érint, és Workers-en pénzben is mérhető. Amíg nem tudod, melyikről van szó, a javítás vaktában lövés.
Lazy prefix és a hydrate-on-* stratégiák között?
A Lazy a chunk-méretet szabályozza: a komponens kódja külön darabba kerül és később töltődik le. De ha a komponens renderelődik, ugyanúgy betöltődik és hidratálódik. A hydrate-on-* stratégiák a hidratálás idejét szabályozzák — láthatóságra, üresjáratra, interakcióra, media queryre, feltételre, vagy soha (hydrate-never).
A hydrate-never azokra a komponensekre, amik sosem lesznek interaktívak: lábléc, statikus fejléc, tartalmi blokkok, jogi szövegek. SSR-ből megjelennek, de kimaradnak a kliensoldali munkából — a HTML ugyanaz, csak nem fizetsz érte CPU-t.
A kérdés félrevezető: a kliens-JS a .output/public/-ba kerül, ami static asset, és nem számít bele a Worker-méretbe. A 3/10 MB gzip-limit a .output/server/ Worker-kódra vonatkozik. A két méretet külön kell figyelni: az egyiket wrangler deploy --dry-run-nal, a másikat nuxi analyze-zal.
① Biztonsági: a modul-scope megosztott a kérések között, tehát a kérés-hatókörű állapot ott szivárgást okoz (6. modul). ② Teljesítmény: a modul-szintű kód minden izolátum-indításkor lefut, és beleszámít az 1 másodperces indulási keretbe. Halaszd az első használatig (lusta inicializálás).
Nem a renderelés gyorsítása, hanem az elkerülése: a prerenderelt oldal nulla CPU-t fogyaszt, a cache-találat nullát, az ssr: false útvonal majdnem nullát. Először azt kérdezd meg, kell-e kérésenként rendereled — a legtöbb SaaS-ban az oldalak fele nem igényli.