[1편] JPEG → WebP 전환 후 성능은 어떻게 달라졌을까?

고예진·2025년 7월 1일

프론트엔드

목록 보기
3/4
post-thumbnail

최근에 진행한 같이가요 서비스는 호스트가 원하는 이벤트를 주최하고 여러 참가자들의 신청 받으며 관리 할 수 있는 서비스이다.

그 중 내 티켓 페이지는 사용자가 이벤트 참여를 위해 구매한 티켓들을 카드 형태로 보여주는 페이지이다. 한 티켓 당 호스트가 주최한 이벤트 배너 이미지를 보여주고 있다.

아래 페이지 접근 시, 티켓 목록 이미지가 늦게 로딩되며 첫 화면이 완전히 보이기까지 지연이 발생한다. 한 유저가 여러 티켓을 구매할 수록 구입한 티켓 정보가 많아지게 되는데, 이때 각 이미지 용량이 크면 이미지 로딩 속도가 느려지는 문제가 발생한다.

이로 인해 사용자 체감 성능 저하로 성능 개선이 필요하다고 생각했다.

성능 측정을 통해 어떤 부분을 최적화해야 하는지 판단할 수 있다.

크롬 브라우저에서 제공하는 웹 개발에 도움되는 다양한 툴이 있다.

  1. Network 패널: 현재 웹 페이지에서 발생하는 모든 네트워크 트래픽을 상세하게 볼 수 있다.
  2. Performance 패널: 웹 페이지가 로드될 때 실행되는 모든 작업을 볼 수 있다.
  3. Lighthouse 패널: 구글에서 만든 툴로, 웹 사이트의 성능을 측정하고 개선 방향을 제시해 주는 자동화 툴

→ 이 중에서 Lighthouse를 통해 성능 측정을 한 뒤 개선해보려고 한다.


Lighthouse란?

Lighthouse는 측정한 웹 페이지에서 다섯 가지 지표에 가중치를 적용해 평균값을 계산한 종합 성능 점수이다.

이러한 지표를 웹 바이탈(Web Vitals)이라고 부른다.

  • First Contentful Paint(FCP)
    페이지가 로드될 때 브라우저가 DOM 콘텐츠의 첫 번째 부분을 렌더링하는 데 걸리는 시간
  • Largest Contentful Paint(LCP)
    페이지가 로드될 때 화면 내에 있는 가장 큰 이미지나 텍스트 요소가 렌더링되기까지 걸리는 시간
  • Speed Index(SI)
    페이지 로드 중에 콘텐츠가 시각적으로 표시되는 속도를 나타내는 지표
  • Total Blocking Time(TBT)
    페이지가 클릭, 키보드 입력 등의 사용자 입력에 응답하지 않도록 차단된 시간을 종합한 지표
  • Cummulative Layout Shift(CLS)
    페이지 로드 과정에서 발생하는 예기치 못한 레이아웃 이동을 측정한 지표

Lighthouse를 통한 성능 측정

  • Performance: 56점
  • 주요 성능 지표
    • FCP (First Contentful Paint): 4.9초
    • LCP (Largest Contentful Paint): 6.4초
    • Speed Index: 7.9초

문제 원인 분석

Lighthouse의 진단 결과를 보면 가장 큰 문제는 “이미지”에 있었다.

브라우저가 가장 먼저 보여주려는 주요 콘텐츠(이미지)가 너무 크고, 너무 늦게, 너무 많은 자원과 함께 로딩되고 있었다는 결과를 볼 수 있다.

이벤트 배너 이미지가 성능에 얼마나 영향을 미치는지 알아보기 위해서는 LCP 수치를 확인하면 알 수 있다. 하나의 이미지를 불러오는데 무려 6110ms 시간이 소요되고 있었다.

하지만 Lighthouse가 절대적인 성능 측정의 지표는 아니기 때문에 좀 더 확실하게 성능 개선을 확인하기 위해 네트워크 탭도 확인해봤다.

네트워크 탭을 확인해보니 이미지 용량이 787kB이고, 해당 이미지를 불러오는데 드는 시간은 662ms로, 다른 요소들에 비해 너무 많은 시간이 소요되는 것을 확인할 수 있었다.

[최적화 전 LCP(6110ms)]

[최적화 전 .jpeg 이미지 용량(787kB)]

그래서 어떤 방법으로 성능을 개선할 수 있을지 고민해보았다.

이미지 최적화와 관련된 내용들을 찾아보던 중 구글에서 만든 WebP라는 이미지 포맷이 최적화에 많이 사용된다는 것을 알았다.


WebP란?

구글에서 만든 웹에 최적화된 이미지 포맷이다.

WebP는 이미지 손상을 최소화하면서 png 또는 jpg와 비교했을 때 평균 40% 감소한 크기로 이미지를 압축할 수 있다. 현재 유저가 이미지를 업로드할때 png, jpg, jpeg 파일만 업로드 하도록 설정했는데 이를 webP로 바꾼다면 이미지를 불러올 때 시간이 훨씬 줄어들 수 있겠다고 생각했다.

유저가 이벤트 배너 이미지를 업로드하는 과정에서 이미지 형식을 webP로 바꿔서 업로드 되도록 하는 convertImageToWebP을 구현했다.

const convertImageToWebP = (file: File): Promise<File> => {
  return new Promise((resolve, reject) => {
    const img = new Image();
    const reader = new FileReader();

    reader.onload = () => {
      if (typeof reader.result === 'string') {
        img.src = reader.result;
      }
    };

    img.onload = () => {
      const canvas = document.createElement('canvas');
      canvas.width = img.width;
      canvas.height = img.height;

      const ctx = canvas.getContext('2d');
      if (!ctx) return reject(new Error('Canvas context error'));

      ctx.drawImage(img, 0, 0);

      canvas.toBlob(blob => {
        if (!blob) return reject(new Error('WebP 변환 실패'));
        const webpFile = new File([blob], file.name.replace(/\.\w+$/, '.webp'), { type: 'image/webp' });
        resolve(webpFile);
      }, 'image/webp');
    };

    img.onerror = reject;
    reader.onerror = reject;

    reader.readAsDataURL(file);
  });
};

1. 유저가 업로드한 이미지 읽기

유저가 올린 이미지를 FileReader를 이용해 브라우저가 이해할 수 있는 형태인 데이터 URL로 변환한다. 이 URL은 Image 객체에 넣어 브라우저에서 표시할 수 있도록 준비하는 과정이다.

2. 이미지를 캔버스에 그리기

이미지가 로드되면 브라우저의 <canvas>요소를 생성하고, 그 안에 이미지를 그대로 그린다. 이 과정은 이미지를 가공하거나 포맷을 바꾸기 위해 그림판처럼 복사해놓는 역할을 한다,

3. 캔버스에 복사된 이미지를 WebP로 변환

캔버스에 그려진 이미지를 toBlob() 메서드를 사용해 WebP 포맷이 변환된다.

사진을 직접 첨부한 후 콘솔에서 업로드할 URL을 확인해보면 .webp 포맷이 변환된 것을 확인 할 수 있다!

업로드할 URL: https://gotogetherbucket.s3.~~~.webp

성능 개선 후, LCP와 네트워크 탭을 확인해보니 확실히 성능 개선된 것을 확인할 수 있었다.

  • Performance 56점 → 75점 증가 (19점 증가)
  • LCP 6110ms → 5070ms 감소 (17% 감소)
  • 이미지 용량 787kB→ 84.4kB 감소 (89% 감소)
  • 네트워크 탭의 타임(이미지를 불러오는 시간) 662ms → 112ms 감소 (83% 감소)

다음 포스팅에서는 WebP 최적화가 실제로 어떻게 성능에 영향을 주는지, 기술적인 지표와 개념을 중심으로 더 깊이 있게 살펴볼 예정이다.

0개의 댓글