반응형

웹 페이지가 느리면 우리도 답답하고, 방문자도 금방 떠나버리죠 😅
그래서 이번 글에서는 Next.js로 웹 성능을 직접 실험해보려고 합니다.

 

저도 이제 막 시작하는 입장이라, 성능 최적화에서 가장 많이 언급되는 이미지 최적화부터 차근차근 시도해보려고 해요.
오늘은 그 첫걸음으로, 이미지 최적화 방식을 직접 테스트해보겠습니다!

 

측정할 주요 지표는 Google에서 중요하게 보는 Web Vitals예요:

  • LCP (Largest Contentful Paint): 페이지에서 가장 큰 콘텐츠가 나타나는 시간
  • FID (First Input Delay): 버튼이나 링크 클릭 등 첫 상호작용 반응 속도
  • CLS (Cumulative Layout Shift): 화면 레이아웃이 얼마나 안정적인지

이번 포스트에서는 느린 페이지와 최적화된 페이지를 만들어서 Lighthouse로 점수가 어떻게 바뀌는지 직접 확인해볼께요.

 

1. 실습 준비

  • Next.js 13 App Router 기준으로 /app/imgoptimizedtest 페이지 만들기
  • public 폴더 안에 테스트용 큰 이미지 준비 (public/img_optimized/react-logo.jpg)
  • 간단하게 리스트 데이터도 만들어둡니다

 

2. 느린 페이지 만들기

  • 리스트 3000개를 한 번에 렌더링
  • <img> 태그 그대로 사용 → 느려요 😅 이미 밑줄부터 쳐져있어요.

 

예시는 이렇게 생겼습니다:

<img src="/img_optimized/react-logo.jpg" alt="logo" width={2000} height={1500} />
<ul>
  {list.map((item, i) => (<li key={i}>{item}</li>))}
</ul>

 

이렇게 하면 LCP가 느리고, CLS가 높아져서 점수가 낮아집니다.
방문자가 체감하기에도 페이지가 늦게 뜨는 게 바로 느껴져요.

 

3. 최적화 페이지 만들기
<Image> 컴포넌트 사용 → 자동 이미지 최적화
리스트는 화면에 보이는 100개만 렌더링

코드는 이렇게 바꿔요:

<Image src="/img_optimized/react-logo.jpg" alt="logo" width={600} height={400} priority />
<ul>
  {list.slice(0, 100).map((item, i) => (<li key={i}>{item}</li>))}
</ul>

 

이제 LCP가 빨라지고, CLS가 안정적이에요.
느려서 답답했던 페이지가 한결 부드럽게 느껴질 겁니다 😎

 

 

이제 LightHouse 사용방법을 알려드릴께요!

기본적으로 Lighthouse는 크롬 DevTools에 기본 내장되어 있어서 별도 설치 없이 바로 쓸 수 있어요.

하지만 없으신 분들은 여기 들어가시면 확장프로그램 다운받을 수 있어요!

https://chromewebstore.google.com/detail/lighthouse/blipmdconlkpinefehnmjammfjpmpbjk?hl=ko

 

Lighthouse - Chrome 웹 스토어

Lighthouse is an open-source, automated tool for improving the performance, quality, and correctness of your web apps.

chromewebstore.google.com

 

 

그리고 상세 설명 페이지 필요하신분들을 위해 공식페이지 남겨드릴께요!
https://developer.chrome.com/docs/lighthouse/overview?hl=ko

 

Lighthouse 소개  |  Chrome for Developers

Lighthouse를 설정하여 웹 앱을 감사하는 방법을 알아보세요.

developer.chrome.com

 

 

설치하고 나면 이런 화면을 볼 수 있습니다.

 

Chrome DevTools Lighthouse에서 최신 버전 기준 모드
예전 Mobile/Desktop 대신 3가지 모드가 있습니다:


🔹 Lighthouse 모드 3가지

Mode의미추천

 

Navigation (기본) 페이지를 새로 로드하면서 전체 성능 측정 일반 웹 성능 최적화 연습용, 보통 이걸 씀
Timespan 일정 시간 동안 사용자의 상호작용(스크롤, 클릭 등)을 기록하고 성능 측정 SPA, 유저 상호작용이 많은 페이지 테스트 시 유용
Snapshot 현재 화면 상태만 캡처해 측정 화면 일부만 측정하고 싶거나, 렌더링 지연 없는 정적 페이지 측정

🔹 연습용 권장

지금 저희가 하는 테스트용 코드는 Navigation 모드로 충분합니다.

  • 버튼으로 느린/최적화 버전 전환 후 각각 Navigation 모드에서 측정하면 Before/After 비교 가능

 

1.  Navigation 모드 측정

  1. DevTools → Lighthouse → Mode → Navigation 선택
  2. Performance, Accessibility, Best Practices, SEO 체크 (PWA는 선택)
  3. Analyze page load 클릭 → Lighthouse가 페이지를 새로 로드하면서 측정
  4. 완료되면 결과가 나타남

↓↓↓ 진행중인 상태 

 

 

↓↓↓ 결과 사진 

 

🔹 Lighthouse 상단 4개 점수 - 동그라미의미설명

Performance (성능) 페이지 로딩 속도, 인터랙션 반응성 등 LCP, FID, CLS, TBT, Speed Index 등 다양한 Web Vitals 지표를 종합한 점수
Accessibility (접근성) 시각/청각/조작 편의성 스크린 리더, 색 대비, 폼 라벨 등 접근성 준수 여부
Best Practices (모범 사례) 최신 웹 표준 준수 HTTPS 사용, 이미지 포맷, JS 오류, 라이브러리 보안 등
SEO (검색 엔진 최적화) 검색 엔진 친화성 메타 태그, 링크 구조, 모바일 최적화, 구조화 데이터 등

🔹 Tip

  • Performance → 실제 사용자가 느끼는 속도와 직결
  • Accessibility → 장애가 있는 사용자 포함 모두에게 접근 가능한지
  • Best Practices → 보안, 안정성, 최신 브라우저 권장사항 준수
  • SEO → 검색 결과 노출 최적화

 

 

🔹 주요 Metric 설명 (Performance 기준)  Metric 의미 개선 방법 예시

LCP (Largest Contentful Paint) 페이지에서 가장 큰 콘텐츠가 화면에 나타나는 시간 큰 이미지 최적화, <Image> 사용, font-display 최적화
FID (First Input Delay) 사용자가 첫 상호작용(버튼, 링크 클릭)했을 때 반응 속도 JS 번들 최소화, 리스트 가상화, 이벤트 최적화
CLS (Cumulative Layout Shift) 페이지 로딩 중 레이아웃이 얼마나 움직이는지 이미지/iframe 크기 지정, 광고나 배너 고정
TBT (Total Blocking Time) 페이지 로딩 중 JS 실행으로 인터랙션이 막힌 시간 코드 스플리팅, heavy JS 최적화
Speed Index 화면이 얼마나 빨리 그려지는지 렌더링 블로킹 제거, Lazy Loading

🔹 요약

  • Metric = 측정 가능한 성능 지표
  • Lighthouse는 각 Metric을 계산해서 Performance 점수를 냄
  • 점수뿐 아니라 Metric 수치를 보면 어디를 최적화해야 하는지 구체적으로 확인 가능

 

 

그리고 제일 하단에는 Diagnostics 가 있는데 이 부분은 "페이지 성능과 관련된 추가 진단 정보"를 제공해줘요

  • 실제 점수에 직접적으로 반영되지는 않지만, 성능 개선에 참고할 수 있는 상세 정보 제공

 

 

🔹 주로 나오는 항목

JavaScript execution time JS 실행 시간 코드 스플리팅, 불필요한 라이브러리 제거
Image elements without explicit width and height 이미지 크기 미지정 <Image> 사용, width/height 지정 → CLS 개선
Unused CSS / JS 사용되지 않는 코드 불필요한 코드 제거, 트리 쉐이킹
Network requests 요청 개수와 크기 Lazy load, 번들 크기 줄이기, 캐싱 적용
Third-party scripts 외부 스크립트 영향 필요 없는 외부 스크립트 제거, async/defer 사용

2.  Performance 점수 이해

🔹 현재 테스트 결과 (예시)

Metric설명현재 테스트 수치해석
LCP (Largest Contentful Paint) 페이지에서 가장 큰 콘텐츠가 렌더링되는 시간 8.4 s 너무 느림 → 이미지 최적화, <Image> 사용 필요
FID (First Input Delay) 사용자가 처음 상호작용했을 때 반응 속도 0.9 s 반응 느림 → 리스트 가상화, JS 최적화 필요
CLS (Cumulative Layout Shift) 레이아웃이 예기치 않게 움직인 정도 0 안정적 → 문제 없음
Speed Index / TBT /
Time to Interactive
페이지가 얼마나 빨리 보이고 상호작용 가능한지 1.1 s 빠름 → 화면 렌더링 속도는 괜찮음

단순히 색깔만으로는 구분을 할 수 없어 gpt에게 분석 했더니 이렇게 나오더라구요

🔹 해석

  • LCP 8.4s → 사용자가 페이지에서 가장 큰 콘텐츠를 보는 데 8초 이상 걸림 → 체감 느림
  • FID 0.9s → 첫 클릭 반응 속도가 거의 1초 → 인터랙션 체감 느림
  • CLS 0 → 레이아웃 이동 없음 → 안정적
  • Speed Index 1.1s → 화면 렌더링은 빠르게 이루어짐

이미지 테스트예제에서:

  • 느린 버전: LCP 느림, CLS 높음, FID 낮음
  • 최적화 버전: LCP 빨라지고, CLS 안정, FID 개선

 

 

그럼 여기서 또 궁금증이 생겼는데요!


저게 빠른 건지, 느린 건지 어떻게 판단하는 걸까요?
Lighthouse에서는 Web Vitals 기준에 따라 구간을 나눠서 알려줘요.

 

🔹 Web Vitals 기준 (Performance Metrics)    Metric좋음(Good)개선 필요(Needs Improvement)느림(Poor)설명

LCP ≤ 2.5 s 2.5 ~ 4 s > 4 s 페이지에서 가장 큰 콘텐츠가 화면에 표시되는 시간
FID ≤ 100 ms 100 ~ 300 ms > 300 ms 사용자가 클릭/탭 등 첫 상호작용을 했을 때 반응 속도
CLS ≤ 0.1 0.1 ~ 0.25 > 0.25 레이아웃 이동 정도
TBT ≤ 300 ms 300 ~ 600 ms > 600 ms 렌더링 차단된 총 JS 실행 시간
Speed Index ≤ 3.4 s 3.4 ~ 5.8 s > 5.8 s 화면이 얼마나 빨리 그려지는지

🔹 해석 예시

  • LCP 8.4 s → Poor(느림)
  • FID 0.9 s → 900 ms → Poor
  • CLS 0 → Good
  • Speed Index 1.1 s → Good

Lighthouse 점수는 이 구간 기준으로 색(녹/노랑/빨강) 표시합니다.
Green ✅ → Good
Yellow ⚠️ → Needs Improvement
Red ❌ → Poor


3.  실습 팁

  • 버튼으로 느린 ↔ 최적화 버전 전환 → Navigation 모드로 각각 측정
  • 점수 비교: Before/After 체감
  • 각 항목 클릭하면 상세 분석 + 개선 방법 확인 가능

💡 요약

  • Navigation 모드 → 전체 페이지 로드 성능 측정
  • LCP, FID, CLS 위주로 개선 포인트 확인
  • 이미지 테스트서 <Image>와 리스트 일부 렌더링 적용 후 성능 향상 확인

 

 

최적화한 페이지의 lighthouse 측정 결과

 

여기서

🚨 Lighthouse 실행 시 화면이 이전 상태로 바뀌는 문제를 경험했는데

  • 버튼을 클릭해서 이미지 최적화 전 / 후 화면을 토글할 수 있도록 구현했다.
  • 로컬에서 직접 테스트할 때는 정상 동작.
  • 그런데 Lighthouse Navigation Mode로 분석을 실행하면,
    • 최적화 후 화면이 아닌
    • 다시 최적화 전 화면으로 돌아가 버리는 현상이 발생했다.

📝 원인을 찾아보니,

  • Lighthouse는 기본적으로 페이지 최초 로딩 상태를 기준으로 측정한다.
  • 즉, **유저 인터랙션(버튼 클릭 등)**으로 변경된 UI는 반영되지 않는다.
  • Navigation Mode는 새로고침 후 초기 진입 상태에서 분석하기 때문에
    → 버튼으로 토글한 후 화면은 무시된다.

 

🔍 해결 방법

  • Navigation Mode 대신 Timespan Mode 사용
    • Timespan Mode는 내가 직접 버튼 클릭 같은 동작을 한 뒤 "Record"를 눌러서 측정 가능하다.
  • 또는 URL Parameter / QueryString으로 상태 반영
    • 예: /imgoptimizedtest?mode=optimized
    • 페이지가 로드될 때 이미 최적화 후 화면으로 뜨게 하면 Lighthouse가 그 상태를 기준으로 분석 가능하다.
  • 정리하면, Navigation Mode는 항상 초기 상태만 본다는 특징을 이해하고 목적에 맞는 모드로 측정해야 한다.

 

 

그렇다면 이제부터 이미지를 넣어야한다면 next/image를 써야할 것같은데 어떤 기능이 있는지 알아보자!

 

📌 next/image 주요 기능

1. 자동 최적화 (Image Optimization)

  • 원본 이미지를 그대로 쓰지 않고, 브라우저/디바이스 크기에 맞게 리사이즈 & 압축해서 전달해 줍니다.
  • 예: PC에서는 큰 이미지, 모바일에서는 작은 이미지 → 트래픽 절약 & 로딩 속도 향상

2. Lazy Loading (지연 로딩)

  • 화면에 보이는 순간에만 이미지를 불러옵니다.
  • <img>는 기본적으로 다 불러오는데, next/image는 자동으로 loading="lazy" 적용됨.
  • "lazy" → 화면에 보여야 할 때 불러옴 (기본값)
  • "eager" → 무조건 즉시 불러옴 (LCP 요소 같은 중요한 이미지에 쓰기 좋음)
  • priority -> 가장 중요한 이미지를 가장 먼저 로드하게 만듦. 보통 메인 비주얼 배너, LCP 대상 이미지에 사용.
  • 중요한 LCP 대상 이미지는 priority + loading="eager" 이렇게 쓰시면 성능 점수 최적화에 딱 좋다고 함.
<Image
  src="/img_optimized/big-image.jpg"
  alt="big"
  width={1200}
  height={800}
  loading="lazy"   // 👈 여기
  priority
/>

3. Responsive Image (반응형 사이즈)

  • 뷰포트 크기에 따라 적절한 해상도의 이미지를 자동으로 불러옵니다.
  • sizes 속성을 활용하면, 모바일/데스크탑 각각 최적화된 이미지 제공 가능.
<Image 
  src="/example.jpg" 
  alt="test" 
  width={1200} 
  height={800} 
  sizes="(max-width: 768px) 100vw, 50vw" 
/>

➡️ 모바일에서는 작은 이미지, 큰 화면에서는 큰 이미지 자동 제공.


4. Placeholder 기능

  • 이미지 로드 전 블러 처리된 미리보기(blur-up)를 보여줄 수 있습니다.
  • 사용자 입장에서는 깜빡임 없이 자연스럽게 로딩되는 느낌.
<Image 
  src="/big-image.jpg" 
  alt="big" 
  width={1200} 
  height={800} 
  placeholder="blur" 
  blurDataURL="data:image/png;base64,..." 
/>

 


5. CDN / 캐싱 활용

  • Next.js 서버나 Vercel 배포 시, 이미지가 자동으로 캐싱되고 CDN 통해 빠르게 제공됩니다.

6. 성능 점수(LCP, CLS) 개선

  • LCP: 큰 이미지가 최적화된 상태로 빨리 렌더링됨 → 점수 올라감
  • CLS: width/height가 반드시 필요해서 레이아웃 밀림(Layout Shift) 방지

📊 정리하면 next/image는

  • 이미지 용량 ↓
  • 불필요한 요청 ↓
  • 로딩 속도 ↑
  • SEO 및 Core Web Vitals 점수 ↑

 

따라서 실제 프로젝트에서도 적용 가능한 부분이 있다면 수정해보는 것도 좋을 것같습니다.

 

사실 성능 최적화라는 말 자체가 되게 어렵게 느껴지잖아요.
뭔가 거창한 걸 해야 할 것 같고, 성능 지표도 숫자로만 보이면 부담스럽고요.
근데 이렇게 작은 부분부터 하나씩 실험해보니까, 생각보다 바로 효과가 보이더라고요.

 


특히 이미지 최적화처럼 당장 적용 가능한 것들은 체감 차이가 꽤 크다는 걸 알 수 있었어요.
한 번에 모든 걸 다 고치려고 하면 당연히 힘들겠지만, 작은 실험을 쌓아가면 분명히 서비스에 도움이 될 거예요.

 


저도 이번 테스트를 계기로 실제 프로젝트에 조금씩 적용해보려고 합니다.
👉 성능 최적화, 어렵게만 생각하지 말고 작은 실험부터 점진적으로 시작해보면 어떨까요?

 

 

 

 

ps. next/image 말고 이미지를 최적화하는 다른 방법이 있는지 궁금해서 찾아보았다.

 

✅ 이미지 최적화 방법들

  1. next/image 사용
    • 자동 리사이징, 포맷 변환(WebP 등), lazy loading 지원
    • 가장 간단하고 권장되는 방식
  2. 이미지 포맷 변경
    • JPG/PNG → WebP, AVIF
    • 같은 화질 대비 용량을 크게 줄일 수 있음
  3. 이미지 크기 줄이기 (리사이즈)
    • 화면에 600px만 필요한데 2000px 이미지를 쓰면 낭비
    • 업로드 전 미리 줄여서 저장
  4. 이미지 압축하기
    • TinyPNG, Squoosh 같은 툴 사용
    • 화질은 거의 유지하면서 용량만 줄여줌
  5. CDN을 통한 최적화
    • Cloudflare Images, Imgix, Akamai 같은 이미지 CDN 사용
    • 지역별 캐싱 + 자동 포맷 변환 지원
  6. 스프라이트 이미지 / 아이콘 최적화
    • 작은 아이콘 여러 개를 하나의 이미지에 넣고 CSS로 잘라 쓰는 방식 (예전 방식)
    • 요즘은 주로 SVG 아이콘이나 아이콘 폰트를 사용
반응형

+ Recent posts