diff options
-rw-r--r-- | .changeset/tasty-oranges-bathe.md | 5 | ||||
-rw-r--r-- | packages/astro/components/Image.astro | 4 | ||||
-rw-r--r-- | packages/astro/components/Picture.astro | 21 | ||||
-rw-r--r-- | packages/astro/src/assets/internal.ts | 2 | ||||
-rw-r--r-- | packages/astro/src/assets/services/service.ts | 12 | ||||
-rw-r--r-- | packages/astro/src/assets/types.ts | 15 | ||||
-rw-r--r-- | packages/astro/test/core-image.test.js | 3 | ||||
-rw-r--r-- | packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro | 2 |
8 files changed, 44 insertions, 20 deletions
diff --git a/.changeset/tasty-oranges-bathe.md b/.changeset/tasty-oranges-bathe.md new file mode 100644 index 000000000..b155cd4d8 --- /dev/null +++ b/.changeset/tasty-oranges-bathe.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix `sizes` attribute not being present on `source` elements when using it on the Picture component diff --git a/packages/astro/components/Image.astro b/packages/astro/components/Image.astro index a11efd4f9..9c4fcf7e9 100644 --- a/packages/astro/components/Image.astro +++ b/packages/astro/components/Image.astro @@ -1,6 +1,7 @@ --- import { getImage, type LocalImageProps, type RemoteImageProps } from 'astro:assets'; import { AstroError, AstroErrorData } from '../dist/core/errors/index.js'; +import type { HTMLAttributes } from '../types'; // The TypeScript diagnostic for JSX props uses the last member of the union to suggest props, so it would be better for // LocalImageProps to be last. Unfortunately, when we do this the error messages that remote images get are complete nonsense @@ -24,8 +25,7 @@ if (typeof props.height === 'string') { const image = await getImage(props); -const additionalAttributes: Record<string, any> = {}; - +const additionalAttributes: HTMLAttributes<'img'> = {}; if (image.srcSet.values.length > 0) { additionalAttributes.srcset = image.srcSet.attribute; } diff --git a/packages/astro/components/Picture.astro b/packages/astro/components/Picture.astro index f6c7686e8..d4327840a 100644 --- a/packages/astro/components/Picture.astro +++ b/packages/astro/components/Picture.astro @@ -49,9 +49,16 @@ const fallbackImage = await getImage({ densities: props.densities, }); -const additionalAttributes: Record<string, any> = {}; +const imgAdditionalAttributes: HTMLAttributes<'img'> = {}; +const sourceAdditionaAttributes: HTMLAttributes<'source'> = {}; + +// Propagate the `sizes` attribute to the `source` elements +if (props.sizes) { + sourceAdditionaAttributes.sizes = props.sizes; +} + if (fallbackImage.srcSet.values.length > 0) { - additionalAttributes.srcset = fallbackImage.srcSet.attribute; + imgAdditionalAttributes.srcset = fallbackImage.srcSet.attribute; } --- @@ -62,8 +69,14 @@ if (fallbackImage.srcSet.values.length > 0) { props.densities || (!props.densities && !props.widths) ? `${image.src}${image.srcSet.values.length > 0 ? ', ' + image.srcSet.attribute : ''}` : image.srcSet.attribute; - return <source srcset={srcsetAttribute} type={'image/' + image.options.format} />; + return ( + <source + srcset={srcsetAttribute} + type={'image/' + image.options.format} + {...sourceAdditionaAttributes} + /> + ); }) } - <img src={fallbackImage.src} {...additionalAttributes} {...fallbackImage.attributes} /> + <img src={fallbackImage.src} {...imgAdditionalAttributes} {...fallbackImage.attributes} /> </picture> diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts index f7df11f69..1c26ac6b5 100644 --- a/packages/astro/src/assets/internal.ts +++ b/packages/astro/src/assets/internal.ts @@ -102,6 +102,7 @@ export async function getImage( let imageURL = await service.getURL(validatedOptions, imageConfig); let srcSets: SrcSetValue[] = await Promise.all( srcSetTransforms.map(async (srcSet) => ({ + transform: srcSet.transform, url: await service.getURL(srcSet.transform, imageConfig), descriptor: srcSet.descriptor, attributes: srcSet.attributes, @@ -115,6 +116,7 @@ export async function getImage( ) { imageURL = globalThis.astroAsset.addStaticImage(validatedOptions); srcSets = srcSetTransforms.map((srcSet) => ({ + transform: srcSet.transform, url: globalThis.astroAsset.addStaticImage!(srcSet.transform), descriptor: srcSet.descriptor, attributes: srcSet.attributes, diff --git a/packages/astro/src/assets/services/service.ts b/packages/astro/src/assets/services/service.ts index 7d2f6afb9..8d77442c7 100644 --- a/packages/astro/src/assets/services/service.ts +++ b/packages/astro/src/assets/services/service.ts @@ -3,7 +3,7 @@ import { AstroError, AstroErrorData } from '../../core/errors/index.js'; import { isRemotePath, joinPaths } from '../../core/path.js'; import { DEFAULT_OUTPUT_FORMAT, VALID_SUPPORTED_FORMATS } from '../consts.js'; import { isESMImportedImage, isRemoteAllowed } from '../internal.js'; -import type { ImageOutputFormat, ImageTransform } from '../types.js'; +import type { ImageOutputFormat, ImageTransform, UnresolvedSrcSetValue } from '../types.js'; export type ImageService = LocalImageService | ExternalImageService; @@ -28,12 +28,6 @@ type ImageConfig<T> = Omit<AstroConfig['image'], 'service'> & { service: { entrypoint: string; config: T }; }; -type SrcSetValue = { - transform: ImageTransform; - descriptor?: string; - attributes?: Record<string, any>; -}; - interface SharedServiceProps<T extends Record<string, any> = Record<string, any>> { /** * Return the URL to the endpoint or URL your images are generated from. @@ -53,7 +47,7 @@ interface SharedServiceProps<T extends Record<string, any> = Record<string, any> getSrcSet?: ( options: ImageTransform, imageConfig: ImageConfig<T> - ) => SrcSetValue[] | Promise<SrcSetValue[]>; + ) => UnresolvedSrcSetValue[] | Promise<UnresolvedSrcSetValue[]>; /** * Return any additional HTML attributes separate from `src` that your service requires to show the image properly. * @@ -233,7 +227,7 @@ export const baseService: Omit<LocalImageService, 'transform'> = { }; }, getSrcSet(options) { - const srcSet: SrcSetValue[] = []; + const srcSet: UnresolvedSrcSetValue[] = []; const { targetWidth } = getTargetDimensions(options); const { widths, densities } = options; const targetFormat = options.format ?? DEFAULT_OUTPUT_FORMAT; diff --git a/packages/astro/src/assets/types.ts b/packages/astro/src/assets/types.ts index ec7393e50..c11f58b25 100644 --- a/packages/astro/src/assets/types.ts +++ b/packages/astro/src/assets/types.ts @@ -33,11 +33,18 @@ export interface ImageMetadata { orientation?: number; } -export interface SrcSetValue { - url: string; +/** + * A yet to be completed with an url `SrcSetValue`. Other hooks will only see a resolved value, where the URL of the image has been added. + */ +export type UnresolvedSrcSetValue = { + transform: ImageTransform; descriptor?: string; - attributes?: Record<string, string>; -} + attributes?: Record<string, any>; +}; + +export type SrcSetValue = UnresolvedSrcSetValue & { + url: string; +}; /** * A yet to be resolved image transform. Used by `getImage` diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index ade979918..fb7c7c828 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -222,6 +222,9 @@ describe('astro:image', () => { expect($img).to.have.a.lengthOf(1); expect($picture).to.have.a.lengthOf(1); expect($source).to.have.a.lengthOf(1); + expect($source.attr('sizes')).to.equal( + '(max-width: 448px) 400px, (max-width: 810px) 750px, 1050px' + ); const srcset2 = parseSrcset($source.attr('srcset')); expect(srcset2.every((src) => src.url.startsWith('/_image'))).to.equal(true); diff --git a/packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro b/packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro index 713990d86..2fcf4e06c 100644 --- a/packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro +++ b/packages/astro/test/fixtures/core-image/src/pages/picturecomponent.astro @@ -8,7 +8,7 @@ import myImage from "../assets/penguin1.jpg"; </div> <div id="picture-widths"> -<Picture src={myImage} width={Math.round(myImage.width / 2)} alt="A penguin" widths={[myImage.width]} /> +<Picture src={myImage} width={Math.round(myImage.width / 2)} alt="A penguin" widths={[myImage.width]} sizes="(max-width: 448px) 400px, (max-width: 810px) 750px, 1050px" /> </div> <div id="picture-fallback"> |