이미지는 웹 성능에서 생각보다 큰 비중을 차지한다.
대표적인 이미지 최적화 기법
- WebP, AVIF 등 차세대 포맷으로 변환
- 디바이스 해상도에 맞는 이미지 제공
- Lazy Loading 적용 (보이는 순간에만 로드)
- Blur Placeholder로 깔끔한 로딩 연출
Next.js는 성능 향상을 위해 Image 컴포넌트를 제공한다.
즉, 단순히
<img>대신<Image>를 사용하기만 해도
자동으로 리사이징, 포맷 변환, Lazy Loading, CDN 캐싱이 적용된다.
이미지 최적화에는 다양한 기법이 존재한다.
import Image from 'next/image';
//...
export default function BookItem({
id,
title,
subTitle,
description,
author,
publisher,
coverImgUrl,
}: BookData) {
return (
<Link href={`/book/${id}`} className={style.container}>
<Image src={coverImgUrl} width={80} height={105} alt={`도서 ${title}의 표시 이미지`} />
<div>
<div className={style.title}>{title}</div>
<div className={style.subTitle}>{subTitle}</div>
<br />
<div className={style.author}>
{author} | {publisher}
</div>
</div>
</Link>
);
}
Invalid src prop 오류 해결하기Next.js의 Image는 보안상 외부 도메인의 이미지를 기본적으로 차단한다.
그래서 외부 이미지를 사용하려면 next.config.js에 허용 도메인을 명시해야 한다.
import type { NextConfig } from 'next';
const nextConfig: NextConfig = {
logging: {
fetches: {
fullUrl: true,
},
},
images: {
domains: ['shopping-phinf.pstatic.net'], // 외부 이미지 도메인 등록
},
};
export default nextConfig;
설정 후 빌드하면, Next.js가 자동으로 해당 이미지를 프록시 캐싱 및 최적화해서 제공해준다!
Next.js는 SEO를 위해 metadata라는 정식 속성을 제공한다.
페이지의 제목(title), 설명(description), OG 태그(Open Graph) 등을 손쉽게 설정할 수 있음
검색된 약속어 metadata를 사용하여 설정을 진행하면,
export const metadata: Metadata = {
title: '한입 북스',
description: '한입 북스에 등록된 도서를 만나보세요.',
openGraph: {
title: '한입 북스',
description: '한입 북스에 등록된 도서를 만나보세요.',
images: ['/thumbnail.png'],
},
};
페이지가 검색 엔진에 더 잘 노출괴도, SNS 공유 시 썸네일이 깔끔하게 표시된다.
Next.js는 정적인 메타데이터뿐만 아니라,
페이지별 데이터에 따라 동적으로 메타정보를 설정할 수 있게 해준다.
export async function generateMetadata({
searchParams,
}: {
searchParams: Promise<{ q?: string }>;
}) {
// 현재 페이지의 메타 데이터를 동적으로 생성하는 역할
const { q } = await searchParams;
return {
title: `${q}: 한입북스 검색`,
description: `${q}의 검색 결과입니다.`,
openGraph: {
title: `${q}: 한입북스 검색`,
description: `${q}의 검색 결과입니다.`,
images: ['/thumbnail.png'],
},
};
}
export default async function Page({ searchParams }: { searchParams: Promise<{ q?: string }> }) {
const { q } = await searchParams;
이렇게 하면 검색 결과 페이지의 쿼리(
q) 값에 따라
브라우저 탭 제목, 설명, OG 메타데이터가 동적으로 변한다.
도서 상세 페이지의 경우, 책 정보를 API로 불러와서 그 데이터를 기반으로 SEO 메타를 생성할 수 있다. (따봉)
export async function generateMetadata({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
const response = await fetch(`${process.env.NEXT_PUBLIC_API_SERVER_URL}/book/${id}`);
if (!response.ok) {
throw new Error(response.statusText);
}
const book: BookData = await response.json();
return {
title: `${book.title} - 한입북스`,
description: `${book.description}`,
openGraph: {
title: `${book.title} - 한입북스`,
description: `${book.description}`,
images: [book.coverImgUrl],
},
};
}
export default async function Page({ params }: { params: Promise<{ id: string }> }) {
const { id } = await params;
//...
✅ API를 메타데이터 내부에서 직접 호출해도 안전한 이유는? Request Memoization
같은 페이지 내에서 동일한 API를 여러 번 호출하더라도 자동으로 한 번만 요청하고 캐싱해주는 아름다운 친구,
덕분에generateMetadate()와 실제 페이지 렌더링에서 같은 데이터를 불러와도 불필요한 중복 요청이 발생하지 않는다.
| 구분 | 기능 | 설명 |
|---|---|---|
| Image 컴포넌트 | 이미지 최적화 | WebP 변환, 리사이징, Lazy Loading 자동 적용 |
| next.config.js | 외부 이미지 도메인 등록 | 외부 리소스 접근 허용 |
| Metadata | SEO 설정 | 페이지의 메타 정보 정의 |
| generateMetadata | 동적 SEO | 검색어·데이터 기반 메타데이터 자동 생성 |
| Request Memoization | API 중복 방지 | 동일 요청을 한 번만 수행, 자동 캐싱 |