Nuxt
넉스트
Vue.js 기반 풀스택 프레임워크. SSR, SSG, 하이브리드 렌더링.
넉스트
Vue.js 기반 풀스택 프레임워크. SSR, SSG, 하이브리드 렌더링.
Nuxt는 Vue.js 기반의 풀스택 프레임워크로, React 생태계의 Next.js에 해당하는 Vue 진영의 메타 프레임워크입니다. 서버 사이드 렌더링(SSR), 정적 사이트 생성(SSG), 클라이언트 사이드 렌더링(CSR)을 유연하게 조합하는 하이브리드 렌더링을 지원하며, 파일 기반 라우팅과 자동 코드 스플리팅을 제공합니다.
Nuxt 3는 Vue 3의 Composition API를 완벽하게 지원하고, Nitro라는 새로운 서버 엔진을 도입했습니다. Nitro는 다양한 플랫폼(Node.js, Cloudflare Workers, Vercel, Netlify 등)에 배포 가능한 유니버설 JavaScript 서버로, Edge Runtime에서도 실행됩니다. 또한 TypeScript를 일급 시민으로 지원하여 타입 안전성을 보장합니다.
Auto-imports 기능으로 Vue의 reactive, ref, computed 등의 API와 컴포넌트를 import 문 없이 사용할 수 있습니다. composables/ 디렉토리의 함수들도 자동으로 import되어 코드 작성이 간결해집니다. 또한 server/ 디렉토리에 API 엔드포인트를 정의하여 풀스택 개발이 가능합니다.
Nuxt는 모듈 시스템을 통해 기능을 확장합니다. @nuxt/content(마크다운 기반 CMS), @nuxt/image(이미지 최적화), @pinia/nuxt(상태 관리) 등 다양한 공식/커뮤니티 모듈이 있습니다. nuxt.config.ts 파일에서 모듈을 추가하면 자동으로 설정되어 개발 경험이 향상됩니다.
// === Nuxt 3 프로젝트 구조 ===
// nuxt.config.ts - 프로젝트 설정
export default defineNuxtConfig({
// 렌더링 모드 설정
ssr: true, // SSR 활성화 (기본값)
// 라우트별 렌더링 전략 (하이브리드 렌더링)
routeRules: {
'/': { prerender: true }, // SSG - 빌드 시 정적 생성
'/blog/**': { swr: 3600 }, // ISR - 1시간마다 재검증
'/admin/**': { ssr: false }, // CSR - 클라이언트 전용
'/api/**': { cors: true }, // API 라우트
},
// 모듈 등록
modules: [
'@pinia/nuxt',
'@nuxt/content',
'@nuxt/image',
],
// 런타임 환경 변수
runtimeConfig: {
// 서버 전용 (클라이언트에 노출 안됨)
apiSecret: process.env.API_SECRET,
// public: 클라이언트에서도 접근 가능
public: {
apiBase: process.env.NUXT_PUBLIC_API_BASE || '/api'
}
}
});
// === pages/index.vue - 페이지 컴포넌트 ===
<script setup lang="ts">
// Auto-import: ref, useFetch 등 import 불필요
// SEO 메타데이터
useSeoMeta({
title: '홈',
description: '메인 페이지입니다.',
ogImage: '/og-image.png',
});
// 서버에서 데이터 가져오기
const { data: posts, pending, error } = await useFetch('/api/posts', {
// 캐싱 옵션
key: 'posts',
// 변환
transform: (data) => data.slice(0, 10),
});
// 반응형 상태
const count = ref(0);
const doubled = computed(() => count.value * 2);
</script>
<template>
<div>
<h1>최신 글</h1>
<div v-if="pending">로딩 중...</div>
<div v-else-if="error">에러: {{ error.message }}</div>
<ul v-else>
<li v-for="post in posts" :key="post.id">
<NuxtLink :to="`/blog/${post.slug}`">
{{ post.title }}
</NuxtLink>
</li>
</ul>
<!-- 클라이언트 전용 컴포넌트 -->
<ClientOnly>
<Counter v-model="count" />
<template #fallback>
<p>카운터 로딩 중...</p>
</template>
</ClientOnly>
</div>
</template>
// === pages/blog/[slug].vue - 동적 라우트 ===
<script setup lang="ts">
// URL 파라미터 접근
const route = useRoute();
const slug = route.params.slug as string;
// 데이터 페칭
const { data: post } = await useFetch(`/api/posts/${slug}`);
// 404 처리
if (!post.value) {
throw createError({
statusCode: 404,
statusMessage: 'Post Not Found'
});
}
// 동적 메타데이터
useSeoMeta({
title: () => post.value?.title,
description: () => post.value?.excerpt,
});
</script>
// === server/api/posts/index.get.ts - API 엔드포인트 ===
export default defineEventHandler(async (event) => {
// 쿼리 파라미터
const query = getQuery(event);
const page = Number(query.page) || 1;
// 데이터베이스 조회 (예: Prisma)
const posts = await prisma.post.findMany({
take: 10,
skip: (page - 1) * 10,
orderBy: { createdAt: 'desc' }
});
return posts;
});
// === server/api/posts/[slug].get.ts - 동적 API ===
export default defineEventHandler(async (event) => {
const slug = getRouterParam(event, 'slug');
const post = await prisma.post.findUnique({
where: { slug }
});
if (!post) {
throw createError({
statusCode: 404,
message: 'Post not found'
});
}
return post;
});
// === composables/useAuth.ts - 커스텀 컴포저블 ===
export const useAuth = () => {
const user = useState<User | null>('user', () => null);
const isLoggedIn = computed(() => !!user.value);
const login = async (credentials: LoginInput) => {
const data = await $fetch('/api/auth/login', {
method: 'POST',
body: credentials
});
user.value = data.user;
};
const logout = async () => {
await $fetch('/api/auth/logout', { method: 'POST' });
user.value = null;
navigateTo('/');
};
return { user, isLoggedIn, login, logout };
};
"Vue.js로 SEO가 중요한 웹사이트를 만들어야 하는데, 그냥 Vue CLI로 시작해도 될까요?"
"SEO가 중요하다면 Nuxt를 추천해요. Vue CLI는 기본적으로 SPA라 검색엔진 크롤링이 어렵거든요. Nuxt는 SSR/SSG를 지원해서 검색엔진에 콘텐츠가 제대로 노출되고, 파일 기반 라우팅과 서버 API도 기본 제공돼서 개발 효율도 높아요."
"Nuxt에서 일부 페이지만 SSG로 만들고, 나머지는 SSR로 하고 싶은데 가능해요?"
"하이브리드 렌더링을 쓰면 돼요. nuxt.config.ts의 routeRules에서 라우트별로 렌더링 전략을 지정할 수 있어요. 메인 페이지는 prerender로 SSG, 블로그는 swr로 ISR, 관리자 페이지는 ssr: false로 CSR처럼 유연하게 설정 가능해요."
"Nuxt의 useFetch와 $fetch의 차이점을 설명해주세요."
"useFetch는 SSR에 최적화된 컴포저블로, 서버에서 데이터를 가져온 후 클라이언트로 전달해 중복 요청을 방지합니다. 반응형 상태와 pending, error 같은 상태도 제공해요. $fetch는 ohmyfetch 기반의 범용 HTTP 클라이언트로, 이벤트 핸들러나 서버 사이드에서 사용할 때 적합합니다."
서버/클라이언트 컨텍스트: Nuxt는 서버와 클라이언트 양쪽에서 코드가 실행될 수 있습니다. window, document 같은 브라우저 API는 서버에서 사용할 수 없으므로, process.client로 체크하거나 <ClientOnly> 컴포넌트로 감싸야 합니다.
데이터 페칭 위치: useFetch, useAsyncData는 setup() 최상위 레벨에서만 호출해야 합니다. 이벤트 핸들러나 조건문 안에서 호출하면 SSR 하이드레이션 문제가 발생할 수 있어요. 이런 경우 $fetch를 사용하세요.
useState vs ref: useState는 서버-클라이언트 간 상태를 공유하고 하이드레이션 시 복원됩니다. 반면 ref는 컴포넌트 로컬 상태입니다. 전역 상태가 필요하면 useState나 Pinia를 사용하세요.