feat: better errors for images (#8536)

This commit is contained in:
Erika 2023-09-13 16:44:15 +02:00 committed by GitHub
parent 3be8b67f89
commit b85c8a78a1
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
6 changed files with 43 additions and 21 deletions

View file

@ -0,0 +1,5 @@
---
'astro': patch
---
Improved error messages around `astro:assets`

View file

@ -77,12 +77,12 @@ export async function getImage(
const service = await getConfiguredImageService();
// If the user inlined an import, something fairly common especially in MDX, await it for them
// If the user inlined an import, something fairly common especially in MDX, or passed a function that returns an Image, await it for them
const resolvedOptions: ImageTransform = {
...options,
src:
typeof options.src === 'object' && 'then' in options.src
? (await options.src).default
? (await options.src).default ?? (await options.src)
: options.src,
};

View file

@ -1,6 +1,6 @@
import type { AstroConfig } from '../../@types/astro.js';
import { AstroError, AstroErrorData } from '../../core/errors/index.js';
import { joinPaths } from '../../core/path.js';
import { isRemotePath, joinPaths } from '../../core/path.js';
import { VALID_SUPPORTED_FORMATS } from '../consts.js';
import { isESMImportedImage, isRemoteAllowed } from '../internal.js';
import type { ImageOutputFormat, ImageTransform } from '../types.js';
@ -126,13 +126,20 @@ export const baseService: Omit<LocalImageService, 'transform'> = {
if (!options.src || (typeof options.src !== 'string' && typeof options.src !== 'object')) {
throw new AstroError({
...AstroErrorData.ExpectedImage,
message: AstroErrorData.ExpectedImage.message(JSON.stringify(options.src)),
message: AstroErrorData.ExpectedImage.message(
JSON.stringify(options.src),
typeof options.src,
JSON.stringify(options, (_, v) => (v === undefined ? null : v))
),
});
}
if (!isESMImportedImage(options.src)) {
// User passed an `/@fs/` path instead of the full image.
if (options.src.startsWith('/@fs/')) {
// User passed an `/@fs/` path or a filesystem path instead of the full image.
if (
options.src.startsWith('/@fs/') ||
(!isRemotePath(options.src) && !options.src.startsWith('/'))
) {
throw new AstroError({
...AstroErrorData.LocalImageUsedWrongly,
message: AstroErrorData.LocalImageUsedWrongly.message(options.src),

View file

@ -227,7 +227,7 @@ export function getDocsForError(err: ErrorWithMetadata): string | undefined {
* Render a subset of Markdown to HTML or a CLI output
*/
export function renderErrorMarkdown(markdown: string, target: 'html' | 'cli') {
const linkRegex = /\[(.+)\]\((.+)\)/gm;
const linkRegex = /\[([^\[]+)\]\((.*)\)/gm;
const boldRegex = /\*\*(.+)\*\*/gm;
const urlRegex = / (\b(https?|ftp):\/\/[-A-Z0-9+&@#\\/%?=~_|!:,.;]*[-A-Z0-9+&@#\\/%=~_|])/gim;
const codeRegex = /`([^`]+)`/gim;
@ -240,8 +240,8 @@ export function renderErrorMarkdown(markdown: string, target: 'html' | 'cli') {
.replace(codeRegex, '<code>$1</code>');
} else {
return markdown
.replace(linkRegex, (fullMatch, m1, m2) => `${bold(m1)} ${underline(m2)}`)
.replace(linkRegex, (_, m1, m2) => `${bold(m1)} ${underline(m2)}`)
.replace(urlRegex, (fullMatch) => ` ${underline(fullMatch.trim())}`)
.replace(boldRegex, (fullMatch, m1) => `${bold(m1)}`);
.replace(boldRegex, (_, m1) => `${bold(m1)}`);
}
}

View file

@ -594,9 +594,9 @@ export const PrerenderDynamicEndpointPathCollide = {
export const ExpectedImage = {
name: 'ExpectedImage',
title: 'Expected src to be an image.',
message: (options: string) =>
`Expected \`src\` property to be either an ESM imported image or a string with the path of a remote image. Received \`${options}\`.`,
hint: 'This error can often happen because of a wrong path. Make sure the path to your image is correct.',
message: (src: string, typeofOptions: string, fullOptions: string) =>
`Expected \`src\` property for \`getImage\` or \`<Image />\` to be either an ESM imported image or a string with the path of a remote image. Received \`${src}\` (type: \`${typeofOptions}\`).\n\nFull serialized options received: \`${fullOptions}\`.`,
hint: "This error can often happen because of a wrong path. Make sure the path to your image is correct. If you're passing an async function, make sure to call and await it.",
} satisfies ErrorData;
/**
* @docs
@ -712,12 +712,15 @@ export const LocalsNotAnObject = {
'`locals` can only be assigned to an object. Other values like numbers, strings, etc. are not accepted.',
hint: 'If you tried to remove some information from the `locals` object, try to use `delete` or set the property to `undefined`.',
} satisfies ErrorData;
/**
* @docs
* @see
* - [Images](https://docs.astro.build/en/guides/images/)
* @description
* When using the default image services, `Image`'s and `getImage`'s `src` parameter must be either an imported image or an URL, it cannot be a filepath.
* When using the default image services, `Image`'s and `getImage`'s `src` parameter must be either an imported image or an URL, it cannot be a string of a filepath.
*
* For local images from content collections, you can use the [image() schema helper](https://docs.astro.build/en/guides/images/#images-in-content-collections) to resolve the images.
*
* ```astro
* ---
@ -728,15 +731,22 @@ export const LocalsNotAnObject = {
* <!-- GOOD: `src` is the full imported image. -->
* <Image src={myImage} alt="Cool image" />
*
* <!-- BAD: `src` is an image's `src` path instead of the full image. -->
* <!-- GOOD: `src` is a URL. -->
* <Image src="https://example.com/my_image.png" alt="Cool image" />
*
* <!-- BAD: `src` is an image's `src` path instead of the full image object. -->
* <Image src={myImage.src} alt="Cool image" />
*
* <!-- BAD: `src` is a string filepath. -->
* <Image src="../my_image.png" alt="Cool image" />
* ```
*/
export const LocalImageUsedWrongly = {
name: 'LocalImageUsedWrongly',
title: 'ESM imported images must be passed as-is.',
title: 'Local images must be imported.',
message: (imageFilePath: string) =>
`\`Image\`'s and \`getImage\`'s \`src\` parameter must be an imported image or an URL, it cannot be a filepath. Received \`${imageFilePath}\`.`,
`\`Image\`'s and \`getImage\`'s \`src\` parameter must be an imported image or an URL, it cannot be a string filepath. Received \`${imageFilePath}\`.`,
hint: 'If you want to use an image from your `src` folder, you need to either import it or if the image is coming from a content collection, use the [image() schema helper](https://docs.astro.build/en/guides/images/#images-in-content-collections) See https://docs.astro.build/en/guides/images/#src-required for more information on the `src` property.',
} satisfies ErrorData;
/**

View file

@ -336,7 +336,7 @@ const style = /* css */ `
#message-content,
#hint-content {
white-space: pre-wrap;
line-height: 24px;
line-height: 26px;
flex-grow: 1;
}
@ -369,7 +369,7 @@ const style = /* css */ `
#message-hints code {
font-family: var(--font-monospace);
background-color: var(--border);
padding: 4px;
padding: 2px 4px;
border-radius: var(--roundiness);
white-space: nowrap;
}