Nuxt 4 w 2026: Nowa Struktura Katalogow i Migracja z Nuxt 3

Kompletny przewodnik po Nuxt 4: nowa struktura katalogu app/, migracja krok po kroku z Nuxt 3, singleton data fetching, shallow reactivity, TypeScript context splitting, Vue Router v5, zarzadzanie meta tagami i lista kontrolna migracji.

Diagram nowej struktury katalogow Nuxt 4 z migracją z Nuxt 3

Nuxt 4 wprowadza fundamentalne zmiany w sposobie organizacji projektow opartych na Vue. Nowa struktura katalogow z centralnym folderem app/, ujednolicona warstwa pobierania danych, domyslna plytka reaktywnosc oraz podzielony kontekst TypeScript wymagaja od zespolow programistycznych przemyslanej strategii migracji. Dla programistow pracujacych z ekosystemem Vue i Nuxt zrozumienie tych zmian jest niezbedne zarowno w codziennej pracy, jak i podczas procesow rekrutacyjnych. Niniejszy artykul omawia kazda istotna zmiane w Nuxt 4, prezentuje praktyczne przyklady kodu i dostarcza kompletna liste kontrolna migracji z Nuxt 3.

Automatyzacja migracji

Nuxt 4 oferuje oficjalny codemod, ktory automatyzuje restrukturyzacje katalogow. Przed reczna migracja warto uruchomic npx codemod@latest nuxt/4/file-structure, aby zautomatyzowac wiekszosc zmian strukturalnych. Pozostale kroki -- takie jak dostosowanie composable'ow, konfiguracji TypeScript i zarzadzania meta tagami -- wymagaja jednak recznej interwencji.

Nowa struktura katalogu app/

Najbardziej widoczna zmiana w Nuxt 4 to przeniesienie wszystkich plikow aplikacji kliencko-serwerowej do dedykowanego katalogu app/. W Nuxt 3 komponenty, strony, layouty, middleware i pluginy znajdowaly sie bezposrednio w katalogu glownym projektu. Nuxt 4 wymusza separacje kodu aplikacji od konfiguracji, zasobow publicznych i kodu serwerowego.

text
my-nuxt-app/
├─ app/
│  ├─ assets/
│  ├─ components/
│  ├─ composables/
│  ├─ layouts/
│  ├─ middleware/
│  ├─ pages/
│  ├─ plugins/
│  ├─ utils/
│  ├─ app.vue
│  ├─ app.config.ts
│  └─ error.vue
├─ content/
├─ public/
├─ shared/         # New: code shared between app and server
├─ server/
└─ nuxt.config.ts

Nowy katalog shared/ stanowi istotne uzupelnienie architektury. Umozliwia wspoldzielenie typow, utilit i stalych miedzy kodem aplikacji (app/) a kodem serwerowym (server/). Wczesniej programisci musieli duplikowac definicje typow lub stosowac obejscia z importami wzglednymi. Katalog shared/ rozwiazuje ten problem na poziomie strukturalnym, zapewniajac jedna zrodlowa lokalizacje dla wspolnego kodu.

Plik nuxt.config.ts pozostaje w katalogu glownym projektu -- nie jest przenoszony do app/. Analogicznie, katalog server/ i public/ zachowuja swoje dotychczasowe pozycje. Ta separacja jasno definiuje granice odpowiedzialnosci: app/ zawiera kod renderowany w przegladarce i na serwerze SSR, server/ obsluguje logike backendowa, a shared/ zapewnia most miedzy tymi dwoma warstwami.

Migracja krok po kroku z Nuxt 3

Proces migracji z Nuxt 3 do Nuxt 4 sklada sie z kilku etapow. Pierwszym krokiem jest aktualizacja samego frameworka do najnowszej wersji z jednoczesna deduplikacja zaleznosci.

bash
# Upgrade Nuxt and deduplicate dependencies
npx nuxt upgrade --dedupe

Nastepnie nalezy uruchomic oficjalny codemod, ktory automatycznie przeorganizuje strukture plikow zgodnie z nowym standardem. Codemod przenosi pliki do katalogu app/, aktualizuje sciezki importow i dostosowuje konfiguracje.

bash
# Automate the directory restructuring
npx codemod@latest nuxt/4/file-structure

W przypadku projektow, ktore nie moga natychmiast przejsc na nowa strukture katalogow, Nuxt 4 oferuje opcje kompatybilnosci wstecznej. Ustawienie srcDir i dir.app w konfiguracji pozwala zachowac plaska strukture podczas stopniowej migracji.

nuxt.config.tstypescript
export default defineNuxtConfig({
  srcDir: '.',
  dir: { app: 'app' },
})

Ta opcja fallback jest jednak rozwiazaniem tymczasowym. Zespol Nuxt jednoznacznie rekomenduje pelna migracje do struktury z katalogiem app/, poniewaz przyszle wersje frameworka beda optymalizowane pod katem tego ukladu. Ponadto narzedzia ekosystemu, takie jak Nuxt DevTools i moduly spolecznosci, coraz czesciej zakladaja nowa strukture jako domyslna.

Warstwa pobierania danych: singleton pattern i reaktywne klucze

Nuxt 4 wprowadza fundamentalna zmiane w dzialaniu composable'ow useAsyncData i useFetch. W Nuxt 3 wywolanie tego samego klucza danych z roznych komponentow moglo prowadzic do zduplikowanych zadan sieciowych i niespojnosci w stanie. Nuxt 4 implementuje wzorzec singleton: kazdy unikalny klucz danych jest powiazany z dokladnie jedna instancja pobierania, niezaleznie od liczby komponentow korzystajacych z tych samych danych.

Dodatkowo useAsyncData otrzymuje nowy parametr getCachedData z obiektem kontekstu ctx, ktory informuje o przyczynie ponownego wywolania. Umozliwia to precyzyjne kontrolowanie, kiedy uzywane sa dane z cache'u, a kiedy wymagane jest nowe zapytanie.

app/composables/useProductData.tstypescript
export function useProductData(productId: string) {
  return useAsyncData(
    `product-${productId}`,
    () => $fetch(`/api/products/${productId}`),
    {
      getCachedData: (key, nuxtApp, ctx) => {
        // ctx.cause tells why the fetch is happening
        if (ctx.cause === 'refresh:manual') return undefined
        return nuxtApp.payload.data[key]
      },
    },
  )
}

Parametr ctx.cause moze przyjmowac wartosci takie jak 'refresh:manual' (reczne odswiezenie przez programiste), 'refresh:hook' (odswiezenie wyzwolone przez hook cyklu zycia) czy 'navigation' (nawigacja miedzy stronami). Dzieki temu composable moze inteligentnie decydowac o strategii cache'owania: na przyklad zawsze uzywac cache'u podczas nawigacji, ale wymuszac nowe zapytanie przy recznym odswiezeniu.

Singleton pattern eliminuje rowniez problem race conditions. Gdy wiele komponentow jednoczesnie zadaje tych samych danych, Nuxt 4 wykonuje tylko jedno zapytanie i rozdziela wynik do wszystkich subskrybentow. Redukuje to obciazenie sieciowe i zapewnia spójnosc danych w calej aplikacji.

Domyslna plytka reaktywnosc (shallow reactivity)

Jedna z najbardziej przelomowych zmian w Nuxt 4 jest przejscie na plytka reaktywnosc (shallowRef) jako domyslna dla danych zwracanych przez useAsyncData i useFetch. W Nuxt 3 dane byly opakowane w gleboka reaktywnosc (ref), co oznaczalo, ze kazda zmiana zagniezdzonych wlasciwosci obiektu automatycznie wyzwalala aktualizacje komponentow. W Nuxt 4 jedynie zamiana calej wartosci value powoduje re-render.

app/pages/dashboard.vuetypescript
<script setup lang="ts">
// Data is now a shallowRef by default
const { data: metrics } = await useFetch('/api/dashboard/metrics')

// Direct property mutation won't trigger reactivity
// metrics.value.visits = 100  // Won't trigger re-render

// Replace the entire value to trigger updates
metrics.value = { ...metrics.value, visits: 100 }

// Or opt into deep reactivity for this specific call
const { data: settings } = await useFetch('/api/settings', {
  deep: true,
})
</script>

Ta zmiana ma bezposredni wplyw na wydajnosc. Gleboka reaktywnosc tworzy proxy dla kazdego zagniezdzonegoobiektu i tablicy, co generuje znaczny narzut pamieci i CPU przy duzych strukturach danych. Plytka reaktywnosc eliminuje ten narzut calkowicie -- system reaktywnosci Vue sledzi jedynie referencje najwyzszego poziomu.

Dla zespolow migrujacych z Nuxt 3 oznacza to koniecznosc przegladu wszystkich miejsc, w ktorych kod bezposrednio mutuje zagniezdzonethe wlasciwosci danych pobranych z useFetch lub useAsyncData. Kazda taka mutacja musi zostac zastapiona pelna zamiana wartosci (spread operator) lub jawnym wlaczeniem glebok reaktywnosci za pomoca opcji deep: true.

Gotowy na rozmowy o Vue.js / Nuxt.js?

Ćwicz z naszymi interaktywnymi symulatorami, flashcards i testami technicznymi.

Podzielony kontekst TypeScript (context splitting)

Nuxt 4 dzieli konfiguracje TypeScript na cztery odrebne konteksty zamiast jednego globalnego tsconfig.json. Kazdy kontekst posiada wlasne reguly rozwiazywania typow, co eliminuje problem typow serwerowych widocznych w kodzie klienckim i odwrotnie.

json
{
  "files": [],
  "references": [
    { "path": "./.nuxt/tsconfig.app.json" },
    { "path": "./.nuxt/tsconfig.server.json" },
    { "path": "./.nuxt/tsconfig.shared.json" },
    { "path": "./.nuxt/tsconfig.node.json" }
  ]
}

Kontekst app obejmuje kod w katalogu app/, wlacznie z komponentami, stronami i composable'ami. Kontekst server obsluguje pliki w server/, z dostepem do typow Node.js i API serwerowych. Kontekst shared zapewnia typowanie dla katalogu shared/, widoczne zarowno w app, jak i server. Kontekst node pokrywa pliki konfiguracyjne jak nuxt.config.ts.

Ta separacja wymaga zmiany sposobu uruchamiania weryfikacji typow. Flaga -b (project references build mode) jest teraz wymagana dla vue-tsc.

bash
# Before (Nuxt 3)
nuxt prepare && vue-tsc --noEmit

# After (Nuxt 4)
nuxt prepare && vue-tsc -b --noEmit

Bez flagi -b kompilator TypeScript nie rozpozna referencji miedzy projektami i zglosi bledy dotyczace brakujacych typow. Jest to jedna z najczesciej pomijanych zmian podczas migracji, ktora prowadzi do bledow w pipeline'ach CI/CD.

Znormalizowane nazwy komponentow i Vue Router v5

Nuxt 4 zmienia konwencje nazewnictwa auto-importowanych komponentow. Komponenty zagniezdzone w podkatalogach otrzymuja teraz nazwy oparte na pelnej sciezce katalogu, a nie jedynie na nazwie pliku. Na przyklad komponent components/dashboard/MetricsCard.vue w Nuxt 3 byl dostepny jako DashboardMetricsCard, ale rowniez jako MetricsCard. W Nuxt 4 obowiazuje wylacznie pelna, znormalizowana nazwa.

Ta zmiana ma bezposredni wplyw na konfiguracje <KeepAlive>, ktora wymaga jawnego podania nazw komponentow w tablicy include lub exclude.

vue
<!-- app/pages/dashboard.vue -->
<template>
  <NuxtPage :keepalive="{
    include: ['DashboardMetricsCard', 'DashboardRecentActivity'],
  }" />
</template>

Nalezy zweryfikowac, czy nazwy komponentow uzywane w keepalive, <Transition> i dynamicznych komponentach (<component :is="...">) odpowiadaja nowym, znormalizowanym nazwom. W przeciwnym razie KeepAlive przestanie cache'owac komponenty, a przejscia animacyjne nie beda dzialac.

Rownolegle Nuxt 4 integruje Vue Router v5, ktory wprowadza zmiany w API nawigacji i straznkow (guards). Metoda router.resolve() zwraca teraz rozszerzony obiekt z dodatkowymi metadanymi. Straze nawigacyjne otrzymuja ulepszone typowanie parametrow. Zespoly korzystajace z zaawansowanych wzorcow routingu powinny zweryfikowac kompatybilnosc swoich strazy i middleware'ow z nowym API.

Zmiany w zarzadzaniu meta tagami (Unhead v2)

Nuxt 4 przechodzi na Unhead v2, co wprowadza przelmowe zmiany w sposobie zarzadzania meta tagami i elementami <head>. Usuniete zostaly przestarzale wlasciwosci vmid, hid, children i body, ktore w Nuxt 3 byly uzywane do identyfikacji i deduplikacji tagow.

app/pages/product/[id].vuetypescript
<script setup lang="ts">
const route = useRoute()
const { data: product } = await useFetch(`/api/products/${route.params.id}`)

// Unhead v2: removed vmid, hid, children, body props
useSeoMeta({
  title: () => product.value?.name ?? 'Product',
  ogTitle: () => product.value?.name ?? 'Product',
  description: () => product.value?.description ?? '',
  ogImage: () => product.value?.imageUrl ?? '',
})
</script>

Dodatkowo niektorych pluginow Unhead, takie jak TemplateParamsPlugin i AliasSortingPlugin, nie sa juz domyslnie ladowane. Jesli projekt korzysta z parametrow szablonowych w meta tagach (np. %s | Nazwa Strony), nalezy je jawnie zarejestrwac jako plugin Nuxt.

app/plugins/unhead.tstypescript
import { TemplateParamsPlugin, AliasSortingPlugin } from '@unhead/vue/plugins'

export default defineNuxtPlugin({
  setup() {
    const unhead = injectHead()
    unhead.use(TemplateParamsPlugin)
    unhead.use(AliasSortingPlugin)
  },
})

Brak rejestracji tych pluginow objawia sie subtelnym bledem: szablony tytulu przestaja byc przetwarzane i uzytkownik widzi surowy tekst z symbolami %s zamiast przetworzonego tytulu. Problem ten jest szczegolnie trudny do wykrycia podczas developmentu, poniewaz moze nie wplywac na dzialanie samej aplikacji, a jedynie na metryki SEO.

Lista kontrolna migracji i typowe pulapki

Ponizej znajduje sie kompletna lista kontrolna dla zespolow migrujacych z Nuxt 3 do Nuxt 4. Kazdy punkt powinien zostac zweryfikowany i odznaczony przed wdrozeniem na srodowisko produkcyjne.

  1. Aktualizacja Nuxt -- uruchomienie npx nuxt upgrade --dedupe i weryfikacja, ze wszystkie zaleznosci sa kompatybilne z Nuxt 4
  2. Restrukturyzacja katalogow -- uruchomienie codemoodu lub reczne przeniesienie plikow do app/, shared/ i server/
  3. Weryfikacja importow -- sprawdzenie, czy wszystkie sciezki importow zostaly zaktualizowane po przeniesieniu plikow
  4. Aktualizacja composable'ow data fetching -- przeglad wszystkich uzyc useAsyncData i useFetch pod katem nowego API getCachedData i singleton pattern
  5. Dostosowanie do shallow reactivity -- identyfikacja i naprawa wszystkich miejsc z bezposrednia mutacja zagniezdzonych wlasciwosci danych
  6. Konfiguracja TypeScript -- aktualizacja tsconfig.json do formatu z referencjami projektow i zmiana komendy vue-tsc na tryb -b
  7. Nazwy komponentow -- weryfikacja nazw w keepalive, <Transition> i dynamicznych komponentach pod katem nowych znormalizowanych nazw
  8. Meta tagi (Unhead v2) -- usuniecie przestarzalych wlasciwosci (vmid, hid, children, body) i rejestracja wymaganych pluginow
  9. Testy E2E -- uruchomienie pelnego zestawu testow end-to-end z uwzglednieniem zmian w nawigacji Vue Router v5
  10. Pipeline CI/CD -- aktualizacja komend budowania i weryfikacji typow w konfiguracji pipeline'u

Najczestsze pulapki podczas migracji obejmuja:

  • Zapomniane mutacje shallow ref -- kod, ktory bezposrednio modyfikuje zagniezdzonethe wlasciwosci data.value.property = x, przestaje wyzwalac re-rendery. Jest to najczesciej zglaszany problem po migracji
  • Brakujaca flaga -b w vue-tsc -- powoduje falszywe bledy typow w CI, ktore nie wystepuja lokalnie
  • Nieznormalizowane nazwy komponentow w KeepAlive -- KeepAlive po cichu ignoruje nierozpoznane nazwy, co prowadzi do utraty cache'owania bez widocznych bledow
  • Brakujace pluginy Unhead -- szablony tytulow przestaja dzialac, co objawia sie dopiero po analizie wynikow w Google Search Console

Aby poglebic wiedze na temat ekosystemu Vue i Nuxt, warto zapoznac sie z pytaniami rekrutacyjnymi Vue/Nuxt oraz przewodnikiem po SSR i generowaniu statycznym.

Podsumowanie

Nuxt 4 stanowi znaczacy krok naprzod w ewolucji frameworka, wprowadzajac zmiany, ktore wplywaja na kazdy aspekt procesu wytwarzania oprogramowania. Kluczowe wnioski z migracji:

  • Nowa struktura katalogu app/ separuje kod aplikacji od konfiguracji i zasobow serwerowych, a katalog shared/ eliminuje problem duplikowania typow miedzy klientem a serwerem
  • Singleton data fetching z wzorcem getCachedData i obiektem kontekstu ctx umozliwia precyzyjna kontrole nad strategia cache'owania i eliminuje zduplikowane zapytania sieciowe
  • Domyslna shallow reactivity znaczaco poprawia wydajnosc przy duzych strukturach danych, ale wymaga swiadomego dostosowania kodu mutujacego zagniezdzonethe wlasciwosci
  • Podzielony kontekst TypeScript zapewnia scisla izolacje typow miedzy kodem klienckim, serwerowym i wspoldzielonym, co eliminuje cala klase bledow typowania
  • Znormalizowane nazwy komponentow i integracja Vue Router v5 wymagaja przegladu konfiguracji KeepAlive, przejsc animacyjnych i strazy nawigacyjnych
  • Unhead v2 wymusza jawna rejestracje pluginow szablonowych i usunie przestarzale wlasciwosci meta tagow
  • Oficjalny codemod automatyzuje restrukturyzacje katalogow, ale pozostale zmiany -- composable'e, TypeScript, meta tagi -- wymagaja recznej weryfikacji i dostosowania

Zacznij ćwiczyć!

Sprawdź swoją wiedzę z naszymi symulatorami rozmów i testami technicznymi.

Tagi

#nuxt
#vue
#migration
#typescript
#tutorial

Udostępnij

Powiązane artykuły