Astrowind - Image Component

08/10/2024, Sat
Categories: #JavaScript

Searching for Images

Astro comes with a default image component that you can use to load your images from the /src/assets folder.

From the actual documentation page,

---
// import the Image component and the image
import { Image } from 'astro:assets';
import myImage from "../assets/my_image.png"; // Image is 1600x900
---

<!-- `alt` is mandatory on the Image component -->
<Image src={myImage} alt="A description of my image." />

Using Astro's Image component is useful in that it helps you perform optimizations to your images on the final build. It is able to output to webp format as well as set the width and height for them to improve site layout performance.

However, one of the downside of using the default component is that you have to load the images one by one. Astro also has a suggestion for dynamic images using import.meta.glob, but it still is not as dynamic as compared to that of Astro's glob method.

Supposedly, that you have images in folders located in the ''/src/assets/images/'. There is the expectation that '/src/assets/images/**' pattern will return all your images within those folders when using the that pattern with import.meta.glob

const images = import.meta.glob<{ default: ImageMetadata }>('/src/assets/images/**'.{jpeg,jpg,png,gif}');

But it does not yield any results in the images results.

While if you to use Astro.glob with that search pattern,

const images = await Astro.glob('/src/assets/images/**');

the images will provide the results.

To retain flexibility in searching for images and as well as customization for the , it is helpful go midway between using Astro's default Image component and the plain <img> tag by using Astrowind's Image component.

To search for images dynamically in your src/assets folder, we will define the getImageMetas function in the src/utils/images.ts file. We need this function because we wish to narrow down the results that is returned from using Astro.glob by finding only the image names that we supply to it.

export const getImageMetas = async (searchImages, allImages) => {

  const imgNameToEntry = {};

  allImages.forEach((images, imagesIndex) => {
    const searchedNames = images.default.src;

    let searchImageName = '';
    let searchImageEntry: Record<any, any> = {};

    const foundImages = searchImages.filter((searchImg) => {
      // Account for the differences in the image file name output
      // between development and final build

      // Build
      // my_image.DySEU_5O.jpg
      // Dev
      // my_image.jpg
      if (searchedNames.indexOf(`/${path.parse(searchImg).name}`) > -1) {
        searchImageName = searchImg;
        searchImageEntry = allImages[imagesIndex];
        return true;
      } else {
        return false;
      }
    });

    if (foundImages.length > 0) {
      imgNameToEntry[searchImageName] = searchImageEntry;
    }
  });

  return imgNameToEntry;
}

Within your .astro file, you will define the images that you want to search for in the searchImages array. You will need to get all images from your image folder because Astro.glob does not support the use of dynamic strings in which it uses to search. Finally, call the getImageMetas by passing images to search for and all the images from your image folder.

It is rather unfortunate that Astro doesn't allow you to pass in Astro.glob into our getImageMetas function because the glob function is restricted for use in Astro templates, so you will need to repeat this line in all the other .astro templates that need to perform dynamic image searches.

const searchImages = ['some-image.jpg', 'another-image.jpg'];
const allImages = await Astro.glob('/src/assets/images/**');
const imagesMetas = await getImageMetas(searchImages, allImages);

The output of imagesMetas will look like the following

{
  default: {
    src: '/@fs/home/my-repo-paths/src/assets/images/some-image.jpg?origWidth=1024&origHeight=1024&origFormat=jpg',
    width: 1024,
    height: 1024,
    format: 'jpg'
  },
  [Symbol(Symbol.toStringTag)]: 'Module'
},
{
  default: {
    src: '/@fs/home/my-repo-paths/src/assets/images/another-image.jpg?origWidth=1024&origHeight=1024&origFormat=jpg',
    width: 1024,
    height: 1024,
    format: 'jpg'
  },
  [Symbol(Symbol.toStringTag)]: 'Module'
},

One can start using webp images from the beginning to gain the additional level of image optimization for your images if you forego using Astro's image component.