본문 바로가기

script&css&html&ajax

Next.js에서 파일 및 디렉토리의 이름 규칙과 사용 예제

1. pages 디렉토리와 app 디렉토리

Next.js 13 버전부터는 새로운 app 디렉토리가 도입되었습니다. 이 디렉토리는 React Server Components를 기반으로 한 서버 사이드 렌더링을 지원합니다. 기존의 pages 디렉토리도 계속해서 사용할 수 있습니다만, 새로운 기능과 향상된 퍼포먼스를 위해 app 디렉토리를 사용하는 것이 권장됩니다.

1.1 app 디렉토리 구조

app 디렉토리 안에서는 파일과 폴더 이름이 라우팅과 직접적으로 연결됩니다.

  • 페이지 파일: page.tsx 또는 page.jsx
  • 레이아웃 파일: layout.tsx 또는 layout.jsx
  • 로딩 상태 파일: loading.tsx 또는 loading.jsx
  • 에러 처리 파일: error.tsx 또는 error.jsx
  • 헤드 파일: head.tsx 또는 head.jsx (Next.js 13.2 이전)
  • 라우트 핸들러: route.ts 또는 route.js
  • 미들웨어: middleware.ts 또는 middleware.js

2. page.tsx

2.1 역할

  • 각 경로의 기본 엔트리 포인트로서, 해당 경로에 대한 UI를 정의합니다.
  • Next.js는 app 디렉토리에서 page.tsx 파일을 찾아 해당 경로로 매핑합니다.

2.2 사용 예제

디렉토리 구조 예시:

app/
├── page.tsx
├── about/
│   └── page.tsx
└── blog/
    ├── page.tsx
    └── [slug]/
        └── page.tsx

app/page.tsx

// app/page.tsx
export default function HomePage() {
  return (
    <main>
      <h1>홈 페이지</h1>
    </main>
  );
}

app/about/page.tsx

// app/about/page.tsx
export default function AboutPage() {
  return (
    <main>
      <h1>소개 페이지</h1>
    </main>
  );
}

동적 라우팅 예제:

app/blog/[slug]/page.tsx

// app/blog/[slug]/page.tsx
import { useParams } from 'next/navigation';

export default function BlogPostPage() {
  const params = useParams();
  const { slug } = params;

  return (
    <main>
      <h1>블로그 포스트: {slug}</h1>
    </main>
  );
}

3. route.ts

3.1 역할

  • Next.js에서 API 라우트를 정의하는 데 사용됩니다.
  • 기존의 pages/api 디렉토리 대신 app 디렉토리에서 route.ts 파일을 사용하여 API 엔드포인트를 설정합니다.
  • GET, POST, PUT, DELETE 등의 HTTP 메서드를 처리할 수 있습니다.

3.2 사용 예제

디렉토리 구조 예시:

bash
코드 복사
app/
├── api/
│   └── users/
│       └── route.ts

app/api/users/route.ts

ts
코드 복사
// app/api/users/route.ts
import { NextResponse } from 'next/server';

export async function GET() {
  const users = await fetchUsersFromDatabase();
  return NextResponse.json({ users });
}

export async function POST(request: Request) {
  const data = await request.json();
  const newUser = await createUserInDatabase(data);
  return NextResponse.json({ user: newUser }, { status: 201 });
}

설명:

  • GET 메서드: 사용자 목록을 반환합니다.
  • POST 메서드: 새로운 사용자를 생성합니다.
  • NextResponse를 사용하여 응답을 생성합니다.

4. middleware.js 또는 middleware.ts

4.1 역할

  • 전역적인 요청 처리를 위한 미들웨어를 정의합니다.
  • 예를 들어, 인증, 로깅, 리다이렉션 등의 작업을 수행할 수 있습니다.
  • 모든 경로나 특정 경로에 대해 미들웨어를 적용할 수 있습니다.

4.2 사용 예제

프로젝트 루트에 middleware.ts 파일 생성

ts
코드 복사
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // 예: 인증되지 않은 사용자를 로그인 페이지로 리다이렉트
  const isLoggedIn = checkUserAuthentication(request);

  if (!isLoggedIn) {
    return NextResponse.redirect(new URL('/login', request.url));
  }

  // 요청을 그대로 통과시킵니다.
  return NextResponse.next();
}

// 미들웨어가 적용될 경로 설정
export const config = {
  matcher: ['/protected/:path*'],
};

설명:

  • middleware 함수: 각 요청에 대해 실행되며, NextRequest 객체를 인자로 받습니다.
  • NextResponse: 응답을 생성하거나 요청을 수정할 때 사용합니다.
  • config.matcher: 미들웨어가 적용될 경로를 지정합니다.

5. 기타 파일 및 디렉토리

5.1 layout.tsx

  • 각 경로의 레이아웃 컴포넌트를 정의합니다.
  • 해당 경로의 모든 하위 페이지에 공통으로 적용됩니다.

사용 예제:

tsx
코드 복사
// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="ko">
      <body>
        <Header />
        {children}
        <Footer />
      </body>
    </html>
  );
}

5.2 loading.tsx

  • 동적 데이터 로딩 중에 표시될 로딩 상태를 정의합니다.
  • Suspense를 활용하여 데이터가 로드될 때까지 로딩 UI를 보여줍니다.

사용 예제:

tsx
코드 복사
// app/loading.tsx
export default function Loading() {
  return <div>로딩 중...</div>;
}

5.3 error.tsx

  • 페이지에서 에러가 발생했을 때 표시될 UI를 정의합니다.
  • 에러 복구 로직을 포함할 수 있습니다.

사용 예제:

tsx
코드 복사
// app/error.tsx
'use client'; // 에러 컴포넌트는 클라이언트 컴포넌트여야 합니다.

import { useEffect } from 'react';

export default function Error({ error, reset }: { error: Error; reset: () => void }) {
  useEffect(() => {
    // 에러 로깅 등
    console.error(error);
  }, [error]);

  return (
    <div>
      <h2>에러가 발생했습니다!</h2>
      <button onClick={() => reset()}>다시 시도</button>
    </div>
  );
}

5.4 global.css

  • 전역 스타일을 정의하는 파일입니다.
  • app 디렉토리에서 layout.tsx에서 임포트하여 사용합니다.

사용 예제:

tsx
코드 복사
// app/layout.tsx
import './global.css';

export default function RootLayout({ children }: { children: React.ReactNode }) {
  // ...
}

6. 동적 라우팅과 중첩 라우팅

6.1 동적 라우팅

  • [parameter] 형태의 폴더 이름을 사용하여 동적 경로를 정의합니다.

예제:

css
코드 복사
app/
└── blog/
    └── [slug]/
        └── page.tsx
  • blog/hello-world와 같은 경로로 접근하면 slug 값이 hello-world로 설정됩니다.

6.2 중첩 라우팅

  • 폴더 구조를 통해 라우트를 중첩시킬 수 있습니다.
  • 각 폴더에 layout.tsx를 정의하여 해당 경로의 레이아웃을 지정할 수 있습니다.

예제:

코드 복사
app/
├── dashboard/
│   ├── layout.tsx
│   ├── page.tsx
│   └── settings/
│       ├── layout.tsx
│       └── page.tsx
  • dashboard의 레이아웃은 app/dashboard/layout.tsx에서 정의됩니다.
  • dashboard/settings의 레이아웃은 app/dashboard/settings/layout.tsx에서 정의되며, 상위 레이아웃을 중첩합니다.

7. 폴더 및 파일의 특수 규칙

7.1 app 디렉토리에서의 파일과 폴더

  • 폴더: 라우트 경로를 나타냅니다.
  • page.tsx: 해당 경로의 페이지 컴포넌트를 정의합니다.
  • layout.tsx: 해당 경로 및 하위 경로에 적용될 레이아웃을 정의합니다.
  • loading.tsx: 해당 경로에서 Suspense에 의한 로딩 상태를 정의합니다.
  • error.tsx: 해당 경로에서 발생한 에러를 처리합니다.
  • template.tsx: 동적 렌더링을 위한 템플릿을 정의합니다.
  • not-found.tsx: 404 페이지를 커스터마이징합니다.

7.2 서버 컴포넌트와 클라이언트 컴포넌트

  • 기본적으로 모든 컴포넌트는 서버 컴포넌트입니다.
  • 클라이언트 측 상태나 이벤트를 사용하려면 컴포넌트 파일 상단에 'use client'; 지시어를 추가해야 합니다.

예제:

tsx
코드 복사
// app/components/ClientComponent.tsx
'use client';

import { useState } from 'react';

export default function ClientComponent() {
  const [count, setCount] = useState(0);

  return <button onClick={() => setCount(count + 1)}>클릭: {count}</button>;
}

8. API 라우팅 (route.ts)의 자세한 예제

8.1 동적 API 라우팅

디렉토리 구조:

bash
코드 복사
app/
└── api/
    └── posts/
        └── [id]/
            └── route.ts

app/api/posts/[id]/route.ts

ts
코드 복사
// app/api/posts/[id]/route.ts
import { NextResponse } from 'next/server';

export async function GET(request: Request, { params }: { params: { id: string } }) {
  const post = await getPostById(params.id);
  if (!post) {
    return NextResponse.json({ error: 'Post not found' }, { status: 404 });
  }
  return NextResponse.json({ post });
}

설명:

  • params 객체를 통해 동적 라우트의 매개변수에 접근할 수 있습니다.
  • GET 메서드에서 특정 ID의 포스트를 반환합니다.

8.2 요청 본문 및 헤더 처리

ts
코드 복사
// app/api/data/route.ts
import { NextResponse } from 'next/server';

export async function POST(request: Request) {
  const contentType = request.headers.get('content-type');

  if (contentType !== 'application/json') {
    return NextResponse.json({ error: 'Invalid content type' }, { status: 415 });
  }

  const data = await request.json();
  // 데이터 처리 로직
  return NextResponse.json({ success: true });
}

9. 미들웨어 (middleware.ts)의 상세 예제

9.1 다국어 지원을 위한 리다이렉션

ts
코드 복사
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

const PUBLIC_FILE = /\.(.*)$/;

export function middleware(request: NextRequest) {
  const { pathname } = request.nextUrl;

  // 정적 파일 및 API 경로는 제외
  if (PUBLIC_FILE.test(pathname) || pathname.startsWith('/api')) {
    return NextResponse.next();
  }

  // 브라우저의 언어 설정에 따라 리다이렉트
  const acceptLanguage = request.headers.get('accept-language');
  const language = acceptLanguage?.split(',')[0] || 'en';

  if (!pathname.startsWith(`/${language}`)) {
    return NextResponse.redirect(new URL(`/${language}${pathname}`, request.url));
  }

  return NextResponse.next();
}

설명:

  • 사용자의 브라우저 언어 설정에 따라 해당 언어의 페이지로 리다이렉션합니다.
  • 정적 파일과 API 경로는 미들웨어의 적용을 제외합니다.

9.2 인증 미들웨어

ts
코드 복사
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  const token = request.cookies.get('token');

  if (!token) {
    // 로그인 페이지로 리다이렉트
    return NextResponse.redirect(new URL('/login', request.url));
  }

  // 토큰 유효성 검사 로직 추가 가능

  return NextResponse.next();
}

export const config = {
  matcher: ['/dashboard/:path*', '/settings/:path*'],
};

설명:

  • /dashboard/settings 경로에 대해 인증을 요구합니다.
  • 쿠키에서 토큰을 가져와 인증 여부를 판단합니다.

10. Next.js의 라우팅 규칙 요약

  • 폴더: URL 경로를 정의합니다.
  • page.tsx: 해당 경로의 페이지 컴포넌트.
  • layout.tsx: 해당 경로와 하위 경로에 적용되는 레이아웃.
  • [parameter]: 동적 라우팅을 위한 폴더 이름.
  • (group): URL 경로에 영향을 주지 않는 그룹화 폴더.
  • route.ts: 해당 경로의 API 엔드포인트를 정의.
  • middleware.ts: 전역 또는 특정 경로에 대한 미들웨어를 정의.

요약

  • page.tsx: 각 경로의 UI를 정의하는 엔트리 포인트입니다.
  • route.ts: API 라우트를 정의하며, HTTP 메서드를 처리합니다.
  • middleware.ts: 전역 또는 특정 경로에 대해 요청을 가로채고 처리하는 미들웨어를 정의합니다.
  • 파일 및 디렉토리의 이름 규칙은 Next.js의 라우팅 시스템과 밀접하게 연결되어 있습니다.

도움이 되셨길 바랍니다! 추가로 궁금한 사항이나 도움이 필요한 부분이 있으시면 언제든지 말