프로젝트를 리팩토링 중, 랜딩 페이지에서 메인 페이지로 이동할 때 체감 속도가 살짝 느린 느낌이 들었습니다.
메인 페이지는 로그인 여부에 따라 다른 데이터를 보여줍니다.
이로 인해 로그인 여부 판단 과정에서 시간이 소요되어 전환 속도에 영향을 준다고 판단했습니다.
이 흐름에서 성능을 개선할 수 없을까 고민하다가,
tanstack-query의 prefetch로 사용자 정보를 미리 받아두면 조금 더 빨라질 수 있겠다는 생각이 들었습니다. 직접 적용해보고, 성능 측정까지 진행한 경험을 공유합니다.
랜딩 페이지는 아래와 같이 서버 컴포넌트 + 일부 클라이언트 컴포넌트로 구성되어 있습니다.
export default function Page() {
return (
<>
<LandingView > // 서버 컴포넌트
<StartButton /> // 클라이언트 컴포넌트
</LandingView>
<LandingTracking /> // 클라이언트 컴포넌트
</>
);
}
처음에는 서버 컴포넌트에서 prefetch를 적용하려고 했습니다.
서버 컴포넌트에서 prefetch를 진행한 후에는 hydration을 통해 클라이언트로 직렬화를 해야하는데, 랜딩 페이지에서는 유저 정보를 사용하지 않기 때문에 직렬화를 해야할 이유가 없었습니다.
이에 따라, 클라이언트 컴포넌트에서 useEffect로 초기 렌더링 시 prefetch를 수행했습니다.
useEffect(() => {
browserQueryClient?.prefetchQuery({
queryKey: ['profile'],
queryFn: getProfile,
staleTime: 5 * 60 * 1000,
});
}, []);
성능 비교를 명확하게 하기 위해, 브라우저의 performance.mark()를 사용했습니다.
performance.measure()로 두 지점 간 시간 계산// 랜딩 페이지
performance.mark('landing-to-main-start');
// 메인 페이지
useEffect(() => {
// 'landing-to-main-start' 마크가 없는 경우(바로 메인 페이지로 진입한 경우)를 방지
if (performance.getEntriesByName('landing-to-main-start').length > 0) {
performance.mark('landing-to-main-end');
performance.measure(
'LandingToMain',
'landing-to-main-start',
'landing-to-main-end',
);
}
}, []);
prefetch 미적용

prefetch 적용

| prefetch 수행 여부 | 1차(Cold Start) | 2차 | 3차 |
|---|---|---|---|
| X (미적용) | 2.61s | 688.5ms | 615.53ms |
| O (적용) | 1.92s | 565.88ms | 562.54ms |
👉 Cold Start에서 약 700ms, Warm Start에서는 평균 80ms 이상 개선된 것을 확인할 수 있었습니다.
처음에는 단순히 사용자 여부만 prefetch 적용하는 것이 페이지 전환 속도에 영향을 줄 수 있을까? 반신반의 했지만,
직접 테스트해본 결과, 실제로 개선 효과가 있다는 것을 확인할 수 있었습니다.
또한 이번 경험을 통해,performance.mark()를 활용하면 간편하게 정량적 성능 측정이 가능하다는 점을 배울 수 있었습니다.
앞으로도 Suspense, lazy loading, dynamic import 등의 다양한 전략을 고민하여,
더 빠르고 부드러운 사용자 경험을 만들어 갈 수 있도록 고민하고 개선해나갈 것입니다.