본문 바로가기

Next.js 프로젝트의 파일 구조

codeConnection 2024. 7. 4.

app 폴더

  • Next.js 프로젝트를 세팅하면 src/app 폴더가 생성된다.
  • 앱 라우팅을 담당한다.
  • 이곳의 폴더는 자동으로 라우팅 되며 URL path를 폴더명으로 갖게 된다.

layout.tsx 파일과 page.tsx

이곳에 layout.tsx 파일을 만들면 프로젝트의 모든 파일에 영향을 줄 수 있는 파일을 만들 수 있다.

그리고 page.tsx는 src/app 폴더에 있는 파일은 자동으로 '/'라는 URL path를 갖게 된다. 즉 홈 페이지의 역할을 한다는 것이다.

app 폴더는 '/' home이다.

// app/layout.tsx

export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}
// app/page.tsx

export default function Page() {
  return <h1>Hello, Next.js!</h1>
}

 

  • layout.tsx 파일은 삭제하더라도 개발 모드를 실행하면 프레임워크에 의해 자동 재생성 됨.
  • src/app 폴더 내에 폴더를 만들면 그게 /path가 됨.

app routing 파일 명명 규칙

Next.js는 프레임워크이기 때문에 마음대로 명명하면 안 된다. 프레임워크가 정의한 대로 파일 이름을 작성해야 개발자 의도대로 정상 작동하고, 메타데이터도 자동으로 세팅되어 SEO에 유리해짐.

  • layout : 레이아웃 파일
    • app 라우트 최상단에 위치할 시 모든 페이지에서 보이는 레이아웃임. 예를 들어 헤더, 푸터.
    • app/아무폴더/layout.tsx 처럼 만들면 /아무폴더 라는 path에 접근했을 때만 보이는 레이아웃임.
  • page : 해당 라우트의 페이지
    • app/아무폴더 말고 app 폴더 최상단에 있는 페이지는 / path 를 갖고 홈페이지가 됨.
    • 여기에 홈 페이지를 직접 구성해도 되고, home 폴더를 만들든지 해서 그곳의 page.tsx를 작성하고 이곳에서 컴포넌트를 import만 해도 됨.
  • loading : 로딩 UI
  • not-found : 404 Not found UI
  • error : 특정 페이지에서 보여 줄 에러 UI
    • 특정 게시글을 못 불러온다거나, 게시글을 열람할 권한이 없는 사용자이거나 할 때 보여 줄 에러 등.
  • global-error : 전역에 사용되는 에러 UI
    • 예를 들어 HTTP 네트워크 에러 등은 공통으로 적용되는 에러임.
  • route : API 엔드포인트 설정 파일
    • API fetch는 page.tsx 각 파일에서 하겠지만, 이곳에서 API 엔드 포인트를 지정해놓는다.
  • template : 리렌더링 된 레이아웃 파일
    • 특정 경로 또는 페이지에서만 적용되는 레이아웃.
    • template.tsx 파일은 layout.tsx 파일과 사실상 똑같다. 그러나 시멘틱하게, layout 파일은 공통 레이아웃, template 파일은 특정 레이아웃을 설정한다는 의미를 파일에서부터 내포하기 때문에 적절하게 사용하는 것이 좋다.
    • layout 파일이 공통 레이아웃을 지정하는 파일이기 때문에 이곳에 사용된 state는 하위 폴더로 이동하면서도 계속 유지된다. 그러나 template 파일은 하위 폴더로 이동하면 새 인스턴스를 만들면서 상태를 변경시키기 때문에 페이지의 리렌더링이 발생한다.
    • 따라서 페이지 이동에 따라서 동적인 전환 애니메이션이 필요한 경우에는 template 파일을 사용한다. 그러나 vercel 에서는 꼭 필요한 경우가 아니라면 layout 사용을 권장하고 있다.
  • default : 병렬 경로 폴백 페이지
    • not-found는 사용자가 있지도 않은 url path를 입력했을 때 경로를 찾지 못한다는 에러를 반환하는 페이지이고, default는 경로는 있긴 있는데 특정 id나 게시글 번호 등을 잘못 입력했거나 하는 이유로 찾지 못할 때 보여주는 기본 페이지이다.

error와 global-error의 차이

// app/
//  └─ blog/
//      └─ [id]/
//          └─ page.tsx
//          └─ error.tsx

'use client';

import { useState, useEffect } from 'react';

const BlogPost = ({ params }) => {
  const { id } = params;
  const [post, setPost] = useState(null);
  const [error, setError] = useState(null);

  useEffect(() => {
    fetch(`/api/blog/${id}`)
      .then(response => {
        if (!response.ok) {
          throw new Error('Network response was not ok');
        }
        return response.json();
      })
      .then(data => setPost(data))
      .catch(err => setError(err));
  }, [id]);

  if (error) {
    return <ErrorComponent message="블로그 게시글을 불러오는 중 오류가 발생했습니다." />;
  }

  if (!post) {
    return <div>Loading...</div>;
  }

  return (
    <div>
      <h1>{post.title}</h1>
      <p>{post.content}</p>
    </div>
  );
};

const ErrorComponent = ({ message }) => (
  <div>
    <h1>오류 발생</h1>
    <p>{message}</p>
  </div>
);

export default BlogPost;
// app/global-error.tsx

'use client';

import React from 'react';

export default function GlobalError({ error, reset }) {
  React.useEffect(() => {
    console.error(error);
  }, [error]);

  return (
    <html>
      <body>
        <div>
          <h1>에러가 발생했습니다.</h1>
          <p>{error.message}</p>
          <button onClick={() => reset()}>다시 시도하기</button>
        </div>
      </body>
    </html>
  );
}

layout과 tamplate 파일 구조 예시

app/
  ├─ layout.tsx
  ├─ blog/
      ├─ layout.tsx
      ├─ [id]/
          ├─ layout.tsx (또는 template.tsx)
          ├─ page.tsx

not-found와 default 페이지 차이

  • 작성 방법 차이
    • not-found : app/not-found.tsx에 작성
    • dafault : app/blog/[id]/default.tsx에 작성. /blog path의 기본 UI가 됨.
  • 의미의 차이
    • not-found : app 폴더 내에 wonyoung이라는 폴더는 있지도 않음. 근데 사용자가 /wonyoung 이런 식으로 접근하면 not-found 에러가 출력되며 이 페이지가 렌더링 됨.
    • dafault : 사용자가 /blog/1234 라고 입력했을 때 /blog 라는 app 폴더는 있다고 가정. 만약 뒤에 붙이는 [id]가 있는 id면 그 id를 받아서 렌더링 하는 app/blog/[id]/page.tsx가 렌더링 될 것이고, 없는 id면 default 페이지가 보이게 됨.

Pages 폴더 (라우팅 구버전 방식)

  • App Router vs Pages Router 구분
    • App Router : src/app 폴더 내에 폴더와 page.tsx 파일이 있음.
    • Pages Router : src/pages/index.tsx 와 같이 라우팅이 됨.
  • 두 라우팅 방식을 혼용하면 App Router가 Pages Router 보다 우선되기 때문에 개발자의 의도대로 라우팅이 되지 않을 수 있음.

public 폴더

  • assets 폴더와 같다. 프로젝트에서 사용 할 이미지, 폰트 등을 저장한다.
  • 변하지 않고, 사용자 등급과 관련없이 모두가 볼 수 있는 파일만 넣는 게 좋다.
  • 폴더는 있어도 되고 없어도 됨.

src 폴더

소스 폴더를 의미하는데, 있어도 되고 없어도 된다.

개발 모드

  • yarn dev, npm run dev 등의 명령어로 실행 됨.
  • localhost:3000 포트를 사용함.

그 외 최상위 파일들

  • next.config.js : Next.js를 구성하는 파일.
  • package.json : 프로젝트의 의존성과 스크립트(명령어)들이 정의되어 있음.
  • intumentation.ts : 분석 파일
  • middleware.ts : Next.js의 미들웨어 요청 파일
  • 환경 변수 파일들
    • .env : 환경 변수 파일.
      • 로컬, 프로덕션, 개발 모드에서 공통적으로 사용되는 환경 변수를 지정함.
      • API_URL=https://api.example.com
    • .env.local : 로컬 환경 변수 파일
      • 로컬 환경에서만 사용되는 환경 변수
      • API_URL=http://localhost:3000/api
    • .env.production : 프로덕션 환경 변수 파일
      • 프로덕션(실제 서비스) 환경에서만 사용되는 환경 변수
      • built, start 명령어를 실행할 때 사용됨.
      • API_URL=https://api.example.com
    • .env.development : 개발 환경 변수 파일
      • 개발 환경에서만 사용되는 환경 변수
      • API_URL=http://dev.example.com/api
      • dev 명령어를 실행할 때 사용됨.
  • .gitignore : Git에 올리지 않을 파일과 폴더 지정
  • next-env.d.ts : Next.js용 타입스크립트 선언 파일
  • tsconfig.json : 타입스크립트 설정 파일
  • jsconfig.json : 자바스크립트 설정 파일

폴더 구조에 따른 라우팅

 app 폴더에 폴더를 만들면 그 폴더 이름으로 자동으로 라우팅이 생성됨.

  • app/ive : localhost:3000/ive
  • app/ive/wonyoung : localhost:3000/ive/wonyoung

동적 라우팅

이 개념은 아직 잘 이해가 안 되고 있음. 제대로 이해 되면 추후 수정하겠음.

현재 이해한 정도로 기술하자면...

[folder] : app/blog/[id]/page.tsx

특정 게시물을 만들 때 사용함.

import React from 'react';

const BlogPost = ({ params }: { params: { id: string } }) => {
  return (
    <div>
      <h1>블로그 게시물 ID: {params.id}</h1>
      <p>이것은 {params.id}번 블로그 게시물입니다.</p>
    </div>
  );
};

export default BlogPost;

[...folder] : app/blog/[...categories]/page.tsx

카테고리를 만들 때 사용함.

import React from 'react';

const BlogCategories = ({ params }: { params: { categories: string[] } }) => {
  return (
    <div>
      <h1>카테고리: {params.categories.join(' > ')}</h1>
      <p>이것은 {params.categories.join(', ')} 카테고리에 있는 블로그 게시물입니다.</p>
    </div>
  );
};

export default BlogCategories;

 

[[...folder]] : app/blog/[[...categories]]/page.tsx

URL path에 이 path는 넣어도 되고 안 넣어도 작동하도록 할 때. 넣으면 이곳에 있는 page가 보이고, 안 넣으면 blog의 page를 보여줌.

import React from 'react';

const Blog = ({ params }: { params: { categories?: string[] } }) => {
  return (
    <div>
      <h1>
        {params.categories ? `카테고리: ${params.categories.join(' > ')}` : '전체 블로그'}
      </h1>
      <p>
        {params.categories
          ? `이것은 ${params.categories.join(', ')} 카테고리에 있는 블로그 게시물입니다.`
          : '이것은 전체 블로그 게시물입니다.'}
      </p>
    </div>
  );
};

export default Blog;

Route Group과 Private Folders

Route Group

  • app 폴더 내에 (폴더이름) 소괄호로 폴더를 만들고 이 안에 파일을 만들면 이 소괄호는 라우팅이 되지 않음. 즉 URL 주소로 만들어지지 않음.
  • Next.js에서는 App 폴더 내에서 폴더를 만들면 자동으로 URL path가 생성되며 라우팅이 되나, 소괄호는 단순히 그룹핑 목적임.
  • 비슷한 관심사의 폴더와 페이지 파일을 하나의 폴더로 묶어서 정리할 때 사용.
app/
  ├─ (info)/
      ├─ about/
      │   └─ page.tsx
      ├─ contact/
      │   └─ page.tsx

 

  • 위와 같이 작성하면 라우팅은 (info)는 무시되고 라우팅이 두 개 생기는 것임.
  • /about, /contact

Private Folders

app/
  ├─ _utils/
      ├─ helper.ts
      ├─ constants.ts
  • 라우트 그룹과 유사해보이지만 라우트 그룹은 이미 만들어진 라우트들을 묶는 용도로 사용하는 것이고,
  • 프라이빗 폴더즈는 라우트와 전혀 상관 없는 유틸 파일들을 라우팅에서 제외 시킬 때 _ 언더 스코어를 넣어서 폴더를 만들어 제외시키는 방법임.

메타 데이터 관련 파일

앱 아이콘

  • favicon : 대표 파비콘 .ico
  • icon : 앱 아이콘 .ico .jpg .jpeg. .png .svg
  • icon : JS, TS로 만드는 앱 아이콘 .js .ts. tsx
  • apple-icon : 애플용 앱 아이콘 .jpg .jpeg .png
  • apple-icon : JS, TS로 만드는 애플용 앱 아이콘 .js .ts. tsx

SEO 관련 파일

  • sitemap : 정적, 동적 사이트맵 파일 .xml .js .ts
  • robots : 검색 엔진이 어떤 부분을 크롤링 할 수 있는지 없는지 알려주는 파일 .txt .js .ts
// public/sitemap.xml

<urlset xmlns="http://www.sitemaps.org/schemas/sitemap/0.9">
  <url>
    <loc>https://www.example.com/</loc>
    <lastmod>2024-01-01</lastmod>
    <priority>1.00</priority>
  </url>
  <url>
    <loc>https://www.example.com/about</loc>
    <lastmod>2024-01-01</lastmod>
    <priority>0.80</priority>
  </url>
</urlset>
// public/robots.txt

User-agent: *
Disallow: /admin/
Allow: /

'Programing > Next.js' 카테고리의 다른 글

App Router란 무엇인가?  (0) 2024.07.05
Next.js의 라우팅에서 사용되는 필수 용어 정리  (0) 2024.07.04
Package.json 살펴보기  (0) 2024.07.04
Next.js란?  (0) 2024.07.04
Tailwind CSS  (0) 2024.07.02

댓글