--- import { getImage, type LocalImageProps, type RemoteImageProps } from 'astro:assets'; import type { GetImageResult, ImageOutputFormat } from '../dist/@types/astro'; import { isESMImportedImage } from '../dist/assets/utils/imageKind'; import { AstroError, AstroErrorData } from '../dist/core/errors/index.js'; import type { HTMLAttributes } from '../types'; type Props = (LocalImageProps | RemoteImageProps) & { formats?: ImageOutputFormat[]; fallbackFormat?: ImageOutputFormat; pictureAttributes?: HTMLAttributes<'picture'>; }; const defaultFormats = ['webp'] as const; const defaultFallbackFormat = 'png' as const; // Certain formats don't want PNG fallbacks: // - GIF will typically want to stay as a gif, either for animation or for the lower amount of colors // - SVGs can't be converted to raster formats in most cases // - JPEGs compress photographs and high-noise images better than PNG in most cases // For those, we'll use the original format as the fallback instead. const specialFormatsFallback = ['gif', 'svg', 'jpg', 'jpeg'] as const; const { formats = defaultFormats, pictureAttributes = {}, fallbackFormat, ...props } = Astro.props; if (props.alt === undefined || props.alt === null) { throw new AstroError(AstroErrorData.ImageMissingAlt); } const optimizedImages: GetImageResult[] = await Promise.all( formats.map( async (format) => await getImage({ ...props, format: format, widths: props.widths, densities: props.densities }) ) ); let resultFallbackFormat = fallbackFormat ?? defaultFallbackFormat; if ( !fallbackFormat && isESMImportedImage(props.src) && specialFormatsFallback.includes(props.src.format) ) { resultFallbackFormat = props.src.format; } const fallbackImage = await getImage({ ...props, format: resultFallbackFormat, widths: props.widths, densities: props.densities, }); const imgAdditionalAttributes: HTMLAttributes<'img'> = {}; const sourceAdditionalAttributes: HTMLAttributes<'source'> = {}; // Propagate the `sizes` attribute to the `source` elements if (props.sizes) { sourceAdditionalAttributes.sizes = props.sizes; } if (fallbackImage.srcSet.values.length > 0) { imgAdditionalAttributes.srcset = fallbackImage.srcSet.attribute; } --- { Object.entries(optimizedImages).map(([_, image]) => { const srcsetAttribute = props.densities || (!props.densities && !props.widths) ? `${image.src}${image.srcSet.values.length > 0 ? ', ' + image.srcSet.attribute : ''}` : image.srcSet.attribute; return ( ); }) }