Next.js의 App Router는 종종 어렵다는 평가를 받습니다.
이는 React의 새로운 기능인 Server Components와 같은 Server First 패러다임 전환을 요구하고, 기본 캐시 동작이 초보자들에게 혼란을 줄 수 있기 때문입니다.
Server Components나 Server Actions와 같은 React의 새로운 기능은 초보자를 위한 에러 힌트 및 수정을 돕는 설계가 되어 있으며, 많은 문서와 기사가 공개되어 있습니다.
이러한 점은 hooks가 등장했을 때처럼 시간이 지나면 점차 이해가 확산될 것이라 생각합니다.
하지만 캐시에 대해서는 여러 층으로 나뉘어져 적극적으로 캐시되며, "의도치 않은 캐시 상태"가 에러 없이 동작하기 때문에 초보자들에게는 Next.js의 캐시가 어려운 부분이 됩니다.
특히 클라이언트 사이드 캐시인 Router Cache의 복잡성과 문제점에 대해 이전에 글을 쓴 적이 있습니다.
그 당시에는 Router Cache가 최소 30초 동안 유지되는 것이 문제였으나, 그 후 experimental.staleTime이 도입되어 유효기간을 설정할 수 있게 되어 상황이 크게 개선되었습니다.
그리고 이제 v15에서 Router Cache와 Data Cache의 기본 설정이 변경된다는 발표가 있었습니다.
이는 매우 중요한 변경이라고 생각합니다.
이번 글에서는 v15에서 이루어지는 캐시 관련 파괴적 변경 사항과 그 배경, PPR(Partial Prerendering)과의 관계에 대해 설명하겠습니다.
v15의 파괴적 변경 사항 개요
Next.js 코어 팀 멤버인 Jimmy Lai에 의해, v15에서 변경될 내용이 발표되었습니다.
- 기본적으로 fetch 캐시 사용 중지 ✅
- 기본적으로 클라이언트 캐시 사용 중지 ✅
- 기본적으로 정적 GET 라우트 사용 중지 ✅
이로 인해 Data Cache와 Router Cache가 기본적으로 비활성화됩니다.
그 외에도 다음과 같은 기능이 추가 발표되었습니다.
- 인크리멘탈 PPR(Partial Prerendering) 마이그레이션 지원
- next/after, 우리만의 waitUntil 버전
- 실험적 React Compiler 지원
이 트윗 후 며칠 뒤, 이러한 변경 사항을 설명하는 v15 발표 기사가 공개되었습니다.
업그레이드 가이드는 이 글 작성 시점에는 공식 문서에 아직 공개되지 않았지만, 리포지토리에서는 확인할 수 있었습니다.
캐시 설정의 파괴적 변경
앞서 언급했듯이, v15에서는 Data Cache와 Router Cache가 기본적으로 비활성화됩니다.
간단히 정리하자면, Data Cache는 서버 측 데이터 접근 시 유지되는 데이터 캐시이며, Router Cache는 클라이언트 측에 유지되는 RSC Payload의 캐시입니다.
Data Cache의 비활성화
v14 이전에는 fetch를 사용한 데이터 조회가 기본적으로 무기한 캐시되었습니다.
이는 Next.js가 확장한 fetch 옵션인 cache나 next.revalidate로 변경이 가능했습니다.
// fetch 시 `cache: 'no-store'`를 지정하여 opt-out
fetch('https://...', { cache: 'no-store' })
// fetch 시 `next: { revalidate: 0 }`를 지정하여 opt-out
fetch('https://...', { next: { revalidate: 0 } })
// fetch 시 `next: { revalidate: 3600 }`를 지정하여 유효기간 설정
fetch('https://...', { next: { revalidate: 3600 } })
v15 이후로는 Data Cache가 기본적으로 비활성화되므로, 위 방법으로 Data Cache를 opt-out할 필요가 없어졌습니다.
opt-in하려면 다음과 같이 구현해야 합니다.
// v14 이전과 동일하게 무기한 캐시를 opt-in
fetch('https://...', { cache: 'force-store' })
// fetch 시 `next: { revalidate: 3600 }`를 지정하여 유효기간 설정
fetch('https://...', { next: { revalidate: 3600 } })
Route Segment Config의 fetchCache를 설정하면 fetch 옵션의 기본값을 { cache: 'force-store' }
로 설정할 수 있습니다.
이는 고급 옵션이므로 신중하게 사용해야 합니다.
Router Cache의 비활성화
Router Cache는 기본적으로 비활성화됩니다.
페이지나 레이아웃에 대해 기본적으로 무효화되며, 이는 experimental.staleTimes
를 사용하여 설정할 수 있습니다.
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30, // 기본값: 0
static: 180, // 기본값: 300
},
},
}
module.exports = nextConfig
참고로, 브라우저 백/포워드 시에는 유효기간과 상관없이 Router Cache가 사용됩니다.
왜 이 시점에서 변경되었을까?
이러한 변경은 기본적으로 캐시의 복잡성을 줄이기 위한 좋은 파괴적 변경이라고 생각합니다.
그러나 이러한 변경이 왜 지금 이루어졌는지에 대해서는 Jimmy Lai의 트윗에서 설명하고 있습니다.
요약하면, 다음과 같은 이유가 있습니다.
- 2023년 11월 기준으로 캐시 기본 설정을 변경하려고 했습니다.
- 그러나 이 변경을 위해서는 트레이드오프를 정확히 판단할 필요가 있었습니다.
- 올해의 주요 초점은 PPR의 완성이었으며, PPR은 캐시에 의존하고 있었습니다.
- v15 시점에서는 PPR의 설계가 논란의 여지 없이 진행되었기 때문에, 캐시 기본 설정을 변경할 수 있었습니다.
PPR(Partial Prerendering)은 동적인 fetch가 있더라도 정적화할 수 있게 되었으므로, 기본적으로 Data Cache를 활성화할 동기가 없어졌습니다.
기본 설정에서는 데이터 단위의 캐시 대신 html이나 RSC Payload 단위의 캐시가 확대되었습니다.
v15 이후 Next.js의 설계 사상
Next.js v15 이후에는 페이지 단위의 정적/동적 개념이 아니라, 페이지나 Suspense에 의해 구분된 경계마다 정적/동적을 결정할 수 있게 됩니다.
개발자는 "필요한 부분만 동적으로" 처리할 수 있어, 렌더링 설계가 더 단순해지고 이해하기 쉬워질 것입니다.
요약
Next.js는 정기적으로 큰 개념의 추가와 업데이트가 이루어집니다.
"진화가 너무 빠르다"는 평가도 있지만, 이러한 진화는 사용자 경험을 향상시키기 위한 것입니다.
PPR(Partial Prerendering)은 새로운 개념이며, 이를 이해하고 사용하는 데 학습 비용이 들겠지만, 렌더링 프로세스의 이해와 사용자 경험 모두를 개선할 수 있는 변화라고 생각합니다.
PPR(Partial Prerendering)이 안정화되어 사용할 수 있는 날이 빨리 오기를 기대합니다.
'Javascript' 카테고리의 다른 글
Next.js와 PPR: 프리렌더링의 신시대와 SSR/SSG 논쟁의 종결 (1) | 2024.06.10 |
---|---|
2024년에 Remix 앱을 위한 최적의 호스팅 옵션 가이드 (0) | 2024.06.06 |
자바스크립트 배열 완전 정복: 희소 배열부터 다양한 메서드 활용까지 (0) | 2024.05.17 |
TypeScript 고급 타입 마스터하기 - 객체 키 추출부터 infer 활용까지 (1) | 2024.05.15 |
TypeScript의 효율적인 타입 관리 - any 없이 타입 정의, 타입 파생 및 제네릭 마스터하기 (1) | 2024.05.15 |