π Next.js 15 RC (opens in a new tab)
ποΈ λ²μ λ μ§: 2024.07.30
π§ λ²μν ν¬λ£¨: λ¬κΈ°(λ°μ μ°)
Next.js 15 RC
Next.js 15 Release Candidate (RC)κ° μ΄μ μ¬μ©ν μ μμ΅λλ€. μ΄ μ΄κΈ° λ²μ μ ν΅ν΄ λ€κ°μ€λ μμ ν λ¦΄λ¦¬μ€ μ μ μ΅μ κΈ°λ₯μ ν μ€νΈν μ μμ΅λλ€.
- React: React 19 RC μ§μ, React μ»΄νμΌλ¬(μ€νμ ), νμ΄λλ μ΄μ μ€λ₯ κ°μ
- μΊμ±: fetch μμ², GET λΌμ°νΈ νΈλ€λ¬, ν΄λΌμ΄μΈνΈ νμμ΄ κΈ°λ³Έμ μΌλ‘ μΊμλμ§ μμ
- λΆλΆ ν리λ λλ§(μ€ν): μ μ§μ μ±νμ μν μλ‘μ΄ λ μ΄μμ λ° νμ΄μ§ κ΅¬μ± μ΅μ
- next/after(μ€ν): μλ΅μ΄ μ€νΈλ¦¬λ°λ ν μ½λλ₯Ό μ€ννλ μλ‘μ΄ API
- create-next-app: λ‘컬 κ°λ°μμ Turbopackμ νμ±ννλ μ νλκ·Έμ μ λ°μ΄νΈλ λμμΈ
- μΈλΆ ν¨ν€μ§ λ²λ€λ§(μμ ): App λ° Pages λΌμ°ν°λ₯Ό μν μλ‘μ΄ κ΅¬μ± μ΅μ
μ€λ Next.js 15 RCλ₯Ό μλν΄λ³΄μΈμ:
npm install next@rc react@rc react-dom@rc
μ°Έκ³ : Next.js 15 RC λ¬Έμλ Next.js 15 GAκ° λ°νλ λκΉμ§ rc.nextjs.org/docsμμ λ³Ό μ μμ΅λλ€.
React 19 RC
Next.js μ± λΌμ°ν°λ νλ μμν¬μ© React canary channel
μ κΈ°λ°μΌλ‘ ꡬμΆλμ΄, κ°λ°μλ€μ΄ React 19 μΆμ μ μ μ΄λ¬ν μλ‘μ΄ React APIλ₯Ό μ¬μ©νκ³ νΌλλ°±μ μ 곡ν μ μλλ‘ ν©λλ€.
Next.js 15 RCλ μ΄μ React 19 RCλ₯Ό μ§μνλ©°, μ΄λ Actionsμ κ°μ ν΄λΌμ΄μΈνΈ λ° μλ²μ μλ‘μ΄ κΈ°λ₯μ ν¬ν¨ν©λλ€.
μμΈν λ΄μ©μ μμλ³΄λ €λ©΄ Next.js 15 μ
κ·Έλ μ΄λ κ°μ΄λ, React 19 μ
κ·Έλ μ΄λ κ°μ΄λ, κ·Έλ¦¬κ³ React Conf Keynote
λ₯Ό μ°Έμ‘°νμΈμ.
μ°Έκ³ : μΌλΆ νμ¬ λΌμ΄λΈλ¬λ¦¬λ μμ§ React 19μ νΈνλμ§ μμ μ μμ΅λλ€.
React μ»΄νμΌλ¬(μ€ν)
React μ»΄νμΌλ¬λ Metaμ React νμ΄ λ§λ μλ‘μ΄ μ€νμ μ»΄νμΌλ¬μ λλ€. μ΄ μ»΄νμΌλ¬λ JavaScriptμ μλ―Έμ Reactμ κ·μΉμ κΉμ΄ μ΄ν΄νμ¬ μ½λλ₯Ό μλμΌλ‘ μ΅μ νν μ μμ΅λλ€. μ΄ μ»΄νμΌλ¬λ useMemoμ useCallbackκ³Ό κ°μ APIλ₯Ό ν΅ν΄ κ°λ°μκ° ν΄μΌ ν μλ λ©λͺ¨νλ₯Ό μ€μ¬ μ½λκ° λ κ°λ¨νκ³ μ μ§ κ΄λ¦¬κ° μ¬μμ§λ©° μ€λ₯κ° μ μ΄μ§κ² ν©λλ€.
Next.js 15μμλ React μ»΄νμΌλ¬μ λν μ§μμ μΆκ°νμ΅λλ€.
babel-plugin-react-compilerλ₯Ό μ€μΉνμΈμ:
ν°λ―Έλ
npm install babel-plugin-react-compiler
κ·Έλ° λ€μ next.config.jsμ experimental.reactCompiler μ΅μ μ μΆκ°νμΈμ:
next.config.ts
const nextConfig = {
experimental: {
reactCompiler: true,
},
};
module.exports = nextConfig;
μ νμ μΌλ‘, μ»΄νμΌλ¬λ₯Ό "opt-in" λͺ¨λλ‘ μ€ννλλ‘ κ΅¬μ±ν μ μμ΅λλ€:
next.config.ts
typescriptμ½λ 볡μ¬
const nextConfig = {
experimental: {
reactCompiler: {
compilationMode: 'annotation',
},
},
};
module.exports = nextConfig;
μ°Έκ³ : React μ»΄νμΌλ¬λ νμ¬ Babel νλ¬κ·ΈμΈμ ν΅ν΄ Next.jsμμλ§ μ¬μ©ν μ μμΌλ©°, μ΄λ λΉλ μκ°μ λλ¦¬κ² ν μ μμ΅λλ€.
React μ»΄νμΌλ¬μ μ¬μ© κ°λ₯ν Next.js κ΅¬μ± μ΅μ μ λν΄ μμΈν μμ보μΈμ.
Hydration μ€λ₯ κ°μ
Next.js 14.1μμλ μ€λ₯ λ©μμ§μ νμ΄λλ μ΄μ μ€λ₯κ° κ°μ λμμ΅λλ€. Next.js 15λ μ¬κΈ°μ λν΄ ν₯μλ νμ΄λλ μ΄μ μ€λ₯ λ·°λ₯Ό μΆκ°ν©λλ€. μ΄μ νμ΄λλ μ΄μ μ€λ₯λ μ€λ₯μ μμ€ μ½λμ λ¬Έμ ν΄κ²°μ λν μ μμ νμν©λλ€.
μλ₯Ό λ€μ΄, λ€μμ Next.js 14.1μ μ΄μ νμ΄λλ μ΄μ μ€λ₯ λ©μμ§μ λλ€:
νμ΄λλ μ΄μ μ€λ₯ λ©μμ§ in Next.js 14.1
Next.js 15 RCμμλ μ΄λ₯Ό λ€μκ³Ό κ°μ΄ κ°μ νμ΅λλ€:
νμ΄λλ μ΄μ μ€λ₯ λ©μμ§ improved in Next.js 15 RC
μΊμ± μ λ°μ΄νΈ
Next.js μ± λΌμ°ν°λ μκ²¬μ΄ λ°μλ μΊμ± κΈ°λ³Έκ°μΌλ‘ μΆμλμμ΅λλ€. μ΄λ κΈ°λ³Έμ μΌλ‘ κ°μ₯ μ±λ₯μ΄ μ’μ μ΅μ μ μ 곡νλ©° νμν κ²½μ° μ΅νΈμμν μ μλ κΈ°λ₯μ μ 곡ν©λλ€.
κ·νμ νΌλλ°±μ κΈ°λ°μΌλ‘ μ°λ¦¬λ μΊμ± ν΄λ¦¬μ€ν±κ³Ό κ·Έκ²μ΄ λΆλΆ ν리λ λλ§(PPR) λ° fetchλ₯Ό μ¬μ©νλ νμ¬ λΌμ΄λΈλ¬λ¦¬μ μ΄λ»κ² μνΈ μμ©ν μ§λ₯Ό μ¬νκ°νμ΅λλ€.
Next.js 15μμλ fetch μμ², GET λΌμ°νΈ νΈλ€λ¬ λ° ν΄λΌμ΄μΈνΈ λΌμ°ν° μΊμμ λν μΊμ± κΈ°λ³Έκ°μ μΊμμμ κΈ°λ³Έμ μΌλ‘ μ μΈνλλ‘ λ³κ²½ν©λλ€. μ΄μ λμμ μ μ§νλ €λ©΄ κ³μν΄μ μΊμ±μ μ΅νΈμΈν μ μμ΅λλ€.
μ°λ¦¬λ μμΌλ‘ λͺ λ¬ λμ Next.jsμμ μΊμ±μ κ³μ κ°μ ν κ²μ΄λ©° Next.js 15 GA λ°νμμ λ λ§μ μΈλΆ μ 보λ₯Ό 곡μ ν κ²μ λλ€.
fetch μμ²μ λ μ΄μ κΈ°λ³Έμ μΌλ‘ μΊμλμ§ μμ
Next.jsλ Web fetch API μΊμ μ΅μ μ μ¬μ©νμ¬ μλ² μ¬μ΄λ fetch μμ²μ΄ νλ μμν¬μ μ§μμ μΈ HTTP μΊμμ μ΄λ»κ² μνΈ μμ©ν μ§λ₯Ό ꡬμ±ν©λλ€:
fetch("https://...", { cache: "force-cache" | "no-store" });
- no-store: 맀 μμ²λ§λ€ μ격 μλ²μμ 리μμ€λ₯Ό κ°μ Έμ€λ©° μΊμλ₯Ό μ λ°μ΄νΈνμ§ μμ
- force-cache: μΊμμ 리μμ€κ° μμΌλ©΄ μΊμμμ, κ·Έλ μ§ μμΌλ©΄ μ격 μλ²μμ 리μμ€λ₯Ό κ°μ Έμ€κ³ μΊμλ₯Ό μ λ°μ΄νΈ
Next.js 14μμλ dynamic ν¨μ λλ dynamic κ΅¬μ± μ΅μ μ΄ μ¬μ©λμ§ μλ ν κΈ°λ³Έμ μΌλ‘ force-cacheκ° μ¬μ©λμμ΅λλ€.
Next.js 15μμλ μΊμ μ΅μ μ΄ μ 곡λμ§ μμΌλ©΄ κΈ°λ³Έμ μΌλ‘ no-storeκ° μ¬μ©λ©λλ€. μ΄λ fetch μμ²μ΄ κΈ°λ³Έμ μΌλ‘ μΊμλμ§ μμμ μλ―Έν©λλ€.
μ¬μ ν fetch μμ²μ λν΄ μΊμ±μ μ΅νΈμΈν μ μμ΅λλ€:
- λ¨μΌ fetch νΈμΆμμ μΊμ μ΅μ μ force-cacheλ‘ μ€μ
- λ¨μΌ λΌμ°νΈμ λν΄ dynamic λΌμ°νΈ κ΅¬μ± μ΅μ μ 'force-static'μΌλ‘ μ€μ
- λ μ΄μμ λλ νμ΄μ§μ λͺ¨λ fetch μμ²μ κΈ°λ³Έμ μΌλ‘ force-cacheλ₯Ό μ¬μ©νλλ‘ fetchCache λΌμ°νΈ κ΅¬μ± μ΅μ μ 'default-cache'λ‘ μ€μ νμ¬ μΊμ μ΅μ μ λͺ μμ μΌλ‘ μ§μ νμ§ μμ κ²½μ° λͺ¨λ 무μ
- GET λΌμ°νΈ νΈλ€λ¬λ λ μ΄μ κΈ°λ³Έμ μΌλ‘ μΊμλμ§ μμ
Next 14μμλ dynamic ν¨μ λλ dynamic κ΅¬μ± μ΅μ μ μ¬μ©νμ§ μλ ν GET HTTP λ©μλλ₯Ό μ¬μ©νλ λΌμ°νΈ νΈλ€λ¬κ° κΈ°λ³Έμ μΌλ‘ μΊμλμμ΅λλ€. Next.js 15μμλ GET ν¨μκ° κΈ°λ³Έμ μΌλ‘ μΊμλμ§ μμ΅λλ€.
μ¬μ ν static λΌμ°νΈ κ΅¬μ± μ΅μ μ μ¬μ©νμ¬ μΊμ±μ μ΅νΈμΈν μ μμ΅λλ€(ex. export dynamic = 'force-static').
sitemap.ts, opengraph-image.tsx, icon.tsxμ κ°μ νΉμ λΌμ°νΈ νΈλ€λ¬ λ° κΈ°ν λ©νλ°μ΄ν° νμΌμ dynamic ν¨μ λλ dynamic κ΅¬μ± μ΅μ μ μ¬μ©νμ§ μλ ν κΈ°λ³Έμ μΌλ‘ μ μ μνλ‘ μ μ§λ©λλ€.
ν΄λΌμ΄μΈνΈ λΌμ°ν° μΊμλ κΈ°λ³Έμ μΌλ‘ νμ΄μ§ κ΅¬μ± μμλ₯Ό μΊμνμ§ μμ
Next.js 14.2.0μμλ λΌμ°ν° μΊμμ μ¬μ©μ μ μ ꡬμ±μ νμ©νκΈ° μν΄ μ€νμ staleTimes νλκ·Έλ₯Ό λμ νμ΅λλ€.
Next.js 15μμλ μ΄ νλκ·Έκ° μ¬μ ν μ κ·Ό κ°λ₯νμ§λ§ νμ΄μ§ μΈκ·Έλ¨ΌνΈμ λν staleTimeμ 0μΌλ‘ μ€μ νμ¬ κΈ°λ³Έ λμμ λ³κ²½νκ³ μμ΅λλ€. μ΄λ μ±μ νμν λ ν΄λΌμ΄μΈνΈκ° νμμ μΌλΆλ‘ νμ±νλλ νμ΄μ§ κ΅¬μ± μμμμ νμ μ΅μ λ°μ΄ν°λ₯Ό λ°μν¨μ μλ―Έν©λλ€. κ·Έλ¬λ μ€μν λμμ μ¬μ ν λ³κ²½λμ§ μμ΅λλ€:
곡μ λ μ΄μμ λ°μ΄ν°λ λΆλΆ λ λλ§μ κ³μ μ§μνκΈ° μν΄ μλ²μμ λ€μ κ°μ Έμ€μ§ μμ΅λλ€. μ΄μ /λ€μ νμμ μ¬μ ν μΊμμμ 볡μλμ΄ λΈλΌμ°μ κ° μ€ν¬λ‘€ μμΉλ₯Ό 볡μν μ μλλ‘ ν©λλ€. Loading.jsλ μ¬μ ν 5λΆ λμ μΊμλ©λλ€(λλ staleTimes.static ꡬμ±μ κ°). μ΄μ ν΄λΌμ΄μΈνΈ λΌμ°ν° μΊμ λμμ μ΅νΈμΈνλ €λ©΄ λ€μ ꡬμ±μ μ€μ νμΈμ:
// next.config.ts
const nextConfig = {
experimental: {
staleTimes: {
dynamic: 30,
},
},
};
module.exports = nextConfig;
λΆλΆ ν리λ λλ§μ μ μ§μ μ±ν(μ€νμ )
Next.js 14μμλ λΆλΆ ν리λ λλ§(PPR)μ λμ νμ΅λλ€. μ΄λ κ°μ νμ΄μ§μμ μ μ λ λλ§κ³Ό λμ λ λλ§μ κ²°ν©νλ μ΅μ νμ λλ€.
Next.jsλ νμ¬ cookies()
,Β headers()
λ° μΊμλμ§ μμ λ°μ΄ν° μμ²κ³Ό κ°μ λμ ν¨μλ₯Ό μ¬μ©νμ§ μλ ν μ μ λ λλ§μ κΈ°λ³Έκ°μΌλ‘ ν©λλ€. μ΄λ¬ν APIλ μ 체 λΌμ°νΈλ₯Ό λμ λ λλ§μΌλ‘ μ΅νΈμΈν©λλ€. PPRμ μ¬μ©νλ©΄ λμ UIλ₯Ό Suspense κ²½κ³μ λνν μ μμ΅λλ€. μλ‘μ΄ μμ²μ΄ λ€μ΄μ€λ©΄ Next.jsλ μ μ HTML μμ μ¦μ μ 곡ν λ€μ λμΌν HTTP μμ²μμ λμ λΆλΆμ λ λλ§νκ³ μ€νΈλ¦¬λ°ν©λλ€.
μ μ§μ μ±νμ νμ©νκΈ° μν΄ νΉμ λ μ΄μμ λ° νμ΄μ§λ₯Ό PPRμ μ΅νΈμΈν μ μλ experimental_ppr λΌμ°νΈ κ΅¬μ± μ΅μ μ μΆκ°νμ΅λλ€:
import { Suspense } from "react"
import { StaticComponent, DynamicComponent } from "@/app/ui"
export const experimental_ppr = true
export default