풀 라우트 캐시(full route cache)
Next.js 서버에서 빌드타임에 특정 페이지의 렌더링 결과를 캐싱하는 기능이다
순서를 간단하게 그림으로 표현하면,
이러한 방식으로 flow가 있으며, 기존 page router의 SSG 방식과 유사하다.
static page
만 풀 라우트 캐시가 적용됨!
다이나믹페이지와 스태틱페이지 구분하는 방식(서버 컴포넌트만 해당되고, 클라이언트 컴포넌트는 영향없음):
특정 페이지가 접속요청을 받을때마다 매번 변화가 생기거나 데이터가 달라질 경우
캐싱되지 않은 데이터패칭을 사용할 경우 fetch(api, { cache: "no-store" })
동적 함수를 사용하는 컴포넌트가 있을 때(쿠키, 헤더, 쿼리스트링)
import { cookies, headers } from "next/headers";
const cookieStore = cookies();
const headersList = headers();
const auth = headersList.get("authorization")
데이터 캐시를 사용하지 않을 경우에도 다이나믹 페이지이다. 동적페이지로 설정이 안되면 모두 static 페이지이며, 동적함수가 없고, 데이터 캐시가 있을 경우 static 페이지이다.
full route cache도 revalidate기능을 사용할 수 있다.
넥스트 프로젝트를 빌드할 때, 서치바와 같은 클라이언트 컴포넌트를 실행할 때, useSearchParams
같은 빌드 타임에는 절대로 값을 알 수 없는 쿼리스트링 같은 값을 불러오는 훅을 실행할 수가 없기 때문에 빌드중에 문제가 발생한다.
해결방법은 서치바 "use client"
컴포넌트를 오직 클라이언트 측에서만 실행이 되도록, 사전 렌더링과정에서 배제시키도록 설정하면 된다. 그 방법은 react의 Suspense를 사용해서 넥스트의 사전 렌더링은 배제되고 클라이언트측에서만 렌더링 되도록한다.
Suspense
의 역할은 뭐냐? 이 단어의 의미는 미결, 미완성의 의미이고
이렇게 서스펜스 안에 컴포넌트를 넣어주게 되면,
<Suspense fallback={<div>Loading...</div>}>
<Searchbar />
</Suspense>
넥스트에서 서스펜스로 감싸준 부분은 렌더링을 미완성으로 fallback
으로 대체된 코드를 렌더링하게 된다. 완성되는 시점은 서스펜스 안의 컴포넌트의 비동기 작업이 완료될때까지 이다.
그리고 풀 라우트 캐시 방식으로 하는것이 페이지 응답에 있어 빠를 것이기 때문에 최대한 만든다 하면, fetch의 경우 { cache: "force-cache" }
기능을 넣어 정적페이지로 만들수 있다.
기본적으로 동적함수를 사용하는 페이지는 static 페이지로 전환하기가 어렵다. 또한 풀 라우트 캐시를 적용하기 어렵다.
이럼에도 최대한 최적화를 할 수 있는 방법이 있는데, 데이터 캐시만 따로 적용하는 방법이 있다.
이 방법은 fetch 메서드의 결과를 데이터 캐시에 보관할 수 있다.
const response = await fetch("api", { cache: "force-cache" })
이렇게 되면 만약 검색결과에 대해 똑같은 요청을 보냈을 때 데이터 fetch에 대한 데이터가 캐싱이 되어 조금 더 빠른 페이지를 응답할 수 있게 된다. (페이지는 매번 요청시 재생성)
또는 특정 상품에대한 동적 페이지 /food/[id]
의 경우에는 이런 동적 경로를 갖는 페이지를 static 페이지로 빌드타임에 생성되도록 설정하려면, Next.js 서버가 북페이지에 어떤 경로가 존재할 수 있는지, 파라미터가 있는지 먼저 알려주면 가능하다.
export function generateStaticParams() {
return [{ id: "1" }, { id: "2" }, { id: "3" }]
}
이런식으로 작성하면, 빌드타임에 이 파라미터를 기반으로한 정적인 페이지를 만들게 된다.
추가적으로 고정된 1,2,3 이외의 페이지는 동적 파라미터를 허용하지 않게 하려면
export const dynamicParams = false;
이렇게 설정하면 1,2,3 이외에는 404 페이지로 이동하게 된다.
주의할 점은, 파라미터를 전달하는 값은 반드시 문자열
이어야하고,
페이지 내부에서 데이터 캐싱이 설정되지 않은
data fetch가 일어날 경우에도 static 페이지로 적용된다는 점이다.
getStaticPaths
의 app router 버전이라고 할 수 있다.
여기서 쿼리파라미터로 설정하지 않은 값들도 렌더링이 되긴 한다. 이런경우는 정적으로 만들어진 페이지가 없는 경우에는 실시간으로 Next.js 서버에서 동적으로 static 페이지를 만들게 되기 때문이다.
추가적으로 잘못된 페이지로 404페이지로 이동시키고 싶다면,
import { notFound } from "next/navigation";
notFound
메서드를 사용하여
if(response.status === 404) { notFound() }
이런식으로 이동시키게 할 수 있다.
참고로, 404페이지는 app 폴더에서 not-found.tsx 파일을 만들어서 페이지를 구성할 수 있다.
특정 페이지에 존재하는 모든 컴포넌트들이 혹시나 동적인 함수를 사용하지는 않는지 또는 캐싱되지 않는 데이터 패칭을 하고 있지는 않은지 매번 확인했어야 하는데, 이러한 작업이 페이지나 컴포넌트가 많아진다면 관리가 어려워질 것이다.
이러한 문제를 해결하기 위해 페이지를 스태틱 또는 다이나믹 페이지로 설정한다던지 또는 페이지의 revaildate time
을 강제로 설정한다던지 하는 페이지의 동작을 강제로 설정할 수 있는 라우트 세그먼트 옵션
이라는 기능이 있다.
특정 페이지에 캐싱이나 리벨리데이트 등의 동작을 우리가 직접 강제로 동작하도록 설정할 수있는 옵션을 뜻한다.
페이지 상단에 설정할 수 있다.
export const dynamic = "";
// 1. auto : 기본값, 아무것도 강제하지 않음
// 2. force-dynamic : 강제로 다이나믹 페이지로 설정
// 3. force-static : 강제로 스태틱 페이지로 설정
// 4. error : 페이지를 강제로 스태틱 페이지 설정 (설정하면 안되는 이유 -> 빌드할때 에러 발생시킴)
여기서 동적 함수가 사용된 경우, force-static
으로 설정한다면
모두 undefined
로 값이 설정이 된다. 또한 데이터 fetch의 캐싱도 강제로 설정이 된다.
이러한 경우, 문제가 발생할 수 있는경우는 동적페이지로 구성되어야하는 검색 컴포넌트 같은 경우는 강제로 동적페이지로 구성할 경우 동적함수(쿼리파라미터)가 undefined
이기 때문에 가져올 수 없는 것이다.
이때는 error 옵션을 사용하면 빌드할때 에러를 발생시켜 이러한 부작용을 커버할 수 있긴하다.
하지만, 사실 이러한 기능을 권장하지는 않는다. 이 페이지 내부에 컴포넌트 단위로 동적, 정적 컴포넌트로 설정하는데 페이지 자체를 강제로 동적, 정적으로 바꿔버리면 특정 컴포넌트들이 정상적으로 동작하지 않을 가능성이 있기 때문이다. 검색창 처럼 동적 컴포넌트가 정적페이지를 강제했을 경우에 문제가 발생할 수 있기 때문이다.
브라우저에 저장되는 캐시이며 페이지 이동을 효율적으로 진행하기 위해 페이지의 일부 데이터를 보관하는 방법이다.
기존 알고있던 페이지 렌더링 동작의 그림이다.
이 상황에서라면, 렌더링이 불필요하게 일어나는 경우가 있다.
~/
영역과 ~/search
페이지 영역에서 중복된 레이아웃을 요청하는 경우가 있다.
레이아웃이 서버 컴포넌트라면 서치바, 루트 레이아웃 컴포넌트가 매번 요청이 일어나게 되는 것이다.
이러한 비효율을 개선하기 위해 next.js는 클라이언트단에 클라이언트 라우터 캐시
라는 것을 추가했다.
한번 접속한 페이지의 레이아웃들을 따로 저장하여 다른 페이지로 이동시 중복된 레이아웃을 불러오지 않도록 하는 기능인 것이다.
기본적으로 클라이언트 라우터 캐시는 새로고침을 하면 사라지게 된다.