팀 프로젝트가 마무리 단계에 접어 들면서 코드도 실제 배포 환경에서 에러가 발생하는 부분을 고치고 리팩토링하면서 무엇을 더 할 수 있는게 생각하다가 최적화에 대해서 궁금해졌다.
Next.js 공식 문서에서 프로덕션에 배포하기 전에, next build
명령어를 사용해 로컬에서 애플리케이션을 빌드하고 빌드 오류가 있는지 확인할 수 있고, next start
명령어로 실제 프로덕션 환경과 유사한 상태에서 애플리케이션 성능을 측정할 수 있다고 한다.
웹 성능을 측정하기 위해 Lighthouse를 사용할 것이다. Lighthouse
란 웹 사이트의 성능, 접근성, SEO, 그리고 웹 애플리케이션의 최적화 상태를 자동으로 분석해주는 오픈 소스 도구이다.
LIghthouse 설치 및 실행 설명 링크
이번 글에서는 세부 측정 항목과 항목들에 대한 내용들에 대해서는 다루지 않고 실제 내 페이지에서 LightHouse를 실행했을 때의 결과를 토대로 어떻게 측정 점수를 올렸는지 적어보겠다.
일단 npm run dev로 개발모드를 실행시켜서 개발자 도구에서 console탭을 눌렀을 때 메시지를 확인하겠다.
부분은 홈 페이지 경로에 대한 모임 목록들인데 경고메시지를 보겠다.
LCP
라는 메시지만 기억하고 아래 LightHouse
실행결과를 이어서 확인하자.
참고로 npm run build
로 빌드하고 npm run start
로 실행한 뒤 시크릿 모드
로 접속하여 LightHouse를 실행하자!
시크릿 모드에서 진행하는 이유!
브라우저 확장 프로그램의 간섭 방지: 설치된 확장 프로그램들이 Lighthouse
의 성능 측정에 영향을 줄 수 있다. 예를 들어, 광고 차단기나 스크립트 차단 확장 프로그램이 페이지 로딩 속도나 성능 평가에 부정확한 결과를 초래할 수 있
다.
로그인 및 캐시 배제: 비밀모드는 캐시나 로그인 정보가 저장되지 않기 때문에, 실제 사용자가 처음 웹사이트에 접속하는 환경과 비슷한 조건에서 테스트를 진행할 수 있다. 캐시된 데이터나 로그인 세션이 있으면 Lighthouse
테스트 결과가 실제와 다르게 나올 수 있으므로, 비밀모드를 사용하는 것이 더 권장된다.
시크릿 모드에서 개발자 도구를 열고 Device는 Desktop을 클릭하고 우측 상단에 Analyze page load 버튼을 클릭한다. (1분 정도 소요되는 것 같다.)
우선 LCP는 최대 콘텐츠 렌더링 시간을 나타내고 보고서의 성능(Performance) 섹션에서 추적되는 측정항목 중 하나이다. 구체적으로 LCP는 사용자가 페이지 로드를 시작한 시점부터 표시 영역 내에서 가장 큰 이미지나 텍스트 블록이 렌더링될 때까지의 시간을 측정한다.
우선 LCP를 구성하는 하위 4가지 카테고리를 알아보자.
사용자가 페이지 로드를 시작한 시점부터 브라우저가 실행될 때까지의 시간
HTML 문서 응답의 첫 바이트를 수신
서버에서 첫 번째 응답이 도착한 후, 브라우저가 LCP리소스(이미지나 폰트 같은 주요 리소스)를 로드하기 시작할 때까지 걸리는 시간
즉, 리소스를 로드하는 준비가 되기까지의 대기 시간
브라우저가 LCP 리소스를 실제로 다운로드하는 데 걸리는 시간
리소스 로드 지연 후, 브라우저가 해당 리소스를 로드하기 시작하면, 서버로부터 그 리소스를 가져오는 데 걸리는 시간이 리소스 로드 시간
예를 들어, 이미지 파일이나 폰트 파일을 서버에서 다운받는 시간이 여기에 해당
다시 위에 처음 콘손에 나온 메시지를 보자.
"Please add the "priority" property if this image is above the fold"
"above the fold"란?
above the fold는 사용자가 페이지를 열었을 때 스크롤하지 않아도 바로 보이는 영역을 의미한다. 즉, 화면 상단에 위치한 중요한 콘텐츠들이다.
반대로 below the fold는 스크롤해야 보이는 영역
"priority" 속성이란?
priority
속성은 Next.js에서 이미지를 우선적으로 로드하라고 지시하는 역할을 한다. 페이지의 로딩 성능을 최적화하는 데 중요한 요소다.Next.js image 컴포넌트 priority 속성
메시지의 의미
이미지가 above the fold에 위치해 있기 때문에, 사용자가 페이지를 로드하자마자 바로 보이는 중요한 이미지라는 것을 뜻한다. 따라서 priority
속성을 추가하여 해당 이미지를 빠르게 로드하게 함으로써 페이지의 첫 화면 렌더링 속도를 개선하라는 제안이다.
적용 코드
첫 번째 이미지에서 priority 속성을 추가하라는 메시지가 나타났기 때문에 index 값이 0인(첫 번째 요소) 경우에 priority 프롭스를 boolean 값으로 ProgressCard 컴포넌트에 전달해주었다.
{data.pages.flat().map((gathering, index) => (
<ProgressCard key={gathering.id} gathering={gathering} priority={index === 0} />
))}
<Image
src={gathering.image || '/card-image2.png'}
alt="Image"
fill
className="object-cover rounded-t-3xl md:rounded-t-none"
priority={priority}
/>
이렇게 보는 거와 같이 최종 결과는 performance 점수가 크게 상향하였고 LCP
응답 시간이 2.1s에서 0.3s로 감소하였다. 결론적으로 priority
속성만 추가하면 해결된 부분이였지만 이 과정 속에서 LCP가 무엇인지 어떻게 구성되어있는지 해결방법에 어떻게 접근했는지 배워간 부분이 많다.