vercel / commerce

Next.js Commerce

Home Page:https://demo.vercel.store

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

Slow loading of images on product page

rumfiske opened this issue · comments

Images are extremely slow to load on the product's page.

About 4-6 seconds to load from the server, as i can see from my network's tab. But after its cached it seems to be lightning fast.

"Components>product>gallery.tsx" file is a client component, so i dont get why it is so slow? What can i do?

http://localhost:3000/_next/image?url=https%3A%2F%2Fcdn.shopify.com%2Fs%2Ffiles%2F1%2F0864%2F1229%2F6493%2Ffiles%2Fdesign-1710197568254_4b302d04-8f60-4267-b5fe-d477f472a34c.png%3Fv%3D1710273499&w=1080&q=75

My Gallery file

'use client';

import { ArrowLeftIcon, ArrowRightIcon } from '@heroicons/react/24/outline';
import { GridTileImage } from 'components/grid/tile';
import { ProductVariant } from 'lib/shopify/types';
import { createUrl } from 'lib/utils';
import Image from 'next/image';
import Link from 'next/link';
import { usePathname, useSearchParams } from 'next/navigation';

export function Gallery({
  images,
  variants
}: {
  images: { src: string; altText: string }[];
  variants: ProductVariant[];
}) {
  const pathname = usePathname();
  const searchParams = useSearchParams();
  const imageSearchParam = searchParams.get('image');
  const imageIndex = imageSearchParam ? parseInt(imageSearchParam) : 0;

  const nextSearchParams = new URLSearchParams(searchParams.toString());
  const nextImageIndex = imageIndex + 1 < images.length ? imageIndex + 1 : 0;
  nextSearchParams.set('image', nextImageIndex.toString());
  const nextUrl = createUrl(pathname, nextSearchParams);

  const previousSearchParams = new URLSearchParams(searchParams.toString());
  const previousImageIndex = imageIndex === 0 ? images.length - 1 : imageIndex - 1;
  previousSearchParams.set('image', previousImageIndex.toString());
  const previousUrl = createUrl(pathname, previousSearchParams);

  const buttonClassName =
    'h-full px-6 transition-all ease-in-out hover:scale-110 hover:text-black dark:hover:text-white flex items-center justify-center';

  //if there are variants, then the default variant is the first one
  const defaultVariantId = variants.length ? variants[0]?.id : undefined;

  // Extract the 'farve' parameter from the URL search parameters.
  const selectedFarve = searchParams.get('farve');

  // Find a variant where the 'Farve' option matches the 'farve' URL parameter.
  let variant = variants.find((variant: ProductVariant) =>
    variant.selectedOptions.some(
      (option) =>
        option.name.toLowerCase() === 'farve' &&
        option.value.toLowerCase() === selectedFarve?.toLowerCase()
    )
  );

  const selectedVariantId = variant?.id || defaultVariantId;

  const filteredVariant = variants.filter((item) => item.id === selectedVariantId);
  // console.log(images);
  return (
    <>
      <div className="relative aspect-square h-full max-h-[550px] w-full overflow-hidden">
        {images[imageIndex] && imageSearchParam ? (
          <Image
            className="h-full w-full object-contain opacity-0 transition-opacity duration-[2s] ease-in-out"
            onLoad={(e: any) => {
              e.target.classList.remove('opacity-0');
            }}
            
            fill
            fetchPriority="high"
            alt={images[imageIndex]?.altText as string}
            src={images[imageIndex]?.src as string}
            sizes="(min-width: 1024px) 66vw, 100vw"
            priority={true}
          />
        ) : (
          <Image
            className="h-full w-full object-contain opacity-0 transition-opacity duration-[2s] ease-in-out"
            onLoad={(e: any) => {
              e.target.classList.remove('opacity-0');
            }}
            fill
            fetchPriority="high"
            alt={filteredVariant[0]?.title as string}
            src={filteredVariant[0]?.image?.url as string}
            priority={true}
          />
        )}

        {images.length > 1 ? (
          <div className="absolute bottom-[15%] flex w-full justify-center">
            <div className="mx-auto flex h-11 items-center rounded-full border border-white bg-neutral-50/80 text-neutral-500 backdrop-blur dark:border-black dark:bg-neutral-900/80">
              <Link
                prefetch
                aria-label="Previous product image"
                href={previousUrl}
                className={buttonClassName}
                scroll={false}
              >
                <ArrowLeftIcon className="h-5" />
              </Link>
              <div className="mx-1 h-6 w-px bg-neutral-500"></div>
              <Link
                prefetch
                aria-label="Next product image"
                href={nextUrl}
                className={buttonClassName}
                scroll={false}
              >
                <ArrowRightIcon className="h-5" />
              </Link>
            </div>
          </div>
        ) : null}
      </div>

      {images.length > 1 ? (
        <ul className="my-12 flex items-center justify-center gap-2 overflow-auto py-1 lg:mb-0">
          {images.map((image, index) => {
            const isActive = index === imageIndex && imageSearchParam ? true : false;
            const imageSearchParams = new URLSearchParams(searchParams.toString());

            imageSearchParams.set('image', index.toString());

            return (
              <li key={image.src} className="h-20 w-20">
                <Link
                  prefetch
                  aria-label="Enlarge product image"
                  href={createUrl(pathname, imageSearchParams)}
                  scroll={false}
                  className="h-full w-full"
                >
                  <GridTileImage
                    alt={image.altText}
                    src={image.src}
                    width={80}
                    height={80}
                    active={isActive}
                  />
                </Link>
              </li>
            );
          })}
        </ul>
      ) : null}
    </>
  );
}

Hey there, I cannot reproduce on https://demo.vercel.store/.

Do you have a deployed example where you are seeing them slow to load? It might be running slower on localhost because you're seeing the page first compile, then the image get optimized and cached, and then displayed.

Hey there, I cannot reproduce on https://demo.vercel.store/.

Do you have a deployed example where you are seeing them slow to load? It might be running slower on localhost because you're seeing the page first compile, then the image get optimized and cached, and then displayed.

Yes please see it on drommeriet.dk :)