개발

Next.js 15 이미지 처리와 최적화

윤해용 2025. 5. 24. 16:35

 

크아허브 프로젝트 개발하면서 다양한 이미지 확장자를 처리하는 방법과 Next.js의 Image component 속성을 활용하여 최적화한 방법을 정리하였습니다.

 

다양한 이미지( PNG / GIF )를 처리

크아허브에서 유저가 장착한 아이템의 이미지는 대부분 PNG 파일로 제공하고 있다. 하지만 일부 신규 아이템은 아직 PNG 파일이 없어 GIF 파일을 임시로 사용하고 있다. 이러한 상황에 대응하기 위해 ReactuseState조건부 렌더링을 활용하여 이미지 형식을 구분하고 적절한 파일을 동적으로 표시하도록 처리하였다.

 

export function ItemImage({ itemName }: { itemName: string }) {
  const [imageType, setImageType] = useState<"png" | "gif" | "default">("png");

  const pngUrl = `${URI}${itemName}.png`;
  const gifUrl = `${URI}${itemName}.gif`;

  const size = imageType === "gif" ? 120 : 80;

  const getCurrentSrc = () => {
    switch (imageType) {
      case "png":
        return pngUrl;
      case "gif":
        return gifUrl;
      default:
        return DEFAULT_IMAGE;
    }
  };

  return (
    <Image
      src={getCurrentSrc()}
      alt={itemName || "아이템 이미지"}
      width={size}
      height={size}
      onError={() => {
        if (imageType === "png") {
          setImageType("gif");
        } else if (imageType === "gif") {
          setImageType("default");
        }
      }}
    />
  );
}

 

작동 원리

1. PNG 이미지가 많기 때문에 처음에는 PNG로 탐색을 시도한다.

2. 이미지 로드 실패 시 onError 함수가 실행한다.

3. setImageType로 PNG를 GIF로 상태를 업데이트 하면서 컴포넌트가 리렌더링한다.

4. GIF도 없을 경우 기본 이미지로 상태가 업데이트된다.

 

상태 변경에 따라 컴포넌트가 리렌더링되어 이미지 확장자 파일이 변경된다.

 

Image component 속성 활용

<Image
  src={getCurrentSrc()}
  alt={itemName || "아이템 이미지"}
  width={size}
  height={size}
  style={{ objectFit: "contain" }}
  unoptimized
  placeholder="blur"
  blurDataURL={BLUR_DATA_URL}
  onError={() => {
    // 오류 처리 로직
  }}
/>

 

width와 height

브라우저에게 미리 이미지 공간을 확보하여 로딩 중 레이아웃 시프트를 방지했다.

 

 

unoptimized

대부분의 이미지가 최적화의 이점이 없는 gif와 1KB 이하의 png 파일이다. 그리고 Cloudflare에서 CDN을 활용해 최적화된 이미지를 이미 제공하고 있었기 때문에 최적화 옵션을 사용하지 않았다.

 

 

placeholder와 blurDateURL 함께 사용

placeholder="blur"
blurDataURL={BLUR_DATA_URL}

blur 이미지


이 속성들을 이용해서 이미지가 로드 되는 동안 사용자에게 흐릿한 이미지(매우 작은 이미지)를 보여주어 네트워크 속도가 느린 환경에서의 사용자 경험을 개선하였다.

 

 

fill과 sizes 함께 사용

<div className={styles["logo-wrapper"]}>
  <Image src="/logo.png" alt="CAHUB" fill sizes="(min-width: 768px) 350px, 250px" priority />
</div>

 

fill 속성으로 부모 요소의 전체 공간을 채웠다. sizes 속성으로 브라우저에게 다양한 화면 크기에서 이미지가 어떻게 표시될 지 알려주어 반응형 브라우저에 최적화된 이미지를 제공해주었다.

 

 

 

 

참고 문서

 

Next.js15 공식문서 Image Component