next.js 14버전의 변경점을 알아보기 전, 체감상 가장 많은 변화가 있었던 13버전에 대해 먼저 알아보고자 한다. 아래 기술하는 내용은 next 공식 사이트와 기술 블로그를 찾아보며 나름대로 정리한 내용이다.
next.js 13버전에서는 크게 다음과 같은 변경점이 있었다.
하나하나 알아보도록 하자.
공통적인 UI를 랩핑 컴포넌트 형태로 제공하고, 내부에 children을 포함한다. 폴더 경로 안에, layout.js 컴포넌트만 추가해주면 된다.
// next.config.js
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStricMode: true,
experimental:{
appDir: true
}
}
module.exports = nextConfig
experimental 설정에 appDir:true 설정을 해주어야 경고가 뜨지 않는다.
컴포넌트가 렌더링되는 장소가 서버인지 클라이언트인지의 차이이다.13버전에서는 App 폴더 내 모든 컴포넌트들은 기본적으로 Server Component 이고 기존처럼 클라이언트 컴포넌트로 사용하려면 상단에 "use client" 를 명시해야 한다.
[ Client Component를 사용해야 하는 상황 ]
- useState, useEffect 훅을 사용하는 경우
- 특정 브라우저 API에 의존성이 있는 경우
- 특정 Event Listeners를 추가하는 경우
// client componet 예시
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>You clicked the Count++ button {count} times</p>
<button onClick={() => setCount(count + 1)}>Count++</button>
</div>
);
}
SSR의 경우 서버에서 데이터를 Fetch 하게 되는데 이때 데이터가 필요없는 UI(레이아웃 등...)를 먼저 보여주고 데이터 로딩이 끝나면 화면에 그려준다.
또한, loading.js 파일을 생성하면 React Suspense를 자동으로 래핑하여 로딩 화면을 보여주고 데이터 로딩이 끝나면 자동으로 교체된다.
/* app/dashboard/loading.tsx */
export default function Loading() {
// You can add any UI inside Loading, including a Skeleton.
return <LoadingSkeleton />;
}

fetch() web Api를 사용할 수 있게 되면서 컴포넌트 레벨에서도 SSR의 적용이 가능하고 기존의 SSG/SSR/ISR 등의 기법을 fech() 옵션으로 대체한다.
// 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 } });
Rust 기반의 JS 번들링 툴이며 개발에 필요한 최소한의 어셋만 번들링해 트렌스파일링과 시작 시간이 빠르다.
기존 Image 컴포넌트가 next/legacy/Image로 변경되면서 향상된 기능을 제공한다.
구글 폰트를 내장시켜 새로운 폰트 시스템을 도입했다. 이 시스템을 통해 성능 개선과 개인 정보를 보호하여 모든 구글 폰트를 편하게 관리할 수 있다.
// Roboto 폰트 커스텀
import { Roboto } from '@next/font/google'
const roboto = Roboto({
weight: '400',
subsets: ['latin'],
})
export default function MyApp({ Component, pageProps }) {
return (
<main className={roboto.className}>
<Component {...pageProps} />
</main>
)
}
커스텀 폰트들도 자동 self-hosting, 캐싱, pre-loading 등이 제공된다.
//커스텀 폰트
import localFont from '@next/font/local';
const myFont = localFont({ src: './my-font.woff2' });
<html className={myFont.className}>
폰트를 전역으로 설정할수도 있다.
// 전역 폰트설정
import { Inter } from '@next/font/google'
const inter = Inter({ subsets: ['latin'] })
export default function MyApp({ Component, pageProps }) {
return (
<>
<style jsx global>{`
html {
font-family: ${inter.style.fontFamily};
}
`}</style>
<Component {...pageProps} />
</>
)
}
// next.config.js
module.exports = {
experimental: {
fontLoaders: [
{ loader: '@next/font/google', options: { subsets: ['latin'] } },
],
},
}
Link 컴포넌트에 수동으로 a 태그를 추가할 필요가 없어졌다. 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>
sns를 통해 링크를 공유하면 OG Image라고 하는 소셜 카드가 뜬다.

정적 소셜카드는 시간 소비, 에러 이슈 등 유지보수가 까다로워 스킵되곤 하는데, Next 13에서는 이를 개선한 동적 소셜카드 생성 라이브러리인 @vercel/log를 도입했다.
// 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>
),
);
}
출처