[React] public 이미지에서 import 구조로 (이미지 최적화 개선기)

2025. 12. 27. 19:27·💻 개발/🦕 React
728x90
반응형

| 인트로

안녕하세요, 팡일입니다.

 

프론트엔드 프로젝트에서 이미지를 사용하는 방식은 여러 가지가 있는데, 이번 프로젝트에서는 public 폴더에 이미지를 위치시키고 경로 문자열로 참조하는 방식을 사용하고 있었습니다.

 

기능 구현에는 문제가 없었지만, 실제 서비스 관점에서 바라보았을 때 이미지 로딩 속도와 초기 렌더링 성능에 대한 개선이 필요하다는 판단이 들었고, 이를 계기로 이미지 처리 방식을 다시 점검하게 되었습니다.

 

그래서 이번 글에서는 단순히 “이미지 용량을 줄였다”는 수준을 넘어, 이미지를 다루는 구조 자체를 개선하기 위해 public 이미지 구조에서 import 기반 구조로 전환한 과정과 그에 따른 정량적인 성능 개선 결과를 함께 정리해보려고 합니다.

 

 

 

 

| 문제 인식: 이미지가 느린 것 같았지만, 진짜 원인은 달랐다

기존 구조에서는 이미지들을 public 폴더에 두고, 문자열 경로로 직접 사용하고 있었습니다.

export const slideImages = [
  "/Img/worship/worship3.jpg",
  "/Img/worship/worship5.jpg",
  "/Img/worship/worship6.jpg",
];

 

이 방식은 구현 자체는 간단하지만, 성능 관점에서는 몇 가지 한계를 가지고 있습니다.

  • Webpack이 이미지를 정적 자원으로 인식하지 못함
  • 빌드 과정에서 이미지 최적화·해시 처리·캐싱 전략에 포함되지 않음
  • 이미지 요청 시점이 렌더링 이후로 밀릴 가능성이 큼

 

실제로 Chrome DevTools의 Network 탭을 확인해 보니, 일부 이미지는 파일 크기에 비해 요청 시점이 늦게 잡히는 현상이 관찰되었습니다.

 

 

 

| Before: public 경로 기반 이미지 로딩

먼저, Chrome 브라우저에서 Network 탭을  통해 살펴본 기존 방식은 다음과 같은 특징이 있었습니다.

  • 이미지 파일명: EssenceLogo.png, worship3.jpg 등 원본 파일명 그대로
  • 일부 이미지는 요청 자체가 늦게 발생
  • 이미지 요청 타이밍이 React 렌더링 흐름에 종속된 상태
  • Webpack 관점에서는 “관리되지 않는 리소스”

 

즉, 이미지 자체가 무겁다기보다는 이미지가 언제 로딩되는지를 제어할 수 없는 구조였습니다.

 

 

 

 

| 개선 방향: 이미지를 “자원”으로 만들자

개선의 핵심은 단순합니다.

 

"이미지를 문자열이 아닌 import 대상으로 만들자"

 

이를 위해 다음과 같이 구조를 변경했습니다.

 

 

1️⃣ 이미지 위치 변경

src/assets/images/worship/
 ├─ worship3.jpg
 ├─ worship5.jpg
 └─ worship6.jpg

 

2️⃣ 이미지 import 구조로 전환

import worship3 from "../../../assets/images/worship/worship3.jpg";
import worship5 from "../../../assets/images/worship/worship5.jpg";
import worship6 from "../../../assets/images/worship/worship6.jpg";

export const slideImages = [worship3, worship5, worship6];

 

컴포넌트에서는 기존 코드 거의 그대로 사용이 가능했습니다.

<IntroImage src={slideImages[currentImageIndex]} alt="Intro Image" />

 

이렇게 함으로써, 사용부는 깔끔하게 유지하면서, 이미지 관리 책임을 번들러(Webpack)로 넘기는 구조가 되었습니다.

 

 

 

| After: import 기반 이미지 로딩

개선 후 Chrome 브라우저의 Network 탭을 통해 살펴 본 특징들은 다음과 같습니다.

  • 이미지 파일명에 해시(hash) 가 붙은 형태로 변경
    (worship3.63c9e7a165c7afb7fa6f.jpg 등)
  • 이미지 요청 시점이 페이지 초기 로딩 구간으로 당겨짐
  • 전체 로딩 완료 시간 및 DOMContentLoaded 시점 감소
  • 캐시 친화적인 구조로 전환

 

특히 눈에 띄는 변화는 “늦게 요청되던 이미지가 사라졌다는 점”이었습니다.

 

이미지 용량은 거의 동일하지만, 요청 시점과 로딩 흐름이 개선되면서 체감 성능이 함께 좋아졌습니다.

 

 

 

| 정량적으로 살펴보는 변화 (배포 환경 기준)

이번 측정은 로컬 개발 환경(npm run start)이 아닌, Netlify에 실제 배포된 프로덕션 환경에서 진행되었습니다.

 

따라서 CDN, 네트워크 지연, 캐싱 전략까지 모두 포함된 실사용자 관점의 수치라고 볼 수 있습니다.

 

 

1) 측정 기준

: 먼저 측정 기준은 다음과 같습니다.

  • 측정 도구
    • Chrome DevTools → Network → Img
  • 기준 컬럼
    • 시간(Time)
  • 측정 조건
    • Netlify 배포 URL 접속
    • 새로고침 후 최초 로딩 기준
    • 동일한 페이지에서 5회 반복 측정
  • 비교 대상 이미지
    • EssenceLogoRed.png
    • EssenceLogo.png
    • worship3.jpg (약 1.26MB, 가장 큰 이미지)

 

 

2) 개선 전 (public 경로 직접 참조 · 배포 환경)

: public 폴더에 위치한 이미지를 문자열 경로로 직접 참조하던 시점의 결과입니다.

  • 이미지별 로딩 시간 (5회 측정)

 

이미지 평균 용량 평균 로딩 시간
EssenceLogoRed.png 66.8 KB 약 420 ms
EssenceLogo.png 53.8 KB 약 400 ms
worship3.jpg 1.26 MB 약 1,690 ms
  • 특징
    • 파일명에 해시가 없어 캐시 무효화 전략이 비효율적
    • Webpack 빌드 최적화 대상에서 제외
    • CDN 캐싱 히트율이 낮아 첫 로딩 시 편차가 매우 큼
    • 실제 측정 중 최대 4~5초까지 지연되는 케이스 발생

 

 

3) 개선 후 (import 기반 이미지 관리 · 배포 환경)

: 이미지를 src/assets 하위로 이동한 뒤, JavaScript 파일에서 import하여 사용하는 구조로 변경한 이후의 결과입니다.

  • 이미지별 로딩 시간 (5회 측정)
이미지 평균 용량 평균 로딩 시간
EssenceLogoRed.[hash].png 66.8 KB 약 260 ms
EssenceLogo.[hash].png 53.8 KB 약 290 ms
worship3.[hash].jpg 1.26 MB 약 808 ms
  • 특징
    • 파일명에 content hash 자동 적용
    • Webpack 빌드 파이프라인에 포함
    • CDN 캐싱 효율 증가
    • 로딩 시간이 1초 이내로 안정화

 

 

4) 정량적 성능 개선 요약

: 배포 환경 기준으로 두 방식을 비교하면 다음과 같습니다.

이미지 개선 전 개선 후 감소량 개선율
EssenceLogoRed.png 약 420 ms 약 260 ms 160 ms ↓ 약 38%
EssenceLogo.png 약 400 ms 약 290 ms 110 ms ↓ 약 27%
worship3.jpg 약 1,690 ms 약 808 ms 882 ms ↓ 약 52% 개선

 

5) 이 수치가 의미하는 바

 

  • 초기 렌더링 단계에서 이미지가 차지하는 네트워크 대기 시간이 절반 이상 감소
  • 모든 페이지에서 공통으로 사용되는 로고 이미지의 경우
    → 누적 체감 성능에 직접적인 개선 효과
  • 대용량 이미지(worship3.jpg)는
    동일한 파일 크기임에도 불구하고 전송·캐싱 구조 개선만으로 1초 가까운 시간 단축

 

즉, 이미지 용량을 줄이지 않았음에도, import 기반 구조로 전환한 것만으로 배포 환경에서 네트워크 레벨의 명확한 성능 개선이 확인된 상태라고 볼 수 있습니다.

 

 

 

 

| 왜 이런 차이가 발생했을까?

마지막으로, 이러한 차이가 발생하게 된 부분을 정리하면 핵심은 다음 세 가지입니다.

  1. Webpack 최적화 파이프라인 적용
    • 이미지도 빌드 결과물로 관리
  2. 해시 기반 파일명으로 캐싱 효율 극대화
    • 동일 리소스 재요청 방지
  3. 불필요한 네트워크 병목 감소
    • 브라우저가 더 빠르게 리소스를 확정 가능

 

 

 

 

| 마무리

이번 개선은 단순한 코드 스타일 변경이 아니라, 측정 → 구조 개선 → 재측정 그리고 정량적 수치로 개선 효과를 증명했다는 점에서 의미가 있다고 생각합니다.

 

다음 단계에서는 이미지 포맷(WebP), lazy loading, 혹은 LCP 이미지 우선 로딩 전략까지 확장해볼 수 있을 것 같습니다.

 

프론트엔드 성능 최적화는 결국 “얼마나 빨라졌는지를 숫자로 말할 수 있는가” 에서 완성된다고 생각합니다.

 

728x90
반응형

'💻 개발 > 🦕 React' 카테고리의 다른 글

[React] TanStack Query(React Query) 깊게 파고들기 : useQuery와 캐시 생명주기의 모든 것  (0) 2026.01.15
[React] 코드 스플리팅을 적용했을 뿐인데, 초기 로딩이 줄어들었습니다  (0) 2025.12.27
[React] target="_blank" ESLint 경고의 의미와 해결 방법 (react/jsx-no-target-blank)  (0) 2025.12.27
[React] React에서 한글 입력(IME) 깨짐 문제 해결하기  (1) 2025.08.28
[React] React 프로젝트에 Vercel + GitHub Actions로 CI/CD 구축하기  (1) 2025.08.01
'💻 개발/🦕 React' 카테고리의 다른 글
  • [React] TanStack Query(React Query) 깊게 파고들기 : useQuery와 캐시 생명주기의 모든 것
  • [React] 코드 스플리팅을 적용했을 뿐인데, 초기 로딩이 줄어들었습니다
  • [React] target="_blank" ESLint 경고의 의미와 해결 방법 (react/jsx-no-target-blank)
  • [React] React에서 한글 입력(IME) 깨짐 문제 해결하기
pangil_kim
pangil_kim
기록을 통해 지속적인 성장을 추구합니다.
  • pangil_kim
    멈추지 않는 기록
    pangil_kim
  • 전체
    오늘
    어제
  • 📝 글쓰기
      ⚙️ 관리

    • 분류 전체보기 (405) N
      • 💻 개발 (176) N
        • ※ 참고 지식 (9)
        • 🦕 React (13)
        • 🎩 Next.js (25)
        • 📘 TypeScript (4)
        • 📒 JavaScript (8)
        • 🟩 Node.js (7)
        • 📀 MySQL (24)
        • 🌸 Spring Boot (5)
        • 👷 SveleteKit (24)
        • 🩵 Flutter (11)
        • 🌀 Dart (2)
        • 🌈 CSS (5)
        • 🔸Git (1)
        • 🔥 Firebase (4)
        • 🧑🏻‍💻 코테 (29) N
        • 🕸️ 알고리즘 (4)
        • 🌤️ AWS (1) N
      • 📋 프로젝트 (4) N
        • ☄️ 트러블 슈팅 (2) N
        • 🧑🏻‍💻 서비스 소개 (2)
      • ✍🏻 회고 (52) N
        • ☀️ 취준일지 (6) N
        • 🍀 우테코 (32)
        • 👋 주간회고 (1) N
      • 📰 정보 공유 (12)
      • 🧑🏻‍💻 개발자라면? (1)
      • 🏫 한동대학교 (153)
        • Database (15)
        • Software Engineering (18)
        • EAP (22)
        • 일반화학 (26)
        • 25-1 수업 정리 (19)
        • Computer Networking (36)
        • OPIc (2)
        • 미술의 이해 (15)
  • 최근 글

  • 인기 글

  • 태그

    QT
    프론트엔드
    글로벌리더십학부
    한동대학교
    우테코
    프리코스
    묵상
    데이터베이스
    부트캠프
    찬양
    웹개발
    주일
    네트워킹
    전산전자공학부
    어노인팅
    웹 프론트엔드 8기
    GLS
    컴네
    CCM
    설교
    우테코 8기
    csee
    예배
    FE
    computer networks and the internet
    typeScript
    날솟샘
    날마다 솟는 샘물
    우아한테크코스
    고윤민교수님
  • 최근 댓글

  • 250x250
  • hELLO· Designed By정상우.v4.10.4
pangil_kim
[React] public 이미지에서 import 구조로 (이미지 최적화 개선기)
상단으로

티스토리툴바