통합검색 성능 개선 이후로 진행한 성능개선 작업 2편입니다.
1편인 통합검색 성능 개선이 궁금하신 분은 아래 링크 참고해주세요.
메인페이지 관련 개발 중 해당 로그를 발견했습니다.
이 메시지는 Next.js 애플리케이션에서 Largest Contentful Paint (LCP)를 최적화하기 위해 이미지를 우선적으로 로드해야 한다는 경고입니다. LCP는 사용자가 페이지를 로드할 때 가장 큰 콘텐츠 요소가 화면에 나타나는 시간을 측정하는 웹 성능 지표이며 이는 사용자 경험을 개선하는 데 중요하다고 볼 수 있습니다.
로그를 확인해보니 메인 페이지에 배너와 사용자 사진 등이 들어가는데 이 부분에서 LCP가 발생하는 것으로 파악했습니다.
LCP (Largest Contentful Paint)란?
LCP는 페이지가 로드를 시작한 시점부터 뷰포트 내에서 가장 큰 이미지나 텍스트 블록이 렌더링되는 시간을 측정합니다. 이는 페이지의 주요 콘텐츠가 사용자에게 표시되는 시점을 나타내므로, 사용자가 페이지를 "유용하다"고 인식하는 시간을 반영합니다.
2.5초 시간 이내에 LCP를 달성해야 좋은 사용자 경험을 제공 할 수 있다고 합니다.
LCP 측정 대상
LCP는 다음과 같은 요소들을 측정 대상으로 고려합니다:
- <img> 요소
- <svg> 요소 내부의 <image> 요소
- <video> 요소 (포스터 이미지 사용 시)
- CSS background-image를 통해 로드된 이미지
- 텍스트 노드나 인라인 텍스트 요소를 포함하는 블록 수준 요소
LCP 목표 수치
Google은 다음과 같은 LCP 목표 수치를 제시합니다:
- 좋음: 2.5초 이하
- 개선 필요: 2.5초 ~ 4초
- 나쁨: 4초 초과
LCP 최적화 방법
LCP를 개선하기 위해 다음과 같은 방법들을 고려할 수 있습니다:
1. 서버 응답 시간 개선:
- 서버 성능 최적화
- CDN(Content Delivery Network) 사용
- 캐싱 전략 구현
2. JavaScript와 CSS 최적화:
- 렌더링 차단 리소스 최소화
- 중요한 CSS 인라인화
- JavaScript 지연 로딩
3. 리소스 최적화:
- 이미지 압축 및 최적화
- 적절한 이미지 형식 사용 (예: WebP)
- 이미지 크기 조정
4. 클라이언트 측 렌더링 최소화:
- 서버 사이드 렌더링(SSR) 또는 정적 사이트 생성(SSG) 고려
- LCP 요소를 서버에서 미리 렌더링
5. 프리로드 중요 리소스:
- <link rel="preload"> 사용하여 중요한 리소스 미리 로드
6. 브라우저 캐싱 활용:
- 적절한 캐시 헤더 설정
위 방법을 참고해서 제가 한 방법은 이렇습니다.
1. Image 컴포넌트 최적화
priority 속성 추가, 이 속성은 Next.js가 이미지 로딩을 우선시해줍니다.
<Image
style={{ cursor: 'pointer' }}
src={src}
alt={src}
layout="fill"
onClick={() => onClickViewDetail(itemProp)}
priority
/>
2. 폰트 요청 결합하기
// 기존
<link
href="https://fonts.googleapis.com/css?family=Roboto:400,300,300italic,400italic,700,700italic&subset=latin,vietnamese,latin-ext,cyrillic,cyrillic-ext,greek-ext,greek&display=optional"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Oswald:400,300,700&subset=latin,latin-ext&display=optional"
rel="stylesheet"
/>
<link
href="https://fonts.googleapis.com/css?family=Montserrat:400,700&display=optional"
rel="stylesheet"
/>
// 변경
<link
rel="stylesheet preload"
as="style"
href="https://fonts.googleapis.com/css2?family=Roboto:ital,wght@0,300;0,300i;0,400;0,400i;0,700;0,700i&family=Oswald:wght@300;400;700&family=Montserrat:wght@400;700&family=Open+Sans+Condensed:wght@300;300i;700&display=swap"
/>
여러 개의 폰트를 사용할 경우, 이를 하나의 요청으로 결합하여 요청 수를 줄였습니다.
또한 preload 옵션을 사용함으로서 의도적으로 먼저 로딩시키게 하였습니다.
3. avif 포맷 사용
png나 jpg 등 기존의 포맷보다 작은 용량인 webp지만 여전히 용량이 큰 문제가 있어 webp보다 20% 더 높은 압축률을 보여준다는 avif를 적용했습니다.
Next.js는 v12.0.0부터 avif를 지원하기 시작했습니다. 다음과 같이 next.config.js를 설정하면 avif 지원을 활성화할 수 있습니다.
※ Next.js에서 avif 포맷을 사용하고 싶다면 당연하지만 Image 컴포넌트를 사용해야 합니다.
[참고] AVIF는 인코딩하는 데 일반적으로 WebP보다 20% 더 오래 걸리지만, 결과 파일 크기는 20% 더 작습니다. 따라서 이미지를 처음 요청할 때는 로딩 속도가 느릴 수 있지만, 이후 캐시된 요청에서는 더 빠른 성능을 기대할 수 있습니다.
module.exports = {
images: {
formats: ['image/avif', 'image/webp'], // default: ['image/webp']
},
};
이런 식으로 avif로 인코딩해서 출력되는 것을 확인할 수 있습니다.
LCP 성능은 3.4 -> 1.4초로 개선 된 것을 확인 할 수 있었습니다.
LCP 최적화 외에도 로컬 스토리지 활용, lazy 활용 등 방법을 적용해서 Light house 성능 향상 시킨 방법은 추후 포스팅에 기재하겠습니다.
참고
'Programming > React.js, Next.js' 카테고리의 다른 글
[Next.js] next/dynamic 1. 사용법과 빌드 과정 (0) | 2024.12.10 |
---|---|
우테코(우아한테크코스) 프론트엔드 폴더 구조 톺아보기 (0) | 2024.08.05 |
debounce와 throttle (0) | 2024.07.01 |
[Next.JS] getStaticProps를 이용해서 서버 자원을 효율적으로 사용하고, 비용을 절감하기 (2) | 2024.06.04 |
[React Conf 2024] 이제 useMemo, useCallback 필요 없음. 리액트 컴파일러란?? (0) | 2024.05.31 |