개발자로 전향한 이후 으레 모든 주니어 개발자가 그러하듯 성장 '방법'에 대한 고민에 봉착했다. 개인 프로젝트도 해보고, 책이나 강의를 통해 이론 강의도 듣고 있지만 크게 성장하는 느낌이 들지 않는달까.. 그래서 스터디나 외부 프로그램을 살펴보다가 평소 눈여겨 보던 AWSKRUG(한국AWS사용자모임) 프론트엔드 모임에서 'Next.js와 이미지 최적화'와 관련하여 세미나를 연다 하여 참여해 보았다.
마침 회사에서 Next.js를 쓰고 있기도 하고, 특히 이미지를 많이 뿌리는 커머스 서비스 관련 프론트엔드 개발자라면 깊게 고민해보아야 할 주제라고 생각했기에 더욱 반가웠다.
(여담이지만, 세미나 장소가 당근마켓 회사였다. 높고 넓고 깔끔하고.. 사람들이 화장실 가실 때 킥보드 타신다.. 킥보드.. 타보고 싶었다.)
결과적으로 증말 유익했다. 질문의 예리함이나 답변의 깊이 모두 감탄했다.. 사실 거진 구경하고 왔다고 해도 무방한데.. 나도 언젠간 도달 할 수 있을랑가 저 레베루.. 나 화이팅.. 더 열심히 살아야겠다..
img vs next/image
크롬 브라우저 기준, 일반 이미지 태그를 사용했을 때보다 next/image 컴포넌트를 사용했을 때 이미지 용량과 이미지 다운 속도 모두 확실히 next/image가 성능이 좋다. Next.js 이미지 컴포넌트의 관련 코드를 까보면, 서버가 구동 될 때 _next/image라는 이미지 최적화를 위한 라우터를 만들고 이미지 최적화 모듈을 활용한 최적화를 진행한다. 그래서 우리가 img 태그와 달리 next/image를 사용하면 이미지의 src 경로가 달라지는 것이다.
Next.js는 이미지 요청이 들어왔을 때, dist 폴더 밑에 cache/images 폴더에 최적화된 이미지를 동적으로 만들고, 이후에 동일한 요청에 대해서는 이미 만들어놓은 최적화된 이미지를 사용한다.
이미지 최초 요청 시에는 이미지 최적화 로직을 타기 때문에 시간이 좀 걸리는데, 이후에는 이미 캐시된 걸 사용하기 때문에 최적화 로직을 타지 않아 시간을 더 단축할 수 있다. (그럼 캐시된 이미지인지 아닌지는 어떻게 아는가? Next.js 서버에서 응답 헤더에 커스텀 헤더를 제공한다. X-Nextjs-Cache : MISS(캐시 전), HIT(캐시 후))
그럼 모든 이미지를 Next.js에서 최적화 하는가? 노노.. 이미지 최적화가 필요없는 svg, gif 같이 최적화가 오래 걸리는 애니메이션 이미지의 경우에는 최적화 진행하지 않고 바로 내려준다. (loaderOption을 수정해서 의도적으로 이미지 최적화를 하지 않고 원본을 내려받거나 unoptimized props를 사용해서 이미지를 선택적으로 최적화를 하지 않겠다는 선택을 할 수도 있다.)
Next.js는 기본적으로 Squoosh라고 하는 이미지 최적화 라이브러리를 내장하고 있기 때문에 Sharp를 사용하지 않아도 운영에서 이미지 최적화를 돌릴 수 있다.
그런데 왜 Next.js는 운영에서 Sharp를 사용하라고 추천할까?
Sharp란?
다양한 크기의 JPEG, PNG, WEBP, GIF, AVIF와 같은 이미지들을 더 작은 크기, 웹에 친화적으로 변환해주는 매우 빠른 속도의 모듈
데모로 보여주셨는데, 응답 속도 측면에서 Squoosh로 최적화 했을 때보다 Sharp를 사용했을 때 약 4~6배 정도 빠르게 응답 속도가 개선되었다.
av1이라고 하는 동영상 처리를 위한 코덱인데, 그 코덱에서 나온 이미지 처리용 포맷. 웬만한 모던 브라우저에서는 avif 포맷 제공.
webp vs avif
Next.js에 따르면, webp 포맷으로 변환할 때와 avif 포맷으로 변환할 때를 비교해보면 avif가 20% 정도 압축의 시간이 좀 더 걸리지만 용량은 20% 정도 작아진다. 첫 요청은 느릴 수 있으나 Next.js는 캐시를 하기 때문에 이후에는 webp보다 avif가 좀 더 빠르게 제공할 수 있다.
단, sharp의 예전 버전(0.27.0 이전)을 사용하고 있다면 avif를 사용할 때 버전 업그레이드가 필요함.
avif는 엣지 브라우저에서는 제공되지 않고 있다. 그럼 avif 쓰면 안되는가? 사용해도 괜찮다!! 브라우저에서는 이미지 파일을 요청할 때 accept 헤더를 보내줘서 본인이 사용할 수 있는 이미지 스펙을 전달해준다. Next.js에서 요 헤더 정보(accept)를 읽고, 브라우저에 내려줄 때 최적의 이미지 형식으로 내려준다. 그래서 avif를 사용해도 엣지 브라우저에는 webp 포맷(디폴트)으로 최적화해서 내려줌.