Next.js 프로젝트의 파일 구조
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 명령어를 실행할 때 사용됨.
- .env : 환경 변수 파일.
- .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 |
댓글