이미지 최적화 관련 이슈 기록하기

이효범·2023년 5월 2일
7

React

목록 보기
4/6
post-thumbnail

상세 기능

  • 이미지 관련 최적화 논의

설명

기존 ImageFallback 컴포넌트

  1. 페이지의 첫 화면 스크롤 내에 보여지는 아이템들의 이미지에 추가적인 priority 속성을 부여해서 Next.js에서 권장하는 이미지 사용방식을 차용했습니다.
  2. 기존의 brokenImage 조건을 좀 더 범위를 넓혔습니다.
  3. 페이지의 첫 화면 스크롤 내에 보여지는 아이템들의 이미지에 이미지 로딩을 하는 데 1.5s가 지나도 로딩이 완료되지 않을 시 defaultThumbanil로 src를 설정해주는 코드를 추가했습니다.
  4. 기존 next.config.jsunoptimized: true 설정이 되어있길래 의아해서 삭제했었는데, vercel 프리뷰때에만 설정을 하고 실제 프로덕션에는 unoptimized: true 설정을 해제하는 것으로 나중에 확인을 하였습니다.
import React, { useEffect, useState } from "react";
import NextImage from "next/image";

const DEFAULT_THUMBNAIL = "/default_thumbnail.svg";

export type ProductImageWithFallbackProps = {
  alt: string;
  thumbId: string | undefined;
  // 페이지의 첫 화면 스크롤 내에 보여지는 아이템들에게는 priority 속성을 부여 
  priority?: boolean;
  size?: "sm" | "md" | "lg" | "xs" | "thumb" | "raw";
} & Omit<React.ComponentProps<typeof NextImage>, "src" | "alt">;

export const ProductImageWithFallback = ({
  priority,
  thumbId,
  alt,
  size = "lg",
  ...rest
}: ProductImageWithFallbackProps) => {
  const [isSuccessLoaded, setIsSuccessLoaded] = useState(false);
  const [src, setSrc] = useState(
    thumbId ? `${process.env.NEXT_PUBLIC_CF_IMAGE_URL}/${thumbId}${size ? "?size=" + size : ""}` : DEFAULT_THUMBNAIL,
  );

  const setFallbackImageOnError = () => {
    if (!src.startsWith(process.env.NEXT_PUBLIC_IMAGE_URL as string) && thumbId) {
      setSrc(`${process.env.NEXT_PUBLIC_IMAGE_URL}/${thumbId}`);
      setIsSuccess(true);
    } else {
      setSrc(DEFAULT_THUMBNAIL);
    }
  };

  useEffect(() => {
    // 이미지 로딩을 하는 데 1.5s가 지나도 로딩이 완료되지 않을 시 defaultThumbanil로 src 설정해주는 코드
    const timer = setTimeout(() => {
      priority && !isSuccessLoaded && setSrc(DEFAULT_THUMBNAIL);
    }, 1500);

    return () => clearTimeout(timer);
  }, [priority, isSuccessLoaded]);

  return (
    <NextImage
      src={src}
      alt={alt}
      priority={priority}
      onError={setFallbackImageOnError}
      onLoadingComplete={(result) => {
      // 기존의 brokenImage 조건을 좀 더 범위를 넓혔습니다
        if (result.naturalWidth <= 30) {
          setSrc(DEFAULT_THUMBNAIL);
        } else {
          setIsSuccessLoaded(true);
        }
      }}
      {...rest}
    />
  );
};

빵 부스러기

  1. 현재 리스트 페이지에는 SSR 설정이 되어있는데요, Next.js의 Image 컴포넌트에 priority 속성을 부여하는 것이 SSR에서는 어떻게 동작하는 지 더 자세히 알아봐야겠지만, 이미지를 pre-loading 하는 것과 lazy-loading하는 것의 차이이고 ... 서버사이드렌더링해서 결국에 html 파일을 제공하면 브라우저에서 로딩할 때의 문제기 때문에 상관없지 않을까 싶습니다.
    또한 현재 적용한 코드는 유저가 페이지에 들어왔을 때 보여지는 영역의 아이템들에게만 priority 속성을 부여하고 있습니다.
  1. brokenImage 조건을 기존 result.naturalWidth === 0 에서
    result.naturalWidth <= 30 으로 좀 더 범위를 넓혔습니다.

    위와 같이 이미지가 깨지는 반복적으로 발생하는 이슈가 있어서 위와 같은 이미지의 사이즈를 확인해보며 범위를 넓혔습니다. 적용 후 위와 같은 이미지들은 표시되지 않고 defaultThumbanil로 보여집니다.
  2. 유저가 페이지에 들어왔을 때 보여지는 영역의 아이템들에게 이미지 로딩을 하는 데 1.5s가 지나도 로딩이 완료되지 않을 시 defaultThumbanilsrc를 설정해주는 코드를 추가했습니다.

    위와 같이 첫 화면에서 로딩이 너무 길어져 유저 경험에 불편함이 생기는 경우를 방지하는 것이 목표입니다.
    적용 결과 페이지 첫 화면에서 이미지가 느리게 로딩되는 부분 UX가 개선된 것을 확인할 수 있었습니다.
profile
I'm on Wave, I'm on the Vibe.

0개의 댓글