[๋ฒ์ญ] Next.js 13
- #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 ๊ฒฝ๋ก์ ๊ณต์กดํ ์ ์์ต๋๋ค.
Layouts
app/
๊ฒฝ๋ก๋ ์ํ๋ฅผ ์ ์งํ๊ณ , ๋น์ฉ์ด ๋์ ๋ฆฌ๋ ๋๋ง์ ๋ฐฉ์งํ๋ฉฐ ๊ณ ๊ธ ๋ผ์ฐํ
ํจํด์ ํ์ฑํํ๋ ๋ณต์กํ ์ธํฐํ์ด์ค๋ฅผ ์ฝ๊ฒ ๋ฐฐ์นํ ์ ์์ต๋๋ค. ๋ํ, ์ค์ฒฉ ๋ ์ด์์์ ์์ฑํ ์ ์์ผ๋ฉฐ, ์ปดํฌ๋ํธ, ํ
์คํธ, ์คํ์ผ๊ณผ ๊ฐ์ ๊ฒฝ๋ก์ ์ดํ๋ฆฌ์ผ์ด์
์ฝ๋๋ฅผ ๋ฐฐ์นํ ์ ์์ต๋๋ค.
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๊ฐ ๋ ๋๋ง๋ ๋ ์คํธ๋ฆฌ๋ฐํ๋ ์ธ์ฒด ๊ณตํ์ ๋ฐฉ๋ฒ์ ํ์ฑํํ๊ณ ์์ต๋๋ค. ํฅํ ๋ฆด๋ฆฌ์ค์์๋ ๋ฐ์ดํฐ ๋ณํ๋ ๊ฐ์ ํ๊ณ ๋จ์ํํ ๊ฒ์ ๋๋ค.
์ฐ๋ฆฌ๋ ์คํ์์ค ์ปค๋ฎค๋ํฐ, ํจํค์ง ๊ด๋ฆฌ์, 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๋ฐฐ ๋น ๋ฅธ ์ฝ๋ ์คํํธ
์ฐธ๊ณ : 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
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/link
Next.js 13์ผ๋ก ์
๊ทธ๋ ์ด๋
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+
์์ธํ ๋ด์ฉ์ ์ ๊ทธ๋ ์ด๋ ๊ฐ์ด๋๋ฅผ ํ์ธํ์ธ์