성능 버짓(Performance Budget)은 웹 성능 메트릭에 상한선을 설정하고 이를 유지하는 전략이다. LCP, FID/INP, CLS, JS 번들 크기 등에 구체적인 목표치를 정해 성능 회귀를 방지한다.
Core Web Vitals 기준
| 메트릭 | 좋음 | 개선 필요 | 나쁨 |
|---|
| LCP (최대 콘텐츠풀 페인트) | ≤ 2.5s | 2.5~4s | > 4s |
| INP (다음 페인트까지의 상호작용) | ≤ 200ms | 200~500ms | > 500ms |
| CLS (누적 레이아웃 이동) | ≤ 0.1 | 0.1~0.25 | > 0.25 |
| FCP (최초 콘텐츠풀 페인트) | ≤ 1.8s | 1.8~3s | > 3s |
| TTFB (첫 바이트까지의 시간) | ≤ 800ms | 800ms~1.8s | > 1.8s |
리소스 버짓 설정
JS 번들 버짓 예시:
총 JS: ≤ 300KB (gzip 압축 후)
초기 번들: ≤ 100KB
서드파티 JS: ≤ 50KB
이미지 당: ≤ 100KB (WebP/AVIF)
총 페이지 크기: ≤ 1.5MB
설정 도구:
- webpack-bundle-analyzer: 번들 분석
- bundlesize: CI 자동 검사
- Lighthouse CI: CWV 자동 검사
- web-vitals: 실사용자 측정
Lighthouse CI 설정
yaml
# .lighthouserc.yml
ci:
collect:
url:
- https://my-site.com
- https://my-site.com/blog
numberOfRuns: 3
assert:
assertions:
# Core Web Vitals
'largest-contentful-paint':
- error
- maxNumericValue: 2500
'cumulative-layout-shift':
- error
- maxNumericValue: 0.1
# 번들 크기
'total-byte-weight':
- warn
- maxNumericValue: 1600000 # 1.6MB
'uses-optimized-images':
- warn
# 성능 점수
'categories:performance':
- error
- minScore: 0.9
React 성능 최적화
typescript
// 코드 스플리팅 (React.lazy)
import { lazy, Suspense } from 'react';
const HeavyChart = lazy(() => import('./HeavyChart'));
function Dashboard() {
return (
<Suspense fallback={<Skeleton />}>
<HeavyChart /> {/* 필요 시 로드 */}
</Suspense>
);
}
// 이미지 최적화 (Next.js)
import Image from 'next/image';
<Image
src="/hero.jpg"
alt="Hero"
width={1200}
height={600}
priority // LCP 이미지: preload
sizes="(max-width: 768px) 100vw, 1200px"
/>
// web-vitals 측정
import { onCLS, onINP, onLCP } from 'web-vitals';
onLCP(({ value }) => sendToAnalytics({ metric: 'LCP', value }));
onINP(({ value }) => sendToAnalytics({ metric: 'INP', value }));
onCLS(({ value }) => sendToAnalytics({ metric: 'CLS', value }));
관련 문서