본문으로 바로가기

[Next.js] 페이지 구조

category 1. 웹개발/1_1_6 Next JS 2024. 4. 10. 10:34

 

 

먼저 creatae-next-app으로 Next.js 프로젝트를 만들어봅시다. 저는 타입스크립트를 항상 기반으로해서 타입스크립트도 추가하였습니다.

npx create-next-app@latest --ts

 

위의 명령어를 실행하니 아래와 같은 디렉토리 구조를 띄며 프로젝트가 생성되었습니다. 안의 내용들을 자세히 살펴보면 좋겠지만, 기본적인 것만 살펴보고 Next.js에서 제공하는 예약어로 관리되는 페이지를 추가로 확인해보겠습니다.

package.json

이 파일에는 프로젝트 구동에 필요한 모든 명령어 및 의존성이 포함돼 있으므로 프로젝트의 대략적인 모습을 확인하는 데 매우 유용합니다. 여기에서 눈에 띄는 몇 가지 주요 의존성만 살펴보겠습니다.

{
  "name": "coding hostpital",
  "version": "0.1.0",
  "private": true,
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start",
    "lint": "next lint"
  },
  "dependencies": {
    "react": "^18",
    "react-dom": "^18",
    "next": "14.1.4"
  },
  "devDependencies": {
    "typescript": "^5",
    "@types/node": "^20",
    "@types/react": "^18",
    "@types/react-dom": "^18",
    "autoprefixer": "^10.0.1",
    "postcss": "^8",
    "tailwindcss": "^3.3.0",
    "eslint": "^8",
    "eslint-config-next": "14.1.4"
  }
}
  • next: Next.js의 기반이 되는 패키지
  • eslint-config-next: Next.js 기반 프로젝트에서 사용하도록 만들어진 ESLint 설정

그 밖에 리액트 프로젝트 구동에 필요한 react, react-dom, 타입스크립트 환경에 필요한 @types 패키지와 typescript가 있는 것을 볼 수 있습니다.

next.config.js

그다음으로 눈여겨볼 파일은 next.config.js입니다. 이 파일은 Next.js 프로젝트의 환경 설정을 담당하며, Next.js를 자유자재로 다루려면 반드시 알아야 하는 파일입니다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true, // 14버전에서는 기본으로 설정되어있지 않음
  swcMinify: true	// 14버전에서는 기본으로 설정되어있지 않음
};

export default nextConfig;

 

먼저 첫 줄에 있는 @type으로 시작하는 주석은 자바스크립트 파일에 타입스크립트의 도움을 받기 위해 추가된 코드입니다. 해당 주석이 있다면 next의 NextConfig를 기준으로 타입의 도움을 받을 수 있는 반면, 없다면 일일이 타이핑해야 합니다. 그러므로 특별한 이유가 없다면 사용합시다!

  • reactStrictMode: 리액트의 엄격 모드와 관련된 옵션으로, 리액트 애플리케이션 내부에서 잠재적인 문제를 개발자에게 알리기 위한 도구입니다. 마찬가지로 특별한 이유가 없다면 켜두는 것이 도움이 될 것입니다.
  • swcMinify: Vercel에서는 SWC라 불리는 또 다른 오픈소스를 만들었는데, 이 도구는 번들링과 컴파일을 더욱 빠르게 수행하기 위해 만들어졌습니다. 바벨의 대안이라고 볼 수 있고, 바벨보다 빠를 수 있는 이유는 첫째, 자바스크립트 기반의 바벨과는 다르게 러스트(Rust)라는 완전히 다른 언어로 작성했다는 점(러스트는 C/C++와 동등한 수준의 속도) 그리고 병렬로 작업을 처리한다는 점 등이 있습니다. swcMinify는 이러한 SWC를 기반으로 코드 최소화 작업을 할 것인지 여부를 설정하는 속성입니다.

SWC가 바벨에 비해 더 빠른 속도를 보여주기 때문에 마찬가지로 SWC를 쓰는 것을 권장합니다.

pages/_app.tsx

pages 폴더가 경우에 따라서는 src 하단에 존재할 수도 있습니다. 사실 src에 있거나 혹은 프로젝트 루트에 있어도 동일하게 작동합니다. (저의 경우에는 프로젝트 루트와 동일한 경로에 넣고 dashboard폴더도 추가했습니다.)

 

_app.tsx, 그리고 내부에 있는 default export로 내보낸 함수는 애플리케이션의 전체 페이지의 시작점입니다. 페이지의 시작점이라는 특징 때문에 웹 애플리케이션에서 공통으로 설정해야 하는 것들을 여기에서 실행할 수 있습니다.

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

 

  • 에러 바운더리를 사용해 애플리케이션 전역에서 발생하는 에러 처리
  • reset.css 같은 전역 CSS 선언
  • 모든 페이지에 공통으로 사용 또는 제공해야 하는 데이터 제공 등

pages/_document.tsx

create-next-app으로 생성했다면 해당 페이지가 존재하지 않을 것입니다. 이는 _document.tsx가 없어도 실행에 지장이 없는 파일임을 의미합니다. _app.tsx가 애플리케이션 페이지 전체를 초기화하는 곳이라면, _document.tsx는 애플리케이션의 HTML을 초기화하는 곳입니다. 그렇기에 _app.tsx와 몇 가지 차이점이 있습니다.

  • _document는 무조건 서버에서 실행됩니다. 따라서 API / 이벤트 핸들러 등 포함된 코드들은 실행되지 않습니다.
  • <html>이나 <body>에 DOM 속성을 추가하고 싶다면 _document를 사용하면 됩니다.
  • getServerSideProps, getStateProps 등은 사용 불가합니다.
  • <Head> 태그는 next/head가 아닌 next/document 모듈에서 불러와야 합니다.
    • 두 개의 Head는 다름으로 Head의 Ttitle 설정은 여기서 할 수 없습니다.
    • <Head> 태그에는 모든 문서에 공통으로 적용할 (charset, 뷰포트 메타태그 등)이 들어갑니다.

정리하자면, _app.tsx는 Next.js를 초기화하는 파일로, Next.js 설정과 관련된 코드를 모아두는 곳이며, 경우에 따라 서버와 클라이언트 모두에서 렌더링 될 수 있습니다. _document.tsx는 Next.js로 만드는 웹사이트의 뼈대가 되는 HTML 설정과 관련된 코드를 추가하는 곳이며, 반드시 서버에서만 렌더링이 됩니다.

pages/_error.tsx

이 페이지 역시 create-next-app이 기본으로 생성해 주는 파일은 아니며, 없더라도 실행에 지장없는 파일입니다. 이 에러 페이지는 클라이언트에서 발생하는 에러 또는 서버에서 발생하는 500 에러를 처리할 목적으로 만들어졌습니다. Next.js 프로젝트 전역에서 발생하는 에러를 적절하게 처리하고 싶다면 이 페이지를 활용하면 됩니다. 단, 개발 모드에서는 이 페이지에 방문할 수 없고 에러가 발생하면 Next.js가 제공하는 개발자 에러 팝업이 나타나게 됩니다. 이 페이지가 잘 작동하는지 확인하려면 프로덕션으로 빌드해서 확인해 봐야 합니다.

import { NextPageContext } from "next";

function Error({ statusCode }: { statusCode: number}) {
  return (
    <p>
      {statusCode ? `서버에서 ${statusCode}` : `클라이언트에서`} 에러가 발생했습니다.
    </p>
  )
}

Error.getInitialProps = ({ res, err }: NextPageContext) => {
  const statusCode = res ? res.statusCode : err ? err.statusCode : ''
  return { statusCode }
}

pages/404.tsx

이름에서도 알 수 있듯이 404 페이지를 정의할 수 있는 페이지입니다. 만들지 않으면 Next.js에서 제공하긴 기본 404 페이지를 볼 수 있고, 404페이지를 만들면 원하는 스타일의 페이지를 만들 수 있습니다.

pages/500.tsx

서버에서 발생하는 에러를 핸들링하는 페이지입니다. _error.tsx와 500.tsx가 모두 있다면 500.ts가 우선적으로 실행됩니다. 마찬가지로 500이나 error페이지가 없다면 기본 오류 페이지가 보입니다.

pges/index.tsx

앞서 말씀드린 _app.tsx, _error.tsx, _document.tsx, 404.tsx, 500.tsx가 Next.js에서 제공하는 예약어로 관리되는 페이지라면 지금부터는 개발자가 자유롭게 명칭을 지정해 만들 수 있는 페이지입니다. Next.js의 라우팅 구조는 다음과 같이 /pages 디렉터리를 기초로 구성되며, 각 페이지에 있는 default export로 내보낸 함수가 해당 페이지의 루트 컴포넌트가 됩니다.

  • /pages/index.tsx: 웹 사이트의 루트이며, localhost:3000과 같은 루트 주소를 의미합니다.
  • /pages/hello.tsx: /pages가 생략되고, 파일명이 주소가 됩니다. 즉, 여기서는 /hello이며, localhost:3000/hello로 접근할 수 있습니다.
  • /pages/hello/world.tsx: localhost:3000/hello/world로 접근 가능합니다. 디렉토리의 깊이만큼 주소를 설정할 수 있습니다.
    • 한 가지 주의해야 할 점은 hello/index.tsx와 hello.tsx 모두 같은 주소를 바라본다는 것입니다. 필요에 따라 적절하게 선택하면 됩니다.
  • /pages/hello/[greeting].tsx: []의 의미는 여기에 어떠한 문자도 올 수 있다는 뜻입니다. 이 [greeting]의 경우 서버 사이드에서 greeting이라는 변수에 사용자가 접속한 주소명이 오게 됩니다. 예를 들어, localhost:3000/hello/1, localhost:3000/hello/greeting 모두 유효하며, /pages/hello/[greeting].tsx로 오게 됩니다. 그리고 greeting 변수에는 각각 1, greeting이라는 값이 들어옵니다. 만약 /pages/hello/world.tsx와 같이 이미 정의된 주소가 있다면 미리 정의해 둔 주소인 /pages/hello/world.tsx가 우선합니다.
  • /pages/hi/[...props].tsx: 이 형식은 실제로 스프레드 연산자와 동일합니다. /hi를 제외한 /hi 하위의 모든 주소가 여기로 옵니다. 즉, localhost:3000/hi/hello, localhost:3000/hi/hello/world, localhost:3000/hi/hello/world/foo 등이 여기로 오게 됩니다. 그리고 이 [...props] 값은 props라는 변수에 배열로 오게 됩니다.

/pages/api/hello.ts

/pages 하단에 api라고 작성된 디렉터리가 보이는데 이는 이름에서 예상할 수 있는 것처럼 서버의 API를 정의하는 폴더입니다. 즉, /pages/api/hello.ts는 /api/hello로 호출할 수 있으며, 이 주소는 다른 pages 파일과는 다르게 HTML 요청을 하는 게 아니라 단순히 서버 요청을 주고 받게 됩니다.

 

 

 

References

Next.js란?

클라이언트 사이드 렌더링(CSR)과 서버 사이드 렌더링(SSR)

getServerSideProps 사용법 및 예제

React Deep Dive