NEXT.js 13.0.0 Release Note

December 01, 2022 - 우원

우선 보통의 버전은 세 자리의 숫자와 마침표로 이루어진다
각각의 숫자는 앞에서부터, Major, Minor, Patch로 이루어진다.

# package.json
{
  "name": "nextjs-blog",
  "scripts": {
    "dev": "next dev",
    "build": "next build",
    "start": "next start"
  },
  "dependencies": {
    "next": "12.0.2",
    "react": "17.0.2",
    "react-dom": "17.0.2"
  }
}

package.json 등에서 쉽게 확인 할 수 있다.

2022년 10월 26일,NEXT.js의 Major가 변경됬다. 버전은 어느새 13이라는 Major를 가지게 되었고, 어떤 부분이 바뀌었는지 살펴보기 위해 번역을 해보려고 한다.

😀 NEXT.js 13.0.0(Official Document)

As we announced at Next.js Conf, Next.js 13 (stable) lays the foundations to be dynamic without limits:

  • app Directory (beta) : Easier, faster, less client JS.
    • Layouts
    • React Server Components
    • Streaming
  • Turbopack (alpha) : Up to 700x faster Rust-based Webpack replacement.
  • New next/image: Faster with native browser lazy loading.
  • New @next/font (beta): Automatic self-hosted fonts with zero layout shift.
  • Improved next/link: Simplified API with automatic <a>

우리는 NEXT.js 컨퍼런스에서 NEXT.js 13(안정적인 상태)이 제한들이 없는 역동성의 토대를 마련했다는 것을 발표했습니다.

  • app Directory : 더 쉽게, 더 빠르게, 클라이언트 자바스크립트 코드는 더 적게.
    • Layouts
    • React Server Components
    • Streaming
  • Turbopack(alpha) : 최대 700배 빠른 러스트 기반 웹팩으로 교체.
  • New next/image : 기본 브라우저의 Lazy Loading으로 더 빠르게.
  • New @next/font(beta) : 레이아웃의 이동이 전혀 없는 자동화된 자체 호스팅 글꼴.
  • Improve next/link : 자동화 a 태그와 함께 단순해진 API.

New app Directory(Official Document)

Today, we're improving the routing and layouts experience in Next.js and aligning with the future of React with the introduction of the app directory. This is a follow-up to the Layouts RFC previously published for community feedback. The app directory is currently in beta and we do not recommend using it in production yet. You can use Next.js 13 with the pages directory with stable features like the improved next/image and next/link components, and opt into the app directory at your own pace. The pages directory will continue to be supported for the foreseeable future.

The app directory includes support for:

  • Layouts: Easily share UI between routes while preserving state and avoiding expensive re-renders.
  • Server Components: Making server-first the default for the most dynamic applications.
  • Streaming: Display instant loading states and stream in units of UI as they are rendered.
  • Support for Data Fetching: async Server Components and extended fetch API enables component-level fetching.

오늘 우리는 NEXT.js에서 라우팅 및 레이아웃 경험을 개선하는 중이며, "app Directory"의 소개와 함께 앞으로의 React를 조정하고 있습니다. 이는 커뮤니티의 피드백을 위해 이전에 게시된 Layouts RFC의 후속적인 것입니다.

현재 app Directory는 베타 단계이며, 우리는 상용화 단계에서는 아직 사용하지 않기를 추천합니다. 여러분은 NEXT.js 13을 향상된 next/image, next/link 컴포넌트와 개인의 개발 흐름에 선택적으로 app Directory를 도입하는 것과 같은 안정적인 기능을 pages Directory를 사용할 수 있습니다.

app Directory는 다음과 같은 기능을 지원합니다.

  • Layouts : 상태를 보존하고 비용이 많이 드는 재렌더링을 피하면서 라우트 간에 UI를 쉽게 공유할 수 있습니다.
  • Server Components : 가장 동적인 애플리케이션에 대해 서버 우선이 기본값이 됩니다.
  • Streaming : 렌더링되는 즉시 로드 상태 및 UI 단위 스트림을 표시합니다.
  • Data Fetching : 비동기 Server Components 및 확장된 fetch API는 컴포넌트 수준의 가져오기를 가능하게 합니다.

app Directory

살펴보면 아직 베타 단계이긴 하지만 기존 pages Directory와는 다르게 app Directory가 추가되었다. app Directory는 레이아웃, 서버 컴포넌트, 스트리밍, 데이터 가져오기를 지원한다.

app Directory는 pages Directory와 공존 할 수 없다. 그렇기 때문에 pages Directory를 사용하고 싶다면 app Directory를 사용하지 않아야 한다.

프로젝트를 생성해서 한번 알아보자.

yarn create next-app --typescript "프로젝트 명"

이제 app Directory를 사용하기 위해서는 next.config.js 파일을 수정해야 한다.

기본적인 초기 next.config.js는 아래와 같다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
}

module.exports = nextConfig

이제 app Directory를 사용하기 위해 "experimental: { appDir: true }"를 nextConfig에 추가해준다.

/** @type {import('next').NextConfig} */
const nextConfig = {
  reactStrictMode: true,
  swcMinify: true,
  experimental: { appDir: true },
}

module.exports = nextConfig

그렇다면 이제 app Directory를 사용할 수 있다.

pages Directory를 삭제하면 app Directory가 생성되고 layout.tsx가 자동 생성된다.

Layouts

app Directory는 레이아웃을 지원한다. 레이아웃은 페이지를 렌더링하는 데 사용되는 공통 UI를 정의하는 데 사용된다.

공식 문서에서 제공하는 예는 아래와 같다.

먼저 app Directory 최상단의 page.tsx는 "This file maps to the index route"이라고 되어있다. 그렇다 index.tsx와 같다.

// app/page.tsx
// This file maps to the index route (/)
export default function Page() {
  return <h1>Hello, Next.js!</h1>;
}

이제 app/blog/layout.tsx를 보자. ReactNode를 사용해서 children을 받아오면 해당 경로만의 layout으로 감싼 children을 반환한다.

// app/blog/layout.tsx
export default function BlogLayout({ children }: { children: React.ReactNode }) {
  return <section>{children}</section>;
}

Layouts Example

폴더 구조는 단순히 아래와 같이 구성했다.

app
├── blog
│   ├── layout.tsx
│   └── page.tsx
└── layout.tsx
└── page.tsx

// app/layout.tsx
export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html>
        <head>
            
        </head>
        <body>
            <div style={{"backgroundColor":"green"}}>
            {children}
            </div>
        </body>
    </html>
  );
}
// app/page.tsx

export default function Page() {
    return <h1>NEXT.js 13 /app/page.tsx</h1>;
  }
// app/blog/layout.tsx

export default function BlogLayout({ children }: { children: React.ReactNode }) {
  return (
    <div>
        <div style={{"backgroundColor":"pink","height":"100px","fontSize":"30px"}}>
        NEXT.js 13 /app/blog/layout.tsx
        </div>
        <div>
            {children}
         </div>
    </div>
  );
}
// app/blog/page.tsx

export default function Blog() {

    return <h1>NEXT.js 13 /app/blog/page.tsx</h1>;
  }

이제 실제 라우팅을 해보자.

localhost:3000으로 접속하면 /app/layout.tsx에 감싸진 /app/page.tsx의 내용 출력된다.

spring

이제 localhost:3000/blog로 접속하면 /app/blog/layout.tsx에 감싸진 /app/blog/page.tsx의 내용이 출력된다.

이때 /app/layout.tsx에 감싸진 /app/page.tsx의 내용은 출력되지 않는다. /app/layout.tsx의 내용은 /app/blog/layout.tsx에 감싸진 /app/blog/page.tsx의 내용과 함께 출력된다.

spring

Server Components

app Directory는 리액트의 새로운 기능인 서버 컴포넌트를 지원한다.

서버 컴포넌트란 클라이언트에서 렌더링되는 컴포넌트가 아니라 서버에서 렌더링되는 컴포넌트를 말한다.

서버 컴포넌트는 클라이언트에서 렌더링되는 컴포넌트와 다르게 서버에서 렌더링되기 때문에 클라이언트에서 렌더링되는 컴포넌트보다 더 많은 작업을 할 수 있다.

이번 NEXT.js의 발표 취지는 확실히 client에서 처리하는 자바스크립트를 줄이는 것에 목표를 두고 있다.

Client components

useState 또는 useEffect와 같은 클라이언트 훅을 사용하는 경우 Components에 'use client'를 표시한다.

다른 클라이언트 컴포넌트로부터 Import해서 사용되지 않을 때 자동으로 서버 컴포넌트로 렌더링 되어 사용될 수 있도록 되도록이면 'use client'문을 직접적으로 사용하지 않는 것이 좋다.

'use client';

import {useState} from 'react';

export default function Counter(){
  const [count, setCount] = useState(0);

  return (
    <div>
      <p>Count: {count}</p>
      <button onClick={() => setCount(count + 1)}>Increment</button>
    </div>
  );
}

Server Components VS Client Components

  1. Fetch Data
  • 서버 컴포넌트를 사용하는 것을 추천한다.
  1. 백엔드 자원에 직접적으로 접근할 때
  • 서버 컴포넌트를 사용하는 것을 추천한다.
  1. 서버에 민감한 정보를 계속해서 유지해야할 때
  • 서버 컴포넌트를 사용하는 것을 추천한다.
  1. 서버에 많은 의존성이 있을 때
  • 서버 컴포넌트를 사용하는 것을 추천한다.
  1. 상호작용을 추가하거나 이벤트 리스너를 추가할 때(onClick, onChange, onMouseOver 등)
  • 클라이언트 컴포넌트를 사용하는 것을 추천한다.
  1. 스테이트와 생명 주기 훅을 사용할 때(useState, useEffect 등)
  • 클라이언트 컴포넌트를 사용하는 것을 추천한다.
  1. 브라우저 API를 사용할 때
  • 클라이언트 컴포넌트를 사용하는 것을 추천한다.
  1. 스테이트에 의존하는 커스텀 훅, effects, 브라우저 API를 사용할 때
  • 클라이언트 컴포넌트를 사용하는 것을 추천한다.
  1. 리액트 클래스 컴포넌트를 사용할 때
  • 클라이언트 컴포넌트를 사용하는 것을 추천한다.

Streaming

app Directory는 클라이언트의 UI 단위별로 점진적인 렌더링과 증분적인 스트림을 소개한다.

app Directory의 layout 기능을 사용하면 데이터가 필요하지 않은 부분은 즉시 렌더링할 수 있고, 데이터를 가져오는 부분에 대해서도 로드 상태를 표시할 수 있다. 이러한 접근 방식을 사용하면 사용자는 전체 페이지가 로드될 때까지 기다릴 필요가 없다.

spring

왼쪽은 데이터 페칭이 필요한 부분을 제외하고는 바로 렌더링 되었고, 현재 로드 상태를 확인하고 있다. 오른쪽은 데이터가 로드 되어 이미지와 텍스트가 출력된 상태이다.

Data Fetching

리액트는 공식적으로 컴포넌트 내에서 데이터를 가져오고 프로미스를 다루는 강력한 새로운 방법을 소개했다.

// app/page.js
async function getData() {
  const res = await fetch('https://api.example.com/...');
  // 반환되는 데이터는 시리얼라이즈되지 않고 전달된다.
  // 그리고 데이터는 Date, Map, Set 등의 객체로 반환할 수 있다.
  return res.json();
}

// This is an async Server Component
export default async function Page() {
  const data = await getData();

  return <main>{/* ... */}</main>;
}

이러한 특징은 리액트뿐만아니라 Next.js에서도 사용할 수 있다. 그리고 데이터 가져오기, 캐시하기, 컴포넌트 레벨에서 데이터를 검증하는 하나의 탄력적인 방식을 제공하고 자동으로 적용된다. 이러한 방식은 SSG, SSR에 이점이 있고, ISR의 정적인 재생성이 하나의 API에서 유효하다는 것을 말한다.

옵션은 아래와 같다.

// getStaticProps와 비슷한 부분이다.
fetch(URL, { cache: 'force-cache' });
// getServerSideProps와 비슷한 부분이다.
fetch(URL, { cache: 'no-store' });
// getStaticProps의 revalidate와 비슷한 부분이다.
fetch(URL, { next: { revalidate: 10 } });

app Directory에서는 레이아웃과 페이지 그리고 컴포넌트에서 서버에서 스트리밍을 활용하여 데이터를 가져올 수 있다. 향후 릴리스에서는 데이터 변형도 개선하고 단순화할 예정이다.

Introducing Turbopack (Alpha)

Next.js 13에는 Webpack의 새로운 Rust 기반 후속 제품인 Turbopack이 포함되어 있다.

Next.js 12버전부터 러스트 기반 도구로 전환을 시작했다. 우리는 Babel로부터 마이그레이션하는 것으로 시작해서 17배 더 빠른 트랜스파일을 얻었다. 그런 다음 Terser를 교체하여 축소가 6배 빨라졌다. 번들링을 위해 네이티브에 올인할 때이다.

터보팩 사용으로 인한 결과는 아래와 같다.

  • 웹팩(Webpack)보다 700배 더 빠르다.
  • 바이트(Vite)보다 10배 더 빠르다.
  • 웹팩보다(Webpack)보다 4배 더 빠른 Cold starts

Cold Start

아무것도 없는 상태(캐시가 없는 상태)에서 앱을 처음 시작하는 것을 말한다. -> 최초 실행 시간

Benchmark

spring

NEXT/Image

강력한 새로운 이미지 컴포넌트를 소개한다. 당신이 성능 향상을 위해 요구되는 레이아웃의 변경 및 최적화 작업 없이 손쉽게 이미지를 표시할 수 있다.

커뮤니티의 조사에 따르면 70%의 응답자가 Next.js 이미지 컴포넌트를 실제 프로덕션에서 사용하고 있고 그 결과로 Core Web Vitals이 개선되었다. 그리고 Next.js 13 버전에서는 더욱 향상된 이미지 컴포넌트가 나왔다.

새로운 이미지 컴포넌트 특징

  • 클라이언트 사이드로 더 적은 코드를 보냄
  • 쉬운 스타일링과 설정
  • alt 태그가 자동으로 추가되어 더 나아진 접근성
  • 웹 플랫폼과 상응
  • 하이드레이션을 필요로 하지 않는 Lazy Loading으로 더 빨라짐
import Image from 'next/image';
import avatar from './lee.png';

function Home() {
  // 현재는 alt 속성이 접근성을 위해 필수이다. 
  return <Image alt="leeerob" src={avatar} placeholder="blur" />;
}

이전 이미지 컴포넌트

이전 이미지 컴포넌트는 레거시로 이동했다. next/legacy/image

@next/font

Next.js는 새로운 폰트 시스템을 소개했다.

특징은 아래와 같다.

  • 커스텀 폰트를 포함해 사용자의 폰트를 자동으로 최적화함
  • 외부의 네트워크를 개인 프라이버시와 성능 개선을 위해 제거
  • 어떤 폰트 파일이더라도 내장된 자동 자체 호스팅이 가능
  • CSS size-adjust 속성을 활용해서 자동으로 제로 레이아웃 변형

새로운 폰트 시스템은 사용자가 구글 폰트를 높은 성능과 개인 프라이버시를 보장하면서 편리하게 사용할 수 있도록 도와준다. 브라우저에 의해서 구글에 보내는 요청이 전혀 필요없게 되었다.

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

next/link에서는 더이상 자식노드로 a 태그가 필요없다.

실험적으로 12.2 버전부터 추가된 기능이지만 현재는 기본적으로 사용 가능하다.

import Link from 'next/link'

// Next.js 12
<Link href="/about">
  <a>About</a>
</Link>

// Next.js 13
<Link href="/about">
  About
</Link>
logo

우원 /

안녕하세요👏
우원입니다.
Email
Gihub
안녕하세요. 우원봇입니다.
logo