Image 컴포넌트는 img 태그의 확장입니다. 공식문서에 따르면, 우수한 Core Web Vitals를 달성하기 위해 Image 컴포넌트에 기본으로 최적화 기능이 포함되어 있습니다. 이때 Core Web Vitals은 사용자 경험을 측정하는 중요한 척도이고, Google 검색 순위에 반영이 됩니다.
우선 사용하는 방법은 기본 img 태그 사용할 때와 동일합니다.
import Image from 'next/image';
export default function Page() {
return (
<Image
src="/profile.png"
width={500}
height={500}
alt="Picture of the author" />
);
}
이때 외부 이미지 경로를 사용할 때는 next.config.js에서 외부 이미지 경로를 설정 해야 한다.
images: {
//domains는 next.js에서 권장하지 않는다고 합니다.
//첫번째 방법
domains: ['www.test.come'],
//원격 이미지의 호스트 패턴 등록 (권장)
//두번째 방법
remotePatterns: [
remotePatterns: [
{
protocol: 'https',
hostname: 'www.test.com',
port: '',
pathname: '/v1/image/*/*',
},
{
protocol: 'https',
hostname: 'api.test',
port: '',
pathname: '/v1/image/*/*',
},
{
protocol: 'https',
hostname: 'api.test',
port: '',
pathname: '/v1/image/*/*',
},
],
},
width & height
alt
Optional Props
loader
import Image from 'next/image';
const imageLoader = ({ src, width, quality }) => {
return `https://example.com/${src}?w=${width}&q=${quality || 75}`;
};
export default function Page(
) {
return (
<Image
loader={imageLoader}
src="me.png"
alt="Picture of the author"
width={500}
height={500}
/>
);
}
또는 prop을 전달하지 않고 next.config.js의 loaderFile 구성을 사용하여 애플리케이션에서 next/image의 모든 인스턴스를 구성할 수 있습니다.
Fill
fill={true} // {true} | {false}
너비와 높이를 설정하는 대신 이미지가 부모 요소를 채우도록 하는 option 값 입니다.
기본 이미지 맞춤 동작은 컨테이너에 맞게 이미지를 늘립니다. 컨테이너에 맞고 가로 세로 비율을 유지하도록 레터박스로 된 이미지에 대해 object-fit: "contain"을 설정하는 것을 선호합니다.
또는 object-fit: "cover"를 설정하면 이미지가 전체 컨테이너를 채우고 가로 세로 비율을 유지하기 위해 잘립니다. 이 경우 올바르게 보이려면 overflow: "hidden"스타일을 부모 요소에 할당해야 합니다.
Sizes
다른 중단점에서 이미지가 얼마나 넓어질지에 대한 정보를 제공하는 문자열입니다. 즉 반응형 이미지에서 쓰일 수 있습니다.
또한 페이지가 로딩될 때 화면의 레이아웃이 엉켜 보이는 현상인 Cummulative Layout Shift 현상을 방지하기 위해서는 이미지의 사이즈를 화면 뷰포트에 맞게 로딩해야 합니다.
이때도 쓰이는 옵션이며, 이 옵션을 쓰면 브라우저가 페이지를 로딩할 때 페이지 레이아웃을 헤치지 않는 상태에서 적절한 사이즈의 이미지를 로딩하게 됩니다.
Next.js의 Image 컴포넌트의 가장 강력한 기능 중에 자동으로 source set을 생성하는 기능이 있는데, source set을 생성하면 뷰포트에 맞게 알맞은 사이즈의 이미지를 로딩해서 페이지의 레이아웃을 망치지 않게 됩니다
sizes 속성은 이미지 성능과 관련된 두 가지 중요한 용도로 사용됩니다:
첫째, sizes 값은 브라우저가 next/image의 자동 생성된 source set에서 다운로드할 이미지의 크기를 결정하는 데 사용됩니다. 브라우저가 선택할 때 페이지에 있는 이미지의 크기를 아직 알지 못하므로 뷰포트와 크기가 같거나 더 큰 이미지를 선택합니다. sizes 를 사용하면 이미지가 실제로 전체 화면보다 작을 것이라고 브라우저에 알릴 수 있습니다. fill 속성을 사용하여 이미지에 sizes 지정하지 않으면 기본값인 100vw (full screen width)가 사용됩니다.
둘째, sizes는 next/image 가 image source set를 자동으로 생성하는 방법을 구성합니다. 만약에 sizes 값이 없으면 고정 크기 이미지에 small source set이 생성됩니다. sizes가 정의되어 있으면 반응형 이미지에 적합한 large source set가 생성됩니다.
srcset이란 뷰포트 너비에 따라 로드될 이미지 후보들을 설정하는 CSS 속성입니다. 이때 srcset에 작성된 이미지 파일들은 뷰포트 너비에 맞는 이미지를 로드하여 렌더링되며 렌더링될 최적화 너비는 sizes CSS 속성을 통해 작성할 수 있습니다.
import Image from 'next/image';
export default function Page() {
return (
<div className="grid-element">
<Image
fill
src="/example.png"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
);
}
srcset and sizes 에 대해서는 아래에서 확인할 수 있습니다.
quality
quality={75} // {number 1-100}
최적화된 이미지의 품질로, 1에서 100 사이의 정수이며 100이 가장 좋은 품질이므로 파일 크기가 가장 큽니다. 기본값은 75입니다.
priority
priority={false} // {false} | {true}
true이면 이미지가 우선순위가 높은 것으로 간주되어 preload 됩니다. priority를 사용하는 이미지에 대해서는 Lazy loading이 자동으로 비활성화됩니다.
가장 큰 콘텐츠가 많은 페인트(LCP) 요소로 감지된 모든 이미지에 priority 속성을 사용해야 합니다.
상단에 보여지는 이미지들에 주로 사용되며, 뷰포트 크기에 따라 다른 이미지가 LCP 요소가 될 수 있으므로 여러 개의 우선순위 이미지를 사용하는 것이 적절할 수 있습니다.
기본값은 false입니다.
placeholder
placeholder = 'empty'; // {empty} | {blur}
Next/Image는 레이아웃이 흔들리는 현상을 방지하기 위해 CLS(Cumulative Layout Shift) placeholder를 제공합니다. 이미지가 로드되기 전에도 이미지 높이만큼 영역을 표시해서 이미지가 로드된 후에 레이아웃이 흔들리지 않도록 합니다. placeholder는 빈 영역 또는 blur 이미지(로컬 이미지의 경우 build 타임에 생성, 리모트 이미지의 경우에는 base64로 인코딩된 data url 을 지정해 줘야 함)로 적용할 수도 있고, 커스텀 하게 설정할 수도 있습니다
사용 가능한 값은 blur 또는 empty가 있습니다. deafult 값은 empty 입니다.
그리고 정적으로 제공된 이미지 확장자가 .jpg, .png, .webp, .avf일 경우 Next.js Image 컴포넌트가 자동으로 blurDataURL을 제공해 줍니다.
dynamic images의 경우 blurDataURL 속성을 제공해야 합니다. placeholder와 같은 솔루션을 사용하면 base64 생성을 지원할 수 있습니다.
empty 일때는, 이미지가 로드되는 동안 placeholder가 표시되지 않고 빈 공간만 표시됩니다.
https://png-pixel.com/
<Image
placeholder="blur"
blurDataURL="data:image/gif;base64,iVBORw0KGgoAAAANSUhEUgAAAAoAAAAKCAYAAACNMs+9AAAAFklEQVR42mN8//HLfwYiAOOoQvoqBABbWyZJf74GZgAAAABJRU5ErkJggg=="
src="https://www.d.lunit.care/v1/image/1/4a9954fb-a055-465e-9156-c55d96341e17"
alt="solution image"
width={100}
height={100}
/>
Advanced Props
경우에 따라 고급 사용이 필요할 수 있습니다. Image component는 선택적으로 다음과 같은 고급 속성을 허용합니다.
styles
기본 이미지 요소에 CSS 스타일을 전달할 수 있습니다.
const imageStyle = {
borderRadius: '50%',
border: '1px solid #fff',
};
export default function ProfileImage() {
return <Image src="..." style={imageStyle} />;
}
필요한 너비 및 높이 prop은 스타일링과 상호 작용할 수 있다는 점을 기억하세요. 스타일링을 사용하여 이미지의 너비를 수정하는 경우 내재적 측면 비율를 유지하기 위해 높이도 auto으로 스타일링해야 하며, 그렇지 않으면 이미지가 왜곡됩니다.
onLoadingComplete
<Image onLoadingComplete={(img) => console.log(img.naturalWidth)} />
이미지가 완전히 로드되고 플레이스홀더가 제거되면 호출되는 콜백 함수입니다.
콜백 함수는 하나의 인수를 사용하여 호출되며, 이 인수는 기본 img element에 대한 참조입니다.
onLoad
<Image onLoad={(e) => console.log(e.target.naturalWidth)} />
이미지가 로드될 때 호출되는 콜백 함수입니다.
placeholder가 제거되고 이미지가 완전히 디코딩되기 전에 로드 이벤트가 발생할 수 있다는 점에 유의하세요.
대신 onLoadingComplete를 사용하십시오.
onError
<Image onError={(e) => console.error(e.target.id)} />
이미지 로드에 실패할 경우 호출되는 콜백 함수입니다.
loading
권장 사항: 이 속성은 고급 사용 사례에만 사용하세요. 이미지를 eager 로드 상태로 전환하면 일반적으로 성능이 저하됩니다. 대신 이미지를 열심히 미리 로드하는 우선순위 속성을 사용하는 것이 좋습니다.
loading = 'lazy'; // {lazy} | {eager}
이미지의 로딩 동작입니다. 기본값은 lazy입니다.
lazy을 선택하면 이미지가 뷰포트에서 계산된 거리에 도달할 때까지 이미지 로드를 지연합니다.
eager한 경우 이미지를 즉시 로드합니다.
더 자세한 내용을 보실 수 있습니다. loading attribute.
blurDataURL
플레이스홀더 이미지로 사용할 데이터 URL입니다. placeholder="blur"와 함께 사용할 때만 적용됩니다.
base64로 인코딩된 이미지여야 합니다. 이미지가 확대되고 흐릿해지므로 매우 작은 이미지(10px 이하)를 사용하는 것이 좋습니다. 큰 이미지를 플레이스홀더로 포함하면 애플리케이션 성능이 저하될 수 있습니다.
generate a solid color Data URL을 생성할 수도 있습니다.
unoptimized
unoptimized = {false} // {false} | {true}
true이면 원본 이미지가 품질, 크기 또는 형식을 변경하지 않고 그대로 제공됩니다. 기본값은 false입니다.
import Image from 'next/image';
const UnoptimizedImage = (props) => {
return <Image {...props} unoptimized />;
};
Next.js 12.3.0부터 다음 구성으로 next.config.js를 업데이트하여 모든 이미지에 이 소품을 할당할 수 있습니다:
module.exports = {
images: {
unoptimized: true,
},
};
other Props
컴포넌트의 다른 프로퍼티는 다음을 제외하고 img element 로 전달됩니다:
Configuration Options
props 외에도next.config.js에서 이미지 컴포넌트를 구성할 수 있습니다. 다음 옵션을 사용할 수 있습니다
remotePatterns
악의적인 사용자로부터 애플리케이션을 보호하려면 외부 이미지를 사용하려면 구성이 필요합니다. 이렇게 하면 계정의 외부 이미지만 next.js 이미지 최적화 API에서 제공될 수 있습니다. 이러한 외부 이미지는 아래와 같이 next.config.js 파일의 remotePatterns 속성을 사용하여 구성할 수 있습니다
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: 'http://example.com ',
port: '',
pathname: '/account123/**',
},
],
},
};
참고: 위의 예에서는 다음/이미지의 src 속성이 https://example.com/account123/ 로 시작해야 합니다. 다른 프로토콜, 호스트 이름, 포트 또는 일치하지 않는 경로가 있으면 400 잘못된 요청으로 응답합니다.
다음은 next.config.js 파일에 있는 원격 패턴 속성의 또 다른 예입니다.
module.exports = {
images: {
remotePatterns: [
{
protocol: 'https',
hostname: '**.example.com',
},
],
},
};
참고: 위의 예에서는 다음/이미지의 src 속성이 https://img1.example.com 또는 https://me.avatar.example.com 또는 여러 하위 도메인으로 시작해야 합니다. 다른 프로토콜이나 일치하지 않는 호스트 이름은 400 Bad Request로 응답합니다.
domains
경고: 악의적인 사용자로부터 애플리케이션을 보호하려면 도메인 대신 엄격한 원격 패턴을 구성하는 것이 좋습니다. 도메인에서 제공되는 모든 콘텐츠를 소유한 경우에만 도메인을 사용하세요.
remotepatterns과 마찬가지로 domains 구성을 사용하여 외부 이미지에 허용되는 호스트 이름 목록을 제공할 수 있습니다.
그러나 domains 구성은 와일드카드 패턴 일치를 지원하지 않으며 프로토콜, 포트 또는 경로명을 제한할 수 없습니다.
다음은 next.config.js 파일에 있는 domains의 속성 예시입니다.
module.exports = {
images: {
domains: ['assets.acme.com'],
},
};
loaderFile
Next.js에 내장된 이미지 최적화 API를 사용하는 대신 클라우드 제공업체를 사용하여 이미지를 최적화하려면 다음과 같이 next.config.js에서 loaderFile을 구성할 수 있습니다.
module.exports = {
images: {
loader: 'custom',
loaderFile: './my/image/loader.js',
},
};
이 파일은 Next.js 애플리케이션의 루트를 기준으로 파일을 가리켜야 합니다. 파일은 예를 들어 문자열을 반환하는 기본 함수를 내보내야 합니다
export default function myImageLoader({ src, width, quality }) {
return <https://example.com/${src}?w=${width}&q=${quality> || 75};
}
또는 loader prop을 사용하여 next/image의 각 인스턴스를 구성할 수 있습니다.
Advanced
다음 구성은 고급 사용 사례를 위한 것으로 일반적으로는 필요하지 않습니다. 아래 속성을 구성하도록 선택하면 향후 업데이트에서 Next.js 기본값에 대한 모든 변경 사항을 재정의하게 됩니다.
deviceSizes
사용자의 예상 디바이스 너비를 알고 있는 경우 next.config.js의 deviceSizes 속성을 사용하여 디바이스 너비 중단점 목록을 지정할 수 있습니다. 이 너비는 next/image 컴포넌트가 사용자의 기기에 올바른 이미지가 표시되도록 하기 위해 크기 프로퍼티를 사용할 때 사용됩니다.
구성을 제공하지 않으면 아래의 기본값이 사용됩니다.
module.exports = {
images: {
deviceSizes: [640, 750, 828, 1080, 1200, 1920, 2048, 3840],
},
};
imageSizes
next.config.js 파일에서 images.imageSizes 속성을 사용하여 이미지 너비 목록을 지정할 수 있습니다. 이러한 너비는 디바이스 크기 배열과 연결되어 이미지 srcset을 생성하는 데 사용되는 전체 크기 배열을 형성합니다.
두 개의 별도 목록이 있는 이유는 이미지가 화면의 전체 너비보다 작다는 것을 나타내는 size prop를 제공하는 이미지에만 imageSizes가 사용되기 때문입니다. 따라서 imageSizes의 크기는 모두 deviceSizes의 가장 작은 크기보다 작아야 합니다.
설정이 제공되지 않으면 아래 기본값이 사용됩니다.
module.exports = {
images: {
imageSizes: [16, 32, 48, 64, 96, 128, 256, 384],
},
};
formats
기본 이미지 최적화 API는 요청의 Accept 헤더를 통해 브라우저에서 지원되는 이미지 형식을 자동으로 감지합니다.
Accept 헤더가 구성된 형식 중 둘 이상의 형식과 일치하는 경우 배열에서 첫 번째로 일치하는 형식이 사용됩니다. 따라서 배열 순서가 중요합니다. 일치하는 항목이 없거나 소스 이미지가 애니메이션인 경우 이미지 최적화 API는 원본 이미지의 형식으로 fallback합니다.
구성을 제공하지 않으면 아래의 기본값이 사용됩니다.
module.exports = {
images: {
formats: ['image/webp'],
},
};
다음 구성을 통해 AVIF 지원을 활성화할 수 있습니다.
module.exports = {
images: {
formats: ['image/avif', 'image/webp'],
},
};
참고: AVIF는 일반적으로 인코딩하는 데 20% 더 오래 걸리지만 WebP에 비해 20% 더 작게 압축됩니다. 즉, 이미지를 처음 요청할 때는 일반적으로 속도가 느리고 이후 캐시된 요청은 더 빨라집니다.
참고: Next.js 앞에 프록시/CDN을 사용하여 셀프 호스팅하는 경우, 프록시가 Accept 헤더를 전달하도록 구성해야 합니다.
Caching Behavior
다음은 기본 로더의 캐싱 알고리즘에 대해 설명합니다. 다른 모든 loader에 대해서는 클라우드 제공업체의 설명서를 참조하세요.
이미지는 요청 시 동적으로 최적화되어 distDir/cache/images 디렉터리에 저장됩니다. 최적화된 이미지 파일은 만료에 도달할 때까지 후속 요청에 제공됩니다. 캐시되었지만 만료된 파일과 일치하는 요청이 발생하면 만료된 이미지는 즉시 부실 이미지로 제공됩니다. 그런 다음 이미지가 백그라운드에서 다시 최적화되고(재검증이라고도 함) 새 만료일과 함께 캐시에 저장됩니다.
이미지의 캐시 상태는 x-nextjs-cach응답 헤더의 값을 읽어서 확인할 수 있습니다. 가능한 값은 다음과 같습니다:
만료(또는 최대 사용 기간)는 minimumCacheTTL 구성 또는 업스트림 이미지 Cache-Control 헤더 중 더 큰 값으로 정의됩니다. 구체적으로는 Cache-Control 헤더의 max-age 값이 사용됩니다. s-maxage와 max-age가 모두 발견되면 s-maxage가 선호됩니다. 최대 연령은 CDN과 브라우저를 포함한 모든 다운스트림 클라이언트에도 전달됩니다.
minimumCacheTTL
캐시된 최적화된 이미지에 대해 TTL(Time to Live)을 초 단위로 구성할 수 있습니다. 대부분의 경우 파일 내용을 자동으로 해시하고 Cache-Control 헤더를 immutable으로 설정하여 이미지를 영구적으로 캐싱하는 정적 이미지 가져오기를 사용하는 것이 좋습니다.
module.exports = {
images: {
minimumCacheTTL: 60,
},
};
최적화된 이미지의 만료(또는 최대 사용 기간)는 minimumCacheTTL 또는 업스트림 이미지 Cache-Control 헤더 중 더 큰 값으로 정의됩니다.
이미지별 캐싱 동작을 변경해야 하는 경우 업스트림 이미지(예: /_next/image 자체가 아닌/some-asset.jpg)에 Cache-Control헤더를 설정하도록 헤더를 구성할 수 있습니다.
현재로서는 캐시를 무효화하는 메커니즘이 없으므로 최소minimumCacheTTL을 낮게 유지하는 것이 가장 좋습니다. 그렇지 않으면 수동으로 src 프로퍼티를 변경하거나 distDir/cache/images를 삭제해야 할 수 있습니다.
disableStaticImages
기본 동작은import icon from './icon.png와 같은 정적 파일을 가져온 다음 이를 src 속성으로 전달할 수 있습니다.경우에 따라 가져오기가 다르게 동작할 것으로 예상되는 다른 플러그인과 충돌하는 경우 이 기능을 비활성화할 수 있습니다.
정적 이미지 가져오기는 next.config.js 내에서 비활성화할 수 있습니다.
module.exports = {
images: {
disableStaticImages: true,
},
};
dangerouslyAllowSVG
기본 loader는 몇 가지 이유로 SVG 이미지를 최적화하지 않습니다.
첫째, SVG는 벡터 형식이므로 손실 없이 크기를 조정할 수 있습니다.
둘째, SVG에는 HTML/CSS와 동일한 기능이 많기 때문에 적절한 CSP(콘텐츠 보안 정책) 헤더가 없으면 취약점이 발생할 수 있습니다.
기본 이미지 최적화 API로 SVG 이미지를 제공해야 하는 경우, next.config.js 내에서 위험하게 허용SVG를 설정하면 됩니다.
module.exports = {
images: {
dangerouslyAllowSVG: true,
contentDispositionType: 'attachment',
contentSecurityPolicy: "default-src 'self'; script-src 'none'; sandbox;",
},
};
또한 브라우저가 이미지를 강제로 다운로드하도록 하는 contentDispositionType과 이미지에 포함된 스크립트가 실행되지 않도록 하는 contentSecurityPolicy를 함께 설정하는 것이 좋습니다.
Animated Images
기본 로더는 애니메이션 이미지에 대한 이미지 최적화를 자동으로 우회하여 이미지를 있는 그대로 제공합니다.
애니메이션 파일에 대한 자동 감지는 최선의 노력이며 GIF, APNG 및 WebP를 지원합니다. 특정 애니메이션 이미지에 대한 이미지 최적화를 명시적으로 우회하려면 unoptimized prop을 사용하면 됩니다.
Known Browser Bugs
이 next/image 컴포넌트는 브라우저 기본 지연 로딩을 사용하므로 Safari 15.4 이전의 구형 브라우저에서는 지연 로딩으로 대체될 수 있습니다. blur-up placeholder를 사용하는 경우 Safari 12 이전의 구형 브라우저에서는 empty placeholder로 fallback됩니다. width/height가 자동인 스타일을 사용하는 경우 Safari 15 이전의 구형 브라우저에서 가로 세로 비율이 유지되지 않는 레이아웃 시프트가 발생할 수 있습니다. 자세한 내용은 이 MDN 비디오를 참조하세요.
srcSet에 너무 많은 이미지들이 지정되는 이슈
Next/Image를 사용할 경우 이미지에 대한 초기 요청 시에 Next.js 서버에서 사이즈, 포맷 등이 최적화된 이미지 파일들을 생성하게 됩니다. 이 때문에 최초로 페이지를 로드하게 되는 사용자는 Next.js 서버에서 이미지 생성이 완료될 때까지 기다려야 하기 때문에 오랜 시간 대기해야 할 수 있습니다. 다음과 같은 해결방법이 있습니다.
첫 번째로, 이미지 사이즈가 고정되어 있는 경우
1x, 2x 2개의 srcSet만 생성되기 때문에 이미지가 최초 요청되더라도 빠르게 이미지 파일을 서빙할 수 있습니다.
<Image
src="https://www.test.com/v1/image/1/4a9954fb-a055-465e-9156-c55d96341e17"
width={200}
height={300}
alt="감튀"
/>
두 번째로, srcSet에 생성되는 이미지 srcSet을 변경하는 방법
next.config.js에서 imageSizes,deviceSizes 에 사용에 맞게 설정을 합니다. 이미지마다 명시된 모든 사이즈를 포함하는 srcSet을 가지게 되어 지나치게 세분화된 사이즈에 대응되는 이미지 파일들을 생성하게 될 수 있습니다.
<div className="h-[200px] relative">
<Image
priority={true}
fill
src="/assets/images/guide/guide-bg-1.webp"
alt="solution image"
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
/>
</div>
//next.config.js에서 아래와 같이 설정할 경우
imageSizes: [16, 32, 48, 64, 96, 128],
deviceSizes: [640, 750, 828, 1080, 1200, 1920],
기존 img를 사용할 경우
NextJS Image를 적용할 경우
파일은 jpeg에서 webp로 바뀌게 되면서 파일 크기 또한 엄청나게 줄어든 것을 확인할 수 있습니다.
파일의 유형 및 파일 크기에서 확연히 차이가 나는 것을 확인할 수 있습니다.
unstable_getImgProps()
import { unstable_getImgProps as getImgProps } from 'next/image';
export default function Page() {
const common = { alt: 'Hero', width: 800, height: 400 };
const {
props: { srcSet: dark },
} = getImgProps({ ...common, src: '/dark.png' });
const {
props: { srcSet: light, ...rest },
} = getImgProps({ ...common, src: '/light.png' });
return (
<picture>
<source media="(prefers-color-scheme: dark)" srcSet={dark} />
<source media="(prefers-color-scheme: light)" srcSet={light} />
<img {...rest} />
</picture>
);
}
또한 placeholder props는 이제 흐릿해서는 안 되는 placeholder 이미지에 대해 임의의 data:image/ 제공을 지원합니다.
참고