diff --git a/.changeset/stupid-suns-beg.md b/.changeset/stupid-suns-beg.md new file mode 100644 index 000000000000..ef398d2908f6 --- /dev/null +++ b/.changeset/stupid-suns-beg.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Update frontmatter assets to be relative to the current file instead of `src/assets` diff --git a/packages/astro/src/content/runtime-assets.ts b/packages/astro/src/content/runtime-assets.ts index f6448b10c69e..6aa0c71fd277 100644 --- a/packages/astro/src/content/runtime-assets.ts +++ b/packages/astro/src/content/runtime-assets.ts @@ -1,3 +1,4 @@ +import { pathToFileURL } from 'url'; import { z } from 'zod'; import { imageMetadata, type Metadata } from '../assets/utils/metadata.js'; @@ -7,9 +8,8 @@ export function createImage(options: { assetsDir: string; relAssetsDir: string } throw new Error('Enable `experimental.assets` in your Astro config to use image()'); } - return z.string().transform(async (imagePath) => { - const fullPath = new URL(imagePath, options.assetsDir); - return await getImageMetadata(fullPath); + return z.string({ description: '__image' }).transform(async (imagePath) => { + return await getImageMetadata(pathToFileURL(imagePath)); }); }; } diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index e162ff735fe9..d2ba5207e8bb 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -3,8 +3,8 @@ import matter from 'gray-matter'; import fsMod from 'node:fs'; import path from 'node:path'; import { fileURLToPath, pathToFileURL } from 'node:url'; -import type { EmitFile } from 'rollup'; -import { normalizePath, type ErrorPayload as ViteErrorPayload, type ViteDevServer } from 'vite'; +import type { EmitFile, PluginContext } from 'rollup'; +import { normalizePath, type ViteDevServer, type ErrorPayload as ViteErrorPayload } from 'vite'; import { z } from 'zod'; import type { AstroConfig, AstroSettings } from '../@types/astro.js'; import { emitESMImage } from '../assets/utils/emitAsset.js'; @@ -88,7 +88,8 @@ export function getEntrySlug({ export async function getEntryData( entry: EntryInfo & { unvalidatedData: Record; _internal: EntryInternal }, - collectionConfig: CollectionConfig + collectionConfig: CollectionConfig, + resolver: (idToResolve: string) => ReturnType ) { // Remove reserved `slug` field before parsing data let { slug, ...data } = entry.unvalidatedData; @@ -117,6 +118,37 @@ export async function getEntryData( message: AstroErrorData.ContentSchemaContainsSlugError.message(entry.collection), }); } + + /** + * Resolve all the images referred to in the frontmatter from the file requesting them + */ + async function preprocessAssetPaths(object: Record) { + if (typeof object !== 'object' || object === null) return; + + for (let [schemaName, schema] of Object.entries(object)) { + if (schema._def.description === '__image') { + object[schemaName] = z.preprocess( + async (value: unknown) => { + if (!value || typeof value !== 'string') return value; + return (await resolver(value))?.id; + }, + schema, + { description: undefined } + ); + } else if ('shape' in schema) { + await preprocessAssetPaths(schema.shape); + } else if ('unwrap' in schema) { + const unwrapped = schema.unwrap().shape; + + if (unwrapped) { + await preprocessAssetPaths(unwrapped); + } + } + } + } + + await preprocessAssetPaths(collectionConfig.schema.shape); + // Use `safeParseAsync` to allow async transforms const parsed = await collectionConfig.schema.safeParseAsync(entry.unvalidatedData, { errorMap, diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts index cc1d3856595b..6790a9b95464 100644 --- a/packages/astro/src/content/vite-plugin-content-imports.ts +++ b/packages/astro/src/content/vite-plugin-content-imports.ts @@ -10,6 +10,7 @@ import { AstroError } from '../core/errors/errors.js'; import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index.js'; import { CONTENT_FLAG } from './consts.js'; import { + NoCollectionError, getContentEntryExts, getContentPaths, getEntryData, @@ -17,7 +18,6 @@ import { getEntrySlug, getEntryType, globalContentConfigObserver, - NoCollectionError, patchAssets, type ContentConfig, } from './utils.js'; @@ -232,7 +232,11 @@ export const _internal = { const collectionConfig = contentConfig?.collections[collection]; let data = collectionConfig - ? await getEntryData({ id, collection, slug, _internal, unvalidatedData }, collectionConfig) + ? await getEntryData( + { id, collection, slug, _internal, unvalidatedData }, + collectionConfig, + (idToResolve: string) => pluginContext.resolve(idToResolve, fileId) + ) : unvalidatedData; await patchAssets(data, pluginContext.meta.watchMode, pluginContext.emitFile, settings); diff --git a/packages/astro/test/fixtures/core-image-ssg/src/content/blog/one.md b/packages/astro/test/fixtures/core-image-ssg/src/content/blog/one.md index 88a210b75504..59a5b77baf03 100644 --- a/packages/astro/test/fixtures/core-image-ssg/src/content/blog/one.md +++ b/packages/astro/test/fixtures/core-image-ssg/src/content/blog/one.md @@ -1,8 +1,8 @@ --- title: One -image: penguin2.jpg +image: ~/assets/penguin2.jpg cover: - image: penguin1.jpg + image: ../../assets/penguin1.jpg --- # A post diff --git a/packages/astro/test/fixtures/core-image/src/content/blog/one.md b/packages/astro/test/fixtures/core-image/src/content/blog/one.md index 88a210b75504..59a5b77baf03 100644 --- a/packages/astro/test/fixtures/core-image/src/content/blog/one.md +++ b/packages/astro/test/fixtures/core-image/src/content/blog/one.md @@ -1,8 +1,8 @@ --- title: One -image: penguin2.jpg +image: ~/assets/penguin2.jpg cover: - image: penguin1.jpg + image: ../../assets/penguin1.jpg --- # A post