Nuxt.js 시작하기 - 설치 및 프로젝트 생성

Nuxt.js란?

Nuxt.js는 Vue.js 기반의 프레임워크로, 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG), 그리고 단일 페이지 애플리케이션(SPA)을 쉽게 구축할 수 있게 해줍니다. Nuxt 3부터는 Vue 3와 Vite를 기반으로 더욱 빠르고 강력해졌습니다.

주요 특징

  • 하이브리드 렌더링: SSR, SSG, SPA 중 선택 가능
  • 자동 라우팅: 파일 기반 라우팅 시스템
  • TypeScript 지원: 완벽한 TypeScript 지원
  • 자동 Import: 컴포넌트와 컴포저블 자동 임포트
  • SEO 최적화: 메타 태그 관리와 서버 사이드 렌더링
  • 모듈 시스템: 풍부한 모듈 생태계
  • 빠른 성능: Vite와 Nitro 엔진 기반

Nuxt 2 vs Nuxt 3

특징 Nuxt 2 Nuxt 3
Vue 버전 Vue 2 Vue 3
빌드 도구 Webpack Vite
서버 엔진 Node.js Nitro
TypeScript 추가 설정 필요 기본 지원
Composition API 플러그인 필요 기본 지원

현재는 Nuxt 3 사용을 권장합니다.

사전 요구사항

Nuxt.js를 사용하기 위해서는 다음이 설치되어 있어야 합니다:

  • Node.js (v18 이상, v20 권장)
  • npm, yarn, 또는 pnpm
# Node.js 버전 확인
node -v

# npm 버전 확인
npm -v

Nuxt 3 프로젝트 생성

1. 기본 프로젝트 생성 (권장)

가장 간단하고 권장되는 방법입니다.

# npx 사용
npx nuxi@latest init project-name

# pnpm 사용
pnpm dlx nuxi@latest init project-name

# yarn 사용
yarn dlx nuxi@latest init project-name

# bun 사용
bunx nuxi@latest init project-name

2. 프로젝트 시작

# 프로젝트 디렉토리로 이동
cd project-name

# 의존성 설치
npm install

# 개발 서버 시작
npm run dev

기본적으로 http://localhost:3000에서 실행됩니다.

3. 템플릿으로 시작하기

공식 스타터 템플릿을 사용할 수도 있습니다:

# 기본 템플릿
npx nuxi@latest init -t v3

# UI 라이브러리가 포함된 템플릿
npx nuxi@latest init -t ui

# Content 모듈이 포함된 템플릿
npx nuxi@latest init -t content

# 모듈 예제 템플릿
npx nuxi@latest init -t module

프로젝트 구조

Nuxt 3의 기본 프로젝트 구조:

project-name/
├── .nuxt/ # 빌드 파일 (자동 생성)
├── .output/ # 프로덕션 빌드 결과
├── node_modules/
├── public/ # 정적 파일
│ └── favicon.ico
├── server/ # 서버 API 및 미들웨어
│ ├── api/ # API 라우트
│ ├── routes/ # 서버 라우트
│ └── middleware/ # 서버 미들웨어
├── assets/ # 빌드될 리소스 (CSS, 이미지 등)
├── components/ # Vue 컴포넌트
├── composables/ # 컴포저블 함수
├── layouts/ # 레이아웃 컴포넌트
├── middleware/ # 라우트 미들웨어
├── pages/ # 페이지 컴포넌트 (자동 라우팅)
├── plugins/ # 플러그인
├── utils/ # 유틸리티 함수
├── app.vue # 메인 앱 컴포넌트
├── nuxt.config.ts # Nuxt 설정 파일
├── package.json
├── tsconfig.json # TypeScript 설정
└── .gitignore

핵심 디렉토리 설명

pages/ - 자동 라우팅

pages/ 디렉토리의 파일 구조가 자동으로 라우트가 됩니다.

pages/
├── index.vue → /
├── about.vue → /about
├── users/
│ ├── index.vue → /users
│ └── [id].vue → /users/:id
└── posts/
└── [slug].vue → /posts/:slug

components/ - 자동 Import

컴포넌트는 자동으로 임포트되므로 import 문이 필요 없습니다.

<!-- components/MyButton.vue -->
<template>
<button>Click me</button>
</template>

<!-- pages/index.vue -->
<template>
<div>
<MyButton /> <!-- 자동으로 사용 가능 -->
</div>
</template>

composables/ - 재사용 가능한 로직

// composables/useCounter.ts
export const useCounter = () => {
const count = ref(0)
const increment = () => count.value++

return {
count,
increment
}
}

// 페이지에서 자동으로 사용 가능
// const { count, increment } = useCounter()

server/api/ - API 엔드포인트

// server/api/hello.ts
export default defineEventHandler((event) => {
return {
message: 'Hello from API!'
}
})

// 클라이언트에서 호출: /api/hello

기본 파일 설명

app.vue - 메인 애플리케이션

<template>
<div>
<NuxtPage />
</div>
</template>

<script setup lang="ts">
// 전역 설정 및 로직
</script>

nuxt.config.ts - Nuxt 설정

export default defineNuxtConfig({
devtools: { enabled: true },

// 앱 설정
app: {
head: {
title: 'My Nuxt App',
meta: [
{ charset: 'utf-8' },
{ name: 'viewport', content: 'width=device-width, initial-scale=1' },
{ name: 'description', content: 'My awesome Nuxt 3 app' }
]
}
},

// 런타임 설정
runtimeConfig: {
// 서버 전용
apiSecret: '',
// 클라이언트에 노출
public: {
apiBase: '/api'
}
},

// CSS
css: ['~/assets/css/main.css'],

// 모듈
modules: [],

// Vite 설정
vite: {
// Vite 설정 옵션
}
})

페이지 생성 예제

기본 페이지

<!-- pages/index.vue -->
<template>
<div>
<h1>Welcome to Nuxt 3</h1>
<p>Count: {{ count }}</p>
<button @click="increment">Increment</button>
</div>
</template>

<script setup lang="ts">
const count = ref(0)
const increment = () => count.value++

// SEO 메타 태그
useSeoMeta({
title: 'Home Page',
description: 'Welcome to my Nuxt 3 app'
})
</script>

동적 라우트

<!-- pages/users/[id].vue -->
<template>
<div>
<h1>User Profile</h1>
<p>User ID: {{ route.params.id }}</p>
<div v-if="data">
<h2>{{ data.name }}</h2>
<p>{{ data.email }}</p>
</div>
</div>
</template>

<script setup lang="ts">
const route = useRoute()

// 데이터 페칭
const { data } = await useFetch(`/api/users/${route.params.id}`)
</script>

데이터 페칭

Nuxt 3는 다양한 데이터 페칭 방법을 제공합니다:

useFetch

<script setup lang="ts">
// GET 요청
const { data, pending, error, refresh } = await useFetch('/api/posts')

// POST 요청
const { data } = await useFetch('/api/posts', {
method: 'POST',
body: { title: 'New Post' }
})

// 옵션과 함께
const { data } = await useFetch('/api/posts', {
query: { page: 1 },
headers: { 'Authorization': 'Bearer token' }
})
</script>

useAsyncData

<script setup lang="ts">
const { data } = await useAsyncData('posts', () => $fetch('/api/posts'))

// 의존성이 있는 경우
const route = useRoute()
const { data } = await useAsyncData(
`post-${route.params.id}`,
() => $fetch(`/api/posts/${route.params.id}`)
)
</script>

$fetch (클라이언트 사이드)

// 클라이언트에서만 실행
const data = await $fetch('/api/posts')

레이아웃 사용

기본 레이아웃

<!-- layouts/default.vue -->
<template>
<div>
<header>
<nav>
<NuxtLink to="/">Home</NuxtLink>
<NuxtLink to="/about">About</NuxtLink>
</nav>
</header>
<main>
<slot />
</main>
<footer>
<p>&copy; 2025 My App</p>
</footer>
</div>
</template>

커스텀 레이아웃

<!-- layouts/custom.vue -->
<template>
<div class="custom-layout">
<slot />
</div>
</template>

<!-- pages/special.vue -->
<template>
<div>
<h1>Special Page</h1>
</div>
</template>

<script setup lang="ts">
definePageMeta({
layout: 'custom'
})
</script>

미들웨어

라우트 미들웨어

// middleware/auth.ts
export default defineNuxtRouteMiddleware((to, from) => {
const user = useState('user')

if (!user.value) {
return navigateTo('/login')
}
})

// 페이지에서 사용
// pages/dashboard.vue
<script setup lang="ts">
definePageMeta({
middleware: 'auth'
})
</script>

전역 미들웨어

// middleware/analytics.global.ts
export default defineNuxtRouteMiddleware((to, from) => {
console.log('Navigating to:', to.path)
})

주요 Composables

Nuxt 3가 제공하는 유용한 컴포저블:

// 라우터
const route = useRoute()
const router = useRouter()

// 상태 관리
const state = useState('key', () => 'default value')

// 헤드 관리
useHead({
title: 'Page Title'
})

useSeoMeta({
title: 'SEO Title',
description: 'SEO Description'
})

// 런타임 설정
const config = useRuntimeConfig()

// 쿠키
const cookie = useCookie('name')

// 에러 처리
const error = useError()
showError({ statusCode: 404, message: 'Not Found' })
clearError()

빌드 및 배포

개발 서버

npm run dev
# 또는
npm run dev -- --port 3001

프로덕션 빌드

# 빌드
npm run build

# 미리보기
npm run preview

SSR 배포

# Node.js 서버용 빌드
npm run build

# .output 디렉토리 배포
node .output/server/index.mjs

정적 사이트 생성 (SSG)

// nuxt.config.ts
export default defineNuxtConfig({
ssr: true,
nitro: {
preset: 'static'
}
})
npm run generate

SPA 모드

// nuxt.config.ts
export default defineNuxtConfig({
ssr: false
})

인기 있는 Nuxt 모듈

Nuxt 생태계의 유용한 모듈들:

UI 프레임워크

# Nuxt UI
npm install @nuxt/ui

# Tailwind CSS
npm install -D @nuxtjs/tailwindcss

# Vuetify
npm install vuetify @nuxtjs/vuetify

Content 관리

# Nuxt Content (마크다운 기반 CMS)
npm install @nuxt/content

이미지 최적화

# Nuxt Image
npm install @nuxt/image

국제화

# Nuxt i18n
npm install @nuxtjs/i18n

HTTP 클라이언트

# Axios 모듈
npm install @nuxtjs/axios

인증

# Nuxt Auth
npm install @sidebase/nuxt-auth

PWA

# Nuxt PWA
npm install @vite-pwa/nuxt

환경 변수

.env 파일

# .env
NUXT_PUBLIC_API_BASE=https://api.example.com
NUXT_API_SECRET=secret-key

nuxt.config.ts에서 사용

export default defineNuxtConfig({
runtimeConfig: {
// 서버 전용 (NUXT_로 시작하는 환경변수)
apiSecret: process.env.NUXT_API_SECRET,

// 클라이언트 노출 (NUXT_PUBLIC_으로 시작)
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE
}
}
})

컴포넌트에서 사용

<script setup lang="ts">
const config = useRuntimeConfig()

// 클라이언트에서 사용 가능
console.log(config.public.apiBase)

// 서버에서만 사용 가능
console.log(config.apiSecret) // 클라이언트에서는 undefined
</script>

TypeScript 설정

Nuxt 3는 TypeScript를 기본으로 지원합니다.

자동 타입 생성

개발 서버를 실행하면 .nuxt/nuxt.d.ts 에 자동으로 타입이 생성됩니다.

tsconfig.json

{
"extends": "./.nuxt/tsconfig.json",
"compilerOptions": {
"strict": true,
"types": [
"@nuxt/types",
"@types/node"
]
}
}

타입 체크

# 타입 체크
npx nuxi typecheck

유용한 CLI 명령어

# 개발 서버 시작
npx nuxi dev

# 프로덕션 빌드
npx nuxi build

# 프로덕션 미리보기
npx nuxi preview

# 정적 사이트 생성
npx nuxi generate

# 프로젝트 정보
npx nuxi info

# 타입 체크
npx nuxi typecheck

# 의존성 업그레이드
npx nuxi upgrade

# 캐시 정리
npx nuxi cleanup

성능 최적화 팁

1. 지연 로딩

<template>
<div>
<LazyMyHeavyComponent v-if="show" />
</div>
</template>

2. 클라이언트 전용 렌더링

<template>
<div>
<ClientOnly>
<HeavyComponent />
<template #fallback>
<LoadingSpinner />
</template>
</ClientOnly>
</div>
</template>

3. 이미지 최적화

<template>
<NuxtImg
src="/image.jpg"
width="300"
height="200"
loading="lazy"
/>
</template>

4. 프리페칭 제어

<template>
<NuxtLink to="/about" :prefetch="false">
About
</NuxtLink>
</template>

디버깅

Vue DevTools

Nuxt 3는 Vue DevTools를 내장하고 있습니다:

// nuxt.config.ts
export default defineNuxtConfig({
devtools: { enabled: true }
})

서버 로그

// server/api/example.ts
export default defineEventHandler((event) => {
console.log('Server log:', event.path)
return { success: true }
})

문제 해결

포트 변경

# 개발 서버 포트 변경
npm run dev -- --port 3001

캐시 문제

# .nuxt 디렉토리 삭제
rm -rf .nuxt

# node_modules 재설치
rm -rf node_modules
npm install

타입 오류

# 타입 재생성
npx nuxi prepare

다음 단계

프로젝트를 성공적으로 생성했다면:

  1. 컴포넌트 작성: Vue 3 Composition API 활용
  2. 라우팅 이해: 파일 기반 라우팅 시스템 학습
  3. 데이터 페칭: useFetch, useAsyncData 활용
  4. 상태 관리: useState 또는 Pinia 사용
  5. API 개발: server/api 디렉토리 활용
  6. SEO 최적화: useSeoMeta 설정
  7. 모듈 탐색: Nuxt 모듈 생태계 활용

참고 자료

마무리

Nuxt.js는 Vue.js 애플리케이션 개발을 더욱 쉽고 강력하게 만들어주는 프레임워크입니다. 자동 라우팅, 서버 사이드 렌더링, 정적 사이트 생성 등 다양한 기능을 제공하며, Nuxt 3부터는 Vite 기반으로 더욱 빠른 개발 경험을 제공합니다. 파일 기반의 직관적인 구조와 풍부한 모듈 생태계로 빠르게 프로덕션 레벨의 애플리케이션을 개발할 수 있습니다.

Share