dynamicIO를 통해 Next.js가 요청 데이터 접근을 감지하는 데 사용하는 핵심 메커니즘 중 일부를 반복했습니다.redirect()와 notFound()와 같은 다른 API들처럼 작동할 것이라고 가정했으며, 이들은 오늘날에도 여전히 오류 던지기를 신호로 사용합니다. 문제는 기존 애플리케이션을 마이그레이션하는 개발자들이 예상치 못한 곳에서 오류가 던져지는 상황에서 발생했습니다.import { setTimeout } from "node:timers/promises"import { cookies } from "next/headers"async function getPosts() { for (let i = 0; i < 3; i++) { try { // Next.js 14에서는 사전 렌더링 중에 오류를 던졌습니다. const session = cookies().get("session") // ... } catch (err) { if (i === 2) { throw err } // 여기서는 fetch가 실패했을 때 타임아웃이 추가됩니다. await setTimeout(500 + i * 500) } }}export default async function Page() { const posts = await getPosts() // ...}async function checkAuthorization() { try { const session = cookies().get("session") // ... } catch (err) { throw new Error("AUTHORIZATION_CHECK_FAILED") }}unstable_rethrow(err) API를 도입하여 이 문제를 해결하려고 시도했습니다:import { unstable_rethrow } from "next/navigation"async function checkAuthorization() { try { const session = cookies().get("session") // ... } catch (err) { unstable_rethrow(err) throw new Error("AUTHORIZATION_CHECK_FAILED") }}try/catch 블록의 문제는 요청 데이터가 사용되고 있음을 Next.js에 알리기 위한 이러한 신호가 신뢰할 수 없을 것이며, 재시도 로직으로 인해 예상보다 긴 빌드 시간으로 이어질 수 있음을 의미했습니다.// 이전 - 오류 던지기를 포함한 동기식function cookies() { if (isPrerendering) { throw new PostponeError("Cannot access cookies during prerendering") } return getCookies()}// 이후 - Promise를 포함한 비동기식async function cookies() { if (isPrerendering) { // 절대 해결되지 않는 Promise 반환 return new Promise(() => {}) } return getCookies()}// Next.js 15 요청 APIawait cookies()await headers()await connection() // unstable_noStore() 대체import { prerender } from 'react-dom/static.edge'const controller = new AbortController()await { prelude, postponed } = new Promise((resolve, reject) => { let result setImmediate(() => { try { result = prerender(<App />, { signal: controller.signal }) resolve(result) } catch (err) { reject(err) } }) setImmediate(() => { controller.abort() resolve(result) })})// Next.js 캐시 API 사용async function getData() { 'use cache' const res = await fetch('...') return res.json()}// 또는 unstable_cache 포함const getData = unstable_cache(async () => { const res = await fetch('...') return res.json()})async function Page() { const data = await fetch('...') // 캐시 없음 return ( <Suspense fallback={<Skeleton />}> <Component data={data} /> </Suspense> )}async function Page() { const data = await getData() // 캐시됨 return <Component data={data} />}import { Suspense } from "react"import { cookies } from "next/headers"async function getCart() { const jar = await cookies() // 세션을 기반으로 장바구니 데이터 가져오기 return fetchCartData(jar.get("session"))}async function Cart() { const cart = await getCart() return <CartDisplay items={cart.items} />}export default function Page() { return ( <div> <Header /> {/* 정적 - 셸에 포함됨 */} <Suspense fallback={<CartSkeleton />}> <Cart /> {/* 동적 - 나중에 스트리밍됨 */} </Suspense> <ProductListing /> {/* 정적 - 셸에 포함됨 */} </div> )}Header와 ProductListing은 정적이며 초기 셸에 포함됩니다Cart는 쿠키에 접근하므로 동적입니다CartSkeleton은 정적 셸의 일부입니다// next.config.jsmodule.exports = { experimental: { ppr: true, dynamicIO: true }}dynamicIO 플래그는 Promise 기반 감지 메커니즘을 활성화합니다. 계획은 PPR이 안정화되면 결국 이 플래그를 제거하는 것입니다./products/[id]와 같은 동적 경로는 전체 페이지를 동적으로 강제합니다. PPR과 비동기 params를 사용하면:type Props = { params: Promise<{ id: string }>}export default function Page({ params }: Props) { return ( <Suspense fallback={<ProductDetailsSkeleton />}> <ProductDetails params={params} /> </Suspense> )}dynamicIO 플래그 요구 사항 제거아직 댓글이 없습니다.
첫 번째 댓글을 작성해보세요!

Dead Framework Theory
Inkyu Oh • Front-End

Directive와 플랫폼 경계
Inkyu Oh • Front-End

URL은 상태를 나타냅니다
Inkyu Oh • Front-End

플랫폼을 넘어서: Vercel이 설계하는 미래의 프로그래밍 언어
Inkyu Oh • Front-End