Frontend

[NextJS] 이미지 파일 관리, 최적화 (SVG, SVGO)

Daejlee 2025. 2. 9. 02:47
들어가기에 앞서, 프론트엔드에 많은 양의 이미지를 저장하는 것은 유지보수가 어렵고, 권장되지 않습니다.
많은 이미지를 수반한다면 CDN 서비스를 사용하는 것이 좋습니다.
이 포스팅은 프론트엔드 서버를 사용하지 않는 정적 배포를 기준으로 작성합니다 !!

1. 이미지 파일을 어떻게 관리할까?

NextJS 환경에서 이미지 저장 경로는 크게 2종류로 나눌 수 있습니다.

  1. public 폴더
  2. src 폴더 하위 경로
You can store static files, like images and fonts, under a folder called public in the root directory. Files inside public can then be referenced by your code starting from the base URL (/).

공식 문서는 이미지나 폰트같은 '정적 파일'들은 public 폴더에 보관할 수 있다고 소개합니다.

혹은 이와 달리 알려진 방법으로 src/assets 폴더를 활용하여 src 폴더 안에 이미지를 저장할 수 있습니다.

무엇이 더 나은 방법일까요? 차이점을 명확하게 구별해봅시다.

public에 저장

import Image from 'next/image';

export default function HomeImg() {
  return <Image src="/image/home.svg" alt="home" />;
}

ex) http://localhost:3000/image/home.svg

  • 자원이 빌드 과정에 포함되지 않는다.
  • 빌드를 건너뛰므로, 해당 경로에 이미지가 없어도 검증이 이뤄지지 않아 알 수가 없다.
  • 번들링되지 않으므로 파일 이름이 변경되지 않는다.

src에 저장

import Image from 'next/image';
import home from '@/assets/home.svg';

export function HomeImg() {
  return <Image src={home} alt="home" />;
}

ex) http://localhost:3000/_next/static/media/home.84b1efa.svg

  • 자원이 Webpack, Vite 등의 빌드 과정에 포함된다.
  • 빌드 과정에 포함되므로, 해당 이미지가 올바로 import 되었는지 검증이 일어난다.
  • 번들링되므로 파일 이름이 변경되며, 번들러의 최적화가 적용된다. (번들러 옵션을 어떻게 지정하냐에 따라 다름)

어느 방법을 쓰든 NextJS의 Image 최적화 이점은 동일하게 누릴 수 있으며,

이미지는 결국 dist 폴더에 담겨 정적으로 브라우저에 서빙됩니다.

저는 이미지를 src 폴더에 소스 코드와 함께 넣어두고 번들링의 이점을 누리는 것을 선호합니다.

public 폴더에는 favicon, robot.txt 등의 에셋들을 넣어두고 관리합니다. 정답은 없습니다!

 

2. NextJS의 이미지 최적화

공식 문서는 NextJS의 <Image> 컴포넌트의 이점에 대해 이렇게 간단히 설명합니다.

  1. 크기 최적화: WebP와 AVIF같은 모던 이미지 포맷을 사용해 사용자 기기에 맞는 크기의 이미지를 제공합니다.
  2. 시각적 안정: 이미지 로딩 중 레이아웃 이동을 막습니다.
  3. 빠른 페이지 로딩: 브라우저의 lazy-loading을 활용해 뷰포인트에 이미지가 들어왔을 때만 로딩합니다.
  4. 에셋 유동성: 원격 서버에 저장된 이미지까지 필요에 따라 이미지를 리사이징합니다.

확실히 브라우저의 <img> 태그에 비해 여러 이점을 제공합니다.

또한 자동으로 최적화되기 때문에 개발자가 크게 신경쓸 부분이 없습니다.

다만 NextJS의 <Image> 컴포넌트도 "이미지 자체"에 대한 최적화는 해주지 않습니다.

 

3. SVGO를 활용한 SVG 이미지 최적화

이미지 자체를 최적화하고 거기에 NextJS의 <Image> 컴포넌트를 사용하면 더할 나위 없겠습니다.

많은 SVG 이미지를 사용하는 프로젝트에서 package.json 빌드 과정에 SVGO 스크립트를 추가하였습니다.

  "scripts": {
    "dev": "next dev",
    "svgo": "svgo -rf src/assets/ -o src/assets/",
    "build": "npm run svgo && next build",
    "start": "next start",
    "lint": "next lint"
  },

55kb 정도의 크기를 절약했습니다.