Sentry - Assets

하니·2025년 2월 22일

React 길잡이

목록 보기
14/21
post-thumbnail

최적화 우선순위를 Average Duration으로 잡았다. Average Duration이 높은 파일순으로 정렬하여 진행하였다.

이미지 최적화

📺 Sentry-Assets 첫페이지

📺 Next.js의 이미지 assets에 대한 상세 분석 화면

현재 상황

  • 동일한 이미지(background.png)가 같은 크기로 여러 번 요청되고 있다.
  • 평균 응답 시간이 매우 높다. (197-311ms)
  • 이미지 크기가 매우 크다. (모두 1.1 MiB)

살펴본 결과

이미지 사용 위치 검토
Next.js의 Image 컴포넌트 캐싱 설정 확인
이미지 요청이 발생하는 컴포넌트의 렌더링 패턴 검토

1. 이미지 사용 위치 검토

📁 frontend/src/components/layouts/main-layout.tsx

  • before
        <Image
          src="/background.png"
          alt="배경"
          fill
          priority
          className="object-cover"
        />
  • after
        <Image
          src="/background.png"
          alt="배경"
          fill
          priority
          quality={60} // 품질 명시
          sizes="100vw"
          // size 없을 시, 모든 viewport 크기에 대해 최적화된 이미지를 생성하여, 불필요한 여러 크기의 이미지가 생성
          // -> 이 이미지는 항상 viewport 전체 너비를 사용할 거라는 것을 명확히 알려주어, 불필요한 크기 변형 만들지 X
          className="object-cover"
          placeholder="blur" // 로딩 중 블러 효과
          blurDataURL="데이터URL" // 작은 블러 이미지
        />

2. Next.js의 Image 컴포넌트 캐싱 설정 확인

  • after : 이미지 관련 설정 추가 (이미지 최적화와 캐싱)

📁 frontend/next.config.ts

deviceSizes :
화면 전체 너비를 차지하는 큰 이미지용 (예: 배경, 히어로 이미지)
width가 아닌 fill prop을 사용하거나 sizes 속성이 있는 이미지에 적용
귀하의 케이스: background.png가 여기에 해당
imageSizes :
UI 요소로 들어가는 작은 이미지용 (예: 아이콘, 썸네일, 프로필 사진)
명시적인 width prop을 사용하는 이미지에 적용
보통 작은 크기부터 시작

  images: {
    // 이미지의 실제 크기와 가장 가까운 크기를 선택
    deviceSizes: [640, 750, 828, 1080, 1200, 1920], // 화면 전체 너비를 차지하는 큰 이미지용
    imageSizes: [16, 32, 48, 64, 96, 128, 256], // UI 요소로 들어가는 작은 이미지용 (예: 아이콘, 썸네일, 프로필 사진)
    minimumCacheTTL: 60 * 60 * 24, // 24시간 캐싱
    formats: ["image/webp"], // WebP 포맷 사용
  },

3. 이미지 요청이 발생하는 컴포넌트의 렌더링 패턴 검토

background 이미지가 로그인 페이지와 모든 메인 페이지에서 사용이 되고 있는데, 로그인 페이지의 background에 opacity만 달라서 auth-layout.tsx와 main-layout.tsx에서 각각 <Image/>를 부르고 있었다. 그래서 동일한 이미지임에도 불구하고 계속 렌더링 되었다.

  • before
app/
├── layout.tsx (RootLayout)
├── (auth)/
│   └── layout.tsx (AuthLayout) - 배경 이미지 포함
└── (main)/
    └── layout.tsx (MainLayout) - 배경 이미지 포함
  • after
app/
├── layout.tsx (RootLayout) - 배경 이미지
├── (auth)/
│   └── layout.tsx (AuthLayout) - 로그인 페이지용
└── (main)/
    └── layout.tsx (MainLayout) - 로그인 후 페이지용

📁 frontend/src/components/layouts/auth-layout.tsx

  • main-layout.tsx에서도 부분 제거해주면된다.
"use client";
import Image from "next/image";
import { usePathname } from "next/navigation";
export function AuthLayout({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();
  const path = pathname.split("/").pop();
  const title = path === "login" ? "Sign In" : "Password";
  return (
    <div className="flex h-screen ">
      <div className="fixed inset-0 -z-10 bg-white opacity-80" /> // ✅ 이미지를 여기서 부르지 않고 이걸로 로그인 페이지의 opacity만 적용
      // ❌ 이미지 코드 부분 제거
      {/* <div className="fixed inset-0 -z-10 opacity-10">
        <Image
          src="/background.png"
          alt="배경"
          fill
          priority
          className="object-cover"
        />
      </div> */}
      <section className="w-full max-w-[1280px] mx-auto px-8 pt-16 pb-40">
        <div className="h-full ">
          <header className="flex justify-between items-center py-5">
            <h1 className="text-bold-xxl">{title}</h1>
            <div className="flex items-center text-md-sm">
              <span className="text-gray">mywarehome</span>
              <span className="text-primary02 mx-1">/</span>
              <span className="text-primary02">{path}</span>
            </div>
          </header>
          <main className="flex-1 h-full bg-white shadow-custom-table rounded-lg">
            {children}
          </main>
        </div>
      </section>
    </div>
  );
}
profile
Hi, I am HANI Developer(╹◡╹). .....1hani me?

0개의 댓글