My Boundary As Much As I Experienced

Next.js가 제공하는 <Link>태그와 <Image> 태그가 제공하는 브라우저 최적화 이점 본문

FrontEnd/Next.js

Next.js가 제공하는 <Link>태그와 <Image> 태그가 제공하는 브라우저 최적화 이점

Bumang 2024. 4. 22. 00:17

들어가기 앞서

Next.js는 framework로써 여러 성능 최적화 유틸 태그를 제공한다.

대표적으로 Link태그나 Image태그를 제공한다. (React에도 Link태그가 있다고?

아니다. 리액트 환경에서 사용하는 Link태그는 React-Router-Dom 라이브러리가 제공하는 태그이다.)

 

특히 Next.js의 Link 태그는 리액트 라우터 돔의 Link태그보다 더욱 성능 최적화가 되어있고,

Image태그도 기존 img태그에 비해 많은 최적화가 되어있는 유틸 태그이다.

이번 시간은 이에 대해서 알아보도록 하자.

 

Link 태그와 a태그와의 성능 비교

 

 

위 이미지는 예제 블로그 사이트이다. 저기서 첫 번째 글은 하이퍼링크로 되어있고 클릭하면 첫 번째 글로 이동한다.

이를 a태그와 Link태그로 각각 구현했을 때 어떤 성능 차이가 발생할까?

 

1. a태그로 구현된 하이퍼링크를 클릭해서 페이지 이동을 했을 때

뭔가 많이 불러온 것을 볼 수 있다.

기존 레이아웃에서 겹치는 요소라도 상관없이 처음부터 모든 요소를 불러오기 때문에 데이터 패칭이 많이 일어난 것이다.

뒤로가기를 했을땐 어떨까? 뒤로가기를 해도 이전에 다운 받은 데이터였을텐데도 모두 다시 데이터 패칭을 하게 된다.

 

 

 

2. Link 태그를 사용했을 때

Link태그로 구현했을 때이다.

사실 메인과 첫번째 포스트를 이동할 때 레이아웃은 거의 변하지 않고 글만 조금 바뀌는 수준의 차이만 있다.

그렇기에 필요한 파일만 추가로 패칭한 것을 볼 수 있다.

 

(실제로 페이지 이동을 발생시키는게 아니라, js로 브라우저의 history 배열을 모사한 배열에

새로운 페이지를 추가하고 이로 교체하는 것이기 때문이다.)

그리고 뒤로 가기를 눌러도 기존에 캐싱한 이전페이지 데이터를 보여준다.

 

*조금 더 단적으로  시험해보고 싶으면 next로 만든 페이지에 background-color: pink같이 임의의 색을 주입한 다음에
Navigation등을 이용하여 다른 페이지로 이동해보아라. 색이 변하지 않고 계속 유지되는 것을 알 수 있다. 그러나 a태그로 이동 시에는 background-color가 해제되며 뒤로가기를 해도 background-color가 다시 먹히지도 않는다.

요약
a태그:
  - 페이지 이동 시 모든 데이터를 다시 패칭한다.
  - 히스토리도 모두 날려버린다.
  - 뒤로가기를 해도 캐싱된게 없으니 다시 모든 데이터를 패칭한다.
Link태그:
  - 페이지 이동 시 이전 페이지와 공통된 부분은 제외하고 달라진 부분만 데이터 패칭한다.
  - 뒤로가기를 하면 캐싱해뒀던 이전 페이지로 교체하여 데이터 패칭이 일어나지 않는다.

 

3. Next.js의 Link태그의 Prefetching 기능

위에 소개한데 까지는 리액트 라우터 돔의 Link태그도 같은 성능최적화를 보여준다고 할 수 있다.

그러나 Next의 Link태그가 리액트 라우터 돔의 Link태그보다도 조금 더 좋은 이유가 하나 있는데, 그건 바로 prefetch 기능이다.

 

Next의 <Link> 컴포넌트를 이용하면, 뷰포트에 Link 컴포넌트가 노출되었을 때에 비로소 href로 연결된 페이지의 chunk를 로드한다.

이른바 Link태그에도 Lazy-loading이 걸려있는 것이다. 그래서 초기에 불러올 데이터의 양을 조금이라도 더 줄일 수 있게 해준다.

그런데 이는 개발 모드에선 알 수 없고 빌드된 사이트에서만 확인할 수 있다. (왜지? 조금 더 공부해봐야겠다.)

이는 리액트 라우터 돔에는 없는 최적화이다.

 

*Link태그를 사용하며 주의할 점

Next.js의 링크 태그 자체에는 스타일을 줄 수가 없다고 한다. 그러므로 wrapper를 만들거나 children에다가 주는 식으로 사용해야겠다.

 

img태그와 Image태그의 차이점

Next환경에선 img태그 말고 Next.js가 제공하는 Image태그를 사용할 것이 권장된다. Image태그 또한 기존 img태그보다

더욱 많은 최적화가 되어있다. 어떤 부분에서 최적화가 되었는지 알아보자.

 

1. img태그로 했을 때의 특징

img로 이미지를 만들었을 때, 개발자 도구의 network탭을 보면 아래와 같은 특징이 있다.

 

- 네트워크 탭에 public에 넣어놨던 이미지이름과 확장자명이 기존과 똑같게 나온다.

- payload가 따로 보이지 않는다.

 

 

2. Image태그로 했을 때의 특징

일단 Next의 Image태그를 사용한 경우에는 파일이름이 url로 나오고 비동기 요청을 한 흔적이 보인다.

기존 파일을 그대로 불러오는게 아니라 여러 성능 최적화를 위해 이미지 데이터를 어딘가로 post한 후 결과값을 받아오는거 같은데.. 추가적으로 공부해봐야겠다.

 

- width와 height를 명시해야된다.

    - Cumulative Layout Shift(누적 레이아웃 이동, 로딩 시 이미지 영역 동적으로 뒤바뀌며 레이아웃 변동 심하게 보이는 현상)을
    방지하기 위해서이다.

- 확장자명이 webp이다.

    - 이미지 최적화에서 가장 중요한 부분이 이미지 경량화이다. 개발자가 직접 모든 이미지를 webp같은
    낮은 용량의 포맷으로 안 바꿔도 Image태그가 알아서 다 바꿔준 것이다! 이로 인해 드라마틱한 성능 향상을 볼수도 있다.

- 기기 해상도에 따라 알아서 적절한 사이즈로 resizing한 것을 패칭해온다. 

    - 브라우저에 로드될 때 이미지의 크기를 자동으로 조정하고, 필요에 따라 여러 크기의 이미지를 생성하여 제공한다.
       이는 사용자의 디바이스 스크린 크기 및 해상도에 적합한 이미지를 선택적으로 로드할 수 있게 한다.

 

 

---

*추가) Image태그에 width와 height를 꼭 명시해야된다면 반응형은 어떻게 설정하는가?

 

fill 속성을 사용하기

fill을 사용하면 부모 컨테이너의 width/height에 맞춰 비율을 무시한채로 꽉 차게 된다.

만약 비율을 유지하면서 부모 영역을 꽉 채우고 싶다면 object-fit을 cover로 설정해주면 된다. 이 외에도 contain, none, scale-down 등의 속성을 jsx에 줘서 변경할 수 있다. 그러나 fill 속성을 사용할 땐 부모 요소에 position값을 꼭 줘야한다는 것을 유념해야된다. (Image에 fill 속성을 준 시점에서 Image태그는 absolute로 전환되기 때문이다.)

 

+ 추가적으로 몇몇 블로그를 보니 layout="responsive"를 사용해도 괜찮다는 얘기를 들었는데, 실제로 해보니 작동하지 않는다. 공식 홈페이지에서 Image태그 속성 중 아무리 찾아봐도 없다. gpt가 만들어낸 일루미네이션을 그대로 썼거나 혹은 deprecated된 속성인거 같다.

jsxCopy code
import Image from 'next/image';

function MyComponent() {
  return (
    <div style={{ width: '100%', height: 240 }}> {/* 부모 컨테이너의 너비를 제어 */}
      <Image
        src="/path/to/image.jpg"
        alt="Description of the image"
        fill
        objectFit="cover"
      />
    </div>
  );
}