Frontend
Next.js 15 + Turbopack - 개발 속도 700배 향상의 비밀 ⚡
관리자
10일 전
11400
#Next.js#Turbopack#JavaScript#Frontend#성능최적화#Bundler
Next.js 15가 Turbopack과 함께 새로운 차원의 개발 경험을 제공합니다!
2024년 10월, Next.js 15가 정식 출시되면서 Turbopack이 stable로 전환되었습니다. 이제 개발 서버 시작이 700배 빨라지고, HMR이 94% 개선된 놀라운 성능을 경험할 수 있습니다.
🎯 핵심 요약
- Turbopack: Rust 기반 번들러로 Webpack보다 700배 빠른 시작 속도
- React 19 지원: 최신 React 기능 완벽 통합
- Async Request APIs: 비동기 처리의 새로운 패러다임
- Partial Prerendering: 정적/동적 렌더링의 완벽한 조화
- Enhanced Caching: 더 스마트해진 캐싱 전략
1. Turbopack - 게임 체인저의 등장 🚀
실제 성능 비교 (대규모 프로젝트 기준)
Webpack 시절 (Next.js 14)
# 개발 서버 시작: 30초
# HMR 적용: 2-3초
# 빌드 시간: 5-10분
npm run dev
Turbopack 시대 (Next.js 15)
# 개발 서버 시작: 0.5초 이내
# HMR 적용: 131ms
# 빌드 시간: 1-2분
npm run dev --turbopack
벤치마크 결과
- 🚀 시작 속도: 30,000ms → 43ms (700배 향상)
- ⚡ HMR 속도: 2,000ms → 131ms (94% 개선)
- 📦 메모리 사용량: 2GB → 500MB (75% 감소)
- 🔄 리빌드 속도: 증분 컴파일로 10배 향상
Turbopack 활성화 방법
// package.json
{
"scripts": {
"dev": "next dev --turbopack",
"build": "next build", // 빌드는 아직 Webpack 사용
"start": "next start"
}
}
// next.config.js
module.exports = {
experimental: {
// Turbopack for dev (stable)
turbopack: {
// 커스텀 설정 가능
rules: {
'*.svg': {
loaders: ['@svgr/webpack'],
as: '*.js',
},
},
},
},
}
2. React 19 완벽 통합 🎨
Async Request APIs - 서버 컴포넌트의 진화
Before (Next.js 14)
// 복잡한 params 처리
export default function Page({ params, searchParams }) {
const id = params.id // 동기적 접근
const query = searchParams.q
// ...
}
After (Next.js 15)
// 비동기 params - 더 일관된 API
export default async function Page({
params,
searchParams
}: {
params: Promise<{ id: string }>
searchParams: Promise<{ q: string }>
}) {
const { id } = await params // 비동기 처리
const { q } = await searchParams
// 더 예측 가능한 동작
return <div>{id}</div>
}
왜 비동기로 바뀌었나?
- 일관성: cookies(), headers()와 동일한 패턴
- 성능: 필요한 시점에만 값 계산
- 미래 대비: Partial Prerendering 최적화
3. Partial Prerendering (PPR) - 혁신적인 렌더링 ⚡
정적과 동적의 완벽한 조화
// app/product/[id]/page.tsx
import { Suspense } from 'react'
export const experimental_ppr = true // PPR 활성화
export default async function ProductPage({
params
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
// 정적 부분 - 빌드 시 생성
const staticData = await getStaticProductData(id)
return (
<div>
{/* 정적 콘텐츠 - 즉시 표시 */}
<h1>{staticData.title}</h1>
<p>{staticData.description}</p>
{/* 동적 콘텐츠 - 스트리밍 */}
<Suspense fallback={<PriceSkeleton />}>
<DynamicPrice productId={id} />
</Suspense>
<Suspense fallback={<ReviewsSkeleton />}>
<UserReviews productId={id} />
</Suspense>
</div>
)
}
// 동적 컴포넌트 - 요청 시 렌더링
async function DynamicPrice({ productId }: { productId: string }) {
const price = await getCurrentPrice(productId) // 실시간 가격
return <div className="price">{price}</div>
}
PPR의 장점
- 🚀 초기 로딩: 정적 부분 즉시 표시 (TTFB 개선)
- 🔄 점진적 렌더링: 동적 부분 스트리밍
- 📈 SEO 최적화: 정적 콘텐츠로 크롤링 가능
- ⚡ 사용자 경험: 빠른 인터랙션
4. 향상된 캐싱 전략 📦
fetch() 캐싱 개선
// app/api/data/route.ts
export async function GET() {
// 1. 기본 캐싱 (force-cache)
const staticData = await fetch('https://api.example.com/static')
// 2. 재검증 캐싱 (15초마다)
const revalidatedData = await fetch('https://api.example.com/data', {
next: {
revalidate: 15,
tags: ['products'] // 태그 기반 재검증
}
})
// 3. 동적 데이터 (캐싱 안 함)
const dynamicData = await fetch('https://api.example.com/realtime', {
cache: 'no-store'
})
// 4. 새로운 stale-while-revalidate 전략
const swrData = await fetch('https://api.example.com/swr', {
next: {
revalidate: 60,
stale: 30 // 30초간 stale 데이터 허용
}
})
}
// 태그 기반 재검증
import { revalidateTag } from 'next/cache'
export async function POST() {
// 특정 태그의 캐시 무효화
revalidateTag('products')
return Response.json({ revalidated: true })
}
5. 새로운 Instrumentation API 📊
성능 모니터링 자동화
// app/instrumentation.ts
import { registerOTel } from '@vercel/otel'
export function register() {
// OpenTelemetry 자동 설정
registerOTel({
serviceName: 'my-nextjs-app',
// 성능 추적
instrumentations: {
fetch: true,
http: true,
database: true,
},
// 커스텀 메트릭
onTrace: (span) => {
if (span.name.includes('api')) {
span.setAttribute('custom.api', true)
}
}
})
}
// Web Vitals 추적
export function onWebVitalsMetric(metric: any) {
// 성능 메트릭 수집
switch (metric.name) {
case 'FCP':
console.log('First Contentful Paint:', metric.value)
break
case 'LCP':
console.log('Largest Contentful Paint:', metric.value)
break
case 'CLS':
console.log('Cumulative Layout Shift:', metric.value)
break
}
}
6. 개발자 경험 개선사항 🛠️
1. 에러 메시지 개선
// 이전: 암호같은 에러
TypeError: Cannot read property 'x' of undefined
at <anonymous>:1:1
// 현재: 명확한 에러와 해결책
Error: Dynamic server usage detected.
Page: /dashboard
Reason: cookies() was called in a Server Component
Solution:
- Wrap the component with Suspense boundary
- Or use 'use client' directive
Learn more: https://nextjs.org/docs/app/partial-prerendering
2. TypeScript 5.0+ 지원
// 자동 타입 추론 개선
import type { Metadata } from 'next'
export async function generateMetadata({
params
}: {
params: Promise<{ id: string }>
}): Promise<Metadata> {
const { id } = await params
return {
title: `Product ${id}`,
description: 'Product details',
// 새로운 메타데이터 옵션
alternates: {
canonical: `/products/${id}`,
languages: {
'en-US': `/en/products/${id}`,
'ko-KR': `/ko/products/${id}`,
},
},
}
}
3. 번들 분석 도구 개선
# 번들 크기 분석 (시각화)
ANALYZE=true npm run build
# Turbopack 트레이싱 (성능 분석)
NEXT_TURBOPACK_TRACING=1 npm run dev
7. Server Actions 2.0 🎬
더 강력해진 서버 액션
// app/actions.ts
'use server'
import { revalidatePath } from 'next/cache'
import { redirect } from 'next/navigation'
// 폼 액션 with 검증
export async function createPost(
prevState: any,
formData: FormData
) {
// Zod 검증
const schema = z.object({
title: z.string().min(1),
content: z.string().min(10),
})
const validatedFields = schema.safeParse({
title: formData.get('title'),
content: formData.get('content'),
})
if (!validatedFields.success) {
return {
errors: validatedFields.error.flatten().fieldErrors,
}
}
// DB 저장
const post = await db.post.create({
data: validatedFields.data,
})
// 캐시 재검증 & 리다이렉트
revalidatePath('/posts')
redirect(`/posts/${post.id}`)
}
// 클라이언트 컴포넌트에서 사용
'use client'
import { useActionState } from 'react'
import { createPost } from './actions'
export function PostForm() {
const [state, formAction, isPending] = useActionState(createPost, null)
return (
<form action={formAction}>
<input name="title" />
{state?.errors?.title && (
<p className="error">{state.errors.title}</p>
)}
<textarea name="content" />
{state?.errors?.content && (
<p className="error">{state.errors.content}</p>
)}
<button disabled={isPending}>
{isPending ? '저장 중...' : '저장'}
</button>
</form>
)
}
8. 마이그레이션 가이드 📝
Next.js 14 → 15 업그레이드
# 1. 의존성 업데이트
npm install next@15 react@19 react-dom@19
npm install -D @types/react@19 @types/react-dom@19
# 2. Turbopack 활성화
npm run dev --turbopack
# 3. 코드 수정 (codemods 사용)
npx @next/codemod@latest upgrade
주요 변경사항 체크리스트
// ❌ Before (Next.js 14)
export default function Page({ params }) {
return <div>{params.id}</div>
}
// ✅ After (Next.js 15)
export default async function Page({
params
}: {
params: Promise<{ id: string }>
}) {
const { id } = await params
return <div>{id}</div>
}
9. 실제 프로덕션 사례 📊
Vercel Dashboard
- 개발 서버 시작: 40초 → 2초 (95% 개선)
- HMR 속도: 3초 → 200ms (93% 개선)
- 빌드 시간: 12분 → 3분 (75% 개선)
- 번들 크기: 2.3MB → 1.8MB (22% 감소)
Linear
- 초기 로딩: 4.2초 → 1.8초 (57% 개선)
- Time to Interactive: 5.5초 → 2.3초 (58% 개선)
- Lighthouse 점수: 72 → 95
Loom
- 개발자 생산성: 2배 향상
- CI/CD 시간: 15분 → 5분
- 메모리 사용량: 60% 감소
10. 꼭 알아야 할 팁과 트릭 💡
1. Turbopack 디버깅
# 성능 트레이싱 활성화
NEXT_TURBOPACK_TRACING=1 npm run dev
# 트레이스 파일 분석
npx @next/trace analyze .next/trace-turbopack
2. 최적 설정
// next.config.js
module.exports = {
// 이미지 최적화
images: {
formats: ['image/avif', 'image/webp'],
deviceSizes: [640, 750, 828, 1080, 1200],
},
// 번들 최적화
modularizeImports: {
'lucide-react': {
transform: 'lucide-react/dist/esm/icons/{{member}}',
},
},
// PPR 활성화
experimental: {
ppr: true,
// 타입 라우트
typedRoutes: true,
},
}
3. 성능 모니터링
// app/components/WebVitals.tsx
'use client'
import { useReportWebVitals } from 'next/web-vitals'
export function WebVitals() {
useReportWebVitals((metric) => {
// Analytics로 전송
window.gtag?.('event', metric.name, {
value: Math.round(
metric.name === 'CLS' ? metric.value * 1000 : metric.value
),
metric_id: metric.id,
metric_value: metric.value,
metric_delta: metric.delta,
})
})
return null
}
🎯 마무리
Next.js 15와 Turbopack은 단순한 업데이트가 아닙니다. 개발자 경험의 혁명입니다.
핵심 이점
- 🚀 700배 빠른 시작: 30초 → 0.04초
- ⚡ 94% 빠른 HMR: 즉각적인 피드백
- 📦 75% 적은 메모리: 리소스 효율성
- 🎯 PPR: 최적의 렌더링 전략
- 🛠️ 개발자 경험: 명확한 에러, 강력한 도구
당장 시작하기
# 새 프로젝트
npx create-next-app@latest my-app
# 기존 프로젝트 업그레이드
npm install next@15
npm run dev --turbopack
이제 더 이상 "빌드가 느려서", "HMR이 안 돼서" 같은 변명은 없습니다.
Turbopack과 함께 날아다니는 개발 경험을 즐기세요! 🚀
🔗 참고 자료
당신의 Next.js 프로젝트, 이제 Turbopack으로 날개를 달아보세요! ⚡
댓글로 Turbopack 사용 후기를 공유해주세요!
댓글 0개
아직 댓글이 없습니다
첫 번째 댓글을 작성해보세요!