2. modulA Nuxt anatómiája: mi épül, és mi hol fut
Nuxt for Devs · 2. modul

A Nuxt anatómiája: mi épül, és mi hol fut

Ez az a modul, ami nélkül a későbbi hibák érthetetlenek maradnak. Három kérdésre válaszol: mi történik pontosan nuxt build-kor, mi kerül a .output/-ba (és mit tölt fel a wrangler), és — a legfontosabb — melyik kódod hol fut le. Ha csak egy táblázatot jegyzel meg a tananyagból, az a 2.4-es legyen.

2.1A három futásidő

Vue SPA-ban egyetlen futásidő van: a böngésző. Nuxtban három, és ezek különböző időpontokban, különböző környezetben futnak — más globális objektumokkal, más API-kkal, más korlátokkal.

① BUILD-TIME a te gépeden / a CI-ben, egyszer · nuxt.config.ts kiértékelése · modulok lefutása (modules/) · route-tábla generálása · komponensek fordítása · auto-import-térkép, típusok · prerender (ha van) Node.js — itt még minden megy ② SZERVER a Workerben, MINDEN kérésnél · server/middleware · server/api, server/routes · SSR: komponensek renderelése · useFetch / useAsyncData · route middleware (első kérés) · plugins (a .client-esek nélkül) workerd — se fs, se Node-processz ③ KLIENS a böngészőben, hydration után · hydration · onMounted és a lifecycle · minden interakció · kliensoldali navigáció · .client komponensek/pluginek · window, document, localStorage böngésző — nincs titok, nincs DB A KÖZÉPSŐ SÁV: ez a kód ② és ③ helyen IS lefut komponensek <script setup> törzse · composable-ok · sima plugins · route middleware
A hibák túlnyomó része abból ered, hogy a középső sáv kódját valaki csak az egyik oszlop szemüvegén át írta meg.

A középső sáv a kritikus. Egy komponens <script setup> blokkja kétszer fut le: egyszer a szerveren az SSR alatt, egyszer a böngészőben a hydration alatt. Ha a kettő nem ugyanazt az eredményt adja, hydration mismatch lesz belőle. Ha valami olyat használsz, ami csak az egyik helyen létezik (window, vagy fordítva: egy adatbázis-kliens), akkor hiba.

2.2Mi történik nuxt build-kor

A build nem egy lépés, hanem négy, és a hibaüzenetek attól függően néznek ki, hogy melyikben akadtál el:

a forrásod app/ · server/ · shared/ nuxt.config.ts · modules/ ① nuxt prepare modulok lefutnak, virtuális fájlok + típusok → .nuxt/ ② kliens build (Vite) JS/CSS chunkok, assetek ③ szerver build (Vite) SSR-renderer + server routes ④ Nitro + preset platformra szabott csomagolás → .output/ wrangler deploy Hol akadtál el? ① modul- vagy konfighiba · ② hiányzó import, CSS, típus ③ Node-only csomag a szerverkódban · ④ preset/bundle-méret A leggyakoribb Workers-hiba a ③-ban és a ④-ben születik — de csak deploy után robban.
Négy fázis, két külön Vite-build. A kliens és a szerver ugyanabból a forrásból, de külön bundle-be fordul.

Két dolgot érdemes ebből megjegyezni. Egyrészt a .nuxt/ nem szemét, hanem a fordítás félkész terméke: itt találod a generált route-táblát, az auto-import térképet és a típusokat. Amikor nem érted, honnan jön egy useValami(), ide nézel. Másrészt a kliens- és a szerverkód külön bundle — ezért fordulhat elő, hogy valami a böngészőben megy, a szerveren nem, vagy fordítva.

2.3Mi kerül a .output/-ba

Ez a deploy-artefakt. Semmi mást nem kell feltölteni, és semmit nem kell benne kézzel módosítani (a következő build felülírja):

.output/
├─ public/                 ← statikus fájlok — ez lesz a Workers static assets
│  ├─ _nuxt/                  a buildelt JS/CSS chunkok, hash-elt névvel
│  │  ├─ entry.C3f1a9.js
│  │  └─ default.a71b2c.css
│  ├─ favicon.ico             a public/ mappád tartalma változatlanul
│  └─ ...                     plusz a prerenderelt oldalak, ha vannak
├─ server/
│  ├─ index.mjs            ← A BELÉPÉSI PONT. Workers-en ez a Worker modul.
│  └─ chunks/                 a szerverkód darabjai (SSR + server/api)
└─ nitro.json                 metaadat: melyik presettel készült, verziók

Node-szerveren ezt így indítanád: node .output/server/index.mjs. Workers-en viszont ugyanez az index.mjs nem egy szerver, amit elindítasz, hanem egy Worker-modul, amit a platform hív meg — a wrangler.jsonc-ben ez lesz a main, a .output/public pedig az assets.directory. A 17. modulban ezt kirakjuk teljes konfigurációval.

Miért fontos ezt látni? Mert innen érthető meg, hogy a Nuxt nem „egy Node-app, amit valahogy Workersre tuszkolunk". A Nitro a preset alapján más kimenetet generál: más belépési pontot, más polyfilleket, más storage-drivereket. A Cloudflare nem célplatform-utólag, hanem egy first-class build-célpont.

2.4Melyik kódom hol fut? — a referencia-tábla

Ezt tedd a könyvjelzők közé. A tananyag hátralévő részében erre fogok visszautalni:

HelyBuildSzerverKliensMegjegyzés
nuxt.config.tsCsak build-time fut. Az értékei beépülnek — futásidőben nem olvasod.
modules/Saját Nuxt-modulok: a buildet módosítják, nem a futást.
app/components/*.vuefordításKétszer fut. Itt születik a hydration mismatch.
*.client.vuefordításCsak böngészőben renderel (térkép, chart, szerkesztő).
*.server.vuefordításNem hidratálódik — statikus marad.
app/composables/Auto-import. Ide ne tegyél titkot vagy DB-hívást.
app/plugins/x.tsMindkét oldalon lefut, app-indításkor.
app/plugins/x.client.tsAnalitika, böngésző-API-k ide.
app/middleware/Első kérésnél szerveren, utána navigációnál kliensen. Nem biztonsági határ.
server/api/, server/routes/Soha nem kerül a kliens-bundle-be. Itt vannak a titkok.
server/middleware/Minden szerverre érkező kérésnél fut. Tenant-feloldás helye.
server/utils/Auto-import, de csak szerveroldalon. DB-wrapper, session ide.
shared/Nuxt 4 újdonság: közös típusok és tiszta segédfüggvények.
public/másolásletöltésVáltozatlanul kikerül a gyökérre. Nem megy át a buildon.
A tábla két legfontosabb sora. ① A server/ alatti kód soha nem kerül a böngészőbe — ide, és csak ide való minden titok, adatbázis-hozzáférés és jogosultság-ellenőrzés. ② Az app/middleware/ route middleware nem biztonsági határ: kliensoldali navigációnál a böngészőben fut, tehát megkerülhető. Ha egy adatot védeni akarsz, azt a server/-ben kell ellenőrizni. Erre a 10. modulban visszatérünk, de a hibát most is el lehet követni.

A gyakorlati eszköz: import.meta

Amikor kódban kell eldöntened, hol vagy:

const width = ref(0)

// ✗ így szokták — működik, de nem tree-shake-elhető, és a szerverbundle-ben is ott marad
if (typeof window !== 'undefined') width.value = window.innerWidth

// ✓ így kell — a build ki tudja dobni a nem oda való ágat
if (import.meta.client) width.value = window.innerWidth

// a teljes készlet
import.meta.client      // böngészőben fut
import.meta.server      // szerveren fut (SSR vagy server route)
import.meta.dev         // nuxt dev alatt
import.meta.prerender   // build-time prerender közben

A régi process.server / process.client párost felejtsd el — nem véletlenül tűnt el: Workers-en nincs értelmes process globális, és a Nuxt 5 felé az import.meta.* a járható út.

2.5A Nuxt 4 könyvtárszerkezete

A Nuxt 4 legfeltűnőbb változása, hogy az alkalmazás-kód bekerült egy app/ mappába. Nem esztétikai döntés: így a fájlfigyelő nem a node_modules/ és a .git/ mellett kutat, és a szerver-, kliens- és megosztott kód szétválasztása a TypeScript-projektek szintjén is megtörténik.

a-projekted/
├─ app/                    ← ALKALMAZÁS (kliens + SSR)
│  ├─ app.vue                 a gyökérkomponens
│  ├─ pages/                  route-ok (4. modul)
│  ├─ layouts/
│  ├─ components/             auto-import
│  ├─ composables/            auto-import
│  ├─ middleware/             route middleware
│  ├─ plugins/
│  ├─ utils/                  auto-import
│  └─ assets/                 amin átmegy a build (SCSS, kép)
├─ server/                 ← SZERVER — a gyökérben marad, NEM az app/ alatt
│  ├─ api/
│  ├─ routes/
│  ├─ middleware/
│  ├─ utils/                  auto-import, csak szerveroldalon
│  └─ plugins/                Nitro-pluginek (nem app-pluginek!)
├─ shared/                 ← KÖZÖS: típusok, tiszta függvények (Nuxt 4)
├─ public/                    változatlanul kikerül
├─ modules/                   saját build-idejű Nuxt-modulok
├─ nuxt.config.ts
├─ wrangler.jsonc             a Cloudflare-oldal (17. modul)
└─ tsconfig.json              egyetlen fájl a gyökérben, a többit a Nuxt generálja
Két gyakori félreértés. ① A server/plugins/ nem ugyanaz, mint az app/plugins/: az előbbi Nitro-szintű (kérés-hookok, hibakezelés), az utóbbi Vue-app-szintű. ② A shared/ csak olyasmit bír el, ami mindkét környezetben értelmes — típusok, validációs sémák, formázó függvények. Ha oda importálsz egy adatbázis-klienst, az bekerül a kliens-bundle-be is, és vagy elszáll, vagy kiszivárogtat.

2.6Nitro és a presetek

A Nitro a Nuxt szerver-rétege — de önálló projekt, saját életet él. Ő felel a server/api útvonalakért, a fájl-alapú szerver-routingért, a storage-rétegért (useStorage()), a cache-elésért, és a platformra szabott csomagolásért.

Ez utóbbi a preset-rendszer. Ugyanaz a forráskód különböző kimenetté fordul aszerint, hova megy:

// nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: 'cloudflare_module',   // Workers + static assets — ez kell nekünk
  },
})

// vagy környezeti változóból, CI-ben:
// NITRO_PRESET=cloudflare_module nuxt build

A cloudflare_module preset Workersre épít (ez az ajánlott út); a régebbi cloudflare_pages a Pages-hez tartozik, ami a Cloudflare-anyag szerint kifutó irány. A preset dönti el, hogy milyen belépési pont készül, milyen polyfillek kellenek, hogyan viselkedik a useStorage(), és mit tud a beépített cache-réteg.

Ez a Nuxt egyik legerősebb érve. A platformfüggő rész egyetlen konfigsorban van — a te kódod nem tud róla. Ha holnap mégis Node-szerverre kellene visszaállni, az elvileg egy preset-csere (a gyakorlatban plusz a platformspecifikus feltételezéseid átnézése). Ez a hordozhatóság az, amit egy adapter-alapú megoldás nehezebben ad.

2.7nuxt dev — és miért „ment lokálisan”

A fejlesztői szerver nem ugyanaz, ami élesben fut, és a különbség pont Workers-en a legnagyobb:

nuxt devéles Workers
RuntimeNode.js a gépedenworkerd az edge-en
npm-csomagokgyakorlatilag mind működikcsak ami Web-API-kkal beéri (19. modul)
Fájlrendszervannincs
Szerverkódigény szerint, Vite-tal transzformálvaegyetlen bundle-be fordítva
Bindingsnincs — hacsak nem állítod be (18. modul)van
Méret- és CPU-limitnincsvan

Innen ered a leggyakoribb frusztráció: „lokálisan tökéletesen ment, deploy után 500-as”. Nem véletlen, hanem szerkezeti: dev alatt a szerverkódod Node-ban fut, élesben a workerd-ben. Két dolog véd ellene, és mindkettőt korán érdemes bevezetni:

2.8Felkészülés a Nuxt 5-re — anélkül, hogy rá várnánk

A Nuxt 5 a Nitro v3-mal együtt érkezik, és még nincs kint; a 4.5 már tartalmaz hozzá előkészítést. Nem érdemes rá várni — viszont van négy szokás, amivel most, ingyen csökkented a jövőbeli migráció költségét:

És egy dátum, amit érdemes naptárba tenni: a Nuxt 3 támogatása 2026. július 31-én lejárt. A Nuxt 4-nél is lesz ilyen nap. Amikor a projekt tervezésénél időt osztasz, tervezz be nagyjából kétévente egy-két hetes keretrendszer-frissítést. Ez nem pesszimizmus, hanem a keretrendszer-használat üzemeltetési költsége.

2.9Ellenőrizd magad

  1. Egy komponens <script setup> blokkjában meghívod a localStorage-ot. Mi történik, és hogyan javítod?
    Válasz

    SSR alatt a szerveren nincs localStorage, tehát a renderelés hibára fut. Javítás: tedd if (import.meta.client) ágba, vagy onMounted()-be (az csak kliensen fut), vagy ha az egész komponens böngésző-függő, nevezd át *.client.vue-ra. A typeof window !== 'undefined' is működik, de az import.meta.client jobb, mert a build ki tudja dobni a nem oda való ágat.

  2. Miért nem tehetsz API-kulcsot egy app/composables/ alatti fájlba?
    Válasz

    Mert a composable-ok a kliens-bundle-be is bekerülnek — a felhasználó megnyitja a forrást, és ott a kulcs. Titok csak a server/ alá vagy a runtimeConfig szerveroldali (nem public) részébe kerülhet, és csak szerveroldali kód olvashatja. Erre a 12. modulban külön kitérünk.

  3. Mi a különbség a server/plugins/ és az app/plugins/ között?
    Válasz

    A server/plugins/ Nitro-szintű: a szerver életciklusához és a kérés-hookokhoz kapcsolódik (például globális hibakezelés, minden válaszra fejléc). Az app/plugins/ a Vue-alkalmazás indulásakor fut le, és a Vue-példányhoz ad hozzá dolgokat (direktívák, providek). Nevük hasonló, közük nincs egymáshoz.

  4. Lokálisan megy a kódod, deploy után 500-as hibát kapsz. Melyik build-fázisban keletkezett a probléma, és miért csak most derült ki?
    Válasz

    Jellemzően a szerver-buildben (③) vagy a Nitro-csomagolásnál (④) — például egy Node-only csomag került a server/ kódba, vagy átlépted a bundle-limitet. Azért csak most derül ki, mert a nuxt dev Node.js-ben futtatja a szerverkódot, élesben viszont workerd-ben fut. Megelőzés: platform-emuláció dev alatt (18. modul) és korai preview-deploy.

  5. Mit tölt fel valójában a wrangler deploy egy Nuxt-projektnél?
    Válasz

    Két dolgot, egy műveletben: a .output/server/index.mjs-t Worker-kódként (ez a main), és a .output/public/ tartalmát static assetsként. A forráskódod, a node_modules és a .nuxt/ nem megy sehova — a .output/ a teljes deploy-artefakt.

  6. Miért nem elég az app/middleware/-be tett jogosultság-ellenőrzés?
    Válasz

    Mert a route middleware kliensoldali navigációnál a böngészőben fut, tehát a felhasználó megkerülheti. Jó arra, hogy a UI ne villantson fel olyat, amihez nincs joga — de az adatot a server/ oldalon kell védeni, minden egyes végponton. A kettő nem helyettesíti egymást.

Előző1. modul — Miért Nuxt? — és miért pont Cloudflare-en Következő 3. modul — Vue-fejjel Nuxtba: mi változik