[Docs] Next.js Getting Started from 'Installation' to 'CSS'

백상휘·2025년 4월 16일
0

FE

목록 보기
1/5

Next.js 공부를 위해 공식문서를 읽기 쉽게 제가 생각하는 핵심내용만 짚어서 정리합니다.

Installation

How to set up a new Next.js project

  • Node 18.18 이상
  • macOS, Windows, Linux OS

Automatic installation (자동이라고 할 것 까지야...)

create-next-app 라는 명령어를 사용한다.

npx create-next-app@latest

명령어 입력하면 프로젝트의 여러 옵션이 표시되고 결정할 수 있는데 TailWind CSS, import alias 만 개인 취향으로 하고 나머지는 그냥 Yes 하면 될 것 같다.

Manual installation

아래 명령어를 입력해 직접 패키지를 설치한다.

npm install next@latest react@latest react-dom@latest

package.json 파일은 아래와 같이 수정한다.

{
  "scripts": {
    "dev": "next dev", // 개발서버를 실행
    "build": "next build", // 앱을 프로덕션 버전으로 빌드
    "start": "next start", // 프로덕션 서버 실행
    "lint": "next lint" // ESLint 실행
  }
}

Create the "app" directory

Next.js 는 파일 시스템 기반의 라우팅을 제공하기 때문에 필요한 작업이다. 루트 경로에 app 디렉토리를 만들고 layout.tsx 파일을 만든다. 이 파일은 Root Layout 이다. (참고로 이 파일 생성을 잊어먹으면 프레임워크가 자동으로 생성한다)

Root Layout 은 반드시 html, body 를 포함해야 한다.

type Children = { children: React.ReactNode };
export default function RootLayout({ children }: Children) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

app 디렉토리에 page.tsx 를 만들어준다. 이건 레이아웃 내에 포함될 페이지 컴포넌트이다.

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

이 컴포넌트는 URL 의 [schema]://[domain]/ 으로 접속 가능하다 (예시: https://localhost:3000/)

여기까지 진행했다면 아래와 같은 파일 구조일 것이다.

[app]
|-layout.tsx
|-page.tsx

src 디렉토리를 넣고 싶다면 app 폴더를 포함해서 넣도록 한다.

Create the "public" folder (optional)

public 폴더를 루트 경로에 추가하여 정적 애셋을 추가한다. 이 애셋들은 base URL 으로 접근 가능하다.

import Image from 'next/image'
 
export default function Page() {
  return <Image
  	src="/profile.png"
  	alt="Profile"
  	width={100}
  	height={100}
  />
}

Run the development server

  1. npm run dev
  2. https://localhost:3000 접속
  3. app/page.tsx 파일을 수정하고 반영되는지 확인

Set up Typescript

최소 타입스크립트 버전은 4.5.2

Next.js 는 타입스크립트를 내장한다. 그러므로 js / jsx 확장자를 ts / tsx 로만 바꾸고 개발서버를 실행하면 된다. tsconfig.json 을 넣으면 원하는 설정을 추가할 수도 있다.

Set up ESLint

실행은 npm run lint 로 한다. (package.json 설정은 위에 참조)

콘솔창에 이 명령어를 실행하면 Lint 실행 옵션이 보인다.

  • Strict : Next.js 기반 ESLint 설정에 Core Web Vitals rule-set 을 적용한다(뭔지는 잘 모르겠다).
  • Base : Next.js 기반 ESLint 설정을 적용한다.
  • Cance : 자신이 설정한 ESLint 설정을 적용한다.

Strict, Base 를 실행하면 ESLint 가 자동 설치. 이후엔 next lint 로 실행 가능.

Set up Absolute Imports and Module Path Aliases

tsconfig.json 혹은 jsconfig.json 에서 paths, baseUrl 설정이 가능하다. 절대경로를 @ 를 이용해서 가독성이 좋은 상대경로로 바꿀 수 있다. 이외에도 다른 경로도 alias 로 만들 수 있다.

{
  "compilerOptions": {
    "baseUrl": "src/",
    "paths": {
      "@/styles/*": ["styles/*"],
      "@/components/*": ["components/*"]
    }
  }
}

Project structure and organization

Next.js 의 파일 컨벤션과 추천사항들을 다룬다.

Folder and file conventions

public
src
|--app

Top-level folders

  • app : App Router
  • pages : Pages Router
  • public : Static assets
  • src : "Optional"

Top-level files

의존성, 미들웨어, 모니터링 툴, 환경변수 설정

  • next.config.js : Next.js 설정
  • package.json : Node 패키지 설정
  • middleware.ts : Next.js request middleware
  • .env : 환경변수
    • .env.local : 로컬 환경변수
    • .env.production : 배포 환경변수
    • .env.development : 개발 환경변수
    • .eslintrc.json : ESLint 설정
  • next-env.d.ts : Next.js Typescript 선언 파일
  • tsconfig.json / jsconfig.js : TS / JS 설정 파일

Routing Files

  • layout
  • page
  • loading
  • not-found
  • error
  • global-error
  • route
  • template
  • default : Parallel route 시 fallback page

Nested routes

  • folder : Route 세그먼트
  • folder/folder : Nested Route 세그먼트

Dynamic routes

  • [folder] : Dynamic route 세그먼트
  • [...folder] : Catch-all route 세그먼트
  • [[...folder]] : Optional catch-all route 세그먼트

Route Groups and private folders

  • (folder) : Route 에 영향을 주지 않는 그룹
  • _folder : Route 에 영향을 주지 않는 그룹의 하위 폴더

Parallel and Intercepted Routes

  • @folder : Slot
  • (.)folder : 같은 레벨 Intercept
  • (..)folder : 한 레벨 위 Intercept
  • (..)(..)folder : 두 레벨 위 Intercept
  • (...)folder : 루트 Intercept

Metadata file convention

  • App icons
    • favicon : ".ico" / 앱 Favicon
    • icon : ".ico" 비롯한 이미지 확장자 / 앱 아이콘
    • icon : ".js", ".ts", ".tsx" / 생성된 앱 아이콘
    • apple-icon : 이미지 확장자 / 애플 앱 아이콘
    • apple-icon : ".js", ".ts", ".tsx" / 생성된 애플 앱 아이콘
  • Open Graph and Twitter images
    • opengraph-image : 이미지 확장자 / Open graph 이미지 파일
    • opengraph-image : ".js", ".ts", ".tsx" / 생성된 Open graph 이미지 파일
    • twitter-image : 이미지 확장자 / Open graph 이미지 파일
    • twitter-image : ".js", ".ts", ".tsx" / 생성된 Open graph 이미지 파일
  • SEO
    • sitemap : ".xml" / Sitemap 파일
    • sitemap : ".js", ".ts" / 생성된 Sitemap 파일
    • robots : ".txt" / Robots 파일
    • robots : ".js", ".ts" / 생성된 Robots 파일

Organizing your project

Next.js 는 파일 구성에 대해 이미지 정해진 룰이 있으나 아래 사항을 참고하면 좋다.

Component hierarchy

아래 파일에 정의된 컴포넌트는 위계구조를 갖는다.

  • layout.js
  • template.js
  • error.js (React error boundary)
  • loading.js (React suspense boundary)
  • not-found.js (React error boundary)
  • page.js / nested layout.js
<Layout>
  <Template>
  	<ErrorBoundary fallback={<Error />}>
      <Suspense fallback={<Loading />}>
        <ErrorBoundary fallback={<NotFound />}>
          <Page />
        </ErrorBoundary>
      </Suspense>
    </ErrorBoundary>
  </Template>
</Layout>

컴포넌트들은 연속적으로 렌더링된다. nested 세그먼트는 부모 세그먼트 안에 렌더링된다.

dashboard
|--layout.ts
|--error.js
|--loading.js
|---settings
   |---layout.ts
   |---error.js
   |---loading.js
   |---page.js

<Layout>
  <ErrorBoundary fallback={<Error />}>
    <Suspense fallback={<Loading />}>
      // Start of settings
      <Layout>
        <ErrorBoundary fallback={<Error />}>
          <Suspense fallback={<Loading />}>
            <Page />      
          </Suspense>
        </ErrorBoundary> 
      </Layout>
      // End of settings
    </Suspense>
  </ErrorBoundary>
</Layout>

Colocation

app 디렉토리에는 아래 폴더들이 Route 세그먼트를 정의한다(URL 의 세그먼트). 하지만 page.js 혹은 route.js 가 없으면 Route 세그먼트로 작동하지 않는다.

app
|---dashboard    Not Routable
   |---settings    Not Routable
|---api    Not Routable

반대로 page.js 혹은 route.js 만 있는 폴더라면 Route 세그먼트로 작동한다.

app
|---dashboard    
   |---page.js    Routablable, /dashboard
   |----settings
       |----page.js    Routable, /dashboard/settings
|---api
   |---route.js    Routable, /dashboard/api/

이는 라우팅할 파일이 정해져 있다는 뜻이기 때문에 실수를 줄일 수 있다.

Private folders

폴더 앞에 _ 를 붙인다(%5F 도 가능). Route 세그먼트에 포함되지 않는다.

app
|---dashboard    
   |---page.js    Routablable, /dashboard
   |----_components
       |----buttons.js
   |----_lib
       |----format-date.js
       |----page.jsroute.js    Not Routable, /dashboard/_lib/

Private folder 는 아래의 상황에서 사용한다.

  • UI logic 을 routing logic 과 분리하고 싶음
  • 사용할 내부 파일을 만들고 싶음
  • 코드와 파일 정리
  • Next.js 파일 컨벤션과 충돌을 방지

Route groups

(폴더이름) 으로 만들 수 있다. Route 세그먼트에 포함되지 않는다.

app
|---(admin)
       |---dashboard
           |---page.js    Routablable, /dashboard
|---(marketing)
       |---about
           |---page.js    Routablable, /about
       |---blog
           |---page.js    Routablable, /blog

Route groups 는 아래의 상황에서 사용한다.

  • 용도에 따라 Route 세그먼트 파일들을 묶고 싶음.
  • 특정 Route 세그먼트들에만 적용되는 레이아웃을 만들고 싶음.
    • loading.tsx 등도 같은 그룹 내에서 공유한다.
    • 하나의 Route 세그먼트에서 여러 개의 loading, layout 가질 수 있다.

src directory

Optional. 루트의 루트. 앱의 코드와 프로젝트 설정파일 (예: package.json) 을 나누기 좋음.

Layouts and Pages

How to create layouts and pages

Creating a page

page 는 렌더링 되는 컴포넌트이다.

app
|--page.js    Routable, /

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

Creating a layout

다수의 page 에서 공유하며, navigation 에도 그 상태와 상호작용이 유지된다. 렌더링 사이클은 page 와 같이 가져가지 않는다.

layout 파일을 만들면 된다. 아래 예시는 Root Layout 이다. Root Layout 은 특별히 html, body xormfmf 가져야 한다.

app
|--layout.js
|--page.js    Routable, /

type Children = { children: React.ReactNode }
export default function DashboardLayout({ children }: Children) {
  return (
    <html lang="en">
      <body>
        <main>{children}</main>
      </body>
    </html>
  )
}

Creating a nested route

앱 내 여러 URL 세그먼트를 정의할 수 있다.

/blog/[slug]

  • / = 루트 세그먼트
  • blog = 세그먼트
  • [slug] = 자식 세그먼트 (다이나믹 라우팅 세그먼트)

Nesting layouts

Layout 도 nested 된다. nested 된 layout 은 부모 layout 내에 렌더링 된다.

Linking between pages

<Link> 컴포넌트를 이용하면 라우팅이 가능하다. Next.js 빌트인 컴포넌트이고 a 태그를 확장하였다.

아래 코드는 '/blog/[Dynamic_Routing_Segment]' 로 라우팅 하는 예제이다.

import Link from 'next/link';

export default async function Post({ post }) {
  const posts = await getPosts();
  
  return (
    <ul>
      {posts.map((post) => (
        <li key={post.slug}>
          <Link href={`/blog/${post.slug}`}>{post.title}</Link>
        </li>
      ))}
    </ul>
  )
}

Link 컴포넌트는 대부분의 라우팅 상황에서 사용할 수 있지만 useRouter 훅을 이용해야 할 경우도 있다.

Images and Fonts

Next.js 는 이미지와 폰트에 대한 최적화가 이미 되어 있다.

Optimizing images

Image 컴포넌트는 html <img> 태그를 확장한다. 이 컴포넌트는 다음의 기능을 제공한다.

  • 크기(파일 크기, 이미지 크기) 최적화, 모던 이미지 형식인 WebP 을 사용한다.
  • 이미지 로딩 최적화
import Image from 'next/image';

export default function Page() {
  return <Image src="" alt="" />
}

src 속성은 로컬, 원격 주소 모두 가능.

Local images

public 폴더 내에 있다면 가능.

import Image from 'next/image';
import profilePic from './me.png';

export default function Page() {
  return <Image src={profilePic} alt="Picture of the author" />
}

Next.js 는 import 한 이미지 크기를 이용해 내부 폭, 높이를 설정한다. blurDataURL, placeholder 속성도 있는데 설정 안하면 기본값이 제공된다.

Remote images

URL string 을 제공한다.

import Image from 'next/image'
 
export default function Page() {
  return (
    <Image
      src="https://s3.amazonaws.com/my-bucket/profile.png"
      alt="Picture of the author"
      width={500} height={500}
    />
  )
}

이 경우는 빌드 타임에 이미지 크기를 Next.js 는 모르니 width, height 를 제공해주는 것이 좋다.

next.config.js 파일에 제공될 URL 패턴을 제공하면 자칫 잘못된 URL 을 사용하는 것을 막을 수 있다.

import { NextConfig } from 'next';

const config: NextConfig = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 's3.amazonaws.com',
        port: '',
        pathname: '/my-bucket/**',
        search: '',
      },
    ],
  },
}

export default config;

Optimizing fonts

next/font 모듈은 폰트를 최적화하고 네트워크 요청을 최소화 한다. 거기다 Next.js 는 내장된 폰트가 따로 있다.

만약 로컬 파일로 존재하는 폰트를 가져오기 위해서는 'next/font/local' 혹은 'next/font/google' 을 사용한다.

import { Geist } from 'next/font/google';

const geist = Geist({
  weight: '400', // 속성 적용 가능
  subsets: ['latin'],
});

export default function Layout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={geist.className}>
      <body>{children}</body>
    </html>
  )
}
import localFont from 'next/font/local';

const myFont = localFont({
  src: './my-font.woff2',
})

// 아래도 가능.
// const roboto = localFont({
//   src: [
//     {
//       path: './Roboto-Regular.woff2',
//       weight: '400',
//       style: 'normal',
//     },
//     {
//       path: './Roboto-Italic.woff2',
//       weight: '400',
//       style: 'italic',
//     },
//     {
//       path: './Roboto-Bold.woff2',
//       weight: '700',
//       style: 'normal',
//     },
//     {
//       path: './Roboto-BoldItalic.woff2',
//       weight: '700',
//       style: 'italic',
//     },
//   ],
// })

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en" className={geist.className}>
      <body>{children}</body>
    </html>
  )
}

CSS

CSS 에 관해서 Next.js 는 여러 개의 방식을 제공한다.

  • CSS Modules
  • Global CSS
  • Tailwind CSS
  • Sass
  • CSS-in-JS
  • External Stylesheets

CSS Modules

CSS classname 을 만들고 적용한다.

// app/blog/styles.module.css
.blog {
  padding: 24px;
}

// app/blog/page.tsx
import styles from './styles.module.css'
 
export default function Page({ children }: { children: React.ReactNode }) {
  return <main className={styles.blog}>{children}</main>
}

Global CSS

앱 전체에 적용하는 CSS 를 정의한다.

// app/global.css
body {
  padding: 20px 20px 60px;
  max-width: 680px;
  margin: 0 auto;
}

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

Tailwind CSS

Next.js 와 호환이 잘 된다.

Installing Tailwind

npm install tailwindcss @tailwindcss/postcss postcss

Configuring Tailwind

root 프로젝트에 postcss.config.mjs 파일을 넣는다.

/** @type {import('tailwindcss').Config} */
export default {
  plugins: {
    '@tailwindcss/postcss': {},
  },
}

Using Tailwind

Global Stylesheet (app/globals.css) 에 Tailwind directives 를 넣는다.

@import 'tailwindcss';

그리고 root layout 에 Global Stylesheet 를 추가한다.

import type { Metadata } from 'next'
// These styles apply to every route in the application
import './globals.css'
 
export const metadata: Metadata = {
  title: 'Create Next App',
  description: 'Generated by create next app',
}
 
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>{children}</body>
    </html>
  )
}

이제 사용 가능

export default function Page() {
  return <h1 className="text-3xl font-bold underline">Hello, Next.js!</h1>
}

Sass

Installing Sass

npm install --save-dev sass

Customizing Sass options

next.config.js 에서 아래와 같이 작성한다.

import type { NextConfig } from 'next';

const nextConfig: NextConfig = {
  sassOptions: {
    additionalData: `$var: red;`,
  },
}

export default nextConfig;

나머지는 나중에 필요하면 따로 공부.

profile
plug-compatible programming unit

0개의 댓글