티스토리 뷰

 

웹 성능 최적화는 단순히 '빠르게 만드는 것'을 넘어, 사용자에게 '부드러운 경험'을 제공하는 예술에 가깝습니다. 특히 현대의 웹 프런트엔드 생태계에서 사용자 이탈을 막는 가장 큰 요소는 페이지 로딩 시 발생하는 **레이아웃 시프트(LSS)**와 초기 렌더링 속도입니다.

Next.js는 이러한 고질적인 문제들을 해결하기 위해 강력한 내장 컴포넌트 3종 세트를 제공합니다. 오늘은 이 컴포넌트들이 왜 필요하며, 실무에서 어떻게 적용해야 '진짜 성능'을 끌어낼 수 있는지 딥다이브해 보겠습니다.


1. 이미지 최적화의 마법: next/image

왜 사용해야 할까요?

전통적인 <img> 태그는 브라우저에게 "이 주소에 있는 사진을 가져와"라고 말할 뿐입니다. 하지만 사진 용량이 5MB라면? 혹은 모바일 사용자에게 4K 이미지를 전송하고 있다면? 이는 데이터 낭비이자 로딩 지연의 주범입니다.

next/image는 레스토랑의 서빙 시스템과 같습니다. 손님이 오면 그 손님의 위장 크기(디바이스 해상도)에 맞춰 음식을 적절히 배분하고, 손님이 앉은 테이블에 음식이 나갈 때쯤(뷰포트 진입) 요리를 시작합니다.

핵심 기능 (Deep Dive)

  • Lazy Loading: 이미지가 화면에 보일 때만 로딩하여 초기 대역폭을 절약합니다.
  • WebP/AVIF 변환: 브라우저가 지원하는 최신 고효율 포맷으로 자동 변환합니다.
  • Placeholder: 이미지가 로드되기 전 부드러운 블러(Blur) 처리를 통해 사용자에게 시각적 안정감을 줍니다.

2. 폰트의 반란 방지: next/font

왜 중요할까요?

폰트가 늦게 로드되면 텍스트가 갑자기 바뀌거나(FOIT), 기본 폰트에서 커스텀 폰트로 변하면서 글자 크기 차이로 인해 화면이 덜컥거리는 현상이 발생합니다. 이를 폰트 가시성 문제라고 합니다.

next/font는 폰트 파일을 빌드 시점에 미리 다운로드하여 셀프 호스팅합니다. 구글 폰트를 사용하더라도 브라우저가 구글 서버로 요청을 보내지 않고, 서비스의 자체 서버에서 폰트를 바로 쏴주기 때문에 개인정보 보호와 속도라는 두 마리 토끼를 모두 잡습니다.


3. 스크립트의 질서 유지: next/script

전략적인 스크립트 배치

GTM(Google Tag Manager), 카카오톡 상담 채널, 광고 스크립트 등 외부 라이브러리는 우리 서비스의 로직보다 중요하지 않은 경우가 많습니다. next/script는 이러한 외부 스크립트가 메인 페이지 렌더링을 방해하지 않도록 실행 우선순위를 결정합니다.

  • beforeInteractive: 페이지가 상호작용하기 전에 로드 (예: 보안 봇 방지).
  • afterInteractive: (기본값) 페이지 로드 직후 로드 (예: 분석 툴).
  • lazyOnload: 브라우저가 한가할 때 로드 (예: 채팅 상담 챗봇).

실전 Hands-on: 이커머스 상세 페이지 적용

실제 비즈니스 환경에서 이 세 가지를 어떻게 조합하는지 코드로 살펴보겠습니다.

JavaScript
 
import Image from 'next/image';
import Script from 'next/script';
import { Inter } from 'next/font/google';

// 1. 폰트 최적화: 가변 폰트 적용 및 subset 설정으로 용량 최소화
const inter = Inter({
  subsets: ['latin'],
  display: 'swap', // 폰트 로드 전까지 기본 폰트 노출하여 텍스트 가독성 확보
});

export default function ProductDetail({ product }) {
  return (
    <div className={inter.className}>
      {/* 2. 스크립트 최적화: 마케팅 스크립트는 페이지 로드 완료 후 여유 있을 때 실행 */}
      <Script
        src="https://example.com/analytics.js"
        strategy="lazyOnload"
        onLoad={() => console.log('분석 스크립트 로드 완료')}
      />

      <section>
        <h1>{product.name}</h1>
        
        {/* 3. 이미지 최적화: LCP(가장 큰 콘텐츠) 요소는 priority 속성 부여 */}
        <div style={{ position: 'relative', width: '100%', height: '400px' }}>
          <Image
            src={product.imageSrc}
            alt={product.name}
            fill // 부모 컨테이너를 가득 채움
            priority // 가장 먼저 로드해야 하는 중요한 이미지임을 명시
            sizes="(max-width: 768px) 100vw, 50vw" // 반응형 크기 최적화 힌트 제공
            style={{ objectFit: 'cover' }}
            placeholder="blur"
            blurDataURL="data:image/png;base64,..." // 저화질 이미지 프리뷰
          />
        </div>
        
        <p>{product.description}</p>
      </section>
    </div>
  );
}

트러블슈팅: 이미지가 왜 안 나올까요?

만약 외부 URL(예: S3, Cloudinary)의 이미지를 사용한다면 next.config.js에 해당 도메인을 반드시 등록해야 합니다. 보안상의 이유로 Next.js는 허용되지 않은 도메인의 이미지 호스팅을 차단하기 때문입니다.


장단점 및 고려사항 (Trade-offs)

장점

  • 자동화: 개발자가 복잡한 최적화 로직을 짜지 않아도 프레임워크 수준에서 처리해 줍니다.
  • Core Web Vitals 점수 상승: 구글 검색 순위에 직접적인 영향을 주는 지표들이 개선됩니다.

고려사항

  • 서버 리소스: next/image는 서버(혹은 Vercel)에서 이미지 최적화 과정을 거치므로 빈번한 이미지 요청 시 서버 부하가 발생할 수 있습니다. 캐싱 전략을 적절히 세워야 합니다.
  • 제한적인 폰트: 모든 폰트가 next/font에서 완벽하게 지원되는 것은 아니므로, 특수한 유료 폰트는 별도의 설정이 필요할 수 있습니다.

결론 및 제언

웹 최적화는 '한 번에 끝내는 작업'이 아니라 '지속적으로 관리하는 습관'입니다. Next.js가 제공하는 이 세 가지 도구는 성능 최적화의 80%를 자동으로 해결해 줍니다.

혹시 아직도 일반 <img> 태그나 <link> 폰트 태그를 습관적으로 사용하고 계신가요? 오늘 바로 가장 중요한 페이지의 이미지부터 next/image로 교체해 보세요. 라이트하우스(Lighthouse) 점수가 달라지는 것을 즉각 확인하실 수 있을 겁니다.

반응형
공지사항
최근에 올라온 글
최근에 달린 댓글
Total
Today
Yesterday
링크
«   2026/04   »
1 2 3 4
5 6 7 8 9 10 11
12 13 14 15 16 17 18
19 20 21 22 23 24 25
26 27 28 29 30
글 보관함