본문으로 건너뛰기

Next.js의 prefetch는 어떻게 동작하는가?

 · reading-time-plural · 

Next.js 에서 prefetch 를 사용하면 미리 데이터가 로드되어 페이지 로드 시간이 단축된다는데 꼭 Next.jsLink 컴포넌트가 아니면 달성이 불가능한 것인가? SSR 인 경우는 어떻게 되는가? 미리 불러오면 안 될 텐데? 와 같은 호기심이 발생했습니다. 어떻게 동작하는지 확인해 봅시다!

개요

Next.js 에서는 큰 문제가 없는 이상 <a> 보다는 <Link> Component를 사용하는 것이 더 나아 보입니다.

그런데 prefetch 에 대해서 아래의 의문이 생겼습니다.

  • Next.jsLink 컴포넌트가 아니면 달성이 불가능한 것인가?
  • SSR 인 경우는 어떻게 되는가? 미리 불러오면 안 될 텐데

궁금증을 해결하기 위해서 프로젝트를 만들어서 실험해 보았습니다.

실험한 프로젝트 코드는 parkgang/next.js-prefetch 에서 확인할 수 있습니다.

코드를 보고 실제로 어떻게 동작하는지, 여러 컨셉을 시도해볼 수 있습니다!

Insight

Prod 에서만 활성화 된다.

어쩐지 열심히 테스트해도 안되길래 뭐지 했는데 Prod 에서만 활성화된다고 합니다.

공식 문서 router.prefetch 에 작성되어 있습니다.

코드의 컨셉을 보면

  • 로그인 하는 페이지에 들어왔을 때 미리 Dashboard 경로의 정보를 prefetch 하고
  • 로그인 이 완료되면 빠르게 Dashboard 으로 넘어갈 수 있도록 하는 것입니다.
import { useCallback, useEffect } from "react";
import { useRouter } from "next/router";

export default function Login() {
const router = useRouter();
const handleSubmit = useCallback((e) => {
e.preventDefault();

fetch("/api/login", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify({
/* Form data */
}),
}).then((res) => {
// Do a fast client-side transition to the already prefetched dashboard page
if (res.ok) router.push("/dashboard");
});
}, []);

useEffect(() => {
// Prefetch the dashboard page
router.prefetch("/dashboard");
}, [router]);

return (
<form onSubmit={handleSubmit}>
{/* Form fields */}
<button type="submit">Login</button>
</form>
);
}

prefetch 라고 해서 SSR 이 미리 되는 것은 아니다. prefetch정적 자료 만 미리 불러오는 것이다.

prefetch정적 자료 만 미리 가져오며 prefetch 라고 해서 getServerSideProps 함수를 미리 수행하지 않는다고 합니다.

실험 결과 prefetchPageComponent 에서 미리 사용할 수 있는 형태로 JS 을 가공해 놓는 것을 볼 수 있었습니다.

import SlowImages from "@/components/SlowImages";
import type { GetServerSideProps } from "next";

type PageProps = {
ssrFinalizedDisplayDate: string;
};

export const getServerSideProps: GetServerSideProps<PageProps> = async () => {
// prefetch과 관련 없이 SSR이 잘 이뤄지는지 보기위해서 의도적으로 기다립니다.
await new Promise((resolve) => {
setTimeout(() => {
resolve(null);
}, 3000);
});

return {
props: {
ssrFinalizedDisplayDate: new Date().toLocaleString("ko-KR"),
},
};
};

export default function SsrPage({
ssrFinalizedDisplayDate: nowDateIso,
}: PageProps) {
return (
<div>
<h1>SSR Page!</h1>
<p>
SSR이 완료된 시점은 <strong>{nowDateIso}</strong> 입니다.
</p>
<SlowImages />
</div>
);
}

Image 까지는 미리 불러오지 않는다.

실험 시 image 도 미리 불러오는지 궁금해서 확인해 보았는데 그렇지 않았습니다.

Next.js 측에서 Image 의 경우 Image 컴포넌트로 최적화하는 방법으로 사용하라는 것이면서도 사실 Image 는 미리 불러와서 이득이 없다고 판단한 거 같습니다.

페이지에 이미지가 몇 개일 지 모르는데 그걸 어떤 기준으로 모두 확보하느냐, 그래서 화면에 표시되는 이미지만 미리 처리한다 이런 컨셉 같습니다.

실험한 프로젝트에서 보면 Next.jsImage 컴포넌트를 사용하면 Image 를 불러오는 이미지 URL이 http://localhost:3000/_next/image?url= 형식으로 바뀌면서 알아서 캐시 되더군요.

prefetch 시 미리 불러오는 데이터 형식은?

아래와 같습니다.

SSG 는 아래와 같은 느낌으로 불러오더군요.

import SlowImages from "@/components/SlowImages";

export default function SsgPage() {
return (
<div>
<h1>SSG Page!</h1>
<p>ssg 페이지 입니다.</p>
<SlowImages />
</div>
);
}

결론

  • prefetch 으로 미리 불러오는 데이터는 CSS , JS 이다.
    • image 의 경우 미리 불러오지 않는다.
    • CSS 도 미리 불러오는지까지는 확인하지 못함
  • prefetch 되었다고 해서 SSR 안 되는 것이 아니다.
    • getServerSidePropsprefetch 단계에서 수행되지 않는다.

마무리

이렇게 Next.jsprefetch 에서 헷갈릴 만한 것들을 알아보았습니다.

단순하게 미리 불러온다는 라는 개념보다 어떤 경우, 어떻게 불러오는지 알 수 있어 더 섬세하게 사용할 수 있을 거 같습니다.

읽어주셔서 감사합니다.


parkgang
태그 🏷