Pre-study

Resources

Serve images in next-gen formats

Next.js Image Component Documentation

Image Optimization

Next.js Image Optimization Guide
Fix your website's Largest Contentful Paint by optimizing image loading

HTMLImageElement Properties

Decoding Property

FetchPriority Property

Loading Property

Solution 1: Migrate to Next.js Image Component

Conversion

Replace elements with the Next.js Image component.

<img ... />

To:

import Image from 'next/image';

<Image ... />

Local Images

Importing from Public Folder

Remote Images

Note: Provide either width and height or use fill.

Known Width and Height (or Aspect Ratio)

Set width and height based on the intrinsic aspect ratio of the image.

Unknown Width and Height

Extracting Width and Height from Image URL

For example, imgUrl:

'http://image-transfer.my.com/myProject/image/upload/ar_1:1,w_700,c_pad,b_auto:predominant/v12345/artist.png';

Helper Function:

const parseNum = (value, fallback) => {
  const num = Number(value);
  return isNaN(num) ? fallback : num;
};

export const getDimensionsFromImgUrl = (imgUrl) => {
  const defaultSize = 1;
  const arDelimiter = 'ar_';
  const widthDelimiter = 'w_';

  const parts = imgUrl.split(',');
  const arPart = parts.find((part) => part.includes(arDelimiter));
  const widthPart = parts.find((part) => part.includes(widthDelimiter));

  if (!arPart || !widthPart)
    return { width: defaultSize, height: defaultSize };

  const width = parseNum(widthPart.split(widthDelimiter)[1], defaultSize);
  const [w, h] = (arPart.split(arDelimiter)[1]?.split(':') || [defaultSize, defaultSize]).map((size) => parseNum(size, defaultSize));
  const height = Math.round(width * (h / w));

  return { width, height };
};

Usage:

const { width, height } = getDimensionsFromImgUrl(imgUrl);
When Width and Height Cannot Be Extracted

Create a custom image component using the onload event to set dimensions.

Note: This may cause layout shift.

const DynamicImage = ({ logo, alt, imgUrl }) => {
  const [dimensions, setDimensions] = useState({ width: 100, height: 100 }); // Fallback values

  useEffect(() => {
    const img = new window.Image();
    img.src = imgUrl;
    img.onload = () => {
      setDimensions({ width: img.width, height: img.height });
    };
  }, [imgUrl]);

  return (
    <NextImage
      className={classNames(
        { 'page-header__img': !logo.isCP },
        { 'page-header-cp__img': logo.isCP },
        { 'page-header__img--sm': logo.sm }
      )}
      src={imgUrl}
      alt={alt}
      width={dimensions.width}
      height={dimensions.height}
    />
  );
};

Errors and Solutions

Error: 'sharp' is required in standalone mode for image optimization

Solution:

Solution 2: Use Next.js Image for Known Dimensions Only

Since Next.js Image requires width and height (or fill), it is recommended to use it only when dimensions are known.

Other Images: Add Attributes to

For unknown dimensions, continue using the tag with relevant attributes based on requirements.

For example, for LCP (Largest Contentful Paint) images:

decoding='async'
  fetchPriority='high'
  loading='eager'
  src={resizeImg(imgUrl, 'lg', { ar })}
  alt={imgAlt}
/>

For non-LCP images:

decoding='async'
  fetchPriority='low'
  loading='lazy'
  src={resizeImg(imgUrl, 'lg', { ar })}
  alt={imgAlt}
/>