[๋ฒˆ์—ญ] Next.js 13

NaHCoH
  • #NextJS
  • #translate
  • #Vercel
  • #Turbopack

[๋ฒˆ์—ญ] Next.js 13

์›๋ฌธ: https://nextjs.org/blog/next-13\


Next.js Conf์—์„œ ๋ฐœํ‘œํ•œ ๋ฐ”์™€ ๊ฐ™์ด Next.js 13์€ ์ œํ•œ์—†์ด ๋™์ ์œผ๋กœ ๋™์ž‘ํ•  ์ˆ˜ ์žˆ๋Š” ๊ธฐ๋ฐ˜์„ ๋งˆ๋ จํ•ฉ๋‹ˆ๋‹ค.

  • app/ ๋””๋ ‰ํ† ๋ฆฌ(beta): ๋” ์‰ฝ๊ณ , ๋น ๋ฅด๊ณ , client js๊ฐ€ ์ ์Šต๋‹ˆ๋‹ค.
    • Layouts
    • React Server Components
    • Streaming
  • Turbopack (alpha): ์ตœ๋Œ€ 700๋ฐฐ ๋น ๋ฅธ Rust ๊ธฐ๋ฐ˜์˜ Webpack ๋Œ€์ฒด์žฌ
  • ์‹ ๊ธฐ๋Šฅ next/image (stable): ๊ธฐ๋ณธ ๋ธŒ๋ผ์šฐ์ €์˜ lazy loading์œผ๋กœ ๋”์šฑ ๋นจ๋ผ์กŒ์Šต๋‹ˆ๋‹ค.
  • ์‹ ๊ธฐ๋Šฅ @next/font (beta): layout ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๋Š” ์ž๋™ ์ž์ฒด ํ˜ธ์ŠคํŒ… ํฐํŠธ
  • ํ–ฅ์ƒ๋œ next/link: ์ž๋™ ์ƒ์„ฑ๋˜๋Š” <a> ํƒœ๊ทธ๋กœ ๋‹จ์ˆœํ™”๋œ API

์ตœ์‹  ๋ฒ„์ „์œผ๋กœ์˜ ์—…๋ฐ์ดํŠธ๋Š” ํ•˜๋‹จ ์ฝ”๋“œ๋ฅผ ์‹คํ–‰ํ•ด์ฃผ์„ธ์š”

npm i next@latest react@latest react-dom@latest eslint-config-next@latest

app/ Directory (beta)

Next.js์˜ ๊ธฐ๋Šฅ ์ค‘ ๊ฐ€์žฅ ์‚ฌ๋ž‘๋ฐ›์€ ๊ธฐ์ฆ ์ค‘ ํ•˜๋‚˜๋Š” ํŒŒ์ผ ์‹œ์Šคํ…œ ๊ธฐ๋ฐ˜์˜ ๋ผ์šฐํ„ฐ์ž…๋‹ˆ๋‹ค. ํŒŒ์ผ์„ ํด๋” ์•ˆ์— ๋„ฃ๋Š” ๊ฒƒ์œผ๋กœ, ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์˜ ๋ผ์šฐํŠธ๋ฅผ ์ฆ‰์‹œ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ณ„๋„ ์„ค์ •์€ ํ•„์š”ํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” app/ ๋””๋ ‰ํ† ๋ฆฌ(beta)๋ฅผ ๋„์ž…ํ•˜์—ฌ Next.jsdml ๋ผ์šฐํŒ…๊ณผ ๋ ˆ์ด์•„์›ƒ ๊ฒฝํ—˜์„ ๊ฐœ์„ ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Š”, ์ „์— ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”ผ๋“œ๋ฐฑ์—์„œ ๋ฐฐํฌํ•œ Layouts RFC์˜ ๊ฒฐ๊ณผ๋ฌผ์ž…๋‹ˆ๋‹ค. ์ƒˆ๋กœ์šด ๋ผ์šฐํ„ฐ๋Š” ๋‹ค์Œ ์‚ฌํ•ญ๋“ค์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

  • Layouts: ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ  ๋น„์šฉ์ด ๋†’์€ ๋ฆฌ๋ Œ๋”๋ง์„ ํšŒํ”ผํ•˜๋ฉด์„œ ๊ฒฝ๋กœ๊ฐ„์˜ UI๋ฅผ ์‰ฝ๊ฒŒ ๊ณต์œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • Server Components: ๊ฐ€์žฅ ๋™์ ์ธ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด์„œ ๊ธฐ๋ณธ๊ฐ’์„ ์„œ๋ฒ„ ์šฐ์„ ์œผ๋กœ ์„ค์ •ํ•ฉ๋‹ˆ๋‹ค.
  • Streaming: ์ฆ‰๊ฐ์ ์ธ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•˜๊ณ  ๋ Œ๋”๋ง๋˜๋Š” UI ๋‹จ์œ„๋กœ ์ŠคํŠธ๋ฆฌ๋ฐํ•ฉ๋‹ˆ๋‹ค.
  • Support for Data Fetching: async ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ ํ™•์žฅ๋œ fetch API๋Š” ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ์˜ ํŽ˜์นญ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•ฉ๋‹ˆ๋‹ค.

Next.js 13์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•  ๋•Œ, app/ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•  ํ•„์š”๋Š” ์—†์ง€๋งŒ, app/ ๊ฒฝ๋กœ๋Š” ์ ์ง„์  ์ ์šฉ์„ ์œ„ํ•ด ๊ธฐ์กด pages ๊ฒฝ๋กœ์™€ ๊ณต์กดํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

`app/` ๊ฒฝ๋กœ๋Š” ๊ธฐ์กด pages/ ๊ฒฝ๋กœ์—์„œ ์ ์ง„์ ์œผ๋กœ ์ ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.



Layouts

app/ ๊ฒฝ๋กœ๋Š” ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ , ๋น„์šฉ์ด ๋†’์€ ๋ฆฌ๋ Œ๋”๋ง์„ ๋ฐฉ์ง€ํ•˜๋ฉฐ ๊ณ ๊ธ‰ ๋ผ์šฐํŒ… ํŒจํ„ด์„ ํ™œ์„ฑํ™”ํ•˜๋Š” ๋ณต์žกํ•œ ์ธํ„ฐํŽ˜์ด์Šค๋ฅผ ์‰ฝ๊ฒŒ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋˜ํ•œ, ์ค‘์ฒฉ ๋ ˆ์ด์•„์›ƒ์„ ์ž‘์„ฑํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ปดํฌ๋„ŒํŠธ, ํ…Œ์ŠคํŠธ, ์Šคํƒ€์ผ๊ณผ ๊ฐ™์€ ๊ฒฝ๋กœ์— ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

`app/` ๊ฒฝ๋กœ๋Š” ๊ธฐ์กด pages/ ๊ฒฝ๋กœ์—์„œ ์ ์ง„์ ์œผ๋กœ ์ ์šฉ๋  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

app/ ๋‚ด๋ถ€์— ๊ฒฝ๋กœ๋ฅผ ์ƒ์„ฑํ•˜๋ ค๋ฉด page.js ํŒŒ์ผ์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.

// app/page.js
// This file maps to the index route (/)
export default function Page() {
  return <h1>Hello, Next.js!</h1>;
}

ํŒŒ์ผ ์‹œ์Šคํ…œ์„ ํ†ตํ•ด์„œ ๋ ˆ์ด์•„์›ƒ์„ ์ •์˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ๋ ˆ์ด์•„์›ƒ์€ ์—ฌ๋Ÿฌ ํŽ˜์ด์ง€์— UI๋ฅผ ๊ณต์œ ํ•ฉ๋‹ˆ๋‹ค. ๋„ค๋น„๊ฒŒ์ด์…˜ ์ƒ์—์„œ, ๋ ˆ์ด์•„์›ƒ์€ ์ƒํƒœ๋ฅผ ์œ ์ง€ํ•˜๊ณ , ์ƒํ˜ธ์ž‘์šฉํ•  ์ˆ˜ ์žˆ์œผ๋ฉฐ, ๋ฆฌ๋ Œ๋”๋ง์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

// app/blog/layout.js
export default function BlogLayout({ children }) {
  return <section>{children}</section>;
}

layouts, pages์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.




Streaming

app/ ๊ฒฝ๋กœ๋Š” ๋ Œ๋”๋œ UI ๋‹จ์œ„๋ฅผ ์ ์ง„์ ์œผ๋กœ ๋ Œ๋”๋งํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ์ ์ง„์ ์œผ๋กœ ์ŠคํŠธ๋ฆผํ•˜๋Š” ๊ธฐ๋Šฅ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.
Next.js์—์„œ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ์™€ ์ค‘์ฒฉ ๋ ˆ์ด์•„์›ƒ์„ ์‚ฌ์šฉํ•˜๋ฉด, ํŠน๋ณ„ํžˆ ๋ฐ์ดํ„ฐ๊ฐ€ ํ•„์š”ํ•˜์ง€ ์•Š์€ ํ™”๋ฉด์˜ ์ผ๋ถ€๋ฅผ ์ฆ‰์‹œ ๋ Œ๋”ํ•  ์ˆ˜ ์žˆ๊ณ , ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ค๋Š” ํ™”๋ฉด์˜ ๋ถ€๋ถ„์— ๋Œ€ํ•œ ๋กœ๋”ฉ ์ƒํƒœ๋ฅผ ํ‘œ์‹œํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด๋Ÿฌํ•œ ์ ‘๊ทผ๋ฐฉ์‹์„ ์‚ฌ์šฉํ•˜๋ฉด, ์‚ฌ์šฉ์ž๋Š” ์ „์ฒด ํŽ˜์ด์ง€์™€ ์ƒํ˜ธ์ž‘์šฉํ•˜๊ธฐ ์ „์— ์ „์ฒด ํŽ˜์ด์ง€๊ฐ€ ๋ถˆ๋Ÿฌ์ง€๋Š”๊ฑธ ๊ธฐ๋‹ค๋ฆฌ์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜ ์ฝ”๋“œ๋ฅผ ์ปดํฌ๋„ŒํŠธ, ํ…Œ์ŠคํŠธ, ์Šคํƒ€์ผ๊ณผ ๊ฐ™์€ ๊ฒฝ๋กœ์— ๋ฐฐ์น˜ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Vercel์— ๋ฐฐํฌ๋  ๋•Œ, app/ ๊ฒฝ๋กœ๋ฅผ ์‚ฌ์šฉํ•˜๋Š” Next.js 13 ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์€ ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ๊ธฐ๋ณธ์ ์œผ๋กœ Node.js์™€ Edge ๋Ÿฐํƒ€์ž… ๋ชจ๋‘์—์„œ ์‘๋‹ต์„ ์ŠคํŠธ๋ฆผํ•ฉ๋‹ˆ๋‹ค.

์ŠคํŠธ๋ฆฌ๋ฐ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.




Data Fetching

๋ฆฌ์•กํŠธ์˜ ์ตœ๊ทผ Promise ์ง€์› RFC๋Š” ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๋ฐ์ดํ„ฐ๋ฅผ ํŽ˜์นญํ•˜๊ณ  ํ”„๋กœ๋ฏธ์Šค๋ฅผ ํ•ธ๋“ค๋งํ•˜๋Š” ๊ฐ•๋ ฅํ•œ ์ƒˆ๋กœ์šด ๋ฐฉ๋ฒ•์„ ์†Œ๊ฐœํ•œ๋‹ค.

// app/page.js
async function getData() {
  const res = await fetch('https://api.example.com/...');
  // The return value is *not* serialized
  // You can return Date, Map, Set, etc.
  return res.json();
}

// This is an async Server Component
export default async function Page() {
  const data = await getData();

  return <main>{/* ... */}</main>;
}

๋„ค์ดํ‹ฐ๋ธŒ fetch ์›น API๋Š” React, Next.js์—์„œ ํ™•์žฅ๋˜์—ˆ๋‹ค. ์ด๋Š” fetch ์š”์ฒญ์„ ์ž๋™์œผ๋กœ ์ค‘๋ณต ์ œ๊ฑฐํ•˜๊ณ  ์ปดํฌ๋„ŒํŠธ ๋ ˆ๋ฒจ์—์„œ์˜ fetch, ์บ์‹ฑ, ๋ฐ์ดํ„ฐ ์žฌ๊ฒ€์ฆ์— ๋Œ€ํ•œ ์œ ์—ฐํ•œ ๋ฐฉ๋ฒ•์„ ์ œ๊ณตํ•œ๋‹ค. ์ด๋Š” SSG(์ •์  ์‚ฌ์ดํŠธ ์ƒ์„ฑ), SSR(์„œ๋ฒ„ ์‚ฌ์ด๋“œ ๋ Œ๋”๋ง), ISR(์ ์ง„์  ์ •์  ์žฌ์ƒ์„ฑ)์„ ํ•˜๋‚˜์˜ API๋กœ ์ฒ˜๋ฆฌ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•œ๋‹ค.

// This request should be cached until manually invalidated.
// Similar to `getStaticProps`.
// `force-cache` is the default and can be omitted.
fetch(URL, { cache: 'force-cache' });

// This request should be refetched on every request.
// Similar to `getServerSideProps`.
fetch(URL, { cache: 'no-store' });

// This request should be cached with a lifetime of 10 seconds.
// Similar to `getStaticProps` with the `revalidate` option.
fetch(URL, { next: { revalidate: 10 } });

app ๊ฒฝ๋กœ์—์„œ, ์„œ๋ฒ„์˜ ์ŠคํŠธ๋ฆฌ๋ฐ ์‘๋‹ต ์ง€์›์„ ํฌํ•จํ•˜์—ฌ ๋ ˆ์ด์•„์›ƒ, ํŽ˜์ด์ง€ ๋ฐ ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์˜ ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ€์ ธ์˜ฌ ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ๋กœ๋”ฉ ๋ฐ ์˜ค๋ฅ˜ ์ƒํƒœ๋ฅผ ์ฒ˜๋ฆฌํ•˜๊ณ  UI๊ฐ€ ๋ Œ๋”๋ง๋  ๋•Œ ์ŠคํŠธ๋ฆฌ๋ฐํ•˜๋Š” ์ธ์ฒด ๊ณตํ•™์  ๋ฐฉ๋ฒ•์„ ํ™œ์„ฑํ™”ํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค. ํ–ฅํ›„ ๋ฆด๋ฆฌ์Šค์—์„œ๋Š” ๋ฐ์ดํ„ฐ ๋ณ€ํ˜•๋„ ๊ฐœ์„ ํ•˜๊ณ  ๋‹จ์ˆœํ™”ํ•  ๊ฒƒ์ž…๋‹ˆ๋‹ค.

app/ ๊ฒฝ๋กœ์—์„œ ์ƒˆ๋กœ์šด ํŠน๋ณ„ํ•œ ํŒŒ์ผ loading.js๋ฅผ ํ†ตํ•ด์„œ Suspense ๋ฐ”์šด๋”๋ฆฌ์—์„œ Instant Loading UI๋ฅผ ์ž๋™์œผ๋กœ ์ƒ์„ฑํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
์šฐ๋ฆฌ๋Š” ์˜คํ”ˆ์†Œ์Šค ์ปค๋ฎค๋‹ˆํ‹ฐ, ํŒจํ‚ค์ง€ ๊ด€๋ฆฌ์ž, React ์—์ฝ”์‹œ์Šคํ…œ์— ๊ธฐ์—ฌํ•˜๋Š” ๊ธฐํƒ€ ํšŒ์‚ฌ์™€ ํ˜‘๋ ฅํ•˜์—ฌ ์ƒˆ๋กœ์šด React, Next.js ์‹œ๋Œ€๋ฅผ ์œ„ํ•œ ์ž‘์—…์„ ๊ธฐ์˜๊ฒŒ ์ƒ๊ฐํ•ฉ๋‹ˆ๋‹ค. ์ปดํฌ๋„ŒํŠธ ๋‚ด๋ถ€์—์„œ ๊ฐ€์ ธ์˜ค๋Š” ๋ฐ์ดํ„ฐ๋ฅผ ๊ฐ™์€ ์œ„์น˜์— ๋ฐฐ์น˜ํ•˜๊ณ  ํด๋ผ์ด์–ธํŠธ์— ๋” ์ ์€ JavaScript๋ฅผ ์ œ๊ณตํ•˜๋Š” ๊ธฐ๋Šฅ์€ `app/`๋””๋ ‰ํ† ๋ฆฌ์— ํฌํ•จํ•˜๊ฒŒ ๋œ ์ปค๋ฎค๋‹ˆํ‹ฐ ํ”ผ๋“œ๋ฐฑ์˜ ๋‘ ๊ฐ€์ง€ ์ค‘์š”ํ•œ ๋ถ€๋ถ„์ด์—ˆ์Šต๋‹ˆ๋‹ค.

๋ฐ์ดํ„ฐ ๊ฐ€์ ธ์˜ค๊ธฐ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์„ธ์š”.




Turbopack ์†Œ๊ฐœ (alpha)

Next.js 13์€ ์›นํŒฉ์˜ ์ƒˆ๋กœ์šด ๋Ÿฌ์ŠคํŠธ ๊ธฐ๋ฐ˜ ํ›„์† ์ œํ’ˆ์ธ Turbopack์„ ํฌํ•จํ•˜๊ณ  ์žˆ์Šต๋‹ˆ๋‹ค.

์›นํŒฉ์€ 3์–ตํšŒ ์ด์ƒ์˜ ๋‹ค์šด๋กœ๋“œ ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์›นํŒฉ์ด ์›น ๊ตฌ์ถ•์˜ ํ•„์ˆ˜์ ์ธ ๋ถ€๋ถ„์ด์—ˆ์ง€๋งŒ, ์ž๋ฐ”์Šคํฌ๋ฆฝํŠธ ๊ธฐ๋ฐ˜์˜ ๋„๊ตฌ๋กœ์„œ ๊ฐ€๋Šฅํ•œ ์ตœ๋Œ€ ์„ฑ๋Šฅ์— ๋„๋‹ฌํ–ˆ์Šต๋‹ˆ๋‹ค.

Next.js 12์—์„œ ์šฐ๋ฆฌ๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๋Ÿฌ์ŠคํŠธ ๊ธฐ๋ฐ˜ ํˆด๋กœ์˜ ์ „ํ™˜์„ ์‹œ์ž‘ํ–ˆ์Šต๋‹ˆ๋‹ค. ์šฐ๋ฆฌ๋Š” ๋ฐ”๋ฒจ์—์„œ ๋‹ค๋ฅธ ๊ณณ์œผ๋กœ ๋งˆ์ด๊ทธ๋ ˆ์ด์…˜ํ•˜๋Š” ๊ฒƒ์œผ๋กœ ์‹œ์ž‘ํ•˜์—ฌ, 17๋ฐฐ ๋” ๋น ๋ฅธ ํŠธ๋žœ์ŠคํŒŒ์ผ ๊ฒฐ๊ณผ๋ฅผ ์ด๋Œ์–ด ๋ƒˆ์Šต๋‹ˆ๋‹ค. ๊ทธ๋ฆฌ๊ณ , Terser๋ฅผ ๊ต์ฒดํ•˜์—ฌ, 6๋ฐฐ ๋” ๋น ๋ฅธ ์ถ•์†Œ ๊ฒฐ๊ณผ๋ฅผ ์ด๋Œ์–ด ๋ƒˆ์Šต๋‹ˆ๋‹ค. ์ด์ œ ๋ฒˆ๋“ค๋ง์„ ์œ„ํ•ด ๋„ค์ดํ‹ฐ๋ธŒ์— ์˜ฌ์ธํ•  ๋•Œ์ž…๋‹ˆ๋‹ค.

Next.js 13์—์„œ Turbopack ์•ŒํŒŒ๋ฅผ ์‚ฌ์šฉํ–ˆ์„ ๋•Œ์˜ ๊ฒฐ๊ณผ๋Š”

  • Webpack๋ณด๋‹ค 700๋ฐฐ ๋น ๋ฅธ ์—…๋ฐ์ดํŠธ
  • Vite๋ณด๋‹ค 10๋ฐฐ ๋น ๋ฅธ ์—…๋ฐ์ดํŠธ
  • Webpack๋ณด๋‹ค 4๋ฐฐ ๋น ๋ฅธ ์ฝœ๋“œ ์Šคํƒ€ํŠธ

Turbopack์€ ๋Œ€๊ทœ๋ชจ ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์— ๋Œ€ํ•ด 700๋ฐฐ ๋น ๋ฅธ HMR์„ ๊ฐ–์ถ˜ Webpack์˜ ๋Ÿฌ์ŠคํŠธ ๊ธฐ๋ฐ˜ ํ›„์† ์ œํ’ˆ์ž…๋‹ˆ๋‹ค.
Turbopack์€ ๊ฐœ๋ฐœ์— ํ•„์š”ํ•œ ์ตœ์†Œํ•œ์˜ ๋ฒˆ๋“ค๋งŒ ํ•„์š”๋กœ ํ•˜๊ธฐ ๋•Œ๋ฌธ์—, ์‹œ์ž‘ ์‹œ๊ฐ„์ด ๋งค์šฐ ๋น ๋ฆ…๋‹ˆ๋‹ค. 3000๊ฐœ์˜ ๋ชจ๋“ˆ์„ ํฌํ•จํ•˜๋Š” ์–ดํ”Œ๋ฆฌ์ผ€์ด์…˜์—์„œ, Turbopack์€ ๊ธฐ๋™๊นŒ์ง€ 1.8์ดˆ๊ฐ€ ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. ๋ฐ˜๋ฉด์— Vite๋Š” 11.4์ดˆ, Webpack์€ 16.5์ดˆ๊ฐ€ ๊ฑธ๋ ธ์Šต๋‹ˆ๋‹ค. Turbopack์€ ์„œ๋ฒ„ ์ปดํฌ๋„ŒํŠธ, ํƒ€์ž…์Šคํฌ๋ฆฝํŠธ, JSX, CSS ๋“ฑ์— ๋Œ€ํ•˜์—ฌ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. alpha ๋ฒ„์ „๋™์•ˆ, ๋งŽ์€ ๊ธฐ๋Šฅ๋“ค์ด ์•„์ง ์ œ๊ณต๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค. Turbopack์„ ์‚ฌ์šฉํ•˜์—ฌ ๋กœ์ปฌ ๋ฐ˜๋ณต ์†๋„๋ฅผ ๋†’์ด๋Š” ๊ฒƒ์— ๋Œ€ํ•œ ์—ฌ๋Ÿฌ๋ถ„์˜ ํ”ผ๋“œ๋ฐฑ์„ ๋“ฃ๊ณ  ์‹ถ์Šต๋‹ˆ๋‹ค.

์ฐธ๊ณ : Next.js์˜ Turbopack์€ ํ˜„์žฌ next dev๋งŒ์„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค. ์ง€์› ๊ธฐ๋Šฅ์„ ํ™•์ธํ•˜์„ธ์š”. ์šฐ๋ฆฌ๋Š” ํ„ฐ๋ณดํŒฉ์„ ํ†ตํ•œ next build์˜ ์ง€์›์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์ž‘์—…์„ ์ง„ํ–‰์ค‘์ž…๋‹ˆ๋‹ค.

Next.js 13์—์„œ next dev --turbo ๋ช…๋ น์–ด๋ฅผ ํ†ตํ•ด Turbopack alpha๋ฅผ ์‚ฌ์šฉํ•ด๋ณด์„ธ์š”.




next/image

Next.js 13์€ ๊ฐ•๋ ฅํ•œ ์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์†Œ๊ฐœํ•ฉ๋‹ˆ๋‹ค. ๊ฐ„๋‹จํžˆ ์ด๋ฏธ์ง€๋ฅผ ํ‘œ์‹œํ•˜๊ณ , layout ๋ณ€๊ฒฝ์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š๊ณ  ์„ฑ๋Šฅ ํ–ฅ์ƒ์„ ์œ„ํ•ด ํ•„์š”์— ๋”ฐ๋ผ ํŒŒ์ผ์„ ์ตœ์ ํ™” ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

Next.js ์ปค๋ฎค๋‹ˆํ‹ฐ์˜ ์„ค๋ฌธ์กฐ์‚ฌ์—์„œ ์‘๋‹ต์ž์˜ 70%๋Š” ํ”„๋กœ๋•์…˜ ํ™˜๊ฒฝ์—์„œ Next.js ์ด๋ฏธ์ง€ ์ปดํฌ๋„ŒํŠธ๋ฅผ ์‚ฌ์šฉํ–ˆ์œผ๋ฉฐ, ํ•ต์‹ฌ ์›น ๋ฐ”์ดํƒˆ์˜ ํ–ฅ์ƒ์„ ํ™•์ธํ–ˆ๋‹ค๊ณ  ํ–ˆ์Šต๋‹ˆ๋‹ค. Next.js 13์—์„œ next/image๋ฅผ ๋”์šฑ ๋ฐœ์ „์‹œ์ผฐ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ์ด๋ฏธ์ง€ ์ปดํฌ๋„ŒํŠธ๋Š”:

  • ์ ์€ ์–‘์˜ Javascript ์ฝ”๋“œ๋ฅผ ๊ฐ–์Šต๋‹ˆ๋‹ค.
  • ๋” ์‰ฝ๊ฒŒ ์Šคํƒ€์ผ๋ง๊ณผ ์„ค์ •์ด ๊ฐ€๋Šฅํ•ฉ๋‹ˆ๋‹ค.
  • ๊ธฐ๋ณธ์ ์œผ๋กœ alt์†์„ฑ์„ ํ•„์ˆ˜๋กœ ํ•˜์—ฌ ์ ‘๊ทผ์„ฑ ํ–ฅ์ƒ
  • ์›น ํ”Œ๋žซํผ์— ๋งž๊ฒŒ ์กฐ์ •
  • hydration์„ ํ•„์š”๋กœ ํ•˜์ง€ ์•Š๋Š” ๋„ค์ดํ‹ฐ๋ธŒ ๋ ˆ์ด์ง€ ๋กœ๋”ฉ์œผ๋กœ ์ธํ•œ ์†๋„ ํ–ฅ์ƒ
import Image from 'next/image';
import avatar from './lee.png';

function Home() {
  // "alt" is now required for improved accessibility
  // optional: image files can be colocated inside the app/ directory
  return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}

์ด๋ฏธ์ง€ ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์‹ญ์‹œ์˜ค.

next/image Next.js 13์œผ๋กœ ์—…๊ทธ๋ ˆ์ด๋“œํ•˜๊ธฐ

๊ธฐ์กด ์ด๋ฏธ์ง€ ์ปดํฌ๋„ŒํŠธ๋Š” next/legacy/image๋กœ ๋„ค์ด๋ฐ์ด ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ์ž๋™์œผ๋กœ ๊ธฐ์กด์— ์‚ฌ์šฉ์ค‘์ธ next/image์—์„œ next/legacy/image๋กœ ์—…๋˜์ดํŠธ ๋˜๋Š” codemod๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด ์ปค๋งจ๋“œ๋ฅผ root ๊ฒฝ๋กœ์—์„œ ์‹คํ–‰ํ•˜๋ฉด ./pages ๊ฒฝ๋กœ์—์„œ codemod๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

npx @next/codemod next-image-to-legacy-image ./pages

codemod์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ๋ฌธ์„œ๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.




@next/font

Next.js 13์€ ๋‹ค์Œ๊ณผ ๊ฐ™์€ ์ƒˆ๋กœ์šด ํฐํŠธ ์‹œ์Šคํ…œ์„ ๋„์ž…ํ•ฉ๋‹ˆ๋‹ค.

  • ์ปค์Šคํ…€ ํฐํŠธ๋ฅผ ํฌํ•จํ•˜์—ฌ ํฐํŠธ๋ฅผ ์ž๋™์œผ๋กœ ์ตœ์ ํ™”ํ•ฉ๋‹ˆ๋‹ค.
  • ํ–ฅ์ƒ๋œ ์„ฑ๋Šฅ๊ณผ ๊ฐœ์ธ์ •๋ณด ๋ณดํ˜ธ๋ฅผ ์œ„ํ•ด์„œ ์™ธ๋ถ€ ๋„คํŠธ์›Œํฌ์˜ ์š”์ฒญ์„ ์ œ๊ฑฐํ•ฉ๋‹ˆ๋‹ค.
  • ๋ชจ๋“  ํฐํŠธ ํŒŒ์ผ์— ๋Œ€ํ•˜์—ฌ ๋‚ด์žฅํ˜• ์ž๋™ ์ž์ฒด ํ˜ธ์ŠคํŒ…์„ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค.
  • CSS size-adjust ์†์„ฑ์„ ์‚ฌ์šฉํ•˜์—ฌ ์ž๋™์œผ๋กœ ๋ ˆ์ด์•„์›ƒ ์ด๋™์„ ๋ฐœ์ƒ์‹œํ‚ค์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

์ด ์ƒˆ๋กœ์šด ํฐํŠธ ์‹œ์Šคํ…œ์„ ์‚ฌ์šฉํ•˜๋ฉด, ์„ฑ๋Šฅ๊ณผ ๊ฐœ์ธ ์ •๋ณด ๋ณดํ˜ธ๋ฅผ ์—ผ๋‘์— ๋‘๊ณ  ๋ชจ๋“  ๊ตฌ๊ธ€ ํฐํŠธ๋ฅผ ํŽธ๋ฆฌํ•˜๊ฒŒ ์‚ฌ์šฉํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค. CSS ๋ฐ ํฐํŠธ ํŒŒ์ผ์€ ๋นŒ๋“œ ์‹œ ๋‹ค์šด๋กœ๋“œ๋˜๋ฉฐ ๋‚˜๋จธ์ง€ ์ •์  ์š”์†Œ์™€ ํ•จ๊ป˜ ์ž์ฒด ํ˜ธ์ŠคํŒ…๋ฉ๋‹ˆ๋‹ค. ๋ธŒ๋ผ์šฐ์ €์—์„œ ๊ตฌ๊ธ€๋กœ ์š”์ฒญ์„ ๋ณด๋‚ด์ง€ ์•Š์Šต๋‹ˆ๋‹ค.

import { Inter } from '@next/font/google';

const inter = Inter();

<html className={inter.className}>

์ž๋™ ์ž์ฒด ํ˜ธ์ŠคํŒ…, ์บ์‹ฑ ๋ฐ ํฐํŠธ ํŒŒ์ผ ์‚ฌ์ „ ๋กœ๋“œ ์ง€์›์„ ํฌํ•จํ•˜์—ฌ ์ปค์Šคํ…€ ํฐํŠธ๋„ ์ง€์›ํ•ฉ๋‹ˆ๋‹ค.

import localFont from '@next/font/local';

const myFont = localFont({ src: './my-font.woff2' });

<html className={myFont.className}>

font-display, ์‚ฌ์ „ ๋กœ๋”ฉ, fallback ๋“ฑ์„ ํฌํ•จํ•˜์—ฌ ๋›ฐ์–ด๋‚œ ์„ฑ๋Šฅ๊ณผ ๋ ˆ์ด์•„์›ƒ ๋ณ€๊ฒฝ ์—†์ด ํฐํŠธ ๋กœ๋”ฉ์˜ ๊ฒฝํ—˜ ๋Œ€๋ถ€๋ถ„์˜ ๋ถ€๋ถ„์„ ์ปค์Šคํ„ฐ๋งˆ์ด์ฆˆํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

์ƒˆ๋กœ์šด ๊ธ€๊ผด ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์‹ญ์‹œ์˜ค.




next/link์— ๋” ์ด์ƒ ์ˆ˜๋™์œผ๋กœ <a>๋ฅผ ์ž์‹์œผ๋กœ ์ถ”๊ฐ€ํ•˜์ง€ ์•Š์•„๋„ ๋ฉ๋‹ˆ๋‹ค.

์ด๋Š” 12.2 ๋ฒ„์ „์—์„œ ์‹คํ—˜์  ์˜ต์…˜์œผ๋กœ ์ถ”๊ฐ€๋œ ๊ธฐ๋Šฅ์ด๊ณ , ์ง€๊ธˆ์€ ๊ธฐ๋ณธ ์˜ต์…˜์ž…๋‹ˆ๋‹ค. Next.js 13์—์„œ <Link>๋Š” ํ•ญ์ƒ <a>๋ฅผ ๋ Œ๋”๋งํ•˜๊ณ  ๊ธฐ๋ณธ ํƒœ๊ทธ์— props๋ฅผ ์ „๋‹ฌํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

import Link from 'next/link';

// Next.js 12: `<a>` has to be nested otherwise it's excluded
<Link href="/about">
  <a>About</a>
</Link>

// Next.js 13: `<Link>` always renders `<a>`
<Link href="/about">
  About
</Link>

๊ฐœ์„ ๋œ Link ๊ตฌ์„ฑ ์š”์†Œ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์‹ญ์‹œ์˜ค.

Next.js 13์˜ link๋กœ ์—…๊ทธ๋ ˆ์ด๋“œ๋ฅผ ์œ„ํ•ด ์ž๋™์œผ๋กœ ์—ฌ๋Ÿฌ๋ถ„์˜ ์ฝ”๋“œ๋ฒ ์ด์Šค๋ฅผ ์—…๋ฐ์ดํŠธํ•˜๋Š” codemod๋ฅผ ์ œ๊ณตํ•ฉ๋‹ˆ๋‹ค. ์˜ˆ๋ฅผ ๋“ค์–ด, ์ด ์ปค๋งจ๋“œ๋ฅผ root ๊ฒฝ๋กœ์—์„œ ์‹คํ–‰ํ•˜๋ฉด ./pages ๊ฒฝ๋กœ์—์„œ codemod๋ฅผ ์‹คํ–‰ํ•ฉ๋‹ˆ๋‹ค.

npx @next/codemod new-link ./pages

codemod์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ์„ค๋ช…์„œ๋ฅผ ํ™•์ธํ•˜์‹ญ์‹œ์˜ค.




OG ์ด๋ฏธ์ง€ ์ƒ์„ฑ

์˜คํ”ˆ ๊ทธ๋ž˜ํ”„ ์ด๋ฏธ์ง€๋กœ ์•Œ๋ ค์ ธ ์žˆ๋Š” ์†Œ์…œ ์นด๋“œ๋Š” ์ฝ˜ํ…์ธ  ํด๋ฆญ์œจ์„ ํฌ๊ฒŒ ๋†’์ผ ์ˆ˜ ์žˆ์œผ๋ฉฐ, ์ผ๋ถ€ ์‹คํ—˜์—์„œ๋Š” ์ตœ๋Œ€ 40% ๋” ๋‚˜์€ ์ „ํ™˜์„ ๋ณด์—ฌ์ค๋‹ˆ๋‹ค.

์ •์  ์†Œ์…œ ์นด๋“œ๋Š” ์‹œ๊ฐ„์˜ ์†Œ๋น„, ์—๋Ÿฌ ์ฒ˜๋ฆฌ, ์œ ์ง€๋ณด์ˆ˜๊ฐ€ ์–ด๋ ค์šด ๋ฌธ์ œ๊ฐ€ ์žˆ์Šต๋‹ˆ๋‹ค. ์ด ๋•Œ๋ฌธ์—, ์†Œ์…œ ์นด๋“œ๊ฐ€ ๋ถ€์กฑํ•˜๊ฑฐ๋‚˜ ์Šคํ‚ต๋˜๊ดธ ํ•ฉ๋‹ˆ๋‹ค. ์˜ค๋Š˜๋‚ , ๊ฐœ์ธํ™”๋˜๊ณ  ์ฆ‰์‹œ ๊ณ„์‚ฐ๋˜์–ด์•ผ ํ•˜๋Š” ๋™์  ์†Œ์…œ ์นด๋“œ๋Š” ์–ด๋ ต๊ณ  ๋น„์šฉ์ด ๋งŽ์ด ๋ฐœ์ƒํ•ฉ๋‹ˆ๋‹ค.

์šฐ๋ฆฌ๋Š” ์ƒˆ๋กœ์šด ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ @vercel/og๋ฅผ ๋งŒ๋“ค์–ด Next.js์™€ ์›ํ™œํ•˜๊ฒŒ ์ž‘๋™ํ•˜๊ฒŒ ๋งŒ๋“ค์—ˆ์Šต๋‹ˆ๋‹ค.

// pages/api/og.jsx

import { ImageResponse } from '@vercel/og';

export const config = {
  runtime: 'experimental-edge',
};

export default function () {
  return new ImageResponse(
    (
      <div
        style={{
          display: 'flex',
          fontSize: 128,
          background: 'white',
          width: '100%',
          height: '100%',
        }}
      >
        Hello, World!
      </div>
    ),
  );
}

์ด ์ ‘๊ทผ ๋ฐฉ์‹์€ Vercel Edge Functions, WebAssembly ๋ฐ HTML ๋ฐ CSS๋ฅผ ์ด๋ฏธ์ง€๋กœ ๋ณ€ํ™˜ํ•˜๊ณ  React ์ปดํฌ๋„ŒํŠธ ์ถ”์ƒํ™”๋ฅผ ํ™œ์šฉํ•˜๊ธฐ ์œ„ํ•œ ์ƒˆ๋กœ์šด ํ•ต์‹ฌ ๋ผ์ด๋ธŒ๋Ÿฌ๋ฆฌ๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๊ธฐ์กด ์†”๋ฃจ์…˜๋ณด๋‹ค 5๋ฐฐ ๋” ๋น ๋ฆ…๋‹ˆ๋‹ค.

OG ์ด๋ฏธ์ง€ ์ƒ์„ฑ์— ๋Œ€ํ•ด ์ž์„ธํžˆ ์•Œ์•„ ๋ณด๊ฑฐ๋‚˜ ์˜ˆ์ œ๋ฅผ ๋ฐฐํฌํ•˜์—ฌ ์‚ฌ์šฉํ•ด ๋ณด์‹ญ์‹œ์˜ค.




๋ฏธ๋“ค์›จ์–ด API ์—…๋ฐ์ดํŠธ

Next.js 12์—์„œ Next.js ๋ผ์šฐํ„ฐ์™€์˜ ์ตœ๋Œ€ํ•œ์˜ ์œ ์—ฐ์„ฑ์„ ๊ฐ€๋Šฅํ•˜๊ฒŒ ํ•˜๊ธฐ ์œ„ํ•ด Middleware๋ฅผ ๋„์ž…ํ–ˆ์Šต๋‹ˆ๋‹ค. ์ดˆ๊ธฐ API ๋””์ž์ธ์— ๋Œ€ํ•œ ํ”ผ๋“œ๋ฐฑ์„ ๋“ฃ๊ณ , ๊ฐœ๋ฐœ์ž ๊ฒ€ํ—˜๊ณผ ๊ฐ•๋ ฅํ•œ ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ์„ ์ถ”๊ฐ€ํ•˜๊ธฐ ์œ„ํ•ด ์ƒˆ๋กœ์šด ๊ธฐ๋Šฅ๋“ค์„ ์ถ”๊ฐ€ํ–ˆ์Šต๋‹ˆ๋‹ค.

์ด์ œ ์š”์ฒญ์— ๋Œ€ํ•œ ํ—ค๋”๋ฅผ ๋” ์‰ฝ๊ฒŒ ์„ค์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';

export function middleware(request: NextRequest) {
  // Clone the request headers and set a new header `x-version`
  const requestHeaders = new Headers(request.headers);
  requestHeaders.set('x-version', '13');

  // You can also set request headers in NextResponse.rewrite
  const response = NextResponse.next({
    request: {
      // New request headers
      headers: requestHeaders,
    },
  });

  // Set a new response header `x-version`
  response.headers.set('x-version', '13');
  return response;
}

๋˜ํ•œ ์ด์ œ rewrite๋‚˜ redirect ์—†์ด ๋ฏธ๋“ค์›จ์–ด์—์„œ ์ง์ ‘ ๋ฆฌ์Šคํฐ์Šค๋ฅผ ์ œ๊ณตํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.

// middleware.ts
import { NextRequest, NextResponse } from 'next/server';
import { isAuthenticated } from '@lib/auth';

// Limit the middleware to paths starting with `/api/`
export const config = {
  matcher: '/api/:function*',
};

export function middleware(request: NextRequest) {
  // Call our authentication function to check the request
  if (!isAuthenticated(request)) {
    // Respond with JSON indicating an error message
    return NextResponse.json(
      {
        success: false,
        message: 'Auth failed',
      },
      {
        status: 401,
      },
    );
  }
}

๋ฏธ๋“ค์›จ์–ด์—์„œ ๋ฆฌ์Šคํฐ์Šค๋ฅผ ๋ณด๋‚ด๋Š”๊ฑด ํ˜„์žฌ next.config.js์˜ experimental.allowMiddlewareResponseBody์„ค์ •์ด ํ•„์š”ํ•ฉ๋‹ˆ๋‹ค.




์ฃผ์š” ๋ณ€๊ฒฝ์‚ฌํ•ญ

  • ์ตœ์†Œ ์š”๊ตฌ ๋ฆฌ์•กํŠธ ๋ฒ„์ „์ด 17.0.2์—์„œ 18.2.0์œผ๋กœ ์˜ฌ๋ž์Šต๋‹ˆ๋‹ค.
  • 12.x ๋ฒ„์ „์ด ์ง€์› ์ข…๋ฃŒ๋˜์–ด ์ตœ์†Œ ์š”๊ตฌ Node.js ๋ฒ„์ „์ด 12.22.0์—์„œ 14.6.0์œผ๋กœ ์˜ฌ๋ž์Šต๋‹ˆ๋‹ค.
  • swcMinify ์„ค์ •์˜ ๊ธฐ๋ณธ ๊ฐ’์ด false์—์„œ true๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. ๋” ๋งŽ์€ ์ •๋ณด๋ฅผ ์œ„ํ•ด Next.js Compiler๋ฅผ ํ™•์ธํ•˜์„ธ์š”
  • next/image๊ฐ€ next/legacy/image๋กœ, next/future/image๊ฐ€ next/image๋กœ ๋ณ€๊ฒฝ๋˜์—ˆ์Šต๋‹ˆ๋‹ค. codemod๋กœ ์ž๋™์œผ๋กœ ์•ˆ์ „ํ•˜๊ฒŒ import๋ฌธ์„ ์ˆ˜์ •ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • next/link์˜ ์ž์‹์œผ๋กœ <a>๋ฅผ ๊ฐ€์งˆ ์ˆ˜ ์—†์Šต๋‹ˆ๋‹ค. legacyBehavior ์†์„ฑ์„ ํ†ตํ•ด ๊ธฐ์กด ์ฝ”๋“œ๋ฅผ ์œ ์ง€ํ•˜๊ฑฐ๋‚˜ <a>๋ฅผ ์—†์• ์„œ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•˜์„ธ์š”. codemod๋กœ ์ž๋™์œผ๋กœ ์ฝ”๋“œ๋ฅผ ์—…๊ทธ๋ ˆ์ด๋“œ ํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
  • User-Agent๊ฐ€ ๋ด‡์ด๋ฉด ๋”์ด์ƒ ๊ฒฝ๋กœ๋“ค์ด ํ”„๋ฆฌํŽ˜์น˜๋˜์ง€ ์•Š์Šต๋‹ˆ๋‹ค.
  • ์ง€์› ์ข…๋ฃŒ๋œ target ์˜ต์…˜์ด next.config.js์—์„œ ์ œ๊ฑฐ๋˜์—ˆ์Šต๋‹ˆ๋‹ค.
  • ์ง€์› ๋ธŒ๋ผ์šฐ์ €๊ฐ€ ๋ณ€๊ฒฝ๋˜์–ด Internet Explorer๊ฐ€ ์ œ๊ฑฐ๋˜๊ณ  ์ตœ์‹  ๋ธŒ๋ผ์šฐ์ €๋ฅผ ํƒ€๊ฒŸ์œผ๋กœ ์„ค์ •ํ–ˆ์Šต๋‹ˆ๋‹ค. ์—ฌ์ „ํžˆ Browserslist๋ฅผ ์‚ฌ์šฉํ•˜์—ฌ ๋Œ€์ƒ ๋ธŒ๋ผ์šฐ์ €๋ฅผ ๋ณ€๊ฒฝํ•  ์ˆ˜ ์žˆ์Šต๋‹ˆ๋‹ค.
    • ํฌ๋กฌ 64+
    • ์—ฃ์ง€ 79+
    • ํŒŒ์ด์–ดํญ์Šค 67+
    • ์˜คํŽ˜๋ผ 51+
    • ์‚ฌํŒŒ๋ฆฌ 12+

์ž์„ธํ•œ ๋‚ด์šฉ์€ ์—…๊ทธ๋ ˆ์ด๋“œ ๊ฐ€์ด๋“œ๋ฅผ ํ™•์ธํ•˜์„ธ์š”

โ† ๋ชฉ๋ก์œผ๋กœ ๋Œ์•„๊ฐ€๊ธฐ

Art Changes Life

๋…ธ๋จธ์Šค์™€ ํ•จ๊ป˜ ์—”ํ„ฐํ…Œํฌ ์‚ฐ์—…์„ ํ˜์‹ ํ•ด๋‚˜๊ฐˆ ๋ฉค๋ฒ„๋ฅผ ์ฐพ์Šต๋‹ˆ๋‹ค.

์ฑ„์šฉ ์ค‘์ธ ๊ณต๊ณ  ๋ณด๊ธฐ