Next.js 13v 소개

우동이·2022년 11월 6일
2

Next.js

목록 보기
4/4
post-thumbnail

1. app 디렉토리 도입

  • 기존에 next.js는 파일 시스템 라우터 기능을 통해 디렉토리 폴더 내부에 파일 생성만으로 애플리케이션 경로를 설정 할 수 있었습니다.

  • 이번에 /app 디렉토리를 도입하면서 라우팅 및 레이아웃 경험을 개선했다고 합니다.

  • 물론 아직 베타 버전이며 현재 제공하고 있는 pages 디렉토리 기능과 함께 공존할 예정이며 나중에는 app 디렉토리 기능을 권장하고 지원할 예정이라고 합니다.

  • 크게 아래의 4가지 기능을 지원한다고 합니다.

    • 레이아웃: 리렌더링을 성능을 개선하며 경로 간에 UI를 쉽게 공유할 수 있습니다.
    • 서버 컴포넌트: 서버 컴포넌트 기능을 손쉽게 제공하여 성능 향상에 도움을 줄 수 있게 됩니다.
    • 스트리밍: 로딩 상태를 표시하고 렌더링되는 UI 단위로 스트리밍을 제공합니다.
    • 데이터 패칭: 새로운 데이터 패칭 기능을 제공합니다.

레이아웃

  • 여러 페이지들이 공유하는 공통 UI 기능을 제공하며 불필요한 리렌더링을 방지하고 서로 상호작용할 수 있는 기능을 제공합니다.
  • Root에 기존 pages 디렉토리 대신에 app 디렉토리를 생성하고 하위애 page.js를 생성합니다.
    • page.js는 해당 경로에 표시될 페이지를 의미합니다.
export default function Page() {
  return <div>Hello World!</div>;
}

  • 다음에 next.js를 실행하게 되면 놀랍게도 자동으로 layout.js가 생성됩니다.
    • 페이지 영역은 {children}를 통해서 주입 및 배치되며 나머지 변경이 불필요한 부분들은 내부 컴포넌트가 변경되어도 리렌더링이 발생하지 않습니다.
export default function RootLayout({ children }) {
  return (
    <html>
      <head></head>
      <body>{children}</body>
    </html>
  );
}
  • 해당 layout.js를 커스텀하게 되면 위에서 생성한 page.jslayout.js UI가 혼합해서 보여지게 됩니다.
export default function RootLayout({ children }) {
  return (
    <html>
      <head></head>
      <body>
        <div>메뉴</div>
        {children}
      </body>
    </html>
  );
}

  • app/page2/page.js 처럼 하위에 새로운 페이지를 생성하고 실행해도 기존에 생성한 layout.js UI가 보여지게 됩니다.
  • 정리하자면 페이지 단위로 컴포넌트가 계속 변경되어도 Layout 컴포넌트는 리렌더링이 발생하지 않아 성능을 향상시킬 수 있습니다.
  • 이외에도 더 많은 기능을 가지는 예약 파일을 제공하고 있으니 아래의 공식문서를 참고해보세요!

서버 컴포넌트

  • app 디렉토리에 리액트 서버 컴포넌트를 사용하게 될 경우 서버에서만 컴포넌트를 렌더링한다고 합니다.
    • 리엑트 서버 컴포넌트는 React 18에 도입되는 최신 기술이며 서버에서 동작하는 리액트 컴포넌트를 의미합니다.
    • 즉 서버에서 데이터 패칭 등을 수행하여 클라이언트에서 연속된 API 호출을 방지할 수 있게 됩니다.
  • 이렇게 되면 클라이언트에 전송되는 자바스크립트의 양이 줄어들어 초기 페이지 로딩을 더 빠르게 진행할 수 있다고 합니다.
  • 위에서 언급된 app 디렉토리에서 사용되는 컴포넌트는 서버 컴포넌트 방식입니다.
  • 관련 공식문서

스트리밍

  • 서버 사이드에서 고정적인 레이아웃들은 데이터 패칭이 필요없기 때문에 먼저 클라이언트에게 전송하여 렌더링을 진행하게 됩니다.
  • 데이터 패칭이 필요한 부분은 별도로 데이터 패칭이 끝난 후 클라이언트에게 전송하여 렌더링을 마무리합니다.
  • 이 과정에서 app 디렉토리 내부에 loading.js라는 예약 파일을 만들게 될 경우 해당 컴포넌트는 로딩상태를 표현해주는 UI 컴포넌트로 활용됩니다.

데이터 패칭

  • 이번에 next.js 13이 도입되면서 새로운 데이터 패칭 방식을 공개했습니다.
  • 기존에 사용했던 getStaticProps / getServerSideProps 함수를 사용하지 않고 서버 사이드 로직을 구현할 수 있습니다.
  • use hook을 이용하여 아래처럼 간편하게 데이터 패칭을 구현할 수 있게 됩니다.
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 } });

2. Turbopack 지원

  • Rust 기반의 번들러인 Turbopack을 지원한다고 합니다.
  • 기존 Webpack보다 700배, Vite 보다 10배 빠르다고 합니다.

  • Turbopack은 서버 컴포넌트, TypeScript, JSX, CSS 등 많은 부분을 지원한다고 합니다.
  • 또한 기존의 Turbopack에는 많은 기능들이 존재하지만 아직 알파버전이다보니 모든 기능들을 지원하지는 않는다고 합니다.
  • next dev --turbo 스크립트를 통해 바로 turbopack을 사용할 수 있습니다.
  • 관련 공식문서: https://turbo.build/pack

3. next/image

  • 기존에 next.js에서 제공하는 이미지 컴포넌트를 개선하여 향상된 성능을 제공한다고 합니다.
  • 보통 이미지 로드가 늦어질 경우 Layout Shift 현상이 발생하는데 이를 방지하기 위해서는 사전에 이미지의 widthheight를 설정해야 했습니다.
    • Layout Shift 현상: 이미지 로드가 늦어질 경우 나중에 로드되면서 기존 레이아웃 UI가 밀리는 현상
  • 하지만 next.js 13에서는 이를 자동으로 처리합니다!
  • 주요 기능
    • 더 적은 자바스크립트를 클라이언트에 제공
    • 스타일 지정 및 구성 용이
    • 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

4. @next/font

  • next.js 13에서 새로운 폰트 시스템을 도입했습니다.
  • 주요 내용
    • 자동으로 최적화한 기본 및 커스텀 폰트 제공
    • 개인 정보 보호 및 성능 향상을 위해 외부 네트워크 요청 제거
    • 모든 폰트 파일을 자동 셀프 호스팅 방식으로 제공
    • CSS의 속성 중 size-adjust속성을 사용하여 Layout shift 현상 제거
  • 이제는 Google 폰트를 편하게 사용할 수 있게 됩니다.
    • CSS 및 폰트 파일은 빌드 할 때 다운로드되며 static asset 파일들과 함께 셀프 호스팅을 지원합니다.
    • 즉 이제는 더 이상 폰트를 사용하기 위해 브라우저가 Google로 폰트 요청을 하지 않아도 됩니다.
import { Inter } from '@next/font/google';

const inter = Inter();

<html className={inter.className}>
  • 커스텀 폰트 또한 자동 셀프 호스팅, 캐싱, preloading을 지원합니다.
    • 동일하게 Layout shift 현상이 제거되며 사용자 경험을 위해 최적화 기능을 그대로 제공합니다.
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

6. OG Image Generation

  • OpenGraph를 제공하기 위한 social card기능을 제공하여 콘텐츠의 접근성을 향상시켜줍니다.
    • OpenGraph: 해당 사이트를 링크로 걸었을 때 링크 걸린 사이트를 어떻게 표시할지를 결정하는 정보를 의미합니다.
  • @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>
    ),
  );
}

더 자세히 알아보기

7. Middleware API Update

  • 기존에 next.js 12에서 추가되었던 Middleware 기능이 개선되었습니다.
  • 이제는 손쉽게 Request Header 값을 세팅할 수 있게 됩니다.
// 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;

8. 기타 변경 사항

  • 더 이상 사용되지 않는 target 옵션을 next.config.js에서 제거하였습니다.
  • 이제는 Internet Explorer를 지원하지 않는다고 합니다!
    • 최신 브라우저만 대응하도록 변경
      • Chrome 64+
      • Edge 79+
      • Firefox 67+
      • Opera 51+
      • Safari 12+

참고

profile
아직 나는 취해있을 수 없다...

0개의 댓글