목록으로
Performance

웹 성능 최적화 핵심 전략

Core Web Vitals부터 실전 최적화 기법까지. 사용자 경험을 향상시키는 성능 최적화 방법을 알아봅니다.

웹 성능은 사용자 경험과 비즈니스 성과에 직접적인 영향을 미칩니다. 로딩이 1초 늦어지면 전환율이 7% 감소한다는 연구 결과도 있습니다. 성능 최적화는 선택이 아닌 필수입니다.

Core Web Vitals

Google이 정의한 핵심 성능 지표입니다. 검색 순위에도 영향을 미칩니다.

LCP (Largest Contentful Paint)

페이지에서 가장 큰 콘텐츠가 화면에 표시되는 시간입니다. 2.5초 이내가 좋습니다.

개선 방법은 다음과 같습니다.

  • 서버 응답 시간 단축
  • 렌더 블로킹 리소스 제거
  • 이미지 최적화
  • CDN 사용

FID (First Input Delay)

사용자가 첫 상호작용을 했을 때 브라우저가 응답하기까지 걸리는 시간입니다. 100ms 이내가 좋습니다.

개선 방법은 다음과 같습니다.

  • JavaScript 실행 시간 단축
  • 긴 작업을 작은 단위로 분할
  • 메인 스레드 부담 줄이기

CLS (Cumulative Layout Shift)

페이지 로딩 중 레이아웃이 얼마나 이동하는지 측정합니다. 0.1 이하가 좋습니다.

개선 방법은 다음과 같습니다.

  • 이미지와 비디오에 크기 지정
  • 광고 영역 미리 확보
  • 웹폰트 로딩 최적화

이미지 최적화

이미지는 대부분의 웹사이트에서 가장 큰 용량을 차지합니다.

적절한 포맷 선택

<!-- 모던 포맷 우선, 폴백 제공 -->
<picture>
  <source srcset="image.avif" type="image/avif" />
  <source srcset="image.webp" type="image/webp" />
  <img src="image.jpg" alt="설명" />
</picture>

AVIF는 JPEG 대비 50% 이상 용량을 줄일 수 있습니다. WebP도 30% 정도 절약됩니다.

반응형 이미지

<img
  src="image-800.jpg"
  srcset="
    image-400.jpg 400w,
    image-800.jpg 800w,
    image-1200.jpg 1200w
  "
  sizes="(max-width: 600px) 400px, (max-width: 1200px) 800px, 1200px"
  alt="설명"
/>

화면 크기에 맞는 이미지를 로드합니다. 모바일에서 불필요하게 큰 이미지를 다운로드하지 않습니다.

지연 로딩

<img src="image.jpg" alt="설명" loading="lazy" />

뷰포트에 들어올 때까지 이미지 로딩을 지연합니다. 초기 로딩 속도가 빨라집니다.

JavaScript 최적화

코드 스플리팅

// 동적 import로 필요할 때 로드
const Modal = lazy(() => import('./Modal'));

function App() {
  return (
    <Suspense fallback={<Loading />}>
      {showModal && <Modal />}
    </Suspense>
  );
}

초기 번들 크기를 줄이고, 필요한 코드만 로드합니다.

Tree Shaking

사용하지 않는 코드를 번들에서 제거합니다. ES 모듈 문법을 사용해야 합니다.

// 나쁜 예 - 전체 라이브러리 포함
import _ from 'lodash';

// 좋은 예 - 필요한 함수만 포함
import { debounce } from 'lodash-es';

번들 분석

# Next.js
npx @next/bundle-analyzer

# Webpack
npx webpack-bundle-analyzer stats.json

번들 크기를 시각화해서 어떤 라이브러리가 용량을 차지하는지 파악합니다.

캐싱 전략

HTTP 캐싱

# 정적 자산 (이미지, JS, CSS)
Cache-Control: public, max-age=31536000, immutable

# HTML
Cache-Control: no-cache

# API 응답
Cache-Control: private, max-age=0, must-revalidate

정적 자산은 장기 캐싱하고, 파일명에 해시를 포함해서 버전을 관리합니다.

서비스 워커

// 오프라인 지원 및 캐싱
self.addEventListener('fetch', (event) => {
  event.respondWith(
    caches.match(event.request).then((response) => {
      return response || fetch(event.request);
    })
  );
});

폰트 최적화

필요한 글자만 포함

@font-face {
  font-family: 'MyFont';
  src: url('font.woff2') format('woff2');
  unicode-range: U+AC00-D7AF; /* 한글만 */
}

폰트 로딩 전략

<link rel="preload" href="font.woff2" as="font" type="font/woff2" crossorigin />

<style>
  @font-face {
    font-family: 'MyFont';
    src: url('font.woff2') format('woff2');
    font-display: swap; /* 폰트 로딩 중 시스템 폰트 표시 */
  }
</style>

성능 측정 도구

Lighthouse

Chrome DevTools에 내장되어 있습니다. 성능, 접근성, SEO 등을 종합적으로 측정합니다.

WebPageTest

실제 네트워크 환경에서 테스트합니다. 여러 지역에서 테스트할 수 있어 유용합니다.

Chrome DevTools Performance 탭

JavaScript 실행 시간, 레이아웃, 페인트 등을 상세히 분석합니다.

마무리

성능 최적화는 한 번에 끝나는 작업이 아닙니다. 지속적으로 측정하고 개선해야 합니다.

가장 효과적인 전략은 이미지 최적화와 코드 스플리팅입니다. 이 두 가지만 제대로 해도 대부분의 사이트에서 큰 개선을 볼 수 있습니다.

성능 예산을 설정하고, CI/CD 파이프라인에서 자동으로 체크하는 것을 추천합니다.