Skip to content

필사 모드: 성능·Core Web Vitals 2025 완전 정복: LCP·CLS·INP, Real User Monitoring vs Synthetic, Critical Rendering Path, JS 번들·Image·Font 최적화, Caching·Edge·CDN·HTTP/3, Vercel Speed Insights·CrUX·PageSpeed, 한국 네트워크 특성 — Season 6 Ep 6

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

프롤로그 · 성능은 기능이 아니다

개발자들이 자주 착각하는 것: "성능 최적화는 기능 출시 후의 튜닝". 2025년 현실은 다르다.

- Google 검색 순위에 Core Web Vitals 반영 (2021~)

- 이커머스에서 **LCP 0.1초 개선당 전환율 1%+** 연구 (Amazon, Booking)

- 2024년 INP 정식 적용 후 반응성 최적화 경쟁

- 한국 사용자의 **지하철 5G·저전력 모드** 현실

> **"성능은 기능이 아니다. 모든 기능의 조건이다."**

좋은 AI·좋은 UX·좋은 모션도 느리면 아무 가치 없다. 이번 글은 2025년 실전 성능 가이드.

1장 · Core Web Vitals 2025 — 3대 지표

LCP (Largest Contentful Paint)

- 가장 큰 콘텐츠가 뷰포트에 렌더된 시점

- **Good: ≤ 2.5초**, Needs Improvement: ≤ 4초, Poor: > 4초

- 보통 Hero 이미지·텍스트 블록

CLS (Cumulative Layout Shift)

- 뷰포트 이동(레이아웃 시프트) 누적

- **Good: ≤ 0.1**, Needs: ≤ 0.25, Poor: > 0.25

- 이미지 size 미지정·광고 삽입·폰트 로드 등이 주범

INP (Interaction to Next Paint) — 2024 FID 대체

- 사용자 상호작용 → 다음 페인트까지 걸린 시간

- **Good: ≤ 200ms**, Needs: ≤ 500ms, Poor: > 500ms

- 느린 JS·메인스레드 블록 탐지

- FID(First Input Delay)보다 **페이지 생애 전체** 평가

측정 기준

- **p75** (75 백분위수) — 대부분 사용자 경험

- **Real users, 28일 rolling** (CrUX)

- **Mobile·Desktop 분리** 평가

보조 지표

- **FCP (First Contentful Paint)**: 1.8초 목표

- **TTFB (Time to First Byte)**: 0.8초 목표

- **TTI (Time to Interactive)**: 오래된 지표, INP가 대체

2장 · RUM vs Synthetic — 무엇을 측정할까

Synthetic (합성 테스트)

- 도구가 제어된 환경에서 시뮬레이션

- **Lighthouse, WebPageTest, SpeedCurve**

- 장점: 재현성, 회귀 감지

- 단점: 실사용자와 괴리

RUM (Real User Monitoring)

- 실제 사용자 브라우저에서 측정

- **Vercel Speed Insights, Datadog RUM, New Relic Browser, Sentry, CrUX**

- 장점: 진짜 경험 반영

- 단점: 노이즈, 소수 사용자 영향 큼

병행 원칙

- CI에서 **Lighthouse** (회귀 감지)

- Production에서 **RUM** (진짜 성능)

- CrUX 월간 리뷰로 **경쟁사 벤치마크**

CrUX (Chrome User Experience Report)

- Google이 Chrome 사용자 데이터 수집 (opt-in)

- **익명 집계**, 월 단위 업데이트

- PageSpeed Insights가 이를 활용

- BigQuery 공개 데이터셋

3장 · Critical Rendering Path

브라우저의 렌더 파이프라인

1. **Network**: HTML 다운로드

2. **Parse HTML** → DOM

3. **Parse CSS** → CSSOM

4. **DOM + CSSOM** → Render Tree

5. **Layout** (크기·위치)

6. **Paint** (픽셀)

7. **Composite** (레이어 합성)

주요 병목

- **Render-Blocking CSS**: 외부 CSS 로드 중 렌더 불가

- **Render-Blocking JS**: `<script>` 파싱 중 DOM 파싱 중단

- **Font Swap Period**: 폰트 로드 전 FOIT/FOUT

2025년 표준 개선 기법

**(1) Critical CSS Inline**

- Above-the-fold CSS를 `<style>` 로 인라인

- Next.js·Astro·Vite 플러그인 자동화

**(2) defer / async JS**

- `<script defer>` : 문서 끝까지 실행 지연

- `<script async>` : 독립 실행

**(3) fetchpriority**

- `<img fetchpriority="high">` 로 우선순위

- LCP 이미지에 필수

**(4) preconnect / dns-prefetch**

- 외부 도메인 핸드셰이크 미리

- `<link rel="preconnect" href="https://cdn.example.com">`

**(5) preload**

- 중요 리소스 미리 로드

- 폰트·Hero 이미지 등

4장 · JS 번들 다이어트

2025년 번들의 "좋은 크기":

- **Initial**: < 170kb gzipped

- **Per route**: < 50kb

- 모바일 환경에서 Parse·Execute 비용 고려

번들러 지형 2025

- **esbuild**: 가장 빠른 Go 기반

- **swc**: Rust 기반, Next.js 내부

- **Rollup**: 라이브러리·트리셰이킹

- **Turbopack**: Next.js 15 기본, Rust 기반 Webpack 후계

- **Vite**: 개발 서버 최고, 번들은 Rollup

- **Rspack**: Rust 기반 Webpack 호환

- **Bun**: 런타임+번들러 통합

번들 분석 도구

- **Bundle Analyzer** (Next.js, Vite)

- **source-map-explorer**

- **Rollup visualizer**

- **Bundlephobia**: 패키지 크기 사전 조회

흔한 문제

**(1) 무거운 라이브러리**

- `moment` → `date-fns` or `dayjs`

- `lodash` 전체 → 개별 import

- `react-icons` → svg 직접

**(2) 사용 안 하는 코드**

- 트리셰이킹 안 되는 CJS 패키지

- `"sideEffects": false` 명시

**(3) Dynamic Import**

- 차트·모달 등 지연 로드

- `const Chart = dynamic(() => import('./Chart'))`

**(4) Polyfill 과잉**

- 타겟 브라우저 명확히 (Baseline 2024)

- core-js 선택적 import

**(5) CSS-in-JS 오버헤드**

- 런타임 CSS-in-JS → zero-runtime (linaria, Vanilla Extract, Pigment)

- Tailwind·CSS Modules 대세

5장 · Image 최적화 — LCP의 핵심

포맷 선택 (2025)

| 포맷 | 용도 | 압축률 | 지원 |

|---|---|---|---|

| AVIF | 최신 | 최강 (~50% vs JPEG) | 모던 브라우저 |

| WebP | 표준 | JPEG 대비 30% | 모든 모던 |

| JPEG | 사진 | 기본 | 100% |

| PNG | 투명·단순 | 무손실 | 100% |

| SVG | 벡터 | 작음 | 100% |

2025년 권장: **AVIF + WebP + JPEG 폴백**

반응형 이미지

- `<img srcset="..." sizes="...">` 로 기기별 최적 이미지

- 또는 `<picture>` 로 포맷별 분기

Next.js Image 컴포넌트

src="/hero.jpg"

width={1200}

height={600}

priority // LCP 후보

alt="Hero"

placeholder="blur"

blurDataURL={blur}

/>

- 자동 AVIF/WebP 변환

- 반응형 srcset 생성

- Lazy load 기본 (priority만 eager)

- CLS 방지 (width·height 필수)

Astro Image / Astro Assets

- 빌드 타임 최적화

- `getImage()` API로 고급 제어

CDN 이미지 서비스

- Cloudinary, Imgix, Bunny, Cloudflare Images

- 실시간 변환·캐싱

주요 팁

- **항상 width·height 지정** (CLS 0)

- **Lazy Load + priority** 혼합

- **LCP 이미지는 preload + fetchpriority=high**

- **Hero 이미지는 인라인 SVG·data-URL** 검토

6장 · Font 최적화

핵심 이슈

- 폰트 로드 지연 → 텍스트 보이지 않음(FOIT) 또는 전환 깜빡(FOUT)

- CLS 발생

font-display 설정

@font-face {

font-family: 'Pretendard';

src: url('/fonts/pretendard.woff2') format('woff2');

font-display: swap; /* 기본 폰트 먼저, 로드 후 교체 */

}

- `swap`: 기본 폰트 먼저 (CLS↑), 가장 빠름

- `optional`: 100ms 안에 로드 안 되면 기본 폰트 유지 (CLS↓)

- `fallback`: swap과 optional 중간

size-adjust·ascent-override

- 기본 폰트와 웹폰트 **메트릭 맞춤**

- CLS 대폭 감소

@font-face {

font-family: 'Pretendard-fallback';

src: local('Arial');

size-adjust: 105%;

ascent-override: 90%;

}

서브셋팅

- 한국어 폰트는 **크기가 큼** (2-3MB) → 자주 쓰는 글자만

- 주요 자주 사용 문자 (KS X 1001 기본)

- **Subfont** 도구로 자동 서브셋

Variable Font

- 하나의 파일로 여러 굵기·너비·스타일

- `font-variation-settings`

- Pretendard Variable 공개 (국산 대표)

2025년 권장 스택

- Pretendard Variable (한글)

- Inter / Geist (영문)

- Noto Sans KR (폴백)

- `font-display: swap` + `size-adjust`

7장 · Caching 전략

HTTP 캐시

- **Cache-Control**: 가장 중요한 헤더

- `public, max-age=31536000, immutable` — 정적 리소스

- `no-cache` — 항상 검증

- `no-store` — 절대 저장 X

- **ETag / Last-Modified** — 조건부 요청

- **Stale-While-Revalidate** — 만료 후에도 써도 되나 백그라운드 갱신

Next.js 15 Caching (재설계)

- **Request Memoization**: 동일 요청 중복 제거

- **Data Cache**: 서버 fetch 응답 캐시

- **Full Route Cache**: 정적 페이지 HTML

- **Router Cache**: 클라이언트 라우터 캐시

- 2025년부터 `use cache` 지시어로 명시적 opt-in

Service Worker

- **Offline**, **App-shell**, **Cache-first for assets**

- Workbox로 구현 편의

- 2025년 PWA 부활 조짐 (iOS 제한 완화 움직임)

Edge Caching

- CDN 레벨 캐시 (Vercel, Cloudflare, Fastly)

- `stale-while-revalidate` 로 체감 속도↑

- **ISR (Incremental Static Regeneration)** — Next.js 대표 기법

8장 · Edge·CDN·HTTP/3

CDN의 역할

- 지리적 가까운 서버에서 응답

- 원본 서버 부하 감소

- TLS·HTTP/3·압축 오프로딩

2025년 주요 CDN

- **Cloudflare**: 가격·기능 밸런스 최강

- **Vercel Edge Network**: Next.js 친화

- **Fastly**: 개발자 친화, VCL

- **AWS CloudFront**: AWS 생태계 통합

- **Netlify Edge**: JAMstack 친화

- 한국: **Toast KRP, 네이버 클라우드 CDN, KT 올레CDN**

Edge Function

- CDN 레벨에서 로직 실행

- **Cloudflare Workers, Vercel Edge, Deno Deploy, Fastly Compute@Edge**

- Cold Start 거의 없음 (V8 Isolate)

- 사용 사례: A/B, 인증, Rate Limit, i18n

HTTP/3 (QUIC)

- UDP 기반, Head-of-line Blocking 해결

- TLS 1.3 내장, 0-RTT 연결

- 2025년 CDN·주요 사이트 기본

- 모바일·불안정 네트워크에서 특히 이점

한국 네트워크 특성

- **지하철 5G**: 혼잡·지연·패킷 로스

- **공공 WiFi**: 제한·광고 프록시

- **KT·SKT·LGU+ 통신사별 라우팅** 차이

- → Edge·CDN이 특히 중요

9장 · INP 최적화 — 반응성 실전

INP의 원인

- **긴 작업(long task) >50ms** 이 메인 스레드 점유

- 상호작용 처리 지연

실전 기법

**(1) Debounce / Throttle**

- 검색 input·스크롤 리스너

**(2) Scheduler API (Chrome)**

scheduler.postTask(() => heavyWork(), { priority: 'background' });

**(3) useDeferredValue / useTransition (React 18+)**

const [isPending, startTransition] = useTransition();

startTransition(() => setQuery(input));

**(4) Web Workers**

- 무거운 계산·정렬을 워커로

**(5) Virtualization**

- 긴 리스트에 `react-window`, `TanStack Virtual`

**(6) Code Splitting**

- 필요할 때만 로드

측정

- **Chrome DevTools Performance** "INP" 기록

- Long Task API로 production 감지

10장 · Vercel Speed Insights·CrUX·PageSpeed

Vercel Speed Insights

- Vercel 배포 프로젝트에 간단 통합

- RUM 데이터, Web Vitals 자동

- 페이지별·시간별 분해

- 가격: Pro 플랜 포함

Datadog RUM / New Relic Browser

- 엔터프라이즈 APM과 통합

- 사용자 세션 리플레이, 에러 추적

- 가격 비쌈

CrUX Dashboard

- Google이 제공 무료 도구

- **site-level, origin-level** 리포트

- CrUX API·BigQuery로 자동화

PageSpeed Insights

- Google 무료 도구

- Lighthouse + CrUX 결합

- SEO·Accessibility·Best Practices까지

WebPageTest

- 가장 정교한 Synthetic

- 다양한 위치·네트워크·디바이스

- 워터폴 차트, 필름 스트립

11장 · 실전 체크리스트 · 성능 린터

프로젝트 초기 설정

- **Next.js/Astro Image** 활용

- **font-display: swap + size-adjust**

- **Critical CSS** (프레임워크 기본)

- **Bundle Analyzer** 설치

- **Lighthouse CI** 설정 (threshold: `LCP<2.5s`, `CLS<0.1`, `INP<200ms`)

- **Vercel Speed Insights** 또는 자체 RUM

릴리즈 전 체크

- LCP 원인 분석 (DevTools "Performance insights")

- INP 이벤트 핸들러 점검

- CLS 이미지 size 확인

- 번들 < 170kb

- 핵심 폰트 preload

- 3G Fast 에뮬레이션 테스트

릴리즈 후 모니터링

- RUM 75p 추이

- 사고 시 롤백·수정

- **주간 Performance Review** 팀 미팅

12장 · 2025년 고급 패턴

Partial Pre-Rendering (PPR)

- Next.js 15: 정적 셸 + 동적 홀

- LCP 극단 단축 + 개인화 공존

Islands Architecture

- Astro: 기본 정적 + JS 섬만 하이드레이트

- 번들 최소화

Qwik Resumability

- 초기 JS 0에 가까움

- 상호작용 필요 시점에 로드

Bun/Deno 런타임

- Node.js 대비 시작·런타임 속도

- 일부 프로덕션 도입 시작

Turbopack

- Next.js 15 기본

- Dev 서버·빌드 속도 혁명

Server-sent Streaming

- RSC·Suspense로 콘텐츠 조각 전송

- TTFB·LCP 개선

13장 · 다음 글 예고 — Season 6 Ep 7: "접근성과 국제화"

성능을 잘 만들어 놓았다면 다음은 **모두가 쓸 수 있는 제품**. Ep 7은 접근성(a11y)과 국제화(i18n).

- WCAG 2.2 실전 체크리스트

- Screen Reader 테스트 (NVDA·VoiceOver)

- 키보드 내비게이션 설계

- ARIA 패턴과 오남용

- 색 대비·모션·폰트 크기

- EU Accessibility Act 2025·ADA·한국 장애인차별금지법

- i18n: next-intl·react-intl·vue-i18n·Format.js

- Locale-aware 숫자·날짜·통화

- 한국어 타이포그래피의 특수성 (조사·줄바꿈·세로 쓰기)

- 일본·중국어·RTL(아랍어·히브리어) 지원

- AI·LLM의 다국어 품질

**"접근성은 소수의 권리가 아니다. 모두의 품질이다."**

다음 글에서 만나자.

에필로그 · 체크리스트 12

1. Core Web Vitals **p75 기준**을 RUM으로 추적하는가?

2. **LCP < 2.5s, CLS < 0.1, INP < 200ms** 를 달성하는가?

3. **LCP 이미지에 priority + fetchpriority=high** 설정되는가?

4. 모든 이미지에 **width·height** 가 지정되는가?

5. 폰트가 **font-display + size-adjust** 로 FOIT/CLS 방지되는가?

6. 번들이 **초기 `<170kb`, 라우트 `<50kb`** 인가?

7. **Dynamic Import·Code Splitting** 을 적극 활용하는가?

8. **CDN·Edge Caching** 이 설정되어 있는가?

9. **HTTP/3** 가 활성화되어 있는가?

10. **Lighthouse CI**로 회귀 감지되는가?

11. **Vercel Speed Insights** 또는 RUM 운영되는가?

12. 한국 네트워크·모바일 **실사용자 경험**이 고려되는가?

> **"빠른 제품은 좋은 제품이다.**

> **느린 제품은 존재하지 않는 제품이다."**

— Season 6 Ep 6, Fin.

현재 단락 (1/276)

개발자들이 자주 착각하는 것: "성능 최적화는 기능 출시 후의 튜닝". 2025년 현실은 다르다.

작성 글자: 0원문 글자: 7,860작성 단락: 0/276