Używamy cookies, żeby zwiększyć Twoje doświadczenia na stronie
CodeWorlds

Struktura katalogów i plików w Next.js (app/ vs pages/)

W Metropolii Quantum, inżynierowie projektują zaawansowane systemy transportu, które mogą działać zarówno na klasycznych drogach, jak i na nowych szlakach kwantowej teleportacji. Podobnie, Next.js oferuje dwa równoległe systemy routingu: tradycyjny Pages Router i nowoczesny App Router. W tym module szczegółowo przeanalizujemy różnice między tymi dwoma podejściami i zrozumiemy, jak organizować pliki i katalogi w naszych projektach.

Dwie filozofie routingu w Next.js

Next.js pierwotnie opierał się na konwencji routingu opartej na katalogach w folderze

pages/
. W Next.js 13, wprowadzono nowy system routingu oparty na folderze
app/
. Ta ewolucja przypomina przejście od klasycznych systemów transportu do kwantowej teleportacji w Metropolii Quantum - nowa technologia jest bardziej zaawansowana, ale obie nadal współistnieją.

Pages Router: Klasyczne podejście

Pages Router to oryginalny system routingu w Next.js. Jest prosty, dobrze udokumentowany i nadal szeroko używany. W tej konwencji każdy plik JavaScript lub TypeScript w katalogu

pages/
automatycznie staje się ścieżką w aplikacji.

1pages/
2├── index.js                # Trasa: /
3├── about.js                # Trasa: /about
4├── contact.tsx             # Trasa: /contact
5├── products/
6│   ├── index.js            # Trasa: /products
7│   └── [id].js             # Trasa: /products/:id (dynamiczna)
8└── api/
9    └── hello.js            # Endpoint API: /api/hello

W tym systemie:

  • Pliki bezpośrednio mapują się na ścieżki URL
  • Dynamiczne segmenty ścieżki są oznaczane nawiasami kwadratowymi
    [param]
  • Specjalny katalog
    api/
    służy do obsługi endpointów API
  • Każdy plik eksportuje domyślnie komponent React lub funkcję obsługi API

App Router: Nowoczesne podejście

App Router, wprowadzony w Next.js 13 i dopracowany w wersji 15, reprezentuje nowe podejście oparte na React Server Components. Jest to jak przejście od tradycyjnych pojazdów do teleportacji kwantowej - fundamentalna zmiana w sposobie myślenia o aplikacjach webowych.

1app/
2├── layout.tsx              # Główny układ (wymagany)
3├── page.tsx                # Trasa: /
4├── about/
5│   └── page.tsx            # Trasa: /about
6├── blog/
7│   ├── page.tsx            # Trasa: /blog
8│   ├── layout.tsx          # Układ specyficzny dla /blog i jego podścieżek
9│   └── [slug]/
10│       └── page.tsx        # Trasa: /blog/:slug (dynamiczna)
11└── api/
12    └── users/
13        └── route.ts        # Endpoint API: /api/users

W App Router:

  • Tylko katalogi definiują ścieżki, a specjalne pliki wewnątrz tych katalogów pełnią konkretne funkcje
  • Plik
    page.tsx
    renderuje komponent strony dla danej ścieżki
  • Plik
    layout.tsx
    definiuje współdzielony układ dla wszystkich stron w katalogu i jego podkatalogach
  • Dynamiczne segmenty nadal używają nawiasów kwadratowych:
    [param]
  • Endpointy API są tworzone przy użyciu plików
    route.ts

Nazewnictwo plików i konwencje w App Router

App Router wprowadza "konwencję ponad konfiguracją" z szeregiem specjalnych plików, które mają określone role. Jest to jak wyspecjalizowane moduły w systemach Metropolii Quantum - każdy z określoną funkcją w ogólnej architekturze.

Podstawowe pliki specjalne:

  1. page.tsx: Renderuje interfejs użytkownika trasy i sprawia, że ścieżka jest publicznie dostępna.

    1// app/dashboard/page.tsx
    2export default function DashboardPage() {
    3  return (
    4    <section>
    5      <h1>Panel kontrolny Metropolii Quantum</h1>
    6      <p>Witaj w centrum dowodzenia!</p>
    7    </section>
    8  );
    9}
  2. layout.tsx: Definiuje współdzielony interfejs dla segmentu i jego dzieci.

    1// app/dashboard/layout.tsx
    2export default function DashboardLayout({
    3  children,
    4}: {
    5  children: React.ReactNode;
    6}) {
    7  return (
    8    <div className="dashboard-layout">
    9      <nav className="dashboard-sidebar">
    10        {/* Nawigacja panelu bocznego */}
    11      </nav>
    12      <main className="dashboard-main">{children}</main>
    13    </div>
    14  );
    15}
  3. route.ts: Tworzy endpoint API przy użyciu nowego API obsługi żądań.

    1// app/api/status/route.ts
    2import { NextResponse } from 'next/server';
    3
    4export async function GET() {
    5  return NextResponse.json({ 
    6    status: 'online', 
    7    systemsOperational: 15,
    8    time: new Date().toISOString()
    9  });
    10}
    11
    12export async function POST(request: Request) {
    13  const data = await request.json();
    14  // Przetwarzanie danych...
    15  return NextResponse.json({ success: true });
    16}
  4. loading.tsx: Tworzy interfejs ładowania z React Suspense.

    1// app/dashboard/loading.tsx
    2export default function DashboardLoading() {
    3  return (
    4    <div className="dashboard-loading">
    5      <div className="spinner"></div>
    6      <p>Ładowanie danych systemowych Metropolii...</p>
    7    </div>
    8  );
    9}
  5. error.tsx: Tworzy interfejs obsługi błędów z React Error Boundary.

    1'use client'; // Komponenty obsługi błędów muszą być komponentami klienckimi
    2
    3import { useEffect } from 'react';
    4
    5export default function DashboardError({
    6  error,
    7  reset,
    8}: {
    9  error: Error;
    10  reset: () => void;
    11}) {
    12  useEffect(() => {
    13    // Logowanie błędu do systemu monitorowania
    14    console.error(error);
    15  }, [error]);
    16
    17  return (
    18    <div className="error-container">
    19      <h2>Wystąpił błąd w systemach Metropolii!</h2>
    20      <p>{error.message}</p>
    21      <button onClick={reset}>Spróbuj ponownie</button>
    22    </div>
    23  );
    24}
  6. not-found.tsx: Tworzy interfejs dla nieznalezionego zasobu (404).

    1// app/not-found.tsx
    2export default function NotFound() {
    3  return (
    4    <div className="not-found">
    5      <h2>Strefa nieznana</h2>
    6      <p>Nie znaleziono modułu Metropolii Quantum o takim identyfikatorze.</p>
    7      <a href="/">Powrót do centrum dowodzenia</a>
    8    </div>
    9  );
    10}

Zaawansowane funkcje App Router

App Router wprowadza kilka zaawansowanych funkcji organizacyjnych, które przypominają zaawansowane systemy transportu w Metropolii Quantum - pozwalają na bardziej skomplikowane i elastyczne trasy.

1. Grupy tras (Route Groups)

Grupy tras pozwalają na organizowanie plików bez wpływania na strukturę URL. Są oznaczane przez ujęcie nazwy katalogu w nawiasy:

(nazwa-grupy)
.

1app/
2├── (marketing)/        # Grupa tras (nie wpływa na ścieżkę URL)
3│   ├── about/
4│   │   └── page.tsx    # Trasa: /about
5│   └── contact/
6│       └── page.tsx    # Trasa: /contact
7└── (dashboard)/        # Inna grupa tras
8    ├── layout.tsx      # Współdzielony układ dla tras dashboard
9    ├── page.tsx        # Trasa: /
10    └── stats/
11        └── page.tsx    # Trasa: /stats

Grupy tras są jak dzielnice w Metropolii Quantum - pomagają organizować strukturę miasta, ale niekoniecznie wpływają na adresy.

2. Trasy równoległe (Parallel Routes)

Trasy równoległe pozwalają na równoczesne renderowanie wielu stron w tym samym widoku, co jest przydatne dla złożonych układów. Są oznaczane przez nazwę slotu ze znakiem "@":

@nazwa-slotu
.

1app/
2├── layout.tsx          # Główny układ
3├── page.tsx            # Główna strona
4└── dashboard/
5    ├── layout.tsx      # Układ z wieloma slotami
6    │   // layout.tsx definiuje sloty {children, @stats, @notifications}
7    ├── page.tsx        # Domyślna zawartość dla slotu głównego
8    ├── @stats/
9    │   └── page.tsx    # Zawartość dla slotu @stats
10    └── @notifications/
11        └── page.tsx    # Zawartość dla slotu @notifications
1// app/dashboard/layout.tsx
2export default function DashboardLayout({
3  children,
4  stats,
5  notifications,
6}: {
7  children: React.ReactNode;
8  stats: React.ReactNode;
9  notifications: React.ReactNode;
10}) {
11  return (
12    <div className="dashboard-grid">
13      <main>{children}</main>
14      <aside className="stats-panel">{stats}</aside>
15      <section className="notifications-panel">{notifications}</section>
16    </div>
17  );
18}

Trasy równoległe to jak równoległe wymiary w Metropolii Quantum - różne rzeczywistości dostępne jednocześnie.

3. Przechwytujące trasy (Intercepting Routes)

Pozwalają na "przechwycenie" trasy i wyświetlenie jej inaczej, co jest idealne dla modali, które zachowują kontekst nawigacji. Są oznaczane przez nazwę segmentu z znakiem "(.)":

(.)nazwa
,
(..)nazwa
lub
(...)nazwa
.

1app/
2├── layout.tsx
3├── page.tsx            # Trasa: /
4└── dashboard/
5    ├── layout.tsx
6    ├── page.tsx        # Trasa: /dashboard
7    └── projects/
8        ├── page.tsx    # Trasa: /dashboard/projects
9        ├── [id]/
10        │   └── page.tsx # Trasa: /dashboard/projects/:id
11        └── (.)create/  # Przechwytuje /dashboard/projects/create
12            └── page.tsx # Wyświetlane jako modal nad /dashboard/projects

Przechwytujące trasy są jak kwantowe skróty w Metropolii Quantum - pozwalają na szybki dostęp do zasobów bez zmiany kontekstu.

Organizacja kodu w Next.js 15

Oprócz struktury routingu, Next.js 15 sugeruje określone sposoby organizacji kodu. Jest to jak planowanie dzielnic w Metropolii Quantum - właściwa organizacja zwiększa efektywność i czytelność.

Współdzielone komponenty i zasoby

Komponenty, które są używane w wielu miejscach, powinny być zorganizowane w spójny sposób. Oto zalecana struktura:

1src/
2├── app/                 # Aplikacja z App Router
3│   ├── layout.tsx
4│   └── page.tsx
5├── components/          # Współdzielone komponenty
6│   ├── ui/              # Podstawowe komponenty UI
7│   │   ├── Button.tsx
8│   │   └── Card.tsx
9│   └── features/        # Komponenty specyficzne dla funkcji
10│       ├── dashboard/
11│       └── auth/
12├── lib/                 # Współdzielone funkcje i klasy
13│   ├── api/
14│   └── utils/
15├── hooks/               # Niestandardowe hooki React
16│   ├── useAuth.ts
17│   └── useLocalStorage.ts
18└── styles/              # Style globalne
19    └── globals.css

Co-location vs. Centralizacja

Next.js 15 i App Router wspierają podejście "co-location", gdzie pliki związane z konkretną trasą są umieszczane blisko siebie. Jest to jak mikrodystrykty w Metropolii Quantum - wszystko, czego potrzebujesz, jest blisko.

1app/
2└── dashboard/
3    ├── page.tsx
4    ├── loading.tsx       # Ładowanie dla tej trasy
5    ├── error.tsx         # Obsługa błędów dla tej trasy
6    ├── layout.tsx        # Układ dla tej trasy
7    ├── actions.ts        # Server Actions dla tej trasy
8    ├── components/       # Komponenty specyficzne dla tej trasy
9    │   ├── StatusCard.tsx
10    │   └── DashboardNav.tsx
11    └── styles/           # Style specyficzne dla tej trasy
12        └── dashboard.module.css

Porównanie App Router i Pages Router

Teraz, gdy poznaliśmy oba systemy routingu, porównajmy je - podobnie jak inżynierowie Metropolii Quantum mogliby porównywać klasyczny transport z teleportacją kwantową.

Renderowanie

  1. Pages Router:

    • Domyślnie renderowanie po stronie klienta
    • SSR i SSG dostępne przez getServerSideProps i getStaticProps
    • Stosunkowo proste modele danych
  2. App Router:

    • Domyślnie Server Components
    • Wybór między Server i Client Components
    • Bardziej zaawansowany model przepływu danych
    • Streaming renderowania

Ładowanie stanu

  1. Pages Router:

    • Ręczne zarządzanie stanami ładowania
    • Często wykorzystuje zewnętrzne biblioteki
  2. App Router:

    • Wbudowane komponenty loading.tsx
    • Integracja z React Suspense
    • Automatyczne indykatory ładowania

Obsługa błędów

  1. Pages Router:

    • Ręczne zarządzanie błędami
    • Ogólny komponent dla błędów 500
  2. App Router:

    • Komponenty error.tsx z granulamą obsługą błędów
    • Integracja z React Error Boundary
    • Możliwość naprawy/ponowienia po błędzie

Układy

  1. Pages Router:

    • Ręczne tworzenie układów z komponentem _app.js
    • Jeden układ dla całej aplikacji
    • Zagnieżdżone układy wymagają dodatkowej pracy
  2. App Router:

    • Wbudowany system układów poprzez layout.tsx
    • Możliwość tworzenia zagnieżdżonych układów
    • Współdzielenie układów jest proste i intuicyjne

Kiedy używać którego systemu routingu?

Wybór między App Router a Pages Router przypomina wybór między kwantową teleportacją a tradycyjnym transportem w Metropolii Quantum - zależy od konkretnych potrzeb.

Używaj App Router gdy:

  • Tworzysz nowy projekt od podstaw
  • Chcesz korzystać z najnowszych funkcji React i Next.js
  • Potrzebujesz zaawansowanych możliwości układu i organizacji
  • Zależy Ci na lepszej wydajności i streamu renderowania
  • Chcesz korzystać z React Server Components

Używaj Pages Router gdy:

  • Masz istniejący projekt oparty na Pages Router
  • Potrzebujesz prostszego modelu mentalnego
  • Używasz bibliotek, które nie są jeszcze kompatybilne z App Router
  • Chcesz używać gotowych wzorców i rozwiązań

Migracja z Pages Router do App Router

Jeśli masz istniejący projekt używający Pages Router, możesz stopniowo migrować do App Router. Jest to jak modernizacja dzielnic w Metropolii Quantum - nie musisz przebudowywać wszystkiego naraz.

Next.js 15 pozwala na współistnienie obu systemów. Możesz zacząć używać

app/
dla nowych funkcji, jednocześnie zachowując istniejące strony w
pages/
.

1.
2├── app/                # Nowe funkcje używające App Router
3│   ├── new-feature/
4│   │   └── page.tsx    # /new-feature
5│   └── layout.tsx
6└── pages/              # Istniejące strony używające Pages Router
7    ├── index.js        # /
8    └── about.js        # /about

Ważne uwagi dotyczące migracji:

  • Ścieżki w
    app/
    mają priorytet nad ścieżkami w
    pages/
  • Obie struktury używają tej samej konfiguracji Next.js
  • Możesz stopniowo przenosić strony z
    pages/
    do
    app/

Najlepsze praktyki organizacji plików

Niezależnie od wybranego systemu routingu, warto trzymać się pewnych najlepszych praktyk:

  1. Struktura zorientowana na funkcje: Organizuj komponenty i kod wokół funkcji biznesowych, a nie według typów technicznych.

    1src/
    2├── features/
    3│   ├── auth/
    4│   │   ├── components/
    5│   │   ├── hooks/
    6│   │   └── utils/
    7│   └── dashboard/
    8│       ├── components/
    9│       ├── hooks/
    10│       └── utils/
  2. Modułowe podejście: Traktuj każdą funkcjonalność jako izolowany moduł z jasno określonym API.

  3. Spójna konwencja nazewnictwa: Ustal konwencje i trzymaj się ich w całym projekcie.

    • Pliki komponentów: PascalCase (Button.tsx)
    • Hooki: camelCase z przedrostkiem "use" (useAuth.ts)
    • Pomocnicze funkcje: camelCase (formatDate.ts)
  4. Importy względne vs. absolutne: Używaj aliasów importu (

    @/
    ) dla lepszej czytelności i łatwiejszego przenoszenia plików.

  5. Kolokacja testów: Umieszczaj testy blisko testowanych komponentów.

    1src/
    2├── components/
    3│   ├── Button.tsx
    4│   └── Button.test.tsx

Podsumowanie

Struktura katalogów i plików w Next.js 15 jest jak architektura Metropolii Quantum - z odpowiednim planowaniem może być zarówno elegancka, jak i funkcjonalna. App Router wprowadza bardziej zaawansowany, ale także bardziej elastyczny model organizacji aplikacji, podczas gdy Pages Router oferuje prostsze i bardziej bezpośrednie podejście.

Wybór między nimi zależy od specyficznych potrzeb projektu, ale w nowych projektach zaleca się korzystanie z App Router, aby wykorzystać najnowsze funkcje i optymalizacje. Pamiętaj, że dobra organizacja projektu to klucz do łatwej konserwacji i rozszerzalności w przyszłości.

W kolejnym module zagłębimy się w system komponentów Next.js 15, szczególnie różnice między Client Components a Server Components, które są fundamentalną częścią App Router.

Przejdź do CodeWorlds