#Broken SVG images on netlify

23 messages · Page 1 of 1 (latest)

eternal creekBOT
#

Hi @sonic raft. I'm kapa.ai, your friendly support bot. I will try to answer your question by searching through the knowledge base. :wave:

#

I can see why your SVG images are breaking after build on Netlify. This is happening because Astro doesn't support converting between vector (SVG) and raster image formats.

The Issue

The problem is that your component is trying to process SVG files with the <Image /> component, which attempts to optimize them. However, Astro's image optimization doesn't currently support converting between vector images (like SVGs) and raster images (like PNGs and JPEGs).

As mentioned in the Astro documentation:

UnsupportedImageConversion: Converting between vector (such as SVGs) and raster (such as PNGs and JPEGs) images is not currently supported.
Unsupported image conversion

Solutions

Here are a few ways to fix this issue:

1. Use SVG as components directly

Astro 5.7.0+ allows you to import SVG files and use them as Astro components:

---
import Logo from './path/to/svg/file.svg';
---

<Logo width={64} height={64} fill="currentColor" />

This approach inlines the SVG content into your HTML output and allows you to pass props like width, height, and fill directly to the SVG element.
SVG components

2. Use HTML <img> tag for SVGs

For SVG files, you can use the standard HTML <img> tag instead of the <Image /> component:

<img src={imageSource.default.src} alt={alt} width={width} height={height} class={className} loading={loading} />

The Astro documentation recommends using the HTML <img> element when:

#

3. Modify your component to handle SVGs differently

You could update your component to check if the image is an SVG and handle it differently:

---
// Your existing imports and props

const isSvg = src.endsWith('.svg');
const imageSource = images[src] ? await images[src]() : null;
---

{
  imageSource && isSvg && (
    <img 
      src={imageSource.default.src} 
      alt={alt || ""} 
      width={width} 
      height={height} 
      class={className} 
      loading={loading}
    />
  )
}

{
  imageSource && !isSvg && (
    <Image
      src={imageSource.default}
      alt={alt || ""}
      width={width}
      height={height}
      class={className}
      loading={loading}
      format={format}
    />
  )
}

This approach will use the standard <img> tag for SVGs while still using the <Image /> component for other image formats.

By implementing one of these solutions, your SVG images should display correctly on Netlify after building your site.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@sonic raft Kapa.ai is still learning and improving, please let me know how I did by reacting below.

sonic raft
#

but all of my images are loading from src dircotry nit puvlic

#

@eternal creek but all of my images are loading from src dircotry nit puvlic

eternal creekBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

I understand that your images are loading from the src directory rather than the public directory. This is actually the recommended approach in Astro for images that need processing and optimization.

In Astro, there are two main places to store images:

  1. src/ directory (recommended): Images stored here can be processed, transformed, and optimized by Astro. This is ideal for most use cases.

    As the documentation states:

    We recommend that local images are kept in src/ when possible so that Astro can transform, optimize and bundle them.
    Images Guide

  2. public/ directory: Files here are served as-is without any processing.

For your SVG issue, even though your images are correctly stored in the src directory, the problem is that Astro's <Image /> component doesn't support converting between vector (SVG) and raster formats.

Here are your options for handling SVGs from the src directory:

  1. Use the HTML <img> tag for SVGs only:

    {
      imageSource && imageSource.default.src.endsWith('.svg') ? (
        <img
          src={imageSource.default.src}
          alt={alt || ""}
          width={width}
          height={height}
          class={className}
          loading={loading}
        />
      ) : (
        <Image
          src={imageSource.default}
          alt={alt || ""}
          width={width}
          height={height}
          class={className}
          loading={loading}
          format={format}
        />
      )
    }
    
  2. Import SVGs directly as components (if your Astro version supports it):
    This would require a different approach than your current component.

#

The key is to handle SVGs differently than other image formats, even though they're all stored in the src directory.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@sonic raft Kapa.ai is still learning and improving, please let me know how I did by reacting below.

sonic raft
#

@eternal creek console.log(imageSource);

src: '/@fs/Users/adsfdsfdfmir/Documents/GitHub/affordabox-marketing/src/assets/images/social/socialLinks/2/icon.svg?origWidth=32&origHeight=32&origFormat=svg',

eternal creekBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

I see that you're logging the imageSource object and it shows a path to an SVG file in your project. The path includes query parameters like origWidth, origHeight, and origFormat, which are added by Astro's asset handling system.

This confirms that your SVG is being loaded from the src directory as expected, but as we discussed earlier, the issue is that Astro's <Image /> component doesn't properly handle SVG files for optimization.

Since you're working with SVGs in the src directory, you have two main options:

  1. Use SVG as a component (recommended for Astro 5.7.0+):

    ---
    import Icon from '/src/assets/images/social/socialLinks/2/icon.svg';
    ---
    <Icon width={32} height={32} />
    

    This approach lets you use the SVG directly as a component and pass attributes to it.
    SVG components

  2. Use the HTML <img> tag for SVGs:
    Modify your component to use <img> specifically for SVG files:

    {
      imageSource && imageSource.default.src.includes('.svg') ? (
        <img
          src={imageSource.default.src}
          alt={alt || ""}
          width={width}
          height={height}
          class={className}
          loading={loading}
        />
      ) : (
        <Image
          src={imageSource.default}
          alt={alt || ""}
          width={width}
          height={height}
          class={className}
          loading={loading}
          format={format}
        />
      )
    }
    
#

The path you're seeing in the console log confirms that Astro is finding your SVG file correctly, but the <Image /> component is trying to process it in a way that's not compatible with SVGs, which is why they're breaking after build.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@sonic raft Kapa.ai is still learning and improving, please let me know how I did by reacting below.

sonic raft
#

@eternal creek }
22:01:24 [ERROR] Cannot read properties of null (reading 'default')
Stack trace:
at /Users/amir/Documents/GitHub/affordabox-marketing/src/components/ui/CustomImage.astro:47:18

eternal creekBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

I see you're getting a null reference error in your CustomImage.astro component. This error occurs when you're trying to access the default property of imageSource, but imageSource is null.

Looking at your component code from our previous conversation:

const imageSource = images[src] ? await images[src]() : null;

And then later:

{
  imageSource && (
    <Image
      src={imageSource.default}  // This line is causing the error
      alt={alt || ""}
      width={width}
      height={height}
      class={className}
      loading={loading}
      format={format}
    />
  )
}

The error is happening because even though you have a check for imageSource being truthy, there might be cases where imageSource exists but imageSource.default is null or undefined.

Here are some possible fixes:

  1. Add an additional check for imageSource.default:
{
  imageSource && imageSource.default && (
    <Image
      src={imageSource.default}
      alt={alt || ""}
      width={width}
      height={height}
      class={className}
      loading={loading}
      format={format}
    />
  )
}
  1. Check if the issue is related to your glob pattern. Make sure it correctly matches your file paths:
const images = await import.meta.glob<{ default: ImageMetadata }>(
  "/src/assets/**/**/*.{jpeg,jpg,png,gif,webp,svg,avif}"
);

The pattern might need adjustment based on your project structure. For example, you might need to remove one level of ** or adjust the path.

  1. Add more debugging to see what's happening:
console.log("src:", src);
console.log("images keys:", Object.keys(images));
console.log("imageSource:", imageSource);
#

This will help you understand if the path you're providing in src is actually found in the images object, and what imageSource contains when it's not null but doesn't have a default property.

The error suggests that at line 47, you're trying to access imageSource.default, but imageSource is null, which means the image path you're trying to use isn't being found by the glob pattern.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon:

#

@sonic raft Kapa.ai is still learning and improving, please let me know how I did by reacting below.

sonic raft
#

{
imageSource && imageSource.default.src.includes(".svg") ? (
<img
src={imageSource.default.src}
alt={alt || ""}
width={width}
height={height}
class={className}
loading={loading}
/>
) : (
<Image
src={imageSource.default}
alt={alt || ""}
width={width}
height={height}
class={className}
loading={loading}
format={format}
/>
)
}

also wrap <Image
src={imageSource.default} in if(ImagrSourcr exist ) @eternal creek

eternal creekBOT
#

Let me check the knowledge base for you again. One moment! :books:

#

I see you're trying to implement a conditional rendering approach to handle SVG files differently from other image formats. Your code looks good for the most part, but I'll help you fix the issue with the null check for imageSource.default.

Here's the corrected version of your component with proper null checks:

{
  imageSource && imageSource.default ? (
    imageSource.default.src.includes(".svg") ? (
      <img
        src={imageSource.default.src}
        alt={alt || ""}
        width={width}
        height={height}
        class={className}
        loading={loading}
      />
    ) : (
      <Image
        src={imageSource.default}
        alt={alt || ""}
        width={width}
        height={height}
        class={className}
        loading={loading}
        format={format}
      />
    )
  ) : null
}

This code:

  1. First checks if both imageSource AND imageSource.default exist
  2. If they do, it then checks if the image is an SVG using includes(".svg")
  3. For SVGs, it renders a regular <img> tag
  4. For other image formats, it uses Astro's <Image /> component
  5. If imageSource or imageSource.default is null/undefined, it renders nothing

This should prevent the "Cannot read properties of null (reading 'default')" error you were encountering, as we're now properly checking for the existence of imageSource.default before trying to access its properties.

The approach of using a regular <img> tag for SVGs while using the <Image /> component for other formats is the right way to handle this situation, as Astro doesn't support converting between vector and raster images.

Note: you can ask me a follow up question by @ mentioning me again :speech_balloon: