처음 React에서 이미지 컴포넌트를 만드려고 했을때
import React from 'react';
const Image = ({ src, alt, width, height }) => {
return <img src={src} alt={alt} width={width} height={height} />;
};
export default Image;
구조는 이러했었다.
src, alt, width, height를 prop으로 받고 받은 prop을 나타내는 형식의 정말 기본적인 img 컴포넌트 구조였다.
또한 여기서 loading="lazy" 를 사용했던 적이 있었는데 이는 모든 브라우저에서 지원하지 않았기 때문에 후엔 해당 부분을 삭제하였다.
그렇다면 여기서 이미지 컴포넌트의 문제점은 무엇이였을까?
React에서 내가만든 이미지 컴포넌트의 문제점
React에서는 img 태그를 사용한 이미지 컴포넌트를 만들어서 이미지를 관리했었는데 이 방식은 기본적인 이미지 렌더링에는 충분하였었다. 하지만 문제는 얼마 지나지 않아 서버에서 이미지를 받아올때 쉽게 문제점을 발견할 수 있었다.
자동 크기 조정
해당 컴포넌트는 width, height를 prop으로 전달 받고 있다. 그렇기 때문에 아무것도 작성하지 않았을때 서버에서 내려준 크기 혹은 로컬에서 가지고 있는 기본적인 이미지 크기를 가지고 렌더링한다.
서버에서 보내주는 이미지 크기가 너무큰데?
만약 서버에서 가져오는 이미지의 크기가 리사이징 되지않고 그대로 보내지면 어떡할까? 프론트에서 해당 이미지 파일을 리사이징 한다해도 크기에는 변함이 없어진다. 쇼핑몰 상품목록 리스트를 예를 들어보자면 수백, 수만개의 이미지 데이터를 받아 페이지를 렌더하려고 시도하면 이미지의 렌더가 느려져 분명 사용자가 원활히 사용하기 힘들 것이다.
최적의 이미지 확장자
이미지를 최적화하려고 구글링을 열심히 해보았었는데 모든 이미지파일에는 가장 최적의 이미지 파일 확장자가 있다. 어떠한 파일은 PNG로 되어있지만 JPG가 가장 최적일 수 있고 JPEG가 최적일 수 있는 상황인 것이다.
최적의 이미지 확장자를 어떻게알고 어떻게 다바꿔?
소규모 프로젝트는 가능한일 일 수도 있다. 하지만 정말많은 이미지를 가지고 있으면 거의 불가능하다고 느낀다.
Webp
이러한 생각을 가지게 된 시점에 Webp라는 것을 알게 되었다. Webp는 기존 JPEG, PNG, GIF 포맷보다 우수한 압축 기술을 제공한다. 이는 웹에서 이미지를 사용할 때 발생하는 주요 문제인 큰 파일 크기와 로딩 시간을 해결하고자 만들어졌다. Webp 파일의 크기는 같은 내용의 JPG 파일보다 25 ~ 34% PNG 파일보다 26% 작다고 한다.
'프론트 개발에서 이미지를 원활하게 보여주는건 무엇일까' 생각을 해보면 최대한 작은 파일의 크기, 원본 화질 또는 고화질을 유지하는 것이다. Webp는 이 부분에서 최적화 되있다고 보면 되고 또한 많은 브라우저에서 지원하기 때문에 기존보다 최적화된 이미지를 제공할 수 있다고 생각했다.
서버에서 받은 이미지 확장자는 어떻게 바꾸지?
사실 이게 가장 중요한 포인트라고 생각했다. 우리가 이미지를 다운받아 사용하는 경우는 쉽게 변환이 가능하다. 하지만 서버에서 요청받고 그걸 렌더링하는게 이미지 렌더의 90% 인 것 같은데 서버에서 받은 이미지 확장자를 임의로 바꿀수가 없다.
이러면 결국 Cloudinary나 Imgix와 같은 이미지 CDN 서비스를 사용해서 이미지 요청 시점에 동적으로 포맷을 변환하거나 서버에서 리사이징과 포맷 변환을 해야하는 것이다.
Nextjs의 Image 컴포넌트
최근 학습하고 있는 Nextjs를 기반으로 토이 프로젝트를 만들고 있었는데 Image 컴포넌트가 유독 눈에 띄었다. Image 컴포넌트는 이미지 최적화를 자동으로 처리하면서 이미지 로딩 전략을 쉽게 구현할 수 있게 할 수 있었다. 자동 크기 조정과 최적의 포맷을 제공하면서 지연 로딩(lazy loading)을 사용할 수 있고 이미지가 로딩되는 동안 사용자에게 보여줄 placeholder도 따로 설정할 수 있다.
Nextjs의 이미지 컴포넌트는 결국 이미지 컴포넌트가 호출이되면 해당 이미지 소스를 확인하면서(따로 외부에서 불러오는 이미지는 설정이 필요함) 이미지 최적화 요청을 생성하여 서버에서 이미지 최적화 로직을 거쳐서 Webp와 같은 최적의 포맷으로 변환한다는 것이다.
또한 Intersection Observer API를 사용하여 레이지로딩을 구현하였다고 공식문서에 적혀있다. 이는 이미지가 뷰포트 내에 들어올 때 까지 로딩을 지연시키면서 사용자가 스크롤하여 이미지가 화면에 나타나애 할 때 로드한다. 이러면 한페이지에 사진이 많을경우 페이지 로딩이 길어지는 것을 방지할 수 있기 때문에 UX적으로 정말 큰 도움이 되는 것 같다.
이미지 캐싱
이미지 컴포넌트를 최적화하는 로직을 순회하고 이미지를 렌더할 때 분명 시간이 많이 걸릴 것으로 예상이 된다. 그 이유는 최적화 로직을 거쳐 포맷을 변경하고 페이지에 렌더하는 시간 때문이다. 근데 Next에선 이것까지 고려하여 청므 로직을 순회하면서 이미지를 만들고 캐시하는 동작까지 하여서 동일한 요청이 반복적으로 들어올 때 더 빠르게 응답할 수 있게 한다. 또한 이러면 서버 비용을 관리하는데 도움이 될 것이다.
마무리
이미지 최적화는 웹 사이트 성능에 얼마나 영향을 미칠까?
이미지는 웹 사이트 데이터 용량에서 생각보다 큰 비중을 차지하고 있다. 여기에 최적화되지 않은 이미지는 로딩 속도를 느리게 하고 사용자 경험을 저하시킬 수 있다.
이러한 문제 때문에 내가 직접 react를 사용하면서 lazy loading 과 최적화 로직을 구현한다고 했을때 정말 오랜시간을 투자해야 할 것이다.
하지만 Nextjs를 사용하면서 Image컴포넌트를 사용함으로써 이미지 크기를 줄이고 최적 포맷을 적용시키면서 로딩 시간을 단축시켜 전체적인 웹사이트의 성능을 개선할 수 있다. 또한 이는 검색 엔진 최적화인 SEO 에도 좋은 영향을 미친다고 한다.
참고자료
https://oliveyoung.tech/blog/2023-06-09/nextjs-image-optimization/
NEXT.JS의 이미지 최적화는 어떻게 동작하는가? | 올리브영 테크블로그
NEXT.JS는 왜 Sharp를 추천하는가
oliveyoung.tech
https://www.youtube.com/watch?v=Ino03JPppU4
'Nextjs' 카테고리의 다른 글
Next.js는 왜 사용할까? SSR을 위해? (1) | 2024.06.13 |
---|