Next.js 13 (13.1 기준)
- app 디렉토리 생성 및 개선 (beta)
- Turbopack 생성 및 업데이트 (alpha)
- New next/image (stable)
- New @next/font (beta)
- Improved next/link
- Built-in Module Transpilation
- Edge Runtime (Stable)
- Middleware Improvements
- SWC Import Resolution
// next.config.js
/*
app 디렉토리에서 렌더링을 시작하려면 기존의 pages 폴더가 없어야 하고,
nextConfig에 아래와 같은 속성이 추가되어야 한다.
*/
/** @type {import('next').NextConfig} */
const nextConfig = {
experimental: {
appDir: true,
},
};
module.exports = nextConfig;
app 디렉터리를 사용하면 공통으로 사용되는 UI 컴포넌트의 불필요한 리렌더링을 방지하고 라우트 간에 UI를 쉽게 공유할 수 있습니다.
// app/head.js
export default function Head() {
return (
<>
<title>NESTjs 13</title>
<meta name="viewport" content="width=device-width, initial-scale=1" />
</>
);
}
// app/layout.js
export default function RootLayout({ children }) {
return (
<html lang="en">
<head />
<body>{children}</body>
</html>
);
}
// app/page.js
export default function Page() {
return <h1>Hello, Next.js!</h1>;
}
경로는 app 디렉토리 내부에 추가적인 디렉토리로 지정되며, 각 서브 디렉토리들은 page.js 파일을 포함하여야 합니다.
기존 pages 디렉토리 | 13버전 app 디렉토리 | 라우트 (경로) |
---|---|---|
index.js | page.js | / |
dashboard.js | dashboard/page.js | /dashboard |
dashboard/[slug].js | dashboard/[slug]/page.js | /dashboard/post-1 |
각각의 서브 디렉토리에 layout.js를 사용하여 각 경로의 공통 UI를 정의할 수 있습니다.
서버 구성 요소를 사용하여 복잡한 인터페이스를 구축하는 동시에 클라이언트로 전송되는 JavaScript의 양을 줄여 초기 페이지 로드 속도를 높일 수 있는 토대를 마련합니다.
클라이언트에 UI를 점진적으로 렌더링하고 스트리밍하는 기능을 도입합니다.
특별히 데이터가 필요하지 않은 페이지 부분을 즉시 렌더링하고 데이터를 가져오는 페이지 부분에 대한 로드 상태를 표시할 수 있습니다. 이 접근 방식을 사용하면 사용자는 상호 작용을 시작하기 전에 전체 페이지가 로드될 때까지 기다릴 필요가 없습니다.
getServerSideProps나 getStaticProps를 사용하여 data를 fetch했던 이전의 방식에서 좀 더 직관적으로 변경되었습니다.
// 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>;
}
// getStaticProps와 유사 - 빌드 시 딱 한번만 호출
fetch(URL, { cache: 'force-cache' });
// getServerSideProps와 유사 - 매 요청때마다 호출
fetch(URL, { cache: 'no-store' });
// getStaticProps의 revalidate 옵션을 사용하는 것과 유사
fetch(URL, { next: { revalidate: 10 } });
그 외
새로운 Image 구성 요소가 도입되어 레이아웃 변경 없이 이미지를 쉽게 표시하고 ,성능 향상을 위해 필요에 따라 파일을 최적화 가능합니다.
기존에는 width, height값을 적용하지 않으면 레이아웃이 깨지는 Layout shift가 발생하곤 했는데 Next.js 13에서는 이를 자동으로 처리해줍니다.
import Image from 'next/image';
import avatar from './lee.png';
function Home() {
// "alt" 는 더 쉽게 액세스할 수 있는 필수 태그
// optional: 이미지 파일을 app 디렉토리에 배치해도 됨
return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}
자세한 사용 설명은 https://nextjs.org/docs/basic-features/image-optimization 를 참고
size-adjust
속성을 사용하여 Layout shift 발생 방지// 구글 폰트 사용
import { Inter } from '@next/font/google';
const inter = Inter();
<html className={inter.className}></html>
// 사용자 정의 글꼴
import localFont from '@next/font/local';
const myFont = localFont({ src: './my-font.woff2' });
<html className={myFont.className}></html>
자세한 사용 설명은 https://nextjs.org/docs/basic-features/font-optimization 를 참고
next/link는 a태그를 더 이상 자식태그로 추가할 필요가 없습니다.
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>
모듈 트랜스파일을 내부적으로 지원합니다.
이전에는 node_modules의 모듈을 트랜스파일하기 위해 next-transpile-modules이라는 패키지를 사용해야 했지만, 이제는 빌트인 기능으로 지원되어 nextjs 설정 파일에서 transpilePackages: ['모듈명']
와 같이 입력하면 트랜스파일을 수행합니다.
/** @type {import('next').NextConfig} */
const nextConfig = {
transpilePackages: ['@acme/ui', 'lodash-es'],
};
module.exports = nextConfig;
Next.js 미들웨어는 더 나은 성능을 위해 기본적으로 이 Edge 런타임을 이미 사용하고 있습니다. 미들웨어는 애플리케이션의 모든 요청 전에 실행될 수 있으므로 짧은 대기 시간을 보장하려면 가벼운 런타임을 갖는 것이 중요합니다. 이 전에는 베타 단계였기 때문에 "experimental-" 프리픽스가 필요했지만, 이제 Next.js 내부의 Edge 런타임이 API 경로에 대해 안정적이게 되었습니다.
// pages/api/hello.ts - 13.1버전에서 pages/api는 유지(대체 디렉토리 없음)
// "experimental-" prefix is no longer needed
export const config = {
runtime: 'edge',
};
export default function handler(req: Request) {
return new Response('Hello World');
}
13.1에서는 미들웨어에서 응답을 반환하고 요청 시 헤더를 설정할 수 있습니다.
많은 npm 패키지는 배럴 파일을 사용하여 다른 모듈을 다시 내보내는 단일 파일을 제공합니다.
Barrel(배럴) : import 구문을 축약하여 사용함
// Without barrel
import { A } from "@impl/A;
import { B } from "@impl/B;
import { C } from "@impl/C;
// With barrel
import { A, B, C } from "@impl;
번들러는 이 배럴파일을 이해하고 사용하지 않는 re-exports를 제거할 수 있습니다.
일부 npm 패키지는 수천 개의 모듈을 다시 내보낸(export) 배럴 파일을 제공하므로 컴파일 시간이 느려집니다. 이 문제를 해결하기 위해 babel-plugin-transform-imports
의 사용을 추천했었지만, 이제는 SWC에 modularizeImports
라는 설정이 추가되었습니다.
// next.config.js
module.exports = {
modularizeImports: {
'@impl': {
transform: '@impl/dist/{{member}}',
},
},
};
// Before (with barrel file)
import { Button, Slider, Dropdown } from '@impl';
// After (with modularized imports from plugin)
import Button from '@impl/dist/Button';
import Slider from '@impl/dist/Slider';
import Dropdown from '@impl/dist/Dropdown';