Next 강의를 듣고 실습을 해보려 하는데 생성 하자마자 폴더 구조가 다르다?
강의가 오래되어서 버전이 많이 다른가 하고 찾아보다가 알게된
Next.js 13 버전
2022년 10월에 Next.js 컨퍼런스에서 발표 되었다고 한다.
주요 변경 사항
- app/Diectory: 쉽고, 빠르고, 적은 클라이언트 JS (Layout, React Server Components, Streaming)
- Turbopack: Rust 기반. Webpack 보다 700배, Vite 보다 10배 빠른 번들러
- Image: 새로운 next/image. 더 빨라진 Lazy Loading
- Font: 새로운 next/font. 구글 폰트 자체 내장
- Link: 향상된 next/link. <a> 태그를 자식 요소로 넣을 필요 없음
💡
Next.js 13 버전을 사용하기 위한 React와 Node 버전
React 최소 버전: 18.2.0
Node.js 최소 버전: 14.6.0
app/Directory
새로운 디렉토리 구조
기존 Next에선 pages/ 디렉토리 내에 폴더, 파일을 생성하여 라우팅을 설정할 수 있었다.
Next.js 13 부터는 app/ 이라는 새로운 디렉토리로 라우팅을 설정할 수 있으며,
라우팅 환경개션 뿐만 아니라 레이아웃, 서버 컴포넌트, 스트리밍, 데이터 패칭 까지도 지원하는 형태로 향상시켰다.
변경 전
📦 /pages
└─ 📂 home/
├─ 📄 index.tsx >> /home
├─ 📄 page.tsx >> /home/page
└─ 📄 other.tsx >> /home/other
변경 후
📦 /app
└─ 📂 home/
├─ 📄 index.tsx >> 접근불가
├─ 📄 page.tsx >> /home
└─ 📄 other.tsx >> 접근불가
app 폴터로 기존 파일 시스템 라우팅을 구현할 수 있으며, 여기의 page.js가 해당 경로(라우팅)의 페이지 컴포넌트가 된다.
💡 마이그레이션을 위해 기존 pages도 지원중이라고 한다.
하지만 pages 지원이 중단되는 시점부터는 더이상 next 버전을 간단하게 올릴 수 없는 레거시 코드가 될 것 같다.
1. Layouts
공통적인 UI children을 감싸는 래핑 컴포넌트 형태로 쉽게 제공하는 형태이다.
이를 통해, 공통 레이아웃의 상태를 유지하고, 불필요한 리렌더링을 방지하며, 컴포넌트 간 상호작용을 향상시켰다.
폴더 경로 안에 layout.js 컴포넌트만 추가해주면 쉽게 공통 레이아웃을 적용할 수 있다.
📦 /app
├─ 📄 page.tsx
├─ 📄 layout.tsx
└─ 📂 home/
├─ 📄 index.tsx
└─ 📄 layout.tsx
상위 폴더에 위치한 레이아웃은 하위 폴더에 있는 컴포넌트를 감싸고 있는 구조
2. Server Component
app 파일 구조는 React의 Server Components 아키텍쳐를 지원한다. app 디렉토리 내 파일은 디폴트로 서버 컴포넌트다.
서버 컴포넌트는 클라이언트에 전송되는 JS 코드량을 줄여서 초기 페이지 로드가 빨라진다.
또한, route가 로드 되면서 Next.js와 React 런타임이 각각 로드된다.
이는 어플리케이션이 커지더라도 런타임 크기가 증가하지 않으며, 추가적인 JS 기능은 클라이언트 컴포넌트로 부여한다고 한다.
*Client Component
"use client";
import { useState } from "react";
export default function Counter() {
const [count, setCount] = useState(0);
return (
<div>
<p>{ count } times</p>
<button onClick={() => setCount(count + 1)}>plus count</button>
</div>
);
}
클라이언트 컴포넌트를 사용하려면 최상단에 "use client"를 적어준다.
- useState, useEffect 훅을 사용하는 경우
- 특정 브라우저 API에 의존성이 있는 경우
- 특정 Event Listners를 추가하는 경우
위의 상황에선 반드시 클라이언트 컴포넌트를 써야 한다.
3. Streaming
app 파일 구조는 렌더링 되는 UI단위를 점진적으로 렌더링하고 스트리밍하는 기능을 가능케 한다.
Next.js의 레이아웃과 서버 컴포넌트를 사용하면, 데이터가 필요하지 않은 일부는 즉시 렌더링하고 데이터를 가져오는 부분은 로딩을 적용할 수 있다.
로딩 처리는 디렉토리 경로 내의 loading.tsx 또는 <Suspense>로 처리한다.
4. Data Fetching
Nest.js에서 fetch() Web API를 사용할 수 있게 되면서 컴포넌트 레벨에서도 SSR의 적용이 가능해졌다.
- Next.js 컴포넌트들은 기본적으로 서버 컴포넌트 이므로 서버단에서 데이터를 불러온다.
- 데이터는 병렬적으로 일어난다.
- 데이터 패치는 자동으로 중복제거(deduping) 된다. 부모-자식 간의 동일한 요청은 1회로 실행한다.
- Loading UI (혹은 Suspense), Streaming 등을 통해 데이터를 불러오는 영역과 미리 보여주는 영역을 나누어서 표현한다.
React는 fetch() API 중복제거를 제공하며, Next.js는 캐싱과 재요청 처리까지 지원하려고 한다.
이를 통해 기존의 SSG, SSR, ISR등의 기법을 아래와 같은 fetch() 옵션으로 대체 가능하다.
// 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 } });
Turbopack
새로운 번들링 툴
Next.js 13에서는 Rust 기반의 JS 번들링 툴인 Turbopack이 포함 되어있다.
기존 웹팩도 널리 사용 됐지만, JS 기반인 만큼 성능적으로 한계에 도달했다.
Next.js 12부터 Rust 기반 툴링으로 전환했고, 현재는 더 빠른 트렌스파일링과 번들링 성능을 보여주고 있다.
- Webpack 보다 700배 빠른 업데이트
- Vite 보다 10배 빠른 업데이트
- Webpack 보다 4배 빠른 cold start
*cold start
Single Page 표현을 위해 로컬에서 데이터를 불러오고 HTML 기반로 로드 준비가 된 상태
next/image
- 클라이언트 측에서 더 적은 양의 Javascript 코드를 가짐
- 더 쉽게 스타일링과 설정이 가능
- alt 속성을 필수로 제한하여 웹 접근성 향상
- 웹 플랫폼에 맞게 조정 (사이즈, 화질 등)
* 이미지 로드가 느리면 기존 레이아웃이 밀리는 Layout Shift를 방지 (width, height 값 필수 입력)
- hydration을 필요로 하지 않는 네이티브 lazy-loading으로 속도 향상
next/font
Next.js 13 는 새로운 폰트 시스템을 도입했다.
- 커스텀 폰트를 포함하여 폰트를 자동으로 최적화
- 개인 정보 보호 및 성능 향상을 위한 외부 네트워크 요청 제거
- 모든 폰트 파일에 대한 내장형 자동 자체 호스팅 제공
- CSS size-adjust 속성을 적용하여 자동으로 레이아웃 이동이 발생하지 않음
이 폰트 시스템을 통해 성능 개선과 개인 정보를 보호하며 모든 Google 폰트를 편하게 관리할 수 있다.
CSS 및 폰트 파일은 빌드 시간에 다운로드 되고 나머지 정적 assets과 함께 self-hosting 된다. (브라우저에서 Google로 요청 X)
import { Roboto } from "@next/font/google"
const roboto = Roboto({
weight: '400',
subsets: ['latin'],
})
export default function Home({ Component, pageProps }){
return (
<main className={roboto.className}>
<Component {...pageProps} />
</main>
);
}
next/link
<Link> 컴포넌트에 더 이상 수동으로 <a> 태그를 추가할 필요가 없어졌다.
<Link>는 이제 기본값으로 <a> 태그를 렌더링 하며, <a> 태그의 Props 들을 정상적으로 전달 할 수 있다.
변경 전
import Link from 'next/link'
<Link href='/home'>
<a>Home</a>
</Link>
변경 후
import Link from 'next/link'
<Link href='/home'>
Home
</Link>
그 외에도 OG이미지 생성, 미들웨어 API 업데이트도 업데이트 되었다.
📌 참고자료