Next.js가 2016년에 처음 공개되고 나서 시간이 흘러 벌써 7살이 되었습니다 🎉
사실 저는 Next.js 13 버전부터 발을 들인 프론트엔드 응애라서 크게 와닿진 않지만.. 최근에 14로 버전업 되었다는 소식에
Next.js 13도 보내줄 겸, 이전 버전과 어떤 차이가 있는지 한 번 정리하고 넘어가려고 합니다.
지금 글을 쓰는 순간에 이미 버전이 0.1 올라가서 14.1.0이네요..ㅎ
자, 그럼 시작해볼까요?
Next.js 14 버전업 특징 5가지
- Turbopack : app router & pages router에 대한 5000회의 테스트 통과
- 53% 빨라진 로컬 서버 시작 속도
- 94% 빨라진 코드 업데이트 - Server Actions(Stable) : 점진적으로 개선된 mutations
- caching & revalidating 통합
- 간단한 함수 호출 or forms과 함께 기본적으로 동작 - Partial Prerendering(Preview) : 빠른 초기의 정적 응답 + 동적 컨텐츠 스트리밍
- Metadata Improvements : 블로킹 메타데이터와 논 블로킹 메타데이터 분리
- Next.js Learn (New!🌟) : App router, 인증, 데이터베이스 등을 심플 프로젝트를 만들어보면서 가르치는 무료 강좌
이번 14 버전에서는 위 내용처럼 '개선', '안정'이 point 인 것 같네요. Next.js 12 ➡ Next.js 13으로 버전업 될 때 변화가 커서 그런지
이번 업데이트에서는 내실을 다지면서 다음 도약을 준비하는 버전업인 것 같습니다! 원문은 여기를 참고해 주시고, 그럼 하나씩 차례대로 세부 내용을 알아볼게요.
1. Turbopack
터보팩.. 네이밍에서부터 뭔가 빠르고 강력할 것 같은 느낌이 드는데요, turbopack은 vercel에서 개발한 rust언어 기반 번들링 툴입니다.
변화되지 않은 값은 caching 하는 방식으로 처리속도가 굉장히 빠르다고 합니다. vite의 10배, webpack의 700배 빠른 속도라고 하는데,
이전까지는 아직 안정화가 덜 돼서 기존의 webpack을 완전히 대체하기까지는 시간이 필요하다는 말이 있었습니다.
그런데 드디어 이번 Next.js 14에 이르러서 'next dev'에 대한 전체 테스트 중, 5000회 이상 통과하면서 곧 테스트 통과율 100%를 달성할 것으로 보입니다. 테스트 통과율은 여기서 볼 수 있습니다.
Next.js팀은 5000회가 넘는 테스트에 지난 7년간의 버그 수정 및 재현이 포함되어 있다고 언급하면서, 조만간 테스트 통과율이 100%에 도달하면 곧 있을 minor release에서 Turbopack을 Stable 버전으로 전환할 예정이라고 밝혔습니다.
Turbopack 그래서 얼마나 빠른데?
위에서 언급한 것처럼 '53% 빨라진 로컬 서버 시작 속도'를 체감할 수 있을까요? 그래서 제가 한 번 체험해봤습니다!
turbopack을 적용하는 방법은 매우 간단합니다. package.json의 script 명령어에 --turbo 옵션을 달아주면 됩니다.
// package.json
{
"scripts": {
"dev": "next dev --turbo",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
}
그럼 바로 'yarn dev'로 시작해 보죠!
결과는 기존 로컬 서버 1385ms ➡ 666ms로 719ms 감소해서 약 51.8% 빨라졌습니다!
Next.js 팀에서 언급한 것과 매우 비슷한 수치를 보여줬습니다. 확실히 turbopack을 적용했을 때 와 아닐 때 체감이 될 정도의 속도 차이였습니다. 대규모 앱에서도 이런 빠른 속도를 보여준다고 하니, 안정성만 보장된다면 충분히 webpack의 후계자가 될 녀석인 것 같네요.
2. Server Actions(Stable)
두 번째는 Server Actions입니다. 서버 액션은 Next.js를 좀 더 쉽게 풀스택 프레임워크로 활용할 수 있게 도와줍니다.
Next.js는 9 버전부터 API 라우터를 제공하면서 Next.js가 클라이언트와 백엔드 둘의 역할을 모두 수행할 수 있도록 했는데요,
// pages/api/submit.ts
// 기존 API 라우터 방식
import type { NextApiRequest, NextApiResponse } from 'next';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse,
) {
const data = req.body;
const id = await createItem(data);
res.status(200).json({ id });
}
기존의 API 라우터 방식에서 한 단계 더 나아가, 별도의 API 라우터를 생성하지 않고도 서버 컴포넌트에서 바로 DB에 접근할 수 있도록 한 것이 바로 Server Actions입니다. Server Actions을 사용하면 코드가 유저에게 노출되지 않고 DB에 접근해서 데이터를 조작할 수 있다는 장점이 있습니다. Server Actions은 Alpha와 Beta 버전을 거쳐 이번 Next.js 14 버전에서 Stable 되었습니다.
Server Actions 사용법
서버 액션을 사용하기 위해선 'use server'를 사용합니다. 서버 액션으로 만들고자 하는 비동기 함수의 상단에 입력하거나 파일 상단에 입력하면 됩니다. 그러면 Next.js가 'use server' 키워드를 감지하고 해당 함수를 자동으로 서버 API화 해주는 마법을 부려줍니다🪄 또, 파일 상단에 입력하면 해당 파일(모듈)의 모든 내보내기를 서버 액션으로 표시할 수 있습니다. 저도 아직 사용해보지 않아서 설명만 듣고는 어색한데, 예시 코드를 같이 살펴보겠습니다.
// Server Component
export default function Page() {
// Server Action
async function create(formData: FormData) {
'use server';
const id = await createItem(formData);
}
return (
<form action={create}>
<input type="text" name="name" />
<button type="submit">Submit</button>
</form>
);
}
Server Actions의 가장 기본적인 사용법인 Form과 같이 사용하는 예시 코드로, 위 코드에서 create 함수는 'use server' 키워드로 Server Action이 되었고, 그 Server Actions을 포함한 Page 컴포넌트는 Server Component입니다. 앞서 언급한 내용처럼 API 라우터를 거치지 않고 form 태그의 action 속성으로 전달된 'create' Server Action이 'createItem' 함수로 DB에 접근하면서, 서버 컴포넌트 내에서 DB 접근까지 원 큐🌟에 처리하는 것을 볼 수 있습니다.
이러한 Server Actions은 Server Component와 Client Component 두 곳 모두에서 import 해서 사용할 수 있는데요,
단 Client Component에서 서버 액션을 사용하려면 서버 액션이 'module' 수준 레벨이어야만 합니다.
'use server'
export async function create() {
// ...
}
만들어진 Server Actions은 Component의 Props로 넘겨질 수 있고,
<ClientComponent updateItem={updateItem} />
'use client'
export default function ClientComponent({ updateItem }) {
return <form action={updateItem}>{/* ... */}</form>
}
이벤트 핸들러는 물론 useEffect 안에서도 사용할 수 있습니다.
// onClick 이벤트 핸들러
'use client'
import { incrementLike } from './actions'
import { useState } from 'react'
export default function LikeButton({ initialLikes }: { initialLikes: number }) {
const [likes, setLikes] = useState(initialLikes)
return (
<>
<p>Total Likes: {likes}</p>
<button
onClick={async () => {
const updatedLikes = await incrementLike()
setLikes(updatedLikes)
}}
>
Like
</button>
</>
)
}
// useEffect에서 사용
'use client'
import { incrementViews } from './actions'
import { useState, useEffect } from 'react'
export default function ViewCount({ initialViews }: { initialViews: number }) {
const [views, setViews] = useState(initialViews)
useEffect(() => {
const updateViews = async () => {
const updatedViews = await incrementViews()
setViews(updatedViews)
}
updateViews()
}, [])
return <p>Total Views: {views}</p>
}
Server Actions이 가진 능력은 위 사진에 나와있는 것처럼 재검증, 리디렉션, 쿠키접근 등 다양합니다. Server Actions을 잘 이해하고 활용할 수 있다면 Next.js를 지금 보다 더 맛있게? 사용할 수 있겠다는 생각이 드네요!
3. Partial Prerendering(Preview)
다음은 부분 사전 렌더링에 관한 내용인데, 아직 개발 중인 기능입니다. React Suspense를 기반으로 구축되고, Suspense의 경계를 기준으로 부분 사전 렌더링이 정의됩니다. 예시 코드로 같이 살펴보시죠!
export default function Page() {
return (
<main>
<header>
<h1>My Store</h1>
<Suspense fallback={<CartSkeleton />}>
<ShoppingCart />
</Suspense>
</header>
<Banner />
<Suspense fallback={<ProductListSkeleton />}>
<Recommendations />
</Suspense>
<NewProducts />
</main>
);
}
위 코드의 Suspense의 fallback으로 제공된 <CartSkeleton />과 <ProductListSkeleton />이 부분 사전 렌더링 되는 부분이고,
해당 부분의 요청이 이루어지면, 아래 코드와 같은 정적인 HTML을 즉시 제공하고, 추후에 동적 구성요소로 대체됩니다.
<main>
<header>
<h1>My Store</h1>
<div class="cart-skeleton">
<!-- Hole -->
</div>
</header>
<div class="banner" />
<div class="product-list-skeleton">
<!-- Hole -->
</div>
<section class="new-products" />
</main>
부분 사전 렌더링은 현재 활발히 개발 중이어서, 향후 마이너 릴리스에서 더 많은 업데이트를 공유할 예정이라고 하네요!
해당 부분의 원문은 여기를 클릭하세요!
4. Metadata Improvements
페이지의 메타데이터를 설정하는 부분이 변경되었습니다. 기존에는 og, title, description과 함께 viewport, colorScheme, themeColor 정보도 다 같이 설정했었는데요, 새롭게 버전 업된 Next.js 14에서는 viewport, colorScheme, themeColor와 같이 유저의 경험에 영향을 주는 정보는 이제 따로 설정해야 합니다.
// 초기 페이지 컨텐츠와 함께 viewport 정보 전송
import type { Viewport } from 'next'
export const viewport: Viewport = {
themeColor: 'black',
}
export default function Page() { ... }
변경된 이유로, 우선 서버에서 페이지 컨텐츠를 스트리밍 하려면 viewport, themeColor, colorScheme과 같이 중요한 메타데이터를 브라우저로 전송해야 하는데, 이런 메타 정보들을 초기 페이지 컨텐츠와 함께 전송함으로써 viewport 혹은 themeColor 변경으로 인한 Layout 변화로 페이지가 깜빡이는 현상을 방지할 수 있기 때문입니다. 즉, 유저 경험이 저하되는 것을 방지할 수 있겠습니다!
그래서 viewport, themeColor, colorScheme과 같은 논 블로킹 메타데이터를 기존 블로킹 메타데이터와 분리시킴으로써 미리 렌더링 된 정적 페이지를 방해하지 않게끔 하는 것이 목적이라고 합니다.
5. Next.js Learn(New!🌟)
Next.js 무료 강의가 새롭게 업데이트되었습니다! 이번 강의에서는 Simple Project를 만들면서 App Router와 Data Fetching 등,
저도 배워보고 싶은 눈길이 가는 내용들이 포함되어 있네요 ㅎ.. 한 번 도전해 봐야겠습니다!
Other Changes
그 밖에 변경 사항으로 Breaking Point가 존재합니다! 가장 눈에 띄는 건 Node.js 최소 버전이 18.17로 변경되었네요.
자세한 설명은 여기를 참고해 주세요!
마치며
Next.js 14의 버전 업된 특징에 대해 정리하면서 기존에 자세히 알지 못했던 Turbopack, Server Actions 등에 대해 공부해 볼 수 있어서
좋았던 경험이었습니다. 1년마다 스택도 훅훅 변하는 상황에서 감을 잃지 않기 위해서라도 더 열심히 글로 남겨야겠단 생각이 드네요!