
with Next.js 이미지 최적화
CLS는 이전에 운영하던 블로그에서도 최적화를 한 번 해봤기 때문에 어디서 문제가 생기고 있는지 짐작은 가는 상황이었다. 좀 더 확실한 기록을 위해서 lighthouse를 사용해서 성능 테스트를 진행했다. 성능이 28점으로 매우 낮은 것을 볼 수 있었다. CLS 수치도 무려 0.8이 넘는 것을 볼 수 있었다.
스크린샷 2024-12-18 오후 2.17.44.png
- CLS 수치
스크린샷 2024-12-18 오후 2.17.51.png
첫 시도: 기본 높이 설정하기
처음으로 한 시도는 포스트 Header 부분의 최대 높이를 지정해주는 것이었다. 아래 초록색으로 칠해져있는 섹션인데, 해당 부분의 높이가 지정되어있지 않으면 처음에는 적은 공간을 차지하다가 렌더링 이후에 갑자기 차지하는 공간이 커지면서 CLS 수치에 영향을 주는 것이다.
image.png
실제로 로딩이 되기 전에는 적은 공간을 차지하다가 로딩이 완료되면 20%정도 공간이 늘어나는 것을 볼 수 있다. 이런 레이아웃 변경이 CLS 수치를 올리는 이유가 된다.
Dec-18-2024 14-36-54.gif
PostHeader 컴포넌트 높이 지정하기
<div
className={
'post-header h-[300px] relative overflow-hidden w-full text-center'
}
>
기본 높이를 300px로 지정해주는 것만으로도 수치를 반으로 줄일 수 있었다.
스크린샷 2024-12-18 오후 2.22.34.png
PostBody 컴포넌트 높이 지정하기
헤더 뿐만 아니라 body 컴포넌트도 높이를 지정해줬다. 최소 높이를 500px로 고정을 해뒀다.
이런 높이를 지정해주는 것만으로도 CLS 수치를 많이 낮출 수 있었다.
image.png
두 번째 시도: 이미지 최적화하기
내 블로그에서는 글 제목 뒤에 흐리게 블러처리를 한 썸네일 이미지를 지원한다. 이 이미지의 해상도는 1024 x 720의 크기를 사용하고 있었는데, 생각해보니 큰 이미지를 사용할 이유가 전혀없다고 판단했다. 왜냐하면 블러처리를 한 이상 해상도는 중요하지 않고 사실상 이미지의 전체적인 색상 정도만 파악하면 되기 때문이다. 그래서 이미지를 최적화하기로 결정했다.
이미지 최적화: 해상도 리사이징
1024 사이즈는 너무 크다고 생각했고, 720과 480을 비교해보고자 했다. 아래는 순서대로 720과 480의 이미지이다. 화질 차이가 전혀 보이지 않는다고 생각해도 될 정도로 미미했다.
따라서 성능상 더 이득인 480 사이즈로 결정했다.
image.png
image.png
해당 최적화 이후에 검사했을 때 드라마틱한 결과는 아니지만 largest Contentful Paint 0.2초 감소 효과를 얻었다.
image.png
이미지 최적화: 로딩 방식 변경
nextjs에서 기본으로 지원하는 이미지 최적화 방법 중 loading 방식을 eager를 선택했다. lazy 방식과 eager 방식이 있는데, eager 방식은 이미지를 페이지 로드와 동시에 즉시 로딩하는 방식이다. lazy는 반대로 화면에서 보이지 않는 경우에는 로딩을 하지 않고 있다가 뷰포트에 가까워지면 로딩을 하는 방식이다.
스크롤 아래에 있는 이미지라면 lazy가 맞겠지만, 메인 페이지에서 바로 보여야하기 때문에 eager 방식을 선택했다. 이 방식으로 로딩했을 때 아래 성능 지표가 크게 개선이 된 것을 볼 수 있었다.
image.png
어떻게 이렇게 개선되었을까? eager 방식을 적용하지 않으면 다른 리소스들과 비슷하게 로딩을 해서 사진을 가져온다. 하지만 eager 방식을 사용하면 브라우저의 프리로더가 이미지의 우선순위를 좀 더 높게 가져가서 먼저 다운로드하게 된다. 이 방식을 사용하면 hero 이미지나 이미지가 시각적으로 많이 중요한 페이지의 경우에 사용하면 LCP 개선에 큰 도움이 된다고 한다.
NextJS가 아니라면?
순수 자바스크립트나 리액트에서는 link 태그의 rel 속성을 preload를 통해서 비슷하게 프리로드를 지원할 수 있다고 한다.
const link = document.createElement('link');
link.rel = 'preload';
link.href = resource.url;
이미지 최적화: priority 지정
priority를 지정해서 우선순위를 사용하도록 설정해주었다.
<Image
className={'w-full h-full'}
width={480}
height={300}
src={backgroundThumbnail}
alt={`${title} Thumbnail`}
loading={'eager'}
priority={true}
placeholder={'empty'}
/>
이 옵션을 지정하고, CLS 수치가 더 낮아진 것을 확인할 수 있었다.
image.png
Total Blocking Time
Total Blocking Time은 배포 환경에서는 제대로 측정이 되지 않는 것 같다. 배포한 환경에서 페이지를 테스트했을 때 모두 초록색 점수로 개선이 된 것을 알 수 있었다.
알아보니 TBT는 개발환경에서는 아래와 같은 이유로 제대로 측정되지 않을 수 있다고 한다.
- 개발환경의 추가적인 오버헤드
- React의 개발 모드는 다양한 경고와 에러 체크를 수행
- Hot Module Replacement(HMR) 관련 코드가 실행됨
- Source Map 생성 및 처리
- 디버깅을 위한 추가 코드들이 실행
- 환경에 따른 코드
- 배포환경에서는 코드 압축, 트리 쉐이킹 등 최적화가 적용됨
- 개발환경은 빌드 최적화를 거치지 않은 원본 코드가 실행됨
스크린샷 2024-12-18 오후 4.52.30.png
다른건 몰라도 검색엔진 최적화는 100점을 만들어보고 싶다고 생각한다.
