Next.js에서 img태그 사용 시 주의사항
최근 담당한 서비스의 CWV개선작업 중 이상한 현상을 발견했다. 페이지에 <img>
태그를 사용하면 이미지가 강제로 preload처리되는 현상이었다. CWV개선을 위해서는 리소스의 우선순위 최적화가 필수인데. 위의 현상때문에 주요 리소스의 로드를 방해하도록 html이 렌더되었다.
export default function Page() {
return (<>
<img src="a.png" />
</>);
}
// 렌더링 결과:
// "<html><head>
// <link rel="preload" href="a.png" /> ???
// </head> ...생략... </html>"
위 현상 때문에 LCP를 많이 깎아먹고 있었고 이리저리 소스코드를 보다 보니 이 문제가 next.js가 아니라 react-dom의 의도된 동작이라는 것을 알았다.
[Fizz] Preload “suspensey” images
해당 PR은 이미지들의 loading
, fetchPriority
속성에 따라 몇 가지 조건에 해당할 경우 이미지들을 preload처리하는 내용이다.
특이한 건 이후에 <picture>
안의 <img>
들은 preload하지 않는 PR도 발견했다.
[Fizz][Float] <img> inside <picture> should not preload during SSR
위의 내용을 정리하면. react-dom/server 의 스트리밍 버전인 ReactDomFizzServer의 renderToPipableStream
함수는. 이미지가 <picture>
바깥에 있거나, fetchPriority="low"
속성을 주지 않을 경우. 강제로 preload처리한다.
리소스 우선순위를 조절해야 하는 경우. <img>
태그를 직접 사용하려면 위의 조건을 만족하도록 적절히 수정하거나, next.js가 제공하는 <Image>
태그를 사용해야 한다.
위 현상의 경우 별다른 가이드가 없기도 하고. 사실 <img>
태그들을 왜 preload처리하는지 이해가 안 된다. 심지어 이미지 태그가 20개면 20개 다 preload하는데 도대체 왜 그런지…
next.js는 개발자들이 이미지를 사용할 때 대부분 <Image>
등 제공된 API들만 사용하길 바란 듯 하다. 그랬다면 위 문제는 없었을 것이긴 하다…
사실 next.js덕분에 개발자 입장에서는 다양한 렌더링 전략을 요구사항에 맞춰 쉽게 구현할 수 있어 좋긴 하다, 그런데 일전의 Suspense사태도 그렇고. 올바른 방향으로 가고 있는지는 잘 모르겠다.