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 |
---|