Next/image 현명하게 사용하기

김유진·2023년 4월 23일
1

Nextjs

목록 보기
3/9
post-thumbnail

이번 포스팅에서는 Next에서 어떻게 이미지 파일을 불러오는지 알아보고자 한다.
Next에서 이미지는 다양한 방법으로 불러와 화면에 보일 수 있다. 일단 크게 두가지 종류가 존재한다.

  1. public 폴더에 이미지 파일을 저장하고 상대경로로 불러온다.
  2. 배포된 이미지 파일을 그대로 가져온다.

이 두 가지 방법으로 이미지 파일을 불러올 수 있는데 이제 이것을 어떻게 화면에 표현하느냐가 문제가 될 것이다. ㅎㅎ

Img 태그 이용하기

const Images: NextPage = () => {
  return (
    <main>
      <hr style={{ margin: '32px 0' }} />
      <h1>img tag</h1>
      <figure>
        <img
          src="https://example.com/example.jpg"
          alt="example"
          width={500}
          height={100}
          loading="lazy"/>
        <figcaption>example img</figcaption>
      </figure>
	</main>
	)
}

이렇게 img태그를 직접 이용할 수 있으나, 네트워크 페이지를 확인해 보면 미리 example.jpg를 가져오며 용량 그대로 가져옴을 알 수 있다. 만약 이 때 loading 속성에 lazy를 주면 화면에 보이지 않다가 이미지가 화면에 나타날 때에 네트워크 로딩을 해 준다.

Next/image 이용하기

Static한 이미지 사용하기

Next/image를 사용하게 되면 webp 형식으로 이미지를 받아올 뿐만 아니라 사용하는 메모리가 훨씬 줄어들게 된다.
또한 지정하고 싶은 이미지의 가로, 세로 크기를 쉽게 정할 수 있다.

import type { NextPage } from 'next';
import Image from 'next/image';
import LegacyImage from 'next/legacy/image';
import example from '../../public/example.png'

const Images: NextPage = () => {
  return (
    <main>
      <h1>next/image</h1>
      <figure>
        <Image
          src={example}
          alt="v13 image"
          width={500}
          height={100}
        />
        <figcaption>v13 image</figcaption>
      </figure>
	</main>
	)
}

속성에 quality를 준다면 이미지 용량을 얼마나 최적화시킬 것인지에 대하여 정할 수 있다. (기본값은 75)
그리고 속성에 임의로 추가하지 않았지만 lazy loading 속성은 기본적으로 들어가 있다.

만약, placeholder로 blur를 지정하면 화면이 로딩되는 동안에는 블러 이미지가 자동으로 적용된다. (단 개발환경에서는 확인 불가능)

이는 public 폴더에 이미지를 지정해두고, static하게 이미지를 import 시켰기 때문에 Next 입장에서는 이미지의 너비, 높이, 색에 대하여 미리 알고 있어서 만들고자 하는 이미지에 대하여 대응할 수 있기 때문이다.
그렇기 때문에 주의해야 하는 점 중에 하나는 src 를 string링크 형식으로 넘겨주기보다는 외부에서 import하여 가져온 것으로 표현을 해 주어야 한다.

그럼 이미지를 static하게 불러오지 않고, 외부 배포된 링크로 가져온다면 어떻게 될까?

배포한 이미지를 사용하기

<figure>
    <Image
  src="https://inflearn-nextjs.vercel.app/example.jpg"
  alt="v13 image"
  width={500}
  height={100}
  />
    <figcaption>v13 image</figcaption>
</figure>

정적인 이미지 같은 경우에는 빌드타임에 그 크기가 어떻게 되는지 알고 있지만 외부 소스를 통해 가져온 이미지 같은 경우에는 크기를 알 방도가 없다. 그렇기 때문에 외부에서 이미지를 가져오는 경우에는 꼭 크기와 높이를 지정해준 이후 넘겨주어야 한다.

너비와 높이를 모른다면?

항상 외부에서 가져오는 페이지에 대한 높이와 너비를 잘 알고 있지 못할 수도 있다. 그럴 때에는 어떻게 대응해야 할까?

<figure style={{ position: 'relative', width: '500px', height: '100px' }}>
  <Image src="https://inflearn-nextjs.vercel.app/example.jpg" alt="v13 fill"
	fill
	style={{ objectFit: 'cover' }}
	/>
</figure>

그럴 때에는 외부(부모) 컨테이너에 대하여 크기를 정해 두고 fill이라는 속성을 배정한다.

외부에서 가져올 링크가 보이지 않아요!

그럴 때에는 허용된 도메인의 이미지 링크만 가져올 수 있도록 NextJs가 막아둔 것이므로 해당 링크의 가이드에 따라서 next.config.js 파일을 새로 작성할 필요가 있다.

일반적으로 허용하는 도메인

module.exports = {
  images: {
    domains: ['assets.acme.com'],
  },
}

하지만 이 부분은 wildcard pattern 매칭과 엄격한 프로토콜 관리에 유용하지는 않다. 최근에 추천하는 것은 아래와 같다.

Remote Patterns

module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: 'example.com',
        port: '',
        pathname: '/account123/**',
      },
    ],
  },
}

위와 같이 작성한다면 https://example.com/account123/ 링크로 이동하는 것이고, 만약 일치하지 않는다면 400에러를 발생시킨다.
아니면 요렇게 작성해도 된다!

module.exports = {
  images: {
    remotePatterns: [
      {
        protocol: 'https',
        hostname: '**.example.com',
      },
    ],
  },
}

Image의 Props들

loader

이미지에 대한 URL을 string으로 확인할 수 있으며 src, width, quality라는 파라미터가 필요하다.
로더의 예시를 확인해보자.

import Image from 'next/image'

const myLoader = ({ src, width, quality }) => {
  return `https://example.com/${src}?w=${width}&q=${quality || 75}`
}

const MyImage = (props) => {
  return (
    <Image
      loader={myLoader}
      src="me.png"
      alt="Picture of the author"
      width={500}
      height={500}
    />
  )
}

이렇게 로더 함수를 직접 작성하여도 되고, loaderFile을 next.config.js파일에 작성하여도 된다.

module.exports = {
  images: {
    loader: 'custom',
    loaderFile: './my/image/loader.js',
  },
}

fill

widthheight를 정확히 명시하는 것 대신 부모 요소를 채우게끔 이미지를 불러올 수 있다.
parent에는 다음 요소가 꼭 명시되어 있어야 한다.

  • position : "relative"
  • position : "fixed"
  • position : "absolute"
    기본적으로 img 요소는 absolute 특성을 가지고 있다.

이미지는 부모 요소를 기준으로 stretch되기 때문에, 컨텐츠를 부모 요소에 딱 맞게 만들고 싶다면 object-fit: "contain" 요소를 넣어주자.
기호에 따라 ojbect-fit: "cover", overflow: "hidden"을 사용할 수 있다.

sizes

size는 서로 다른 중단점에서 이미지가 어떻게 넓어지는지에 대한 정보를 제공할 수 있다.
가로 세로 길이를 특정하기 어렵지만 브라우저 크기에 대하여 그에 대한 크기 정보가 제공되어야 할 때가 있을 때 sizes는 그 해결점을 제공한다.
아무 것도 설정하지 않는다면

<Image sizes="210px" />

코드를 이렇게 작성하게 되면 이미지 출력 크기는 210px로 고정된다. 예시 코드를 조금 더 살펴보자.

import Image from 'next/image'
const Example = () => (
  <div className="grid-element">
    <Image
      src="/example.png"
      fill
      sizes="(max-width: 768px) 100vw,
              (max-width: 1200px) 50vw,
              33vw"
    />
  </div>
)

이미지 크기가 큰 것이 필요하지 않는데 33vw를 지정하지 않으면 3배 더 큰 이미지를 어쩔 수 없이 다운로드 받게 되고, 결론적으로 이미지의 용량은 크기의 제곱이므로 9배 큰 용량을 낭비하게 될 수 있다.
하지만 이렇게 sizes의 값으로 33vw를 전달해줌으로써 작은 크기의 파일을 쓸데없이 큰 크기로 다운받지 않아도 되는 장점이 있는 것이다.

quality

이미지 크기에 대한 최적화를 진행한다. 1 ~ 100 사이의 숫자로 결정할 수 있고, 100을 설정하게 되면 가장 좋은 퀄리티로 이미지 크기를 최적화 진행한다. 75가 기본값이다.

priority

만약 priority가 true로 설정되어 있다면, 가장 먼저 로드(preload)를 진행한다. Lazy loading은 사용할 수 없게 된다.

placeholder

placeholder는 이미지가 로딩될 때 보여지는 화면이다. 기본값으로는 empty가 설정되어 있다. empty일 때에는 빈 공간이 존재하고, 주로 blur라는 값을 많이 사용하는데 이미지 파일의 배경 DATA를 생성해둔다.

이외에도 다양한 props들이 여전히 존재한다. 더욱 자세한 내용을 알고 싶다면 아래 링크를 참고하자.
https://nextjs.org/docs/api-reference/next/image#advanced-props

0개의 댓글