sns 프로젝트

React 이미지 최적화를 통한 성능 개선하기

우주속공간 2024. 4. 26. 01:21

 

 

지난번 Lighthouse 분석 결과 LCP와 Speed Index가 높은 문제가 발생했다.

LCP(Largest Contentful Paint)는 페이지의 가장 큰 콘텐츠 요소가 화면에 표시되는 시간을 측정하는 지표로 이 값이 높으면 페이지의 주요 콘텐츠가 늦게 나타나는 것을 의미한다.

Speed Index는 페이지의 시각적인 로딩 속도를 측정하는 지표로, 값이 높을수록 페이지가 느리게 로드된다.

 

즉 이 문제들은 웹페이지가 느리게 로드되고 사용자 경험이 저하되는 주요 원인 중에 하나이므로 이를 해결하기 위해 여러가지를 시도해보았다.

 

일단 LCP 콘텐츠가 포함된 최대 페인트 요소를 보니 페이지의 배경화면을 불러올때 많은 시간이 소요되는 것을 확인했다. 

main페이지에서 배경화면을 지우고 로딩했을때 성능이 98점으로 상승했다. 

 

그래서 가장 먼저 이미지 최적화 방법에 대해 조사하여 적용해보았다. 

 

1.  이미지 크기 조정: 이미지 파일의 용량을 줄여서 다운로드 시간을 단축한다. 이를 위해서 이미지 압출 툴을 사용하거나 이미지 압축 서비스를 활용할 수 있다. 

2. 이미지 파일 형식 변경 : WebP와 같은 최신 이미지 형식을 사용하여 파일 크기를 줄인다. 이를 활용하여 로딩 속도를 향상시킬 수 있다. 

3. 이미지 압축 : 이미지 해상도를 줄이거나 필요한 크기로 조정하여 파일 크기를 최적화한다.  크기를 최적화하여 다운로드 시간을 단축하고 페이지 부담을 줄일 수 있다. 

 

위의 방법에 따라 이미지의 크기과 최대 너비를 지정하고 최신 이미지 형식WebP로 변경시켜 로딩시켜보았다. 

 

이미지 크기를 최적화하기 위해서 browser-image-compression 라이브러리를 사용했다. 이 라이브러리를 사용하여 배경이미지를 압축하고 최적화하여 로딩 속도가 줄어들 것이라고 예상했다 

 

 

만들기전에 이미지 최적화하는 코드를 여러곳에서 사용하게 될 것 같아서 분리시켰다.

 

다음은 browser-image-compression을 활용하여 작성한 이미지 최적화 함수(OptimizedImageUtils) 코드이다. 

이 함수는 두가지 인수를 받는데 첫 번째는 최적화할 원본 이미지의 URL인 originalImageUrl이고, 두 번째는 최적화된 이미지 URL을 상태로 설정하는 setStateFunc이다. 

import imageCompression from "browser-image-compression";

const OptimizedImageUtils = async (
  originalImageUrl: string,
  setStateFunc: React.Dispatch<React.SetStateAction<string>>
) => {
  try {
    const options = {
      maxSizeMB: 0.05, // 최대 이미지 크기를 더 낮은 값으로 설정
      maxWidthOrHeight: 300, // 이미지 최대 너비 또는 높이를 더 작은 값으로 설정
      useWebWorker: true, // 웹 워커 사용 여부 유지
    };

    // 이미지 Blob 가져오기
    const imageBlob = await fetch(originalImageUrl).then((res) => res.blob());

    // Blob을 File로 변환
    const imageFile = new File([imageBlob], "image.png", {
      type: "image/png",
    });

    // 이미지 최적화
    const compressedImage = await imageCompression(imageFile, options);
    // 최적화된 이미지 URL 설정
    const optimizedImageUrl = await imageCompression.getDataUrlFromFile(
      compressedImage
    );

    setStateFunc(optimizedImageUrl);
  } catch (error) {
    console.log(error);
  }
};

export default OptimizedImageUtils;

 

 

이미지 최적화 과정

  • options으로 이미지 최적화에 사용되는 옵션을 설정한다. 
  • fetch(originalImageUrl): 원본 이미지의 URL을 사용하여 이미지를 가져옵니다. fetch 함수를 사용하고, 이후에 .blob() 메서드를 호출하여 Blob 객체로 변환한다.
  • new File([imageBlob], "image.png", { type: "image/png" }): Blob 객체를 사용하여 File 객체를 생성합니다. imageCompression을 사용할때 file형식의 데이터를 넣어야되기때문에 blob객체에서 file객체로 변환시킨다. 
  • imageCompression(imageFile, options) : 앞서 정의한 옵션을 사용하여 이미지를 처리하고 최적화된 이미지를 반환한다. 
  • imageCompression.getDataUrlFromFile(compressedImage): 최적화된 이미지를 데이터 URL로 변환하여 웹 페이지에 표시할 수 있게 한다.
  • setStateFunc(optimizedImageUrl): 최적화된 이미지 URL을 React 상태로 설정하여 컴포넌트에서 사용할 수 있도록 한다.

 

WebP형식으로 변환하는 코드는 다음과 같다. 

    // WebP 형식으로 변환
    const webPBlob = await createImageBitmap(compressedImage).then(imageBitmap => {
      const canvas = document.createElement("canvas");
      canvas.width = imageBitmap.width;
      canvas.height = imageBitmap.height;
      const ctx = canvas.getContext("2d");
      ctx?.drawImage(imageBitmap, 0, 0);
      return new Promise(resolve => {
        canvas.toBlob(blob => {
          if (!blob) throw new Error("Failed to convert image to WebP format.");
          resolve(blob);
        }, "image/webp");
      });
    });

    // 최적화된 WebP 이미지 URL 설정
    const optimizedWebPUrl = URL.createObjectURL(webPBlob);

 

 

결과

이미지 최적화와 형식 변환 코드를 추가한 후 성능을 측정하니까 점수는 상승하였지만 페이지가 로딩되는 시간이 더 길어졌다. 렌더링 속도가 향상되었을진 몰라도 페이지에 콘텐츠가 나타나는 시간이 더 오래 걸렸다.

이미지 최적화 및 WebP형식으로의 변환하는 시간이 더 추가된 것이다. 따라서 결론적으로 사용자 입장에서는 처음 로딩하는 시간이 더 길어져서 더욱더 답답한 느낌이 들게 되었다. 

다음 수정에는 배경화면을 로딩하는 코드는 그대로 두고 로딩되기 전까지 사용자에게 콘텐츠를 먼저 보여주는 코드로 수정할 예정이다.