프론트엔드 뉴스레터
#05
이번 이슈 한눈에
- Next.js 16.4, 정적 렌더링 보장과 prefetch 범위 제어
- React Compiler 실험에서 확인한 inlining과 캐시의 관계
- vlt.io, 설치에 필요한 필드만 보내 메타데이터 전송량 축소
- 01
nextjs.org
Next.js 16.4, 정적 렌더링을 보장하고 prefetch 범위를 나눕니다
원문 읽기 ↗Next.js 16.4부터
create-next-app으로 만드는 새 앱은 Cache Components가 기본으로 켜져요.'use cache'로 캐시할 부분을 명시하고, 요청마다 렌더링할 부분과 한 페이지에서 조합합니다.이번 버전의
ensureStatic = 'navigation'은 해당 경로의 서버 출력에 동적 콘텐츠가 들어오면 빌드를 실패시켜요. Partial Prefetching을 켜면await navigation()아래의 runtime 작업은 prefetch에서 실행하지 않고 실제 페이지 이동까지 미룹니다. 캐시 함수를 호출하기 전에 두고, 해당 컴포넌트를Suspense로 감싸야 해요.'use cache'함수 내부에서는 호출할 수 없으며, 정적 prerender에 포함된 콘텐츠는 static prefetch에도 나타날 수 있습니다.- 기존 앱에서 이 모델을 쓰려면 아래 두 설정을 켜야 해요. Next.js 17에서는 기본 모델이 될 예정입니다.
ensureStatic은'shell'·'prefetch'도 지원하며, layout에 지정하면 하위 페이지에 같은 조건을 적용합니다.
import type { NextConfig } from 'next'; const nextConfig: NextConfig = { cacheComponents: true, partialPrefetching: true, }; export default nextConfig; - 02
jimmyhmiller.com
React Compiler에 inlining만 더했더니 오히려 느려졌어요
원문 읽기 ↗Jimmy Miller의 9월 실험에서는 React Compiler에 컴포넌트 inlining을 추가하자, 행을 하나씩 2,000개 넣는 작업이 오히려 느려졌어요. 행마다 있던 캐시가 사라져, 변경되지 않은 행의 JSX도 다시 계산한 겁니다.
정적·동적 부분을 나누고 바뀐 상태에 해당하는 DOM만 갱신하는 blocks 최적화를 함께 적용하자 결과가 개선됐습니다. 행별 캐시를 다시 추가하는 실험까지 이어지며, 컴포넌트 경계를 없애는 작업과 memoization이 어떻게 영향을 주고받는지 보여줘요.
- 공식 React Compiler에 추가된 기능이 아니라 학습용 prototype입니다. 특정 microbenchmark의 결과이며, 실제 앱에 적용할 때는 메모리 사용 같은 다른 비용도 따져야 해요.
- 03
vlt.io
vlt.io, 설치에 쓰지 않는 메타데이터를 응답에서 덜어냈어요
원문 읽기 ↗vlt.io는 패키지의 모든 버전 정보를 담은 메타데이터(packument)에서 설치에 필요한 필드만 기본으로 보내요.
exports같은 실행 시점의 정보는 다운로드한 tarball 안의package.json에서 읽으므로, 레지스트리 응답에서 빼도 설치된 패키지에는 남습니다.npm의 축약 응답에 없는
time·libc는 유지해요. 덕분에 pnpm이minimumReleaseAge를 확인하려고 전체 메타데이터를 다시 받는 일을 피했고, 압축이 잘 안 되는dist.signatures·dist.shasum도 제거하면서 tarball 검증에 쓰는dist.integrity는 남겼습니다.- 다운로드 상위 1,000개 패키지의 축약 메타데이터는 npmjs.org 대비 전송량이 74.9% 줄었어요. tarball은 제외한 수치이며, 설치 시간 개선에는 다른 최적화도 함께 반영됐습니다.
- 04
github.com
Redux Toolkit 2.13, refetch 중 isSuccess가 잘못 바뀌던 문제를 고쳤어요
원문 읽기 ↗9월 29일 나온 Redux Toolkit 2.13은 오류 뒤 refetch하는 동안, 무관한 리렌더링으로
isSuccess가false에서true로 바뀌던 문제를 고쳤어요.useQueryState가 매 렌더링마다 만들던 selector를 memoize하고, 렌더링 중 store를 직접 읽던 코드도 제거했습니다. 이 경우useQuery의isSuccess는 이제false를 유지합니다.- TypeScript 7을 공식 지원하며, 테스트하는 TypeScript 버전은 5.6 이상으로 바뀌었어요. 이전 버전에서도 동작할 수 있지만 더는 검증하지 않습니다.