WEGO ) Next.js의 SSR을 활용한 SEO 최적화와 성능 개선

▪︎ 데이터 페칭 방식의 이해: CSR vs SSR

웹 애플리케이션에서 데이터를 가져오는 방식은 크게 클라이언트 사이드 렌더링(CSR)과 서버 사이드 렌더링(SSR)으로 나눌 수 있습니다.

클라이언트 사이드 데이터 페칭의 경우, 브라우저가 JavaScript를 실행하여 데이터를 가져오기 때문에 초기 HTML은 비어있는 상태입니다. 사용자는 데이터가 로드되기 전까지 로딩 상태를 보게 되며, 검색 엔진은 초기 HTML에서 의미 있는 컨텐츠를 찾을 수 없습니다.

반면 서버 사이드 데이터 페칭은 서버에서 데이터를 미리 가져와 완성된 HTML을 생성합니다. 이는 사용자에게 더 빠른 초기 로드 경험을 제공하며, 검색 엔진이 컨텐츠를 즉시 크롤링할 수 있게 합니다.

▪︎ SEO에서 SSR의 장점

검색 엔진 최적화(SEO)에 있어서 SSR은 다음과 같은 핵심적인 이점을 제공합니다.

▫︎ 완성된 HTML 제공

  • 검색 엔진 크롤러가 JavaScript 실행 없이도 모든 컨텐츠 접근 가능
  • 메타 데이터와 구조화된 데이터를 초기 HTML에 포함 가능

▫︎ 빠른 초기 로드

  • Time to First Contentful Paint (FCP) 개선
  • 사용자 경험 향상으로 인한 간접적 SEO 효과

▫︎ 신뢰성 있는 컨텐츠 제공

  • 동적 데이터 로딩으로 인한 컨텐츠 누락 방지
  • 일관된 컨텐츠 구조 제공

▪︎ 프로젝트 적용 (구현 예시)

예시로 우리 프로젝트에서는 리뷰 상세 페이지에 SSR을 적용했습니다. 이 페이지는 정적인 정보를 주로 다루며 SEO가 중요한 페이지이기 때문입니다.

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
// src/app/review/[id]/page.tsx
const ReviewDetailPage = async ({ params }: { params: Promise<{ id: number }> }) => {
const { id } = await params;
const queryClient = new QueryClient();

// fetchQuery를 사용한 서버 사이드 데이터 페칭
await queryClient.fetchQuery({
queryKey: ["reviews", "detail", id],
queryFn: () => getReviewDetail(id),
});

const data = queryClient.getQueryData<BaseResponse<Review>>(["reviews", "detail", id]);

return (
<div className="pb-[120px]">
<Header title="리뷰 상세보기" />
{data && <ReviewDetailContainer data={data.data} />}
</div>
);
};

▫︎ fetchQuery vs prefetchQuery

구현 과정에서 fetchQuery와 prefetchQuery 중 어떤 것을 사용할지 고민했습니다. 테스트 결과 fetchQuery가 더 나은 성능을 보여주었는데, 이는 다음과 같은 이유 때문입니다.

fetchQuery

  • 데이터를 즉시 가져오고 캐시에 저장
  • Promise가 resolve될 때까지 대기
  • 데이터가 확실히 있는 상태에서 렌더링 시작

prefetchQuery

  • 백그라운드에서 데이터를 가져옴
  • 데이터 로딩 완료를 기다리지 않음
  • 때로는 데이터가 없는 상태에서 렌더링이 시작될 수 있음

prefetchQuery의 경우 가져온 데이터들을 즉시 캐시에 저장하고 반영하는 것이 아니라 prefetch를 통해 백그라운드에 저장해놓은 데이터를 다시 한번 캐시에 등록하는 과정이 추가됩니다. 따라서 fetchQuery에 비해 로딩 속도가 비교적 낮았습니다.

▪︎ 성능 측정 및 개선 효과

SSR 적용 후 다음과 같은 개선 효과를 확인할 수 있었습니다.

▫︎ 검색엔진 크롤링 향상

  • Google Search Console의 색인 생성 증가
  • 크롤링 오류 감소

▫︎ 페이지 성능 개선

기존 CSR 방식과 비교하여 LCP 지표에서 큰 차이가 있었습니다.

image.png

기존 CSR 방식) LCP: 654.93 ms

image.png

수정 SSR 방식) LCP: 182.55 ms

기존 하위 클라이언트 컴포넌트에서 각 데이터를 페칭하여 페이지에 적용했을 경우 LCP 지표가 654.93 ms로 확인되었습니다. 그러나 SSR을 적용한 이후에는 182.55 ms로 약 72% 개선한 수치를 보여주었습니다.

▫︎ LCP 지표 개선의 이유

LCP 지표에 이렇게 큰 차이가 발생하는 이유를 단계별로 확인해보겠습니다.

CSR의 렌더링 단계 (654.93ms)

1
2
3
4
5
6
7
8
1. 빈 HTML 다운로드
2. JavaScript 번들 다운로드
3. React 초기화
4. useQuery 실행
5. API 요청 및 대기
6. 데이터 수신
7. DOM 렌더링
8. 이미지 로드 시작

SSR의 렌더링 단계 (182.55ms)

1
2
3
4
1. 서버에서 데이터 페칭 (다른 단계와 병렬 처리)
2. 서버에서 HTML 생성
3. 완성된 HTML 다운로드 (이미지 URL 포함)
4. 이미지 로드 시작 (HTML 파싱과 동시에)
  • 네트워크 요청 최적화
    • CSR: HTML → JS → API (순차적)
    • SSR: HTML(데이터 포함) → 리소스 (병렬)
  • 렌더링 프로세스 최적화
    • CSR: JS 실행 → 데이터 페칭 → 렌더링
    • SSR: 서버에서 미리 렌더링 완료
  • 리소스 로딩 최적화
    • CSR: 데이터 수신 후 이미지 로드 시작
    • SSR: HTML 파싱과 동시에 이미지 로드

이 측정 결과는 SEO뿐만 아니라 성능 측면에서도 SSR이 매우 효과적인 선택이었음을 입증합니다.

▪︎ 마치며

SSR을 통한 SEO 최적화는 현대 웹 애플리케이션에서 필수적인 요소입니다. 특히 Next.js의 서버 컴포넌트를 활용하면 효과적으로 SSR을 구현할 수 있으며, 이는 검색 엔진 최적화뿐만 아니라 전반적인 사용자 경험 향상에도 큰 도움이 됩니다.

우리 프로젝트에서는 fetchQuery를 활용한 서버 사이드 데이터 페칭으로 완성도 높은 SSR을 구현했으며, 이는 SEO와 성능 모두에서 긍정적인 결과를 가져왔습니다. 앞으로도 지속적인 모니터링과 최적화를 통해 더 나은 사용자 경험을 제공할 계획입니다.