13. modulNuxt-fejlesztés Cloudflare-en
Cloudflare for Devs · 13. modul — keretrendszer-mélymerülés

Nuxt-fejlesztés Cloudflare-en

A 3. modul azt mutatta meg, hogy fut a Nuxt a Workersön. Ez a modul a napi valóság: mi történik build közben a motorháztető alatt, milyen presetek és modulok vannak, hogyan áll fel a projekt, milyen a dev-környezet, hova tedd a Cloudflare-specifikus kódot, és hol vannak a buktatók.

13.1A motorháztető alatt: mi történik nuxt build-kor?

A Nuxt szerveroldali motorja a Nitro, és a lényeg egyetlen szóban: preset. A Nitro egy platformfüggetlen szerver-réteget épít a kódodból, majd a preset megmondja, milyen „csomagolásban" adja ki — Node-szerverként, Lambda-handlerként, vagy éppen Worker-modulként. A te kódod (az server/api/*, a middleware-ek, az SSR) nem tud arról, hol fog futni; a fordítás lépése dönt.

A te forrásod app/ · pages/ · components/ server/api/ · server/utils/ nuxt.config.ts platform-független Nitro build preset: cloudflare_module rollup + polyfillek + routing .output/server/index.mjs EGY Worker-modul: export default { fetch, scheduled, queue } .output/public/ kliens-bundle, képek, _nuxt/* → Static Assets wrangler deploy — a kettő EGY deploy-egységként megy fel main: ./.output/server/index.mjs · assets.directory: ./.output/public A preset cseréjével ugyanez a forrás megy Node-ra vagy máshova.
13/1. ábra — A Nitro a forrásodból egyetlen Worker-modult és egy statikus mappát fordít; a wrangler ezt a kettőt tölti fel egy egységként.

Amit a preset konkrétan elintéz helyetted:

13.2Presetek: melyiket mikor?

PresetMire valóHasználd?
cloudflare_moduleWorker modul-szintaxissal + Static Assets — a mai alapértelmezett útigen, ez az alapeset
cloudflare_durableugyanaz, de Durable Object-alapú kiegészítéssel (pl. WebSocket-kezelés, Nitro task-ok, amikhez állapot kell)ha WebSocketet vagy DO-t használsz a Nitro-rétegből
cloudflare-pagesa régi Pages-célpont (_worker.js + Pages Functions)csak meglévő Pages-projekthez (3. modul: az irány a Workers)
cloudflare (sima)régi service-worker szintaxisne — elavult
Nem kell mindig kézzel beállítani. A modern Wrangler felismeri a keretrendszert: ha egy Nuxt-projektben konfig nélkül futtatsz wrangler deploy-t, felajánlja a szükséges beállítást, telepíti az adaptert és legenerálja a wrangler.jsonc-t (a Workers Builds pedig PR-t nyit ugyanezzel). Kezdésnek kényelmes; éles projektnél viszont érdemes explicit kiírni a presetet és a konfigot, hogy verziózott és kiszámítható legyen (12. modul).

13.3A projekt felállítása

Nulláról

npm create cloudflare@latest -- my-app --framework=nuxt
# → Nuxt projekt, Cloudflare-re konfigurálva: preset, wrangler.jsonc, dev-modul, scriptek

Meglévő Nuxt-app átállítása — a négy fájl, amihez hozzá kell nyúlni

1) nuxt.config.ts — a preset és a dev-modul:

nuxt.config.ts
export default defineNuxtConfig({
  nitro: {
    preset: "cloudflare_module",
    cloudflare: {
      deployConfig: true,        // a Nitro szinkronban tartja a wrangler-konfigot
      nodeCompat: true            // nodejs_compat bekapcsolása
    }
  },
  modules: ["nitro-cloudflare-dev"]  // bindingok a `nuxt dev` alatt (13.4)
});

2) wrangler.jsonc — a 12. modul szerint; a Nuxt-specifikus rész a két útvonal:

wrangler.jsonc (kivonat)
{
  "name": "my-app",
  "main": "./.output/server/index.mjs",   // a Nitro által generált Worker
  "compatibility_date": "2026-08-04",
  "compatibility_flags": ["nodejs_compat"],
  "assets": { "directory": "./.output/public", "binding": "ASSETS" },
  "observability": { "enabled": true },
  "upload_source_maps": true
  // + bindingok és env-ek (12. modul)
}

3) package.json — a scriptek, amik a csapat napi felületét adják:

{
  "scripts": {
    "dev": "wrangler types && nuxt dev",
    "build": "nuxt build",
    "preview": "nuxt build && wrangler dev",          // éles-szerű futtatás lokálisan
    "deploy:staging": "nuxt build && wrangler deploy --env staging",
    "deploy:prod": "nuxt build && wrangler deploy --env production",
    "cf-typegen": "wrangler types"
  }
}

4) .gitignore — a szokásos .nuxt, .output mellé: .dev.vars*, .wrangler/.

13.4A dev-környezet — két út, és melyiket válaszd

Ez az a pont, ahol a Nuxt+Cloudflare ökoszisztéma épp átalakulóban van, ezért érdemes tudni, mi a különbség:

A) nuxt dev + nitro-cloudflare-devB) Cloudflare Vite plugin
Hol fut a szerverkódNode-ban, a bindingok emulálva (getPlatformProxy a Miniflare fölött)valódi workerd-ben
Bindingoka wrangler-konfigból automatikusan, valódi lokális Miniflare-erőforrásokkalugyanúgy, natívan
Hűség az éleshezjó, de a runtime Node — ami ott működik, a Workersön nem feltétlena legmagasabb: ami megy, az élesben is megy
Érettség Nuxttalbevált, dokumentált, stabilújabb; Nitro/Nuxt-oldalon fokozatosan válik alapértelmezetté
DXa megszokott Nuxt HMRVite HMR, de a szerver-oldal is izolátumban

Ajánlás: ma az (A) a biztos alapfelállás a napi fejlesztéshez, és mellé egy „élesség-ellenőrző" lépés: npm run preview (nuxt build && wrangler dev), ami a buildelt Workert futtatja a valódi workerd-ben. Így a gyors hurok megmarad, de commit előtt látod, hogy a runtime-különbségek nem harapnak. Ha a projekted már a Vite-plugin útra állt (vagy új projektet kezdesz), (B) a jövőálló irány.

Titkok és környezeti változók lokálisan

# .dev.vars — NEM megy a repóba
STRIPE_SECRET_KEY="sk_test_…"
NUXT_SESSION_PASSWORD="legalabb-32-karakter-hosszu-titok"

A .dev.vars értékei ugyanúgy az env-en jelennek meg, mint élesben a wrangler secret-tel feltöltöttek. A NUXT_-prefixű változókat a Nitro ezen felül beleköti a runtimeConfig-ba — erről lentebb.

Remote bindings — ha valódi adat kell

A 11. modulból ismerős: bindingonként "remote": true, és az adott erőforrás az éles (staging!) példány lesz, miközben a Nuxt lokálisan fut. Tipikus eset: lokális D1, de valódi R2 vagy AI-binding.

13.5Bindings a Nuxt-kódban — hova tedd, hogy ne fájjon

A nyers hozzáférés így néz ki bármelyik server route-ban:

server/api/hello.get.ts
export default defineEventHandler(async (event) => {
  const { env, cf, context } = event.context.cloudflare;
  // env.DB, env.UPLOADS, env.JOBS… — a 12. modulban deklarált bindingok
  // cf: ország, colo, TLS-adatok…  context: waitUntil (2. modul)
});

Típusok

Futtasd a wrangler types-t, majd egyszer deklaráld a H3-kontextust — innentől az env.DB típusos mindenhol:

env.d.ts
declare module "h3" {
  interface H3EventContext {
    cf: CfProperties;
    cloudflare: {
      request: Request;
      env: Env;                 // a `wrangler types` által generált típus
      context: ExecutionContext;
    };
  }
}
export {};

A minta, ami megment a szétszórt event.context.cloudflare.env-től

Ne szórd tele az egész kódbázist a Cloudflare-specifikus eléréssel — vezess be egy vékony hozzáférési réteget a server/utils/-ban (a Nitro ezt auto-importálja):

server/utils/cf.ts
import type { H3Event } from "h3";

export const cf = (event: H3Event) => event.context.cloudflare;

export const useDb = (event: H3Event) => cf(event).env.DB;
export const useBucket = (event: H3Event) => cf(event).env.UPLOADS;

// háttérmunka: a válasz után is befejeződik (2. modul)
export const background = (event: H3Event, p: Promise<unknown>) =>
  cf(event).context.waitUntil(p);

// tenant-feloldás egy helyen (5b. modul mintája)
export async function useTenant(event: H3Event) {
  const host = getRequestHost(event);
  const slug = host.split(".")[0];
  const cached = await cf(event).env.CONFIG.get(`tenant:${slug}`, { type: "json" });
  if (cached) return cached;
  // … registry-lookup + KV-cache (6. modul)
}
server/api/invoices.get.ts — így lesz olvasható a hívó oldal
export default defineEventHandler(async (event) => {
  const tenant = await useTenant(event);
  const { results } = await useDb(event)
    .prepare("SELECT * FROM invoices WHERE tenant_id = ? ORDER BY created_at DESC")
    .bind(tenant.id).all();

  background(event, logAccess(event, tenant.id));
  return results;
});

runtimeConfig vs. bindings vs. secrets — mikor melyik?

EszközMireHonnan jön
bindings (env.DB)Cloudflare-erőforrásokwrangler-konfig (12. modul)
varsnem titkos beállításwrangler-konfig, a repóban
secretsAPI-kulcs, jelszówrangler secret put / .dev.vars
runtimeConfiga Nuxt saját konfig-rétege (szerver + public a kliensnek)a NUXT_-prefixű env-értékek felülírják futásidőben

Gyakorlat: a Cloudflare-erőforrásokhoz mindig bindingot használj. A runtimeConfig-ot arra tartsd, amire a Nuxt-világ szánta: kliens felé publikálható beállítások (public), illetve olyan szerveroldali értékek, amiket Nuxt-modulok várnak (pl. session-jelszó). Így nem lesz két párhuzamos konfig-rendszered ugyanarra.

13.6Nitro-specialitások Cloudflare-en

Cache és routeRules

export default defineNuxtConfig({
  routeRules: {
    "/":            { swr: 600 },
    "/blog/**":     { isr: 3600 },
    "/app/**":      { ssr: true, cache: false },   // bejelentkezett rész
    "/docs/**":     { prerender: true },            // build-időben generált
    "/api/**":      { cors: true }
  }
});

A cache-elt válaszok tárolására a Nitro a platform cache-ét használja. Fontos árnyalat: az isr/swr a PoP-onkénti cache-re támaszkodik, tehát nem globálisan egy példány frissül — ha szigorúan egységes időzítés kell, azt jobb explicit KV-be tett generált tartalommal megoldani.

useStorage() — a Nitro tárolási absztrakciója

Ha a Nitro useStorage()-ét használod (cache, sessionok, kulcs-érték adat), Cloudflare-en driverrel köthető KV-hez vagy R2-hez:

nitro: {
  storage: {
    cache:   { driver: "cloudflare-kv-binding", binding: "CONFIG" },
    uploads: { driver: "cloudflare-r2-binding",  binding: "UPLOADS" }
  }
}
Buktató: a Nitro alapértelmezett fs-drivere Workersön nem működik (nincs perzisztens fájlrendszer — 2. modul). Ha bárhol useStorage()-et használsz explicit driver nélkül, az memóriában landol, és isolate-enként elveszik. Éles használat előtt mindig kösd be a drivert.

WebSocket és háttérfeladatok

A Nitro WebSocket-támogatásához és a tartós kapcsolatokhoz Cloudflare-en Durable Object kell — erre való a cloudflare_durable preset. Ha komolyabb realtime funkciód lesz (jelenlét, kollaboráció), érdemes inkább saját DO-t írni a 7. modul mintái szerint, és a Nuxt-ot csak kliens-oldali kapcsolódásra használni: átláthatóbb és jobban skálázható.

Cron és queue a Nuxt-projektben

A Nitro `scheduled`/`queue` handlerei a generált Workerbe kerülnek. A gyakorlatban két járható út van: vagy a Nitro task-jait használod és a wrangler-konfigban felveszed a triggers.crons-t, vagy — nagyobb rendszernél tisztább — a háttérmunkát külön Workerbe teszed, és service bindinggel kötöd össze (11. modul). Utóbbi mellett szól, hogy a háttér-Workert külön deployolhatod, külön limitekkel és külön skálázással.

13.7NuxtHub — kell?

A NuxtHub egy Nuxt-réteg a Cloudflare-primitívek fölött: `hubDatabase()` (D1), `hubKV()`, `hubBlob()` (R2), `hubAI()` — plusz admin-felület és egyszerűsített deploy. A mérleg:

MelletteEllene
gyors indulás, kevesebb boilerplate, kényelmes API-kegy absztrakciós réteggel több a stackben
Nuxt-idiomatikus (auto-import, composable-jelleg)a natív bindingok tudásának egy része elfedve
szép admin/DB-böngésző dev alattha kinövöd, vissza kell fejteni a natívra

Az ajánlásom a te helyzetedben: maradj a natív bindingoknál. Egy meglévő, éles multitenant SaaS-nál a saját hozzáférési rétegedet (13.5) úgyis megírod, az pontosan illik a te modelledhez, és nem függ egy köztes csomag életciklusától. A NuxtHub új, kisebb projektnél vagy prototípusnál viszont teljesen jó választás.

13.8Projekt-struktúra — ajánlás multitenant SaaS-hoz

my-app/
├── nuxt.config.ts preset, modulok, routeRules, storage
├── wrangler.jsonc bindingok, env-ek, cron, limitek (12. modul)
├── env.d.ts H3EventContext deklaráció
├── .dev.vars lokális titkok (gitignore)
├── migrations/ D1 séma-migrációk (8. modul)
├── app/ (vagy pages/, components/…)
│ ├── pages/ · components/ · composables/
├── server/
│ ├── api/ végpontok — vékonyak, csak orchestráció
│ ├── routes/ webhookok, nem-JSON válaszok
│ ├── middleware/ auth, tenant-feloldás, request-id
│ ├── utils/ cf.ts, db.ts, tenant.ts — az egyetlen hely, ahol env-hez nyúlsz
│ └── plugins/ nitro plugin: hibakezelés, error tracker init (9. modul)
├── shared/ típusok, zod-sémák — kliens és szerver közösen
└── test/ vitest (11. modul)

Két elv, ami sokat számít éles rendszerben: ① a server/api maradjon vékony — validálás + hívás a server/utils-beli üzleti függvényre; így a logikád tesztelhető marad a HTTP-rétegtől függetlenül (11. modul). ② a tenant-feloldás middleware-ben történjen, egyszer, és az eredmény kerüljön az event kontextusába — ne minden endpoint oldja meg újra.

13.9Deploy

# kézzel
npm run build
npx wrangler deploy --env production

# előtte érdemes: éles-szerű lokális ellenőrzés
npm run preview            # nuxt build && wrangler dev

Workers Builds beállítás Nuxthoz (8. modul):

MezőÉrték
Build commandnpm run build
Deploy command (production branch)npx wrangler deploy --env production
Non-production branch deploy commandnpx wrangler versions upload --env staging
Root directorymonorepóban az app almappája

A séma-migrációk itt is a 8. modul szabálya szerint mennek: a deploy előtt, külön lépésben, stagingen automatikusan, éles környezetben kapuval.

13.10Buktatók — Nuxt-specifikus katalógus

Tünet / helyzetOkMegoldás
Build hibázik natív modulra (sharp, canvas)natív bináris nem fut isolate-ben (2. modul)képfeldolgozás: Cloudflare Images vagy R2+resize-szolgáltatás; végső esetben Containers (10. modul)
@nuxt/image nem működik alapbóla Node-alapú provider natív modult használváltás cloudflare provider vagy Images-integráció
„Worker exceeded size limit"a bundle túllépi a 10 MB-otfüggőség-audit, nuxt build --analyze, nehéz libek lazy importja vagy külön Workerbe emelése
Session/cookie furcsán viselkedika session-tár memóriában van (isolate-enként!)useStorage driver KV-re, vagy signed-cookie alapú session (nuxt-auth-utils jellegű megoldás)
process.env.X undefinedWorkersön nincs klasszikus process-környezetbindingok / runtimeConfig; a NUXT_-prefix köti be az env-értékeket
Globális változóban cache-elt adat „eltűnik"isolate-életciklus (2. modul)KV vagy DO; globális állapotra soha ne építs
DB-kliens a modul tetején jön létrea kapcsolat isolate-hez ragadkliens a handleren belül (4. modul, Hyperdrive)
Lokálisan megy, élesben CPU-hiba (1102)a limitek lokálisan nem érvényesülneknpm run preview + staging; nehéz munka Queues/Workflows-ba (7. modul)
Nagy fájl feltöltése 413-mal hasal elkérés-body limitpresigned URL, közvetlen R2-feltöltés (6. modul)
Prerenderelt oldalak hiányoznaka prerender kimenete a public mappába kerül, de az asset-config nem stimmelassets.directory ellenőrzése; not_found_handling beállítása (3. modul)

13.11Ellenőrizd magad

  1. Mit csinál pontosan a Nitro preset, és miért nem kell átírnod a Nuxt-kódodat a váltáshoz?
    Válasz

    A preset a platform-specifikus csomagolást végzi: egyetlen Worker-modullá bundle-ol, előállítja a export default { fetch, … } alakot, átvezeti a Cloudflare-kontextust (request/env/ctx) a H3 eventbe, és a statikus fájlokat a Static Assetsre bízza. A te forrásod platformfüggetlen marad — a preset cseréjével ugyanaz a kód Node-ra is fordítható.

  2. Mi a különbség a nuxt dev + nitro-cloudflare-dev és a Cloudflare Vite plugin között?
    Válasz

    Az előbbinél a szerverkód Node-ban fut, a bindingok emuláltak (getPlatformProxy/Miniflare) — gyors és bevált, de a runtime nem azonos az élessel. A Vite pluginnél a szerverkód valódi workerd-ben fut, tehát a hűség maximális. Átmeneti megoldásként a napi hurokban (A), commit előtt pedig nuxt build && wrangler dev ellenőrzés.

  3. Miért érdemes a bindings-hozzáférést a server/utils-ba zárni?
    Válasz

    Hogy a Cloudflare-specifikus elérés (event.context.cloudflare.env) egy helyen legyen: olvashatóbb hívó kód, könnyebb tesztelés, és ha változik a modell (pl. per-tenant DB-feloldás jön), egyetlen fájlt kell módosítani.

  4. Mikor használj runtimeConfig-ot és mikor bindingot?
    Válasz

    Cloudflare-erőforráshoz (D1, R2, KV, Queue…) mindig binding. A runtimeConfig a Nuxt saját konfig-rétege: kliens felé publikálható értékek (public) és Nuxt-modulok által várt szerveroldali beállítások; ezeket a NUXT_-prefixű env-értékek írják felül futásidőben.

  5. A useStorage()-ot használod cache-re, és a dev-en tökéletes, élesben viszont „elfelejti" az adatot. Mi történt?
    Válasz

    Nincs bekötve driver, így memóriában tárol — a Workersön viszont isolate-enként külön memória van, és az bármikor eldobható. Kösd be a cloudflare-kv-binding (vagy R2) drivert a nitro.storage-ban.

  6. Sorold fel a Workers Builds négy beállítását egy Nuxt-projekthez.
    Válasz

    Build command: npm run build; Deploy command: npx wrangler deploy --env production; Non-production branch deploy command: npx wrangler versions upload --env staging (hogy a PR-preview a staging erőforrásokon fusson); Root directory: monorepóban az app almappája.

Előző12. modul — A wrangler konfigurációs fájl: teljes referencia Következő 14. modul — Alchemy: Infrastructure as TypeScript