Search code examples
markdownastrojs

Dynamically import/use images from collection markdown with Astro assets?


As an example, I have an Astro app with a collection /collections/artworks where each artwork specifices a cover image via the frontmatter cover: '../assets/artworks/1-hello/cover.png - the file lies at /src/assets/artworks/1-hello/cover.png. I am trying to use Astro's asset support.

Then in my template, I am looping through all the artworks and have <Image width={400} src={artwork.data.cover} alt={artwork.data.coverAlt} /> which does not work and fails to find the file.

Trying to import it inline seems to fail <Image width={400} src={import(artwork.data.cover)} alt={artwork.data.coverAlt} /> with the error "Received unsupported format undefined from undefined ", assuming that it's just not resolving.

However, if I import the image explicitly with the same path as specified in the markdown, it works:

import cover from "../assets/artworks/1-hello/cover.png"
<Image src={cover} ... />

How can I loop through a collection and dynamically import images specified in the markdown accordingly?


Solution

  • To use images in Markdown frontmatter with Astro’s assets feature, you need to use the image helper in your content collection schema.

    Assuming your current schema looks something like this:

    // src/content/config.ts
    
    import { defineCollection, z } from "astro:content";
    
    export const collections = {
      artworks: defineCollection({
        schema: z.object({
          cover: z.string(),
        }),
      }),
    };
    

    You need to update the schema to be a function, and use the image parameter as the schema type for cover:

    // src/content/config.ts
    
    import { defineCollection, z } from "astro:content";
    
    export const collections = {
      artworks: defineCollection({
        schema: ({ image }) => z.object({
          cover: image(),
        }),
      }),
    };
    

    This will import the image for you behind the scenes, so that you can pass artwork.data.cover directly to the <Image> component.