Next.js 기초 및 설정
1. Next.js 란?
Next.js는 React 기반의 웹 프레임워크로, 서버 사이드 렌더링과 정적 파일 생성 등을 지원하여 개발자가 보다 효율적으로 웹 애플리케이션을 구축할 수 있도록 도와줍니다. 이 프레임워크는 React의 기능을 확장하여 더욱 강력한 기능을 제공하며, SSR(Server-Side Rendering), CSR(Client-Side Rendering), Static Site Generation 등의 다양한 렌더링 방식을 지원합니다.
2. Next.js 특징
- 서버 사이드 렌더링(SSR): Next.js는 서버 사이드 렌더링을 지원하여 초기 로딩 시에 페이지를 서버에서 렌더링하여 사용자에게 보여줍니다. 이를 통해 SEO(Search Engine Optimization)를 개선하고, 초기 로딩 속도를 향상시킵니다.
- 정적 파일 생성(Static Site Generation): Next.js는 페이지의 정적 HTML 파일을 빌드할 수 있는 정적 사이트 생성 기능을 제공합니다. 이를 통해 서버 부하를 줄이고, 사용자 경험을 개선할 수 있습니다.
- 동적 라우팅(Dynamic Routing): Next.js는 동적 라우팅을 지원하여 페이지 경로를 동적으로 생성할 수 있습니다. 이를 통해 유연한 라우팅 구조를 구축할 수 있습니다.
- API Routes: Next.js는 API Routes를 제공하여 서버리스(serverless) 함수를 생성할 수 있습니다. 이를 통해 서버리스 아키텍처를 쉽게 구현할 수 있습니다.
- 개발 환경 설정 간소화: Next.js는 기본적으로 웹팩(Webpack)과 바벨(Babel)을 내장하고 있어 개발 환경 설정을 간소화합니다. 또한, 기본적으로 코드 스플리팅(Code Splitting), CSS 모듈화(CSS Modules) 등의 기능을 지원하여 개발자가 보다 효율적으로 개발할 수 있도록 돕습니다.
** 코드 스플리팅(Code Splitting)이란? **
코드 스플리팅(Code Splitting)은 웹 애플리케이션의 자바스크립트 코드를 여러 개의 번들로 분리하는 기술을 말합니다. 이를 통해 사용자가 방문한 페이지에 필요한 코드만 로드하여 초기 로딩 속도를 향상시킬 수 있습니다.
** CSS 모듈화(CSS Modules)이란? **
CSS 모듈화(CSS Modules)는 CSS 파일을 모듈화하여 컴포넌트 단위로 스타일을 적용할 수 있는 기술을 말합니다. 이를 통해 컴포넌트 간의 스타일 충돌을 방지하고, 코드의 일관성을 유지할 수 있습니다.
3. Next.js(Typesrcipt) 시작하기
Next.js 프로젝트를 Typesrcipt 버전으로 시작해보겠습니다. Typesrcipt는 정적 타입을 지원하여 코드의 안정성을 높이고, 개발 생산성을 향상시킬 수 있는 언어입니다. Next.js와 Typesrcipt를 함께 사용하면, 더욱 안정적이고 효율적인 웹 애플리케이션을 구축할 수 있습니다.
next-blog-app 디렉토리에 터미널을 열고 다음과 같이 명령어를 실행합니다.
- 프로젝트 생성:
npx create-next-app ./명령어를 사용하여 Next.js 프로젝트를 생성합니다. - 프로젝트 실행:
npm run dev명령어를 사용하여 Next.js 프로젝트를 실행합니다. - 페이지 생성:
pages디렉토리에 페이지를 생성하여 Next.js 애플리케이션을 구축합니다.
npx create-next-app ./
cd next-blog-app
npm run dev # or yarn dev
위와 같은 방법을 사용하여 Next.js 프로젝트를 생성 시 질문에 따라 Typesrcipt 를 사용할 것인지, ESLint 와 Tailwind 를 사용할 것인지 등을 선택할 수 있습니다.

Typesrcipt: Typesrcipt 를 사용할 것인지 선택합니다.ESLint: ESLint 를 사용하여 코드 스타일을 검사할 것인지 선택합니다. (yes)Tailwind CSS: Tailwind CSS 를 사용하여 스타일을 작성할 것인지 선택합니다. (yes)src디렉토리에 컴포넌트를 생성하여 사용할 것인지 선택합니다. (yes)App Router를 사용하여 라우팅을 구현할 것인지 선택합니다. (yes)import alias를 사용하여 모듈을 더 쉽게 불러올 것인지 선택합니다. (yes)
- src/ 디렉토리 사용 여부
src/ 디렉토리를 사용할지 여부는 프로젝트의 구조와 개발 환경에 따라 다를 수 있지만 사용하는 것을 권장합니다.
- 프로젝트 구조의 명확성: src/ 디렉토리를 사용하면 프로젝트의 주요 소스 코드가 담긴 디렉토리를 명확하게 구분할 수 있습니다. 이는 프로젝트의 구조를 더 쉽게 이해하고 유지보수하기 쉽게 만듭니다.
- 코드의 일관성: src/ 디렉토리를 사용하면 프로젝트의 모든 소스 코드를 한 곳에 모아둘 수 있습니다. 이를 통해 코드의 일관성을 유지하고 관리하기 쉽게 만들 수 있습니다.
- 프로젝트 확장성: src/ 디렉토리를 사용하면 향후 프로젝트를 확장할 때 더 유연하게 구조를 조정할 수 있습니다. 새로운 기능이나 모듈을 추가할 때 기존의 구조를 유지하면서 쉽게 통합할 수 있습니다.
4. Next.js 프로젝트 구조
next-blog-app/
├── src/
│ ├── pages/ # 라우팅과 관련된 페이지 컴포넌트
│ ├── components/ # 재사용 가능한 UI 컴포넌트
│ ├── styles/ # 스타일 관련 파일
│ └── utils/ # 유틸리티 함수
├── public/ # 정적 파일들이 저장되는 디렉토리
├── .next/ # Next.js 빌드 시 생성되는 파일들이 저장되는
├── node_modules/ # 프로젝트에 설치된 모듈들이 저장되는 디렉토리
├── package.json # 프로젝트 정보와 의존성 모듈들이 정의된 파일
└── README.md # 프로젝트의 설명이 작성된 파일
Next.js 프로젝트 구조화
Next.js 페이지는 pages 디렉토리에 생성하여 사용할 수 있습니다. 페이지는 파일 이름에 따라 경로가 자동으로 생성되며, 동적 라우팅을 사용하여 동적 경로를 생성할 수 있습니다.
pages 디렉토리의 파일명은 소문자로 작성하며, 파일명에 따라 경로가 자동으로 생성됩니다.
next-blog-app/
├── src/
│ ├── pages/
│ │ ├── index.tsx
│ │ ├── post/
│ │ │ └── index.tsx
│ │ │ └── [id].tsx
│ │ └── about.tsx
└── ...
pages 디렉토리에 페이지를 생성하고, 파일명에 따라 경로가 자동으로 생성됩니다. index.tsx 파일은 / 경로로 접근할 수 있으며, [id].tsx 파일은 /post/:id 경로로 접근할 수 있습니다.
- 페이지 라우팅
// src/pages/index.tsx
export default function Home() {
return (
<div>
<h1>Home</h1>
</div>
)
}
// src/pages/post/index.tsx
const Post = () => {
return (
<div>
<h1>Post</h1>
</div>
)
}
export default Post
// src/pages/_app.tsx
import { AppProps } from 'next/app'
function MyApp({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}
export default MyApp
서버를 실행하고 http://localhost:3000 경로로 접속하면, Home 페이지가 렌더링됩니다. http://localhost:3000/post 경로로 접속하면, Post 페이지가 렌더링됩니다.
pages 디렉토리에 페이지를 생성하고, React 컴포넌트로 구성할 수 있습니다. 페이지는 export default 키워드를 사용하여 내보내며, pages 디렉토리의 파일명에 따라 경로가 자동으로 생성됩니다.
main 페이지가 렌더링되지 않을 경우,
app폴더의page.tsx을 삭제하면 해결됩니다.
Next.js 레이아웃 구성
Next.js 레이아웃은 components 디렉토리에 컴포넌트를 생성하여 사용할 수 있습니다. 레이아웃은 페이지의 공통 요소를 구성할 때 사용하며, outlet 컴포넌트를 사용하여 페이지 컨텐츠를 렌더링할 수 있습니다.
next-blog-app/
├── components/
│ └── layout/
│ └── Layout.tsx
│ └── Header.tsx
│ └── Footer.tsx
Next.js 레이아웃 적용
Next.js 레이아웃은 페이지에서 Layout 컴포넌트를 사용하여 적용할 수 있습니다. 페이지에서 Layout 컴포넌트를 사용하면, 페이지의 공통 요소를 효율적으로 구성할 수 있습니다.
// src/components/layout/Layout.tsx
import Link from 'next/link'
import React from 'react'
const Header = () => {
return (
<header>
<h1>
<Link href="/">logo</Link>
</h1>
<nav>
<ul>
<li>
<Link href="/about">About</Link>
</li>
<li>
<Link href="/post">Post</Link>
</li>
</ul>
</nav>
</header>
)
}
export default Header
// src/components/layout/Header.tsx
export default function Header() {
return (
<header>
<h1>Header</h1>
</header>
)
}
// src/components/layout/Footer.tsx
export default function Footer() {
return (
<footer>
<h1>Footer</h1>
</footer>
)
}
Layout 컴포넌트를 생성하여 레이아웃을 구성하고, Header 컴포넌트와 Footer 컴포넌트를 생성하여 레이아웃에 적용할 수 있습니다. 이렇게 구성한 레이아웃은 React Router를 사용하여 페이지 간의 이동 시 공통 요소를 효율적으로 구성할 수 있습니다.
// src/pages/_app.tsx
import { AppProps } from 'next/app' // AppProps 타입을 불러옵니다.
import Layout from '@/components/layout/Layout'
function MyApp({ Component, pageProps }: AppProps) {
return (
<Layout>
<Component {...pageProps} />
</Layout>
)
}
export default MyApp
_app.tsx 파일을 생성하여 레이아웃을 적용할 수 있습니다. _app.tsx 파일은 Next.js 애플리케이션의 전역 레이아웃을 설정할 때 사용되며, Layout 컴포넌트를 사용하여 페이지의 공통 요소를 구성할 수 있습니다.
// src/pages/_document.tsx
import Document, { Html, Head, Main, Nextsrcipt } from 'next/document'
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link rel="icon" href="/favicon.ico" />
</Head>
<body>
<Main />
<Nextsrcipt />
</body>
</Html>
)
}
}
export default MyDocument
_document.tsx 파일을 생성하여 HTML 문서의 레이아웃을 설정할 수 있습니다. _document.tsx 파일은 모든 페이지에 공통으로 적용되는 HTML 문서의 레이아웃을 설정할 때 사용되며, Head 컴포넌트를 사용하여 메타 태그나 스타일 시트를 적용할 수 있습니다.
Next.js 페이지 링크
Next.js 페이지 간의 이동은 Link 컴포넌트를 사용하여 구현할 수 있습니다. Link 컴포넌트는 페이지 간의 이동을 자동으로 처리하며, 페이지를 미리 로드하여 사용자 경험을 향상시킵니다.
// pages/home/index.tsx
import Link from 'next/link'
export default const Home = () => {
return (
<div>
<h1>Home</h1>
<Link href="/post">
Go to Post
</Link>
</div>
)
}
Next.js 정적 파일 제공
Next.js는 public 디렉토리를 사용하여 정적 파일을 제공할 수 있습니다. public 디렉토리에 저장된 파일은 / 경로로 접근할 수 있으며, 이미지, CSS 파일, JS 파일 등을 저장할 수 있습니다.
next-blog-app/
├── public/
│ ├── images/
│ │ └── logo.png
│ ├── styles/
│ │ └── main.css
public 디렉토리에 images 디렉토리와 styles 디렉토리를 생성하고, 이미지 파일과 CSS 파일을 저장할 수 있습니다. 이렇게 저장된 파일은 /images/logo.png, /styles/main.css 경로로 접근할 수 있습니다.
Typesrcipt Type 정의
Next.js 프로젝트에서 타입을 정의할 때는 types 디렉토리를 사용하여 타입을 정의할 수 있습니다. types 디렉토리에 타입을 정의하고, 필요한 파일에서 타입을 불러와 사용할 수 있습니다.
next-blog-app/
src/
├── types/
│ └── types.ts # 타입 정의를 모아둔 디렉토리와 파일
| └── utils.ts # 유틸리티 함수를 모아둔 디렉토리와 파일
├── data/
│ └── posts.ts # 데이터를 모아둔 디렉토리와 파일
- Typesrcipt를 사용하여 타입을 정의
// src/types/types.ts
// Post 타입을 정의합니다.
export interface Post {
id: number
title: string
content: string
author: string
date: string // 날짜는 ISO 형식 (예: "2024-01-01")으로 나타냅니다.
tags?: string[] // 태그는 선택적으로 배열 형태로 나타냅니다.
// undefined일 수 있기 때문에 옵셔널 체이닝 연산자(?.)를 사용합니다.
}
- Post 타입을 사용하여 데이터를 정의
// src/data/posts.ts
import { Post } from '@/types/types'
// Post 타입을 사용하여 데이터를 정의합니다.
// posts 배열에 Post 타입의 데이터를 저장합니다.
export const posts: Post[] = [
{
id: 1,
title: 'Javasrcipt 클로저 이해하기',
content: `
클로저는 자바스크립트에서 중요한 개념입니다. 클로저는 함수가 선언된 시점의 스코프(변수 범위)를 기억하여, 나중에 그 함수가 호출될 때 해당 스코프에 접근할 수 있게 합니다.
예를 들어, 내부 함수가 외부 함수의 변수를 기억하고 있는 경우를 생각해 봅시다. 클로저를 잘 이해하면, 고급 자바스크립트 프로그래밍 기법을 쉽게 다룰 수 있습니다. 이 글에서는 클로저의 기초 개념과, 클로저를 활용한 실전 예제를 알아보겠습니다.
`,
author: '홍길동',
date: '2024-05-10',
tags: ['Javasrcipt', '클로저', '프로그래밍'],
},
{
id: 2,
title: 'CSS Grid 레이아웃 가이드',
content: `
CSS Grid 레이아웃은 반응형 디자인을 구현하기 위한 강력한 도구입니다. 그리드 시스템을 사용하면 여러 개의 행과 열을 활용하여 복잡한 레이아웃을 손쉽게 구성할 수 있습니다.
이 가이드에서는 Grid의 기본 개념을 소개하고, 실제 프로젝트에서 그리드 레이아웃을 활용하는 방법을 단계별로 설명합니다. 그리드 아이템 간의 간격 조절부터 다양한 행과 열의 크기 조절에 이르기까지, 이 글을 통해 여러분은 더욱 유연한 웹 디자인을 만들 수 있을 것입니다.
`,
author: '이영희',
date: '2024-05-08',
tags: ['CSS', '웹 디자인', '그리드 레이아웃'],
},
{
id: 3,
title: 'Python 데이터 클래스 활용하기',
content: `
데이터 클래스는 파이썬에서 클래스 구조를 간단하게 정의할 수 있는 방법을 제공합니다. 일반 클래스를 사용할 때보다 코드가 훨씬 간결해지며, 기본적인 기능(예: __init__, __repr__)도 자동으로 제공됩니다.
이 글에서는 데이터 클래스의 사용법과 주요 기능을 살펴보고, 이를 통해 파이썬 코드의 효율성을 높이는 방법을 알아보겠습니다. 또한, 데이터 클래스의 커스터마이징 방법과 기존 클래스와의 비교를 통해 다양한 활용 사례를 소개합니다.
`,
author: '김철수',
date: '2024-05-05',
tags: ['Python', '데이터 클래스', '프로그래밍'],
},
]
Components 구성
next-blog-app/
├── src/
├── ├── components/
│ ├── ├── post/
│ │ │ ├── PostList.tsx
│ │ │ ├── PostItem.tsx
│ │ │ ├── PostDetail.tsx
- PostItem 컴포넌트를 생성하여 Post 데이터를 렌더링
// components/post/PostItem.tsx
// Type-Only Import 문법을 사용하여 타입만 불러옵니다.
import type { Post } from '@/type/types'
import Link from 'next/link' // Link 컴포넌트를 임포트합니다.
// PostProps 타입을 정의합니다.
interface PostProps {
post: Post
}
const PostItem = ({ post }: PostProps) => {
return (
<div>
{/* 제목을 Link 컴포넌트로 감싸고 href에 동적 경로를 지정합니다. */}
<h2>
<Link href={`/post/${post.id}`}>{post.title}</Link>
</h2>
<p style={{ whiteSpace: 'nowrap', width: '80%', overflow: 'hidden', textOverflow: 'ellipsis' }}>
{post.content}
</p>
<p>{post.date}</p>
</div>
)
}
export default PostItem
// components/Post/PostList.tsx
import React from 'react'
import { posts } from '@/data/posts'
import PostItem from '@/components/post/PostItem'
const PostList = () => {
return (
<div>
{posts.map((post) => (
<PostItem key={post.id} post={post} />
))}
</div>
)
}
export default PostList
- 페이지에 데이터 렌더링
// pages/post/index.tsx
import PostList from '@/components/post/PostList'
const PostPage = () => {
return (
<div>
<h1>Post</h1>
<PostList />
</div>
)
}
export default PostPage
Post 컴포넌트를 사용하여 데이터를 렌더링할 수 있습니다. Post 컴포넌트에 Post 타입의 데이터를 전달하고, posts 배열을 사용하여 데이터를 렌더링합니다.
- 페이지에 동적 라우팅 적용
// components/post/PostDetail.tsx
import type { Post } from '@/type/types'
import Link from 'next/link' // Link 컴포넌트를 임포트합니다.
// PostProps 타입을 정의합니다.
interface PostProps {
post: Post
}
const PostDetail = ({ post }: PostProps) => {
return (
<div>
<h2>{post.title}</h2>
<p>{post.content}</p>
<p>{post.author}</p>
<p>{post.date}</p>
{/* && 연산자를 사용하여 tags가 존재하는 경우에만 출력합니다. */}
<ul>{post.tags && post.tags.map((tag, index) => <li key={index}>{tag}</li>)}</ul>
</div>
)
}
export default PostDetail
// pages/post/[id].tsx
import { GetStaticProps, GetStaticPaths } from 'next'
import { posts } from '@/data/posts' // 가정한 경로
import PostDetail from '@/components/post/PostDetail'
// PostType 타입을 정의합니다.
interface PostType {
id: number
title: string
content: string
author: string
date: string
tags?: string[]
}
// PostType 타입을 사용하여 PostProps 타입을 정의합니다.
interface PostProps {
post: PostType
}
// getStaticPaths 함수를 사용하여 동적 경로를 생성합니다.
// async 함수를 사용하여 비동기 처리를 수행합니다.
export const getStaticPaths: GetStaticPaths = async () => {
// posts 배열의 id 값을 사용하여 동적 경로를 생성합니다.
const paths = posts.map((post) => ({
params: { id: post.id.toString() },
// id 값을 문자열로 변환하여 params에 저장합니다.
// 예: { params: { id: '1' } }
}))
return {
paths, // 생성된 동적 경로를 반환합니다.
fallback: false, // fallback을 false로 설정하여 없는 페이지는 404 페이지를 반환합니다.
}
}
// getStaticProps 함수를 사용하여 각 동적 경로에 필요한 데이터를 전달합니다.
// async 함수를 사용하여 비동기 처리를 수행합니다.
export const getStaticProps: GetStaticProps<PostProps, { id: string }> = async ({ params }) => {
// params.id 값을 사용하여 해당 포스트를 찾습니다.
const post = posts.find((post) => post.id === Number(params?.id))
// params.id는 문자열이므로 Number로 변환합니다.
// params가 undefined인 경우를 대비하여 옵셔널 체이닝 연산자(?.)를 사용해 에러를 방지합니다.
if (!post) {
return { notFound: true } // 포스트가 없는 경우 404 페이지를 반환
}
return {
props: {
post,
},
}
}
// Post 컴포넌트를 정의합니다.
const Post: React.FC<PostProps> = ({ post }) => {
return (
<div>
<h1>Post</h1>
<PostDetail post={post} />
</div>
)
}
export default Post
Tailwind CSS 적용
next-blog-app/
src/
├── styles/
│ ├── globals.css
│ ├── Home.module.css
│ ├── Post.module.css
/* styles/globals.css */
@tailwind base;
@tailwind components;
@tailwind utilities;
/* styles/Home.module.css */
.container {
max-width: 960px;
margin: 0 auto;
padding: 0 1rem;
}
.title {
font-size: 2rem;
font-weight: bold;
color: #333;
}
/* styles/Post.module.css */
.post {
margin-bottom: 2rem;
border-bottom: 1px solid #ddd;
}
.postTitle {
font-size: 1.5rem;
font-weight: bold;
color: #333;
}
.postContent {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
width: 80%;
margin-top: 1rem;
color: #666;
}
.postAuthor {
margin-top: 0.5rem;
color: #999;
}
.postDate {
margin-top: 0.5rem;
color: #999;
}
.postTags {
margin-top: 0.5rem;
color: #999;
}
컴포넌트에 스타일 적용
// components/Post/Post.tsx
import type { Post } from '@/type/types'
import Link from 'next/link'
import styles from '@/styles/Post.module.css'
// PostProps 타입을 정의합니다.
interface PostProps {
post: Post
}
const PostItem = ({ post }: PostProps) => {
return (
<div className={styles.post}>
{/* 제목을 Link 컴포넌트로 감싸고 href에 동적 경로를 지정합니다. */}
<h2>
<Link href={`/post/${post.id}`}>
<span className={styles.postTitle}>{post.title}</span>
</Link>
</h2>
<p className={styles.postContent}>{post.content}</p>
<p className={styles.postDate}>{post.date}</p>
</div>
)
}
export default PostItem
Post 컴포넌트에 Post.module.css 파일을 적용하여 스타일을 적용할 수 있습니다. Post.module.css 파일을 사용하여 컴포넌트에 스타일을 적용하고, styles 객체를 사용하여 클래스 이름을 지정할 수 있습니다.
Next.js 빌드 및 실행
next-blog-app/
├── .next/
└── ...
- Next.js 프로젝트를 빌드하고 실행하는 방법
# Next.js 프로젝트 빌드
npm run build # or yarn build
# Next.js 프로젝트 실행
npm run start # or yarn start
npm run build 명령어를 사용하여 Next.js 프로젝트를 빌드하고, npm run start 명령어를 사용하여 Next.js 프로젝트를 실행할 수 있습니다. 빌드된 파일은 .next 디렉토리에 저장되며, 실행 시 .next 디렉토리의 파일을 사용하여 Next.js 애플리케이션을 실행합니다.
Next.js 프로젝트 배포
Next.js 프로젝트를 배포할 때는 Vercel, Netlify, AWS, Heroku 등의 클라우드 서비스를 사용하여 배포할 수 있습니다. 이 중에서 Vercel은 Next.js를 만든 회사이며, Next.js 프로젝트를 쉽게 배포할 수 있는 플랫폼을 제공합니다.
'Front > Next.js' 카테고리의 다른 글
| firebase를 이용한 Next.js 블로그 앱 만들기 (0) | 2024.05.05 |
|---|