[Next.js] Next 공식 튜토리얼 진행하기 - Chapter 3

728x90

이번 글은 Next.js 공식 튜토리얼을 번역한 글입니다.

공식 튜토리얼을 따라하면 Next.js 의 동작원리와 개발 방식에 대해 학습하기 쉽고 잘 쓰여진 튜토리얼이라고 생각되어 번역하게 되었습니다.

오타 또는 오역된 부분이 있다면 댓글 부탁드립니다.

 

Learn Next.js: Optimizing Fonts and Images | Next.js

Optimize fonts and images with the Next.js built-in components.

nextjs.org

 

지난 장에서는 Next.js 애플리케이션의 스타일링에 대해 알아보았습니다. 이번에는 홈페이지에 커스텀 폰트와 히어로 이미지를 추가하는 방법을 배워보겠습니다.

 

이번 장에서 다룰 주제는 다음과 같습니다.

 

  • next/font를 사용하여 커스텀 폰트 추가하기
  • next/image를 사용하여 이미지 추가하기
  • Next.js에서 폰트와 이미지가 최적화되는 방식

폰트를 최적화하는 이유

폰트는 웹사이트의 디자인에 중요한 역할을 하지만, 커스텀 폰트를 사용하면 폰트 파일을 불러오고 로드하는 데 시간이 걸려 성능에 영향을 줄 수 있습니다.

 

구글이 웹사이트의 성능과 사용자 경험을 평가할 때 사용하는 지표 중 하나인 누적 레이아웃 이동(CLS)는 페이지가 로드될 때 콘텐츠가 이동하는 현상을 측정합니다. 폰트의 경우, 브라우저가 처음에는 대체 폰트나 시스템 폰트로 텍스트를 표시하고 이후 커스텀 폰트가 로드되면 이를 교체하는 과정에서 레이아웃이 변경될 수 있습니다.

이렇게 폰트가 로드되면서 발생하는 레이아웃 이동은 요소 간의 위치가 변경되거나 텍스트 크기와 간격이 달라질 수 있는 원인이 됩니다. Next.js는 next/font 모듈을 사용하면 애플리케이션 내 폰트를 자동으로 최적화합니다. 빌드 시 폰트 파일을 다운로드하여 다른 정적 파일과 함께 제공하므로, 사용자가 애플리케이션에 접근할 때 추가적인 폰트 관련 네트워크 요청 없이 빠르게 로드됩니다.

 

퀴즈: 방금 배운 내용을 테스트해봅시다.

Next.js는 어떻게 폰트를 최적화할까요?

  • A: 추가적인 네트워크 요청을 발생시켜 성능을 높입니다.
  • B: 모든 커스텀 폰트를 비활성화합니다.
  • C: 런타임에 모든 폰트를 미리 로드합니다.
  • D: 폰트 파일을 다른 정적 파일과 함께 호스팅하여 추가적인 네트워크 요청 없이 로드합니다.
더보기

정답: D


 

주요 폰트 추가하기

애플리케이션에 커스텀 Google 폰트를 추가해 보면서 이 작동 방식을 알아보겠습니다!

 

/app/ui 폴더에 fonts.ts라는 새 파일을 생성합니다. 이 파일은 애플리케이션 전반에서 사용될 폰트를 보관하는 데 사용됩니다.

 

next/font/google 모듈에서 Inter 폰트를 가져옵니다. 이 폰트는 주 폰트로 사용할 것입니다. 그런 다음, 로드할 서브셋을 지정합니다. 여기서는 'latin'을 사용합니다.

// /app/ui/fonts.ts
import { Inter } from 'next/font/google';
 
export const inter = Inter({ subsets: ['latin'] });

 

마지막으로 /app/layout.tsx<body> 요소에 폰트를 추가합니다.

// /app/layout.tsx
import '@/app/ui/global.css';
import { inter } from '@/app/ui/fonts';
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode;
}) {
  return (
    <html lang="en">
      <body className={`${inter.className} antialiased`}>{children}</body>
    </html>
  );
}

 

Inter 폰트를 <body> 요소에 추가하면 애플리케이션 전반에 폰트가 적용됩니다. 여기서는 Tailwindantialiased 클래스를 추가하여 폰트를 부드럽게 표시하고 있습니다. 꼭 필요한 것은 아니지만, 미관상 도움이 됩니다.

 

브라우저로 이동하여 개발자 도구를 열고 body 요소를 선택합니다. 이제 InterInter_Fallback이 스타일에 적용된 것을 확인할 수 있습니다.

 


연습: 보조 폰트 추가하기

애플리케이션의 특정 요소에 폰트를 추가할 수도 있습니다.

 

이제 여러분 차례입니다! fonts.ts 파일에서 Lusitana라는 보조 폰트를 가져오고, /app/page.tsx 파일의 <p> 요소에 적용해 보세요. 이전과 같이 서브셋을 지정하는 것 외에도 폰트 두께를 지정해야 합니다.

 

준비가 되면 아래 코드 조각을 확장하여 솔루션을 확인하세요.

힌트
- 폰트에 어떤 두께 옵션을 전달해야 할지 모르겠다면 코드 편집기에서 TypeScript 오류를 확인하세요.
- Google Fonts 웹사이트에서 Lusitana를 검색하여 사용할 수 있는 옵션을 확인하세요.
- 여러 폰트를 추가하는 방법과 사용 가능한 옵션 목록을 보려면 문서를 참조하세요

 

더보기
import { Inter, Lusitana } from 'next/font/google';
 
export const inter = Inter({ subsets: ['latin'] });
 
export const lusitana = Lusitana({
  weight: ['400', '700'],
  subsets: ['latin'],
});

 

import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
 
export default function Page() {
  return (
    // ...
    <p
      className={`${lusitana.className} text-xl text-gray-800 md:text-3xl md:leading-normal`}
    >
      <strong>Welcome to Acme.</strong> This is the example for the{' '}
      <a href="https://nextjs.org/learn/" className="text-blue-500">
        Next.js Learn Course
      </a>
      , brought to you by Vercel.
    </p>
    // ...
  );
}

마지막으로, Lusitana 폰트를 사용하는 <AcmeLogo /> 컴포넌트도 주석 처리가 되어 있습니다. 이제 주석을 해제할 수 있습니다.

 

// /app/page.tsx

// ...

export default function Page() {
  return (
    <main className="flex min-h-screen flex-col p-6">
      <div className="flex h-20 shrink-0 items-end rounded-lg bg-blue-500 p-4 md:h-52">
        <AcmeLogo />
        {/* ... */}
      </div>
    </main>
  );
}

 

훌륭합니다!

이제 애플리케이션에 두 개의 커스텀 폰트를 추가했습니다. 다음으로 홈 페이지에 히어로 이미지를 추가해 보겠습니다.

 


왜 이미지를 최적화해야 할까요?

Next.js는 /public 폴더 아래에서 이미지와 같은 정적 자산을 제공할 수 있습니다. /public 안의 파일은 애플리케이션에서 참조할 수 있습니다.

 

일반적인 HTML에서는 다음과 같이 이미지를 추가할 수 있습니다.

<img
  src="/hero.png"
  alt="데스크톱 버전의 대시보드 프로젝트 스크린샷"
/>

 

하지만, 이 경우 다음을 수동으로 수행해야 합니다.

  • 다양한 화면 크기에 대해 이미지가 반응형으로 표시되도록 합니다.
  • 기기별로 이미지 크기를 지정합니다.
  • 이미지를 로드할 때 레이아웃 이동을 방지합니다.
  • 사용자의 뷰포트에 들어오지 않은 이미지를 지연 로드합니다.

이미지 최적화는 웹 개발에서 큰 주제이며 전문 분야로 여겨질 정도입니다. 이러한 최적화를 수동으로 구현하는 대신, next/image 컴포넌트를 사용하여 이미지를 자동으로 최적화할 수 있습니다.

 


<Image> 컴포넌트

<Image> 컴포넌트는 HTML <img> 태그의 확장이며, 다음과 같은 자동 이미지 최적화 기능을 제공합니다.

  • 이미지 로드 시 레이아웃 이동을 자동으로 방지합니다.
  • 작은 뷰포트를 가진 기기에 큰 이미지를 전송하지 않도록 이미지를 크기 조정합니다.
  • 뷰포트에 들어오는 이미지를 기본적으로 지연 로드합니다.
  • 브라우저가 지원할 경우, WebPAVIF와 같은 최신 형식으로 이미지를 제공합니다.

데스크톱 히어로 이미지 추가하기

<Image> 컴포넌트를 사용해 보겠습니다. /public 폴더 안에 hero-desktop.pnghero-mobile.png라는 두 개의 이미지가 있습니다. 이 두 이미지는 완전히 다르며, 사용자의 기기가 데스크톱인지 모바일인지에 따라 표시됩니다.

// /app/page.tsx
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
 
export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* Add Hero Images Here */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="데스크톱 버전의 대시보드 프로젝트 스크린샷"
      />
    </div>
    //...
  );
}

여기서 너비를 1000픽셀, 높이를 760픽셀로 설정하고 있습니다. 레이아웃 이동을 방지하기 위해 이미지의 너비와 높이를 설정하는 것이 좋습니다. 이 비율은 원본 이미지와 동일해야 합니다.

 

또한, hidden 클래스를 사용해 모바일 화면에서는 이미지를 DOM에서 제거하고, md:block 클래스를 사용해 데스크톱 화면에서는 이미지를 표시합니다.

 

이제 홈페이지는 다음과 같아야 합니다.

 

 

연습: 모바일 히어로 이미지 추가하기

이제 여러분 차례입니다! 방금 추가한 이미지 아래에 hero-mobile.png를 위한 <Image> 컴포넌트를 추가해 보세요.

  • 너비는 343픽셀, 높이는 388픽셀로 설정하세요.
  • md:hidden을 사용하여 데스크톱 화면에서는 이미지를 숨기세요.

준비가 되면 아래 코드 조각을 확장하여 솔루션을 확인하세요.

더보기
import AcmeLogo from '@/app/ui/acme-logo';
import { ArrowRightIcon } from '@heroicons/react/24/outline';
import Link from 'next/link';
import { lusitana } from '@/app/ui/fonts';
import Image from 'next/image';
 
export default function Page() {
  return (
    // ...
    <div className="flex items-center justify-center p-6 md:w-3/5 md:px-28 md:py-12">
      {/* Add Hero Images Here */}
      <Image
        src="/hero-desktop.png"
        width={1000}
        height={760}
        className="hidden md:block"
        alt="Screenshots of the dashboard project showing desktop version"
      />
      <Image
        src="/hero-mobile.png"
        width={560}
        height={620}
        className="block md:hidden"
        alt="Screenshot of the dashboard project showing mobile version"
      />
    </div>
    //...
  );
}

좋아요! 이제 홈페이지에 사용자 정의 글꼴과 히어로 이미지가 있습니다.

 

퀴즈: 방금 배운 내용을 테스트해봅시다.

True 또는 False: 너비와 높이가 지정되지 않은 이미지와 웹 폰트는 레이아웃 이동의 흔한 원인이다.

  • A. True
  • B. False
더보기

정답: A

 

추천 문서

이 주제들에 대해 더 배울 것이 많습니다.

여기에는 원격 이미지 최적화와 로컬 폰트 파일 사용이 포함됩니다. 폰트와 이미지에 대해 더 깊이 알아보고 싶다면, 아래 자료를 참고하세요.

728x90