:ledger: Next.js에서 img, font, script 최적화해서 사용하는 방법을 알아보자

웹사이트의 성능을 높이는 중요한 요소 중 하나는 애셋(asset) 최적화다. Next.js는 이미지, 폰트, 스크립트 파일을 효율적으로 관리하고 최적화하는 기능을 제공하여 사용자 경험을 개선할 수 있게 해준다. 어떤 방법이 있는지 알아보자!

:one: Next/Image를 이용해 이미지를 최적화 하자

이미지는 일반적인 웹사이트 페이지 무게의 아주 큰 부분을 차지하며, 웹사이트의 LCP(Largest Contentful Paint) 성능에 큰 영향을 미친다. 하지만 Next.js는 자동으로 이미지 크기를 최적화 해주는 컴포넌트인 Image 컴포넌트를 제공해준다.

:pushpin: 1-1) Image 컴포넌트 설명

공식문서에서의 설명은 아래와 같다.

  • 크기 최적화: 각 기기에 맞는 크기의 이미지를 자동으로 제공하고, WebP 및 AVIF와 같은 최신 이미지 형식을 사용합니다.
  • 시각적 안정성: 이미지가 로딩 될 때 레이아웃 이동을 자동으로 방지합니다.
  • 빠른 페이지 로드: 네이티브 브라우저 지연 로딩을 사용하여 이미지가 뷰포트에 들어올 때만 로드 됩니다. 블러업 플레이스 홀더를 옵션으로 사용 가능.
  • 자산 유연성: 원격 서버에 저장된 이미지도 포함하여 필요에 따라 이미지 크기 조정.

:pushpin: 1-2) Image 컴포넌트 사용 방법

이전에 강의를 들을 때 코드 스니펫을 복붙하며 따라가던 중 Image 에러가 노출되어 수정한 경험이 있다. 사용 방법은 간단하며, Next.js에서도 img태그를 쓸 때 “님 왜 그거 씀?” 이런 식으로 안내를 해준다.

// 사용 방법
import Image from "next/image"; // 임폴트하셈

return (
  {/* 사용하셈 */}
  <Image
    className="rounded-sm object-scale-down"
    width={80}
    src={product.images}
    alt={product.title}
  />
)

:pushpin: 1-3) 로컬 이미지 사용

로컬이미지는 리액트에서 썻던 방식과 똑같음

import Image from 'next/image'
import profilePic from './me.png'

export default function Page() {
  return (
    <Image
      src={profilePic}
      alt="Picture of the author"
      // width={500} 자동 제공
      // height={500} 자동 제공
      // blurDataURL="data:..." 자동 제공
      // placeholder="blur" // 로딩 중 블러업 옵션
    />
  )
}

:pushpin: 1-4) 네트워크 이미지 사용

주소값을 통해 불러오는 네트워크 이미지도 로컬 이미지와 크게 다르지 않음, 하지만 보안에 안전한 프로젝트를 위해 한가지 설정을 해줘야함

  • next.config.js 설정
    • next.config.js 파일에 지원되는 URL 패턴을 정의하여 안전하게 이미지 최적화
const nextConfig = {
  reactStrictMode: false,
  images: {
    remotePatterns: [
      {
        protocol: "https",
        hostname: "fakestoreapi.com", // url
        pathname: "/**", // 전체
      },
    ],
    formats: ["image/avif", "image/webp"], // 자동으로 포멧 변환
  },
};

  • 네트워크 이미지 사용
import Image from 'next/image'

export default function Page() {
  return (
    <Image
      src="<network-image>"
      alt="Picture of the author"
      width={500}
      height={500}
    />
  )
}

:pushpin: 1-5) 테스트

  • Next.js에서는 public 폴더를 사용하여 정적 파일을 쉽게 제공할 수 있음.
  • public 폴더 내의 파일은 기본 URL(/)을 기준으로 참조할 수 있음.
import Image from 'next/image'
import Logo from "/public/assets/logo.png";

<Image height={40} src={Logo} alt="logo"></Image>

:two: Font Optimization

  • Google Fonts를 자동으로 셀프 호스팅할 수 있음.
  • 폰트는 배포 시 포함되어 동일한 도메인에서 제공함.

:pushpin: 2-1) 기본 사용법

import { Inter } from 'next/font/google'

const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})

export default function RootLayout({ children }) {
  return (
    <html lang="en" className={inter.className}>
      <body>{children}</body>
    </html>
  )
}

:pushpin: 2-2) 멀티 폰트 사용

여러 폰트를 사용해야 할 때는 폰트를 내보내고 필요한 곳에서 가져와서 사용하면 됨

import { Inter, Roboto_Mono } from 'next/font/google'

export const inter = Inter({
  subsets: ['latin'],
  display: 'swap',
})

export const roboto_mono = Roboto_Mono({
  subsets: ['latin'],
  display: 'swap',
})

import { inter } from './fonts'

export default function Layout({ children }) {
  return (
    <html lang="en" className={inter.className}>
      <body>
        <div>{children}</div>
      </body>
    </html>
  )
}

:pushpin: 2-3) 로컬 폰트 사용

import localFont from 'next/font/local'
 
// Font files can be colocated inside of `app`
const myFont = localFont({
  src: './my-font.woff2',
  display: 'swap',
})
 
export default function RootLayout({
  children,
}: {
  children: React.ReactNode
}) {
  return (
    <html lang="en" className={myFont.className}>
      <body>{children}</body>
    </html>
  )
}

:three: Script

`

:pushpin: 3-1) 기본 사용법

import Script from 'next/script'

export default function RootLayout({ children }) {
  return (
    <html lang="en">
      <body>{children}</body>
      <Script src="https://example.com/script.js" />
    </html>
  )

:pushpin: 3-2) 세부 조정법

  • beforeInteractive: Next.js 코드 및 페이지 하이드레이션 전에 스크립트 로드
  • afterInteractive: (기본값) 페이지 하이드레이션 후 스크립트 로드
  • lazyOnload: 브라우저 유휴 시간에 스크립트 로드
  • worker: (실험적) 웹 워커에서 스크립트 로드
import Script from 'next/script'

export default function Home() {
  return (
    <>
      <Script src="https://example.com/script.js" strategy="worker" />
    </>
  )
}

:fire: 마무리

Next.js를 사용하여 애셋 최적화를 적용하면 웹사이트 성능을 크게 향상시킬 수 있다. 이미지, 폰트, 스크립트는 페이지 로딩 시간과 사용자 경험에 직접적인 영향을 미치므로, 각각의 최적화 전략을 잘 적용해 봐야겠다.

:pushpin: 참고

:pushpin: 테스트