기존에 next.js는 파일 시스템 라우터 기능을 통해 디렉토리 폴더 내부에 파일 생성만으로 애플리케이션 경로를 설정 할 수 있었습니다.
이번에 /app
디렉토리를 도입하면서 라우팅 및 레이아웃 경험을 개선했다고 합니다.
물론 아직 베타 버전이며 현재 제공하고 있는 pages
디렉토리 기능과 함께 공존할 예정이며 나중에는 app
디렉토리 기능을 권장하고 지원할 예정이라고 합니다.
크게 아래의 4가지 기능을 지원한다고 합니다.
pages
디렉토리 대신에 app
디렉토리를 생성하고 하위애 page.js
를 생성합니다.export default function Page() {
return <div>Hello World!</div>;
}
layout.js
가 생성됩니다.{children}
를 통해서 주입 및 배치되며 나머지 변경이 불필요한 부분들은 내부 컴포넌트가 변경되어도 리렌더링이 발생하지 않습니다.export default function RootLayout({ children }) {
return (
<html>
<head></head>
<body>{children}</body>
</html>
);
}
layout.js
를 커스텀하게 되면 위에서 생성한 page.js
에 layout.js
UI가 혼합해서 보여지게 됩니다.export default function RootLayout({ children }) {
return (
<html>
<head></head>
<body>
<div>메뉴</div>
{children}
</body>
</html>
);
}
app/page2/page.js
처럼 하위에 새로운 페이지를 생성하고 실행해도 기존에 생성한 layout.js
UI가 보여지게 됩니다.loading.js
라는 예약 파일을 만들게 될 경우 해당 컴포넌트는 로딩상태를 표현해주는 UI 컴포넌트로 활용됩니다.getStaticProps
/ getServerSideProps
함수를 사용하지 않고 서버 사이드 로직을 구현할 수 있습니다.use
hook을 이용하여 아래처럼 간편하게 데이터 패칭을 구현할 수 있게 됩니다.use
hook은 React에서 최근에 공개한 데이터를 가져오는 새로운 방법을 제공하는 기능입니다.import { use } from "react";
export default function Page() {
// use Hook을 이용해 제공
const name = use(getData());
return <div>Hello World!</div>;
}
async function getData() {
const res = await fetch("API 주소");
const data = await res.json();
return data;
}
getStaticProps
/ getServerSideProps
에서 제공되는 캐시 기능을 옵션으로 사용할 수 있게 됩니다.// 캐시 기능
// 디폴트 설정이며 기존의 getStaticProps 와 동일하게 동작합니다.
fetch(URL, { cache: 'force-cache' });
// 캐시 기능을 사용하지 않음
// getServerSideProps 와 동일하게 동작합니다.
fetch(URL, { cache: 'no-store' });
// revalidate 단위로 설정된 시간을 주기로 캐시합니다.
// getStaticProps에서 revalidate 옵션을 사용한 것과 동일합니다.
fetch(URL, { next: { revalidate: 10 } });
next dev --turbo
스크립트를 통해 바로 turbopack을 사용할 수 있습니다.width
와 height
를 설정해야 했습니다.alt
를 기본적으로 제공하여 웹 접근성 향상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/legacy/image
로 변경되면서 자동으로 변경해주는 codemode를 제공합니다.// ./pages 디렉토리에 있는 코드들을 변경할 때의 예시
npx @next/codemod next-image-to-legacy-image ./pages
size-adjust
속성을 사용하여 Layout shift 현상 제거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}>
next/link
를 사용하기 위해서는 수동으로 <a>
태그를 자식으로 중첩시켜 사용해야 했습니다.<a>
태그를 제외하고 사용할 수 있습니다.<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>
next.link
기능을 next.js 13 버전으로 업그레이드 하기 위해 codemode를 지원합니다. // ./pages 디렉토리에 있는 코드들을 변경할 때의 예시
npx @next/codemod new-link ./pages
@vercel/og
라는 라이브러리를 통해 직접 사용자가 설정하는 Dynamic socail cards 기능을 제공합니다.// 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>
),
);
}
더 자세히 알아보기
// middleware.ts
import { NextResponse } from 'next/server';
import type { NextRequest } from 'next/server';
export function middleware(request: NextRequest) {
// 기존 헤더를 복사한 후 새로운 헤더를 셋팅
const requestHeaders = new Headers(request.headers);
requestHeaders.set('x-version', '13');
// NextResponse.rewrite에서도 직접 Reqeust header를 설정할 수 있습니다.
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;
}
redirect
기능을 사용할 때 더 이상 rewrite
, redirect
기능을 사용하지 않고 바로 json
형태로 Response를 처리할 수 있게 됩니다.// 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)) {
// 인증을 실패할 경우 오류 메시지를 json 형태로 담아 Response 처리
return NextResponse.json(
{
success: false,
message: 'Auth failed',
},
{
status: 401,
},
);
}
}
next.config.js
에서 experimental.allowMiddlewareResponseBody
설정이 필요합니다.const nextConfig = {
reactStrictMode: true,
swcMinify: true,
// option 추가
experimental: {
allowMiddlewareResponseBody: true
},
};
module.exports = nextConfig;
target
옵션을 next.config.js
에서 제거하였습니다.