✨ 들어가기
글에 들어가기에 앞서, FEW 서비스를 아직 다운받지 않았다면..? 아래의 링크로 웹 서비스를 이용해 보고 앱을 다운로드받아서 사용하길 바란다..! ㅎㅎ
위 서비스는 뉴스레터를 워크북 단위로 모아서 보여주고, 문제 풀이를 통해 지속적인 학습을 유도하는 데에 초점이 맞춰져 있다.
사용자에게 정보를 제공해 주는 서비스의 특징으로 인해 웹 사이트의 로딩 속도 및 로딩 중 사용자 경험 향상이 중요하다.
2가지 중에서 로딩 중 사용자 경험을 높이기 위해서 dynamic import를 통한 loading component 와 data fetching의 상태일 때 보여주는 loading component를 구현하여 CLS 점수를 최소화하도록 프론트엔드 코드를 작성하였다.
하지만, 서버로부터 이미지를 가져와 사용자에게 보여주기까지의 시간이 길어져 loading component가 올바른 위치에 잘 렌더링 되고 있음에도 불구하고, 사용자에게 정보를 보여주는 체감 시간이 길어져 불편함이 야기되는 현상이 발생하였다.
이에 대한 원인을 분석하기 위해 chrome 개발자 도구에서 light house를 통해 웹 사이트 점수를 측정하였다.
참고로 퓨 사이트는 cloud flare로 배포 환경을 구성하였다.
🤔 최초 메인 페이지 성능
아래의 점수는 앞서 언급한 loading component를 적절하게 배치시킨 작업의 최초 성능 측정 사진이다.
확실히 CLS 점수에 공을 기울인 덕분에 0.006이라는 매우 좋은 점수를 얻을 수 있었다.
반면, FCP 과 LCP 속도는 3.3s와 34.3s로 성능이 매우 안 좋았다.
해당 속도를 늦추는 원인으로는 image로 발견되었다.
FCP 속도를 늦추게 하는 것은 png 파일로 이미지를 렌더링시키는 과정이었고, LCP 속도를 느리게 만드는 원인은 뷰포트에 보이는 사진의 크기보다 큰 이미지를 불러오는 과정이었다.
메인 화면 내의 워크북 카드 대표 이미지 부분에서 사용자에게 보이는 크기는 269 x 172 px이지만,
실제 사진이 다운로드 되는 크기는 750 x 676 px로 약 3배가량 큰 사이즈로 불러와지고 있었다.
📍 FCP 개선하기 : png 에서 webp로 변환
우선 FCP 개선하기 위해 차세대 이미지 형식인 WebP 포맷으로 이미지 파일을 변경하여 서버로부터 응답받을 수 있도록 변경하였다.
그 결과, FCP 속도가 3.3s 👉 2.9s 로 0.4s가 줄어든 것을 확인할 수 있었다.
이 과정에서 LCP 속도도 34.3s 👉 28.8s 로 5.5s가 줄어들었지만 여전히 LCP는 낮은 점수를 보이고 있었다.
당연히...원인을 분석하고 개선하기 이전이었기에.....! 그래도 5초가 줄어든 것에 희열을 느꼈다.
📍 LCP 개선하기 : next/image의 기능을 활용하여 이미지 최적화
그런데 말이죠..?
저희 서비스는 Next.js를 사용하고 있었으며 이미지를 보여주는 component도 next/image를 사용하고 있었다.
그런데 왜..? next/image에서 제공해 주는 최적화기능들 ( ex. webp 변환, sizes ,cache 등)이 적용되지 않았을까..?
이에 대한 답은 배포 환경에 있었다.
cloudflare로 배포했을 때, runtime을 edge로 사용하고 있었고 이는 가벼운 배포 환경이었기에 next/image가 제공하는 최적화 기능들을 사용하지 못하고 있었던 것이다..!
그래서 우리는 고민 없이 vercel로 배포 환경을 이관하는 작업을 진행하였다.
이후, 워크북 카드 내 이미지 컴포넌트에서 sizes와 priority 속성을 사용해 rendered size에 적합한 이미지를 불러오도록 조정했다.
const MainImage = ({
mainImageUrl,
isPriorityImage,
}: Pick<WorkbookCardClientInfo, "mainImageUrl" | "isPriorityImage">) => (
<Image
width={269}
height={172}
src={mainImageUrl}
alt="main-image"
priority={isPriorityImage}
quality={90}
sizes="28vw"
className="h-[172px] w-[269px] rounded-t-lg object-cover"
/>
);
...
// ✅ workbook card model
const changeToClientData: WorkbookCardClientInfo = {
id,
badgeInfo: this.getBadeInfo({ cardType }),
mainImageUrl: mainImageUrl,
isPriorityImage: idx < 2, // ✅ 인덱스 0,1만 우선 노출
title,
writers: this.getWriterNameList({ writers }),
metaComponent: this.getMetaComponent({
category,
currentDay,
totalDay,
}),
personCourse: this.getPersonCourse({
totalSubscriber,
subscriberCount,
status,
}),
buttonTitle: this.getButtonTitle({
cardType,
currentDay,
}),
cardType,
articleId: this.getArticleId({ articleInfo }),
};
return changeToClientData;
},
priority 속성은 사용자에게 처음으로 보이는 카드에만 true로 속성을 부여하였다.
그 결과, 2배보다 작은 크기로 이미지의 고유 크기로 불러와지는 것을 확인할 수 있었다.
vercel 이관을 통해 next/image의 최적화 기능 적용과 sizes의 속성 사용을 통해 측정한 최종 lighthouse 점수 결과이다.
최종적으로
FCP 속도는 3.3s 👉 0.9s 로 2.4s가 줄어들면서 안정적인 초록 상태로 성능을 가지게 되었고,
LCP 속도도 34.3s 👉 21.7s 로 12.6s가 줄어드는 결과를 얻게 되었다.
🌈 마치며
사용자에게 정보를 제공하는 서비스라면 어떤 기능을 구현할 때, 단순히 기능 구현에만 초점이 맞춰서 개발하는 것이 아니라 이 기능을 사용할 사람들에게 좋은 경험을 제공하는 것을 지속해서 발전시키는 것이 필요하다.
특히, 서버로부터 이미지나 글, 영상 등을 불러오는 과정에서 로딩 시간이 길어진다면 원인을 분석하고 개선하는 작업은 서비스가 고도화되어 갈수록 서비스의 품질을 높이는 데 기여할 것이다.
next환경에서 next/image가 제공하는 최적화 기능을 적절하게 사용할 줄 아는 것도 중요한 능력임을 깨닫게 되었다.
FEW는 곧 2차 스프린트를 들어갈 예정이며 프론트엔드 개발자로서 이 부분을 놓치지 않고 서비스를 만들어가고자 한다.
'WEB > Next.js' 카테고리의 다른 글
Refine 이관 작업 ( feat. 중고나라 - 셀러지원센터 ) (1) | 2024.09.15 |
---|---|
Link 태그와 SEO (0) | 2023.09.26 |
Next.js - V13 (0) | 2022.11.02 |
Next-auth (0) | 2022.07.12 |