feat(assets): Add support for passing non-awaited imports to the Image component and getImage (#8066)

* feat(assets): Add support for passing non-awaited imports to the Image component and `getImage`

* test: add test
This commit is contained in:
Erika 2023-08-14 15:29:42 +02:00 committed by GitHub
parent c5b60fadb8
commit afc45af202
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 53 additions and 7 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Add support for non-awaited imports to the Image component and `getImage`

View file

@ -48,7 +48,9 @@ declare module 'astro:assets' {
* This is functionally equivalent to using the `<Image />` component, as the component calls this function internally. * This is functionally equivalent to using the `<Image />` component, as the component calls this function internally.
*/ */
getImage: ( getImage: (
options: import('./dist/assets/types.js').ImageTransform options:
| import('./dist/assets/types.js').ImageTransform
| import('./dist/assets/types.js').UnresolvedImageTransform
) => Promise<import('./dist/assets/types.js').GetImageResult>; ) => Promise<import('./dist/assets/types.js').GetImageResult>;
getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService; getConfiguredImageService: typeof import('./dist/assets/index.js').getConfiguredImageService;
Image: typeof import('./components/Image.astro').default; Image: typeof import('./components/Image.astro').default;

View file

@ -1,7 +1,12 @@
import type { AstroSettings } from '../@types/astro.js'; import type { AstroSettings } from '../@types/astro.js';
import { AstroError, AstroErrorData } from '../core/errors/index.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js';
import { isLocalService, type ImageService } from './services/service.js'; import { isLocalService, type ImageService } from './services/service.js';
import type { GetImageResult, ImageMetadata, ImageTransform } from './types.js'; import type {
GetImageResult,
ImageMetadata,
ImageTransform,
UnresolvedImageTransform,
} from './types.js';
export function injectImageEndpoint(settings: AstroSettings) { export function injectImageEndpoint(settings: AstroSettings) {
settings.injectedRoutes.push({ settings.injectedRoutes.push({
@ -37,7 +42,7 @@ export async function getConfiguredImageService(): Promise<ImageService> {
} }
export async function getImage( export async function getImage(
options: ImageTransform, options: ImageTransform | UnresolvedImageTransform,
serviceConfig: Record<string, any> serviceConfig: Record<string, any>
): Promise<GetImageResult> { ): Promise<GetImageResult> {
if (!options || typeof options !== 'object') { if (!options || typeof options !== 'object') {
@ -48,9 +53,19 @@ export async function getImage(
} }
const service = await getConfiguredImageService(); const service = await getConfiguredImageService();
// If the user inlined an import, something fairly common especially in MDX, await it for them
const resolvedOptions: ImageTransform = {
...options,
src:
typeof options.src === 'object' && 'then' in options.src
? (await options.src).default
: options.src,
};
const validatedOptions = service.validateOptions const validatedOptions = service.validateOptions
? await service.validateOptions(options, serviceConfig) ? await service.validateOptions(resolvedOptions, serviceConfig)
: options; : resolvedOptions;
let imageURL = await service.getURL(validatedOptions, serviceConfig); let imageURL = await service.getURL(validatedOptions, serviceConfig);
@ -60,7 +75,7 @@ export async function getImage(
} }
return { return {
rawOptions: options, rawOptions: resolvedOptions,
options: validatedOptions, options: validatedOptions,
src: imageURL, src: imageURL,
attributes: attributes:

View file

@ -27,6 +27,10 @@ export interface ImageMetadata {
orientation?: number; orientation?: number;
} }
export type UnresolvedImageTransform = Omit<ImageTransform, 'src'> & {
src: Promise<{ default: ImageMetadata }>;
};
/** /**
* Options accepted by the image transformation service. * Options accepted by the image transformation service.
*/ */
@ -93,7 +97,7 @@ export type LocalImageProps<T> = ImageSharedProps<T> & {
* <Image src={myImage} alt="..."></Image> * <Image src={myImage} alt="..."></Image>
* ``` * ```
*/ */
src: ImageMetadata; src: ImageMetadata | Promise<{ default: ImageMetadata }>;
/** /**
* Desired output format for the image. Defaults to `webp`. * Desired output format for the image. Defaults to `webp`.
* *

View file

@ -147,6 +147,19 @@ describe('astro:image', () => {
}) })
).to.be.true; ).to.be.true;
}); });
it('supports inlined imports', async () => {
let res = await fixture.fetch('/inlineImport');
let html = await res.text();
$ = cheerio.load(html);
let $img = $('img');
expect($img).to.have.a.lengthOf(1);
let src = $img.attr('src');
res = await fixture.fetch(src);
expect(res.status).to.equal(200);
});
}); });
describe('vite-isms', () => { describe('vite-isms', () => {

View file

@ -0,0 +1,7 @@
---
import { getImage } from "astro:assets";
const optimizedImage = await getImage({src: import('../assets/penguin1.jpg')})
---
<img src={optimizedImage.src} {...optimizedImage.attributes} />