웹 페이지가 느리면 우리도 답답하고, 방문자도 금방 떠나버리죠 😅
그래서 이번 글에서는 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가지
| Navigation (기본) | 페이지를 새로 로드하면서 전체 성능 측정 | 일반 웹 성능 최적화 연습용, 보통 이걸 씀 |
| Timespan | 일정 시간 동안 사용자의 상호작용(스크롤, 클릭 등)을 기록하고 성능 측정 | SPA, 유저 상호작용이 많은 페이지 테스트 시 유용 |
| Snapshot | 현재 화면 상태만 캡처해 측정 | 화면 일부만 측정하고 싶거나, 렌더링 지연 없는 정적 페이지 측정 |
🔹 연습용 권장
지금 저희가 하는 테스트용 코드는 Navigation 모드로 충분합니다.
- 버튼으로 느린/최적화 버전 전환 후 각각 Navigation 모드에서 측정하면 Before/After 비교 가능
1. Navigation 모드 측정
- DevTools → Lighthouse → Mode → Navigation 선택
- Performance, Accessibility, Best Practices, SEO 체크 (PWA는 선택)
- Analyze page load 클릭 → Lighthouse가 페이지를 새로 로드하면서 측정
- 완료되면 결과가 나타남
↓↓↓ 진행중인 상태

↓↓↓ 결과 사진

🔹 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 점수 이해
🔹 현재 테스트 결과 (예시)
| 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 말고 이미지를 최적화하는 다른 방법이 있는지 궁금해서 찾아보았다.
✅ 이미지 최적화 방법들
- next/image 사용
- 자동 리사이징, 포맷 변환(WebP 등), lazy loading 지원
- 가장 간단하고 권장되는 방식
- 이미지 포맷 변경
- JPG/PNG → WebP, AVIF
- 같은 화질 대비 용량을 크게 줄일 수 있음
- 이미지 크기 줄이기 (리사이즈)
- 화면에 600px만 필요한데 2000px 이미지를 쓰면 낭비
- 업로드 전 미리 줄여서 저장
- 이미지 압축하기
- CDN을 통한 최적화
- Cloudflare Images, Imgix, Akamai 같은 이미지 CDN 사용
- 지역별 캐싱 + 자동 포맷 변환 지원
- 스프라이트 이미지 / 아이콘 최적화
- 작은 아이콘 여러 개를 하나의 이미지에 넣고 CSS로 잘라 쓰는 방식 (예전 방식)
- 요즘은 주로 SVG 아이콘이나 아이콘 폰트를 사용
'개발 로그 > 사이드작업실' 카테고리의 다른 글
| [토스 오픈소스 기여 vol.0] 오픈소스 기여 가이드 (2) | 2025.09.15 |
|---|---|
| [사이드 작업실 Vol.2] Next.js 웹 성능 테스트: 코드 스플리팅 적용과 Lighthouse 측정하기 (3) | 2025.09.04 |