Image Optimization With Next.js

Next Image

이 글은 2024-06-16에 작성되었어요.

페이지를 구성하는 여러 콘텐츠 중 이미지는 꽤 큰 용량을 가지고 있습니다. 용량이 큰 이미지를 로드하는 데 오래 걸린다면, 웹 사이트의 퍼포먼스 저하도 일어나는데요. 그렇기 때문에 더욱 사이트의 성능 또는 SEO가 중요하다면 최적화에 신경을 써야합니다.

사내에서는 Next.js를 사용하고 있고 이미지 최적화를 위해 Next/Image를 사용하고 있어서 이와 관련한 포스팅을 하도록 하겠습니다.

Next/Image Optimization


Next의 Image 컴포넌트는 img 태그의 기능을 확장한 컴포넌트입니다.

이 컴포넌트가 제공하는 기능은 아래와 같습니다.

  • 최신 이미지 포맷을 지원 (ex. WebP, AVIF)
  • 이미지를 로딩할 때, 이미지 크기 만큼의 영역을 보장하여 Layout Shift를 방지
  • Lazy Loading를 지원하기 때문에 뷰포트에 보이는 경우 이미지가 로드 됨. 이 경우 뷰포트에 이미지가 완전히 다운로드 되기 전 보여질 수 있는 Blur Image를 선택적으로 제공
  • 외부 이미지를 포함해 리사이징이 가능(SVG 포함)
  • 이 모든 것과 동시에 이미지의 용량을 최적화

위와 같이 Next에서 꽤 많은 기능을 제공합니다. 개발할 때 이미지 최적화를 포함해서 하나하나 신경쓰기 어려운 것을 사용성 좋게 자체적으로 지원해주고 있으니 행복하네요.

그럼 이 컴포넌트는 어떤 원리로 작동이 되는걸까요? 🤔

작동원리


Next.js 프레임워크 내 컴포넌트에서 넥스트 이미지 컴포넌트를 사용한다는 가정 하에

  1. 브라우저가 WebP, AVIF를 지원하는지 체크합니다.

  2. 만약 지원한다면 ‘원본’이미지를 다운로드 합니다.

  3. 기본 이미지 로더로 Squoosh 라이브러리를 사용하여 WebP 또는 AVIF 이미지 포맷으로 변경합니다.

    (* 배포 버전에서는 Sharp를 사용하는 것을 Next에서 권고합니다. )

  4. 변환된 이미지는 .next/cache/images 폴더에 저장됩니다.

    이 때, 변환된 이미지의 파일명은 SHA256과 같은 해시 알고리즘을 통해 고유한 값을 생성합니다.

    만약 동일한 Image의 URL, size, quality, 확장자라면 동일한 캐시가 매칭되는 셈입니다.

  5. 변환된 포맷의 이미지는 경량화 되었기 때문에 ‘img’ 태그로 브라우저에서 로드되지만 더욱 빠르게 이미지가 로드되어 성능이 향상됩니다.

WebP, AVIF


앞서 WebP와 AVIF라는 최신 이미지 포맷을 지원한다고 하는데, 이는 왜 지원하는걸까요?

WebP는 구글에서 개발한 웹에서 사용하기 위한 경량화된 이미지 파일 형식입니다.

대부분의 이미지 포맷은 손실 압축(JPEG) 또는 비손실 압축(PNG, GIF)로 나뉘지만 WebP는 둘 다 지원합니다. (동시에 지원하는 것은 아닙니다.)

손실 압축은 VP8 비디오 코덱의 기술에 기반해서 압축하며 JPEG에 비해 약 30% 정도 파일 크기가 줄어들고, 비손실 압축은 구글이 새로 개발한 방식으로 압축하며 PNG에 비해 20~30% 정도 파일 크기가 줄어든다고 합니다.

화질은 유지되며 파일 크기가 굉장히 많이 줄어들기 때문에 정말 많이 사용됩니다.

AVIF도 마찬가지로 전통적인 이미지 포맷(JPG,PNG,GIF) 등을 대체하기 위해 출시된 이미지 파일 형식입니다.

앞서 말했던 WebP와 달리 비교적 최신 포맷(2019년)인 만큼 품질 대비 용량 효율이 더 좋습니다. WebP는 VP8 기반이고 AVIF는 AV1 기반으로 동작해 움짤에 더 안정적입니다.

AVIF가 압축 효율이 더 좋기 때문에 무조건적으로 AVIF를 사용하는 것이 좋아보일 수 있지만 실제로는 인코딩/디코딩 속도가 AVIF가 느리기 때문에 단순히 이미지를 로딩하는 측면에서는 WebP를 사용하는 것이 효율적일 수 있습니다. 뿐만 아니라 AVIF가 최신 포맷인 만큼 제공해야 하는 브라우저 환경의 범위에 포함되지 않을 수 있습니다. 다만 이 문제는 Next Image 설정할 때, 어떤 우선 순위로 이미지 포맷 형식을 만들지 정해두면 브라우저가 제공하지 않는 경우 후순위의 포맷으로 시도할 테니 큰 걱정거리는 아닐 수 있습니다.

마무리


앞서 이미지 컴포넌트의 작동원리와 제공하는 최신 포맷에 대해서 알아보았습니다.

물론 앞의 내용도 중요하지만 결국 실제 서비스에 적용할 때는 더 디테일한 고민이 필요합니다.

넥스트가 제공하는 이미지 최적화는 변환된 이미지가 저장되는 ‘폴더’가 존재하고 이 ‘폴더’는 애플리케이션을 빌드 할 때 마다 새롭게 생성됩니다.

그렇다면 새롭게 배포되는 순간 이전의 과정을 또 한번 반복해야 하고, 특정 유저는 이미지의 로딩이 오래걸리는 현상이 생기기도 하겠습니다.

그렇기 때문에 제공하는 서비스의 성격에 따라 캐싱된 이미지 폴더를 어떻게 유지하고, 얼마나 유지할 지 생각해봄 직 합니다. 더불어 캐시를 사용하는 만큼 ‘캐시 히트율’을 올릴 수 있도록 가급적 ‘URL, size, quality, 확장자’를 잘 정하는 것도 중요하겠습니다.

피드백은 언제나 환영합니다.

글 읽어주셔서 감사합니다. 🙂