From 6387d3da2866425df17b4c92c3625251f6228d5f Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Thu, 9 Mar 2023 15:08:05 +0100 Subject: [PATCH 1/4] fix(images): Fix not being able to refer to images in content collections --- packages/astro/src/content/internal.ts | 10 +++--- .../src/content/template/virtual-mod.mjs | 2 ++ packages/astro/src/content/utils.ts | 24 +++++++------ .../content/vite-plugin-content-imports.ts | 14 +++----- .../vite-plugin-content-virtual-mod.ts | 8 +++++ packages/astro/test/core-image.test.js | 35 +++++++++++++++++-- .../core-image-ssg/src/content/blog/one.md | 8 +++++ .../core-image-ssg/src/content/config.ts | 12 +++++++ .../src/pages/blog/[...slug].astro | 27 ++++++++++++++ .../core-image/src/pages/blog/[...slug].astro | 14 ++++++-- 10 files changed, 125 insertions(+), 29 deletions(-) create mode 100644 packages/astro/test/fixtures/core-image-ssg/src/content/blog/one.md create mode 100644 packages/astro/test/fixtures/core-image-ssg/src/content/config.ts create mode 100644 packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro diff --git a/packages/astro/src/content/internal.ts b/packages/astro/src/content/internal.ts index 2fdfe74545ab..74e14780d0c4 100644 --- a/packages/astro/src/content/internal.ts +++ b/packages/astro/src/content/internal.ts @@ -1,3 +1,4 @@ +import path from 'path'; import { z } from 'zod'; import { imageMetadata, type Metadata } from '../assets/utils/metadata.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; @@ -191,7 +192,7 @@ async function render({ }; } -export function createImage(options: { assetsDir: string }) { +export function createImage(options: { assetsDir: string; relAssetsDir: string }) { return () => { if (options.assetsDir === 'undefined') { throw new Error('Enable `experimental.assets` in your Astro config to use image()'); @@ -199,13 +200,14 @@ export function createImage(options: { assetsDir: string }) { return z.string().transform(async (imagePath) => { const fullPath = new URL(imagePath, options.assetsDir); - return await getImageMetadata(fullPath); + return await getImageMetadata(fullPath, path.join(options.relAssetsDir, imagePath)); }); }; } async function getImageMetadata( - imagePath: URL + imagePath: URL, + rootRelativePath: string ): Promise<(Metadata & { __astro_asset: true }) | undefined> { const meta = await imageMetadata(imagePath); @@ -214,5 +216,5 @@ async function getImageMetadata( } delete meta.orientation; - return { ...meta, __astro_asset: true }; + return { ...meta, src: rootRelativePath, __astro_asset: true }; } diff --git a/packages/astro/src/content/template/virtual-mod.mjs b/packages/astro/src/content/template/virtual-mod.mjs index 5ce29dcf8fcc..9293ae8be7c4 100644 --- a/packages/astro/src/content/template/virtual-mod.mjs +++ b/packages/astro/src/content/template/virtual-mod.mjs @@ -14,6 +14,7 @@ export function defineCollection(config) { const contentDir = '@@CONTENT_DIR@@'; const assetsDir = '@@ASSETS_DIR@@'; +const relAssetsDir = '@@REL_ASSETS_DIR'; const entryGlob = import.meta.glob('@@ENTRY_GLOB_PATH@@', { query: { astroContent: true }, @@ -43,4 +44,5 @@ export const getEntryBySlug = createGetEntryBySlug({ export const image = createImage({ assetsDir, + relAssetsDir, }); diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index 011ade19f89f..3ff76bf35f75 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -6,7 +6,6 @@ import { fileURLToPath, pathToFileURL } from 'node:url'; import { ErrorPayload as ViteErrorPayload, normalizePath, ViteDevServer } from 'vite'; import { z } from 'zod'; import { AstroConfig, AstroSettings } from '../@types/astro.js'; -import type { ImageMetadata } from '../assets/types.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; import { CONTENT_TYPES_FILE } from './consts.js'; @@ -43,21 +42,24 @@ export const msg = { `${collection} does not have a config. We suggest adding one for type safety!`, }; -export function extractFrontmatterAssets(data: Record): string[] { - function findAssets(potentialAssets: Record): ImageMetadata[] { - return Object.values(potentialAssets).reduce((acc, curr) => { - if (typeof curr === 'object') { - if (curr.__astro === true) { - acc.push(curr); +export function patchFrontmatterAssets(data: Record): Record { + function patchAsset(potentialAssets: Record): Record { + Object.keys(potentialAssets).forEach((entry) => { + if (typeof potentialAssets[entry] === 'object' && potentialAssets[entry] !== null) { + if (potentialAssets[entry].__astro_asset) { + potentialAssets[ + entry + ] = `$$ASSET_(await import('${potentialAssets[entry].src}')).default_ASSET$$`; } else { - acc.push(...findAssets(curr)); + patchAsset(potentialAssets[entry]); } } - return acc; - }, []); + }); + + return potentialAssets; } - return findAssets(data).map((asset) => asset.src); + return patchAsset(data); } export function getEntrySlug({ diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts index 7c335e112956..14e6d1ed8fae 100644 --- a/packages/astro/src/content/vite-plugin-content-imports.ts +++ b/packages/astro/src/content/vite-plugin-content-imports.ts @@ -3,7 +3,6 @@ import type fsMod from 'node:fs'; import { extname } from 'node:path'; import { pathToFileURL } from 'url'; import type { Plugin } from 'vite'; -import { normalizePath } from 'vite'; import { AstroSettings, ContentEntryType } from '../@types/astro.js'; import { AstroErrorData } from '../core/errors/errors-data.js'; import { AstroError } from '../core/errors/errors.js'; @@ -11,7 +10,6 @@ import { escapeViteEnvReferences, getFileInfo } from '../vite-plugin-utils/index import { CONTENT_FLAG } from './consts.js'; import { ContentConfig, - extractFrontmatterAssets, getContentEntryExts, getContentPaths, getEntryData, @@ -19,6 +17,7 @@ import { getEntrySlug, getEntryType, globalContentConfigObserver, + patchFrontmatterAssets, } from './utils.js'; function isContentFlagImport(viteId: string, contentEntryExts: string[]) { @@ -106,26 +105,21 @@ export function astroContentImportPlugin({ const slug = getEntrySlug({ ...generatedInfo, unvalidatedSlug: info.slug }); const collectionConfig = contentConfig?.collections[generatedInfo.collection]; - const data = collectionConfig + let data = collectionConfig ? await getEntryData( { ...generatedInfo, _internal, unvalidatedData: info.data }, collectionConfig ) : info.data; - const images = extractFrontmatterAssets(data).map( - (image) => `'${image}': await import('${normalizePath(image)}'),` - ); + data = patchFrontmatterAssets(data); const code = escapeViteEnvReferences(` export const id = ${JSON.stringify(generatedInfo.id)}; export const collection = ${JSON.stringify(generatedInfo.collection)}; export const slug = ${JSON.stringify(slug)}; export const body = ${JSON.stringify(info.body)}; -const frontmatterImages = { - ${images.join('\n')} -} -export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */}; +export const data = ${devalue.uneval(data).replaceAll(/("\$\$ASSET_)(.+)(_ASSET\$\$")/gm, '$2')}; export const _internal = { filePath: ${JSON.stringify(_internal.filePath)}, rawData: ${JSON.stringify(_internal.rawData)}, diff --git a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts index 99b6e3f3c036..af7d667d23a6 100644 --- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts +++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts @@ -22,6 +22,13 @@ export function astroContentVirtualModPlugin({ ) ) ); + const relAssetsDir = normalizePath( + appendForwardSlash( + prependForwardSlash( + path.relative(settings.config.root.pathname, contentPaths.assetsDir.pathname) + ) + ) + ); const contentEntryExts = getContentEntryExts(settings); const assetsDir = settings.config.experimental.assets @@ -37,6 +44,7 @@ export function astroContentVirtualModPlugin({ .readFileSync(contentPaths.virtualModTemplate, 'utf-8') .replace('@@CONTENT_DIR@@', relContentDir) .replace('@@ASSETS_DIR@@', assetsDir) + .replace('@@REL_ASSETS_DIR', relAssetsDir) .replace('@@ENTRY_GLOB_PATH@@', entryGlob) .replace('@@RENDER_ENTRY_GLOB_PATH@@', entryGlob); diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index 81a793ffc1f2..f54c02933cd6 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -213,10 +213,29 @@ describe('astro:image', () => { $ = cheerio.load(html); }); - it('Adds the tag', () => { + it('Adds the tags', () => { let $img = $('img'); - expect($img).to.have.a.lengthOf(1); + expect($img).to.have.a.lengthOf(3); + }); + + it('has proper source for directly used image', () => { + let $img = $('#direct-image img'); + expect($img.attr('src').startsWith('/src/')).to.equal(true); + }); + + it('has proper attributes for optimized image through getImage', () => { + let $img = $('#optimized-image-get-image img'); expect($img.attr('src').startsWith('/_image')).to.equal(true); + expect($img.attr('width')).to.equal('207'); + expect($img.attr('height')).to.equal('243'); + }); + + it('has proper attributes for optimized image through Image component', () => { + let $img = $('#optimized-image-component img'); + expect($img.attr('src').startsWith('/_image')).to.equal(true); + expect($img.attr('width')).to.equal('207'); + expect($img.attr('height')).to.equal('243'); + expect($img.attr('alt')).to.equal('A penguin!'); }); }); @@ -306,6 +325,18 @@ describe('astro:image', () => { expect(data).to.be.an.instanceOf(Buffer); }); + it('output files for content collections images', async () => { + const html = await fixture.readFile('/blog/one/index.html'); + + const $ = cheerio.load(html); + let $img = $('img'); + expect($img).to.have.a.lengthOf(1); + + const src = $img.attr('src'); + const data = await fixture.readFile(src, null); + expect(data).to.be.an.instanceOf(Buffer); + }); + it('quality attribute produces a different file', async () => { const html = await fixture.readFile('/quality/index.html'); const $ = cheerio.load(html); 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 new file mode 100644 index 000000000000..00e43a6a214d --- /dev/null +++ b/packages/astro/test/fixtures/core-image-ssg/src/content/blog/one.md @@ -0,0 +1,8 @@ +--- +title: One +image: penguin2.jpg +--- + +# A post + +text here diff --git a/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts b/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts new file mode 100644 index 000000000000..bd101a4aa383 --- /dev/null +++ b/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts @@ -0,0 +1,12 @@ +import { image, defineCollection, z } from "astro:content"; + +const blogCollection = defineCollection({ + schema: z.object({ + title: z.string(), + image: image(), + }), +}); + +export const collections = { + blog: blogCollection +}; diff --git a/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro b/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro new file mode 100644 index 000000000000..f8191e2b8965 --- /dev/null +++ b/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro @@ -0,0 +1,27 @@ +--- +import { getImage } from 'astro:assets'; +import { getCollection } from 'astro:content'; + +export async function getStaticPaths() { + const blogEntries = await getCollection('blog'); + return blogEntries.map(entry => ({ + params: { slug: entry.slug }, props: { entry }, + })); +} + +const { entry } = Astro.props; +const { Content } = await entry.render(); +const myImage = await getImage(entry.data.image); +--- + + + Testing + + +

Testing

+ + + + + + diff --git a/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro b/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro index 4f6e5003c114..94fbbd6cd7e7 100644 --- a/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro +++ b/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro @@ -1,6 +1,6 @@ --- +import { getImage,Image } from 'astro:assets'; import { getCollection } from 'astro:content'; -import { getImage } from 'astro:assets'; export async function getStaticPaths() { const blogEntries = await getCollection('blog'); @@ -20,7 +20,17 @@ const myImage = await getImage(entry.data.image);

Testing

- +
+ +
+ +
+ +
+ +
+ A penguin! +
From fc0c5b03e3e6a7ec447a03e8a7e0f2ac556d282a Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Thu, 9 Mar 2023 15:37:35 +0100 Subject: [PATCH 2/4] fix(images): Normalize path --- packages/astro/src/content/utils.ts | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index 3ff76bf35f75..93e6bbc4030a 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -47,9 +47,9 @@ export function patchFrontmatterAssets(data: Record): Record { if (typeof potentialAssets[entry] === 'object' && potentialAssets[entry] !== null) { if (potentialAssets[entry].__astro_asset) { - potentialAssets[ - entry - ] = `$$ASSET_(await import('${potentialAssets[entry].src}')).default_ASSET$$`; + potentialAssets[entry] = `$$ASSET_(await import('${normalizePath( + potentialAssets[entry].src + )}')).default_ASSET$$`; } else { patchAsset(potentialAssets[entry]); } From 5e411f8fb8e52529f629b031a2a2805d104dce15 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Thu, 9 Mar 2023 18:05:17 +0100 Subject: [PATCH 3/4] fix(images): Do it properly --- packages/astro/src/assets/internal.ts | 42 +++++++++++++++++++ .../astro/src/assets/vite-plugin-assets.ts | 35 ++-------------- packages/astro/src/content/internal.ts | 8 ++-- .../src/content/template/virtual-mod.mjs | 2 - packages/astro/src/content/utils.ts | 39 ++++++++++------- .../content/vite-plugin-content-imports.ts | 7 ++-- .../vite-plugin-content-virtual-mod.ts | 8 ---- packages/astro/test/core-image.test.js | 19 ++++++--- .../core-image-ssg/src/content/blog/one.md | 2 + .../core-image-ssg/src/content/config.ts | 5 ++- .../src/pages/blog/[...slug].astro | 8 +++- .../core-image/src/content/blog/one.md | 2 + .../fixtures/core-image/src/content/config.ts | 5 ++- .../core-image/src/pages/blog/[...slug].astro | 4 ++ 14 files changed, 111 insertions(+), 75 deletions(-) diff --git a/packages/astro/src/assets/internal.ts b/packages/astro/src/assets/internal.ts index aa69f7183260..0202e2359ddc 100644 --- a/packages/astro/src/assets/internal.ts +++ b/packages/astro/src/assets/internal.ts @@ -1,8 +1,13 @@ import fs from 'node:fs'; +import path from 'node:path'; +import { pathToFileURL } from 'node:url'; +import { AstroSettings } from '../@types/astro.js'; import { StaticBuildOptions } from '../core/build/types.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; +import { rootRelativePath } from '../core/util.js'; import { ImageService, isLocalService, LocalImageService } from './services/service.js'; import type { ImageMetadata, ImageTransform } from './types.js'; +import { imageMetadata } from './utils/metadata.js'; export function isESMImportedImage(src: ImageMetadata | string): src is ImageMetadata { return typeof src === 'object'; @@ -115,3 +120,40 @@ export async function generateImage( }, }; } + +export async function emitESMImage( + id: string, + watchMode: boolean, + fileEmitter: any, + settings: AstroSettings +) { + const url = pathToFileURL(id); + const meta = await imageMetadata(url); + + if (!meta) { + return; + } + + // Build + if (!watchMode) { + const pathname = decodeURI(url.pathname); + const filename = path.basename(pathname, path.extname(pathname) + `.${meta.format}`); + + const handle = fileEmitter({ + name: filename, + source: await fs.promises.readFile(url), + type: 'asset', + }); + + meta.src = `__ASTRO_ASSET_IMAGE__${handle}__`; + } else { + // Pass the original file information through query params so we don't have to load the file twice + url.searchParams.append('origWidth', meta.width.toString()); + url.searchParams.append('origHeight', meta.height.toString()); + url.searchParams.append('origFormat', meta.format); + + meta.src = rootRelativePath(settings.config, url); + } + + return meta; +} diff --git a/packages/astro/src/assets/vite-plugin-assets.ts b/packages/astro/src/assets/vite-plugin-assets.ts index 1e84b2271803..9af9c6073b36 100644 --- a/packages/astro/src/assets/vite-plugin-assets.ts +++ b/packages/astro/src/assets/vite-plugin-assets.ts @@ -1,17 +1,15 @@ import MagicString from 'magic-string'; import mime from 'mime'; import fs from 'node:fs/promises'; -import path from 'node:path'; import { Readable } from 'node:stream'; -import { fileURLToPath, pathToFileURL } from 'node:url'; +import { fileURLToPath } from 'node:url'; import type * as vite from 'vite'; import { normalizePath } from 'vite'; import { AstroPluginOptions, ImageTransform } from '../@types/astro'; import { error } from '../core/logger/core.js'; import { joinPaths, prependForwardSlash } from '../core/path.js'; -import { rootRelativePath } from '../core/util.js'; import { VIRTUAL_MODULE_ID, VIRTUAL_SERVICE_ID } from './consts.js'; -import { isESMImportedImage } from './internal.js'; +import { emitESMImage, isESMImportedImage } from './internal.js'; import { isLocalService } from './services/service.js'; import { copyWasmFiles } from './services/vendor/squoosh/copy-wasm.js'; import { imageMetadata } from './utils/metadata.js'; @@ -202,34 +200,7 @@ export default function assets({ }, async load(id) { if (/\.(jpeg|jpg|png|tiff|webp|gif|svg)$/.test(id)) { - const url = pathToFileURL(id); - const meta = await imageMetadata(url); - - if (!meta) { - return; - } - - // Build - if (!this.meta.watchMode) { - const pathname = decodeURI(url.pathname); - const filename = path.basename(pathname, path.extname(pathname) + `.${meta.format}`); - - const handle = this.emitFile({ - name: filename, - source: await fs.readFile(url), - type: 'asset', - }); - - meta.src = `__ASTRO_ASSET_IMAGE__${handle}__`; - } else { - // Pass the original file information through query params so we don't have to load the file twice - url.searchParams.append('origWidth', meta.width.toString()); - url.searchParams.append('origHeight', meta.height.toString()); - url.searchParams.append('origFormat', meta.format); - - meta.src = rootRelativePath(settings.config, url); - } - + const meta = await emitESMImage(id, this.meta.watchMode, this.emitFile, settings); return `export default ${JSON.stringify(meta)}`; } }, diff --git a/packages/astro/src/content/internal.ts b/packages/astro/src/content/internal.ts index 74e14780d0c4..bdc99bbc7414 100644 --- a/packages/astro/src/content/internal.ts +++ b/packages/astro/src/content/internal.ts @@ -1,4 +1,3 @@ -import path from 'path'; import { z } from 'zod'; import { imageMetadata, type Metadata } from '../assets/utils/metadata.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; @@ -200,14 +199,13 @@ export function createImage(options: { assetsDir: string; relAssetsDir: string } return z.string().transform(async (imagePath) => { const fullPath = new URL(imagePath, options.assetsDir); - return await getImageMetadata(fullPath, path.join(options.relAssetsDir, imagePath)); + return await getImageMetadata(fullPath); }); }; } async function getImageMetadata( - imagePath: URL, - rootRelativePath: string + imagePath: URL ): Promise<(Metadata & { __astro_asset: true }) | undefined> { const meta = await imageMetadata(imagePath); @@ -216,5 +214,5 @@ async function getImageMetadata( } delete meta.orientation; - return { ...meta, src: rootRelativePath, __astro_asset: true }; + return { ...meta, __astro_asset: true }; } diff --git a/packages/astro/src/content/template/virtual-mod.mjs b/packages/astro/src/content/template/virtual-mod.mjs index 9293ae8be7c4..5ce29dcf8fcc 100644 --- a/packages/astro/src/content/template/virtual-mod.mjs +++ b/packages/astro/src/content/template/virtual-mod.mjs @@ -14,7 +14,6 @@ export function defineCollection(config) { const contentDir = '@@CONTENT_DIR@@'; const assetsDir = '@@ASSETS_DIR@@'; -const relAssetsDir = '@@REL_ASSETS_DIR'; const entryGlob = import.meta.glob('@@ENTRY_GLOB_PATH@@', { query: { astroContent: true }, @@ -44,5 +43,4 @@ export const getEntryBySlug = createGetEntryBySlug({ export const image = createImage({ assetsDir, - relAssetsDir, }); diff --git a/packages/astro/src/content/utils.ts b/packages/astro/src/content/utils.ts index 93e6bbc4030a..22b71e0afe6d 100644 --- a/packages/astro/src/content/utils.ts +++ b/packages/astro/src/content/utils.ts @@ -3,9 +3,11 @@ 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 { ErrorPayload as ViteErrorPayload, normalizePath, ViteDevServer } from 'vite'; import { z } from 'zod'; import { AstroConfig, AstroSettings } from '../@types/astro.js'; +import { emitESMImage } from '../assets/internal.js'; import { AstroError, AstroErrorData } from '../core/errors/index.js'; import { CONTENT_TYPES_FILE } from './consts.js'; @@ -42,24 +44,29 @@ export const msg = { `${collection} does not have a config. We suggest adding one for type safety!`, }; -export function patchFrontmatterAssets(data: Record): Record { - function patchAsset(potentialAssets: Record): Record { - Object.keys(potentialAssets).forEach((entry) => { - if (typeof potentialAssets[entry] === 'object' && potentialAssets[entry] !== null) { - if (potentialAssets[entry].__astro_asset) { - potentialAssets[entry] = `$$ASSET_(await import('${normalizePath( - potentialAssets[entry].src - )}')).default_ASSET$$`; - } else { - patchAsset(potentialAssets[entry]); - } +/** + * Mutate (arf) the entryData to reroute assets to their final paths + */ +export async function patchAssets( + frontmatterEntry: Record, + watchMode: boolean, + fileEmitter: EmitFile, + astroSettings: AstroSettings +) { + for (const key of Object.keys(frontmatterEntry)) { + if (typeof frontmatterEntry[key] === 'object' && frontmatterEntry[key] !== null) { + if (frontmatterEntry[key]['__astro_asset']) { + frontmatterEntry[key] = await emitESMImage( + frontmatterEntry[key].src, + watchMode, + fileEmitter, + astroSettings + ); + } else { + await patchAssets(frontmatterEntry[key], watchMode, fileEmitter, astroSettings); } - }); - - return potentialAssets; + } } - - return patchAsset(data); } export function getEntrySlug({ diff --git a/packages/astro/src/content/vite-plugin-content-imports.ts b/packages/astro/src/content/vite-plugin-content-imports.ts index 14e6d1ed8fae..a81d1febaa76 100644 --- a/packages/astro/src/content/vite-plugin-content-imports.ts +++ b/packages/astro/src/content/vite-plugin-content-imports.ts @@ -17,9 +17,8 @@ import { getEntrySlug, getEntryType, globalContentConfigObserver, - patchFrontmatterAssets, + patchAssets, } from './utils.js'; - function isContentFlagImport(viteId: string, contentEntryExts: string[]) { const { searchParams, pathname } = new URL(viteId, 'file://'); return searchParams.has(CONTENT_FLAG) && contentEntryExts.some((ext) => pathname.endsWith(ext)); @@ -112,14 +111,14 @@ export function astroContentImportPlugin({ ) : info.data; - data = patchFrontmatterAssets(data); + await patchAssets(data, this.meta.watchMode, this.emitFile, settings); const code = escapeViteEnvReferences(` export const id = ${JSON.stringify(generatedInfo.id)}; export const collection = ${JSON.stringify(generatedInfo.collection)}; export const slug = ${JSON.stringify(slug)}; export const body = ${JSON.stringify(info.body)}; -export const data = ${devalue.uneval(data).replaceAll(/("\$\$ASSET_)(.+)(_ASSET\$\$")/gm, '$2')}; +export const data = ${devalue.uneval(data) /* TODO: reuse astro props serializer */}; export const _internal = { filePath: ${JSON.stringify(_internal.filePath)}, rawData: ${JSON.stringify(_internal.rawData)}, diff --git a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts index af7d667d23a6..99b6e3f3c036 100644 --- a/packages/astro/src/content/vite-plugin-content-virtual-mod.ts +++ b/packages/astro/src/content/vite-plugin-content-virtual-mod.ts @@ -22,13 +22,6 @@ export function astroContentVirtualModPlugin({ ) ) ); - const relAssetsDir = normalizePath( - appendForwardSlash( - prependForwardSlash( - path.relative(settings.config.root.pathname, contentPaths.assetsDir.pathname) - ) - ) - ); const contentEntryExts = getContentEntryExts(settings); const assetsDir = settings.config.experimental.assets @@ -44,7 +37,6 @@ export function astroContentVirtualModPlugin({ .readFileSync(contentPaths.virtualModTemplate, 'utf-8') .replace('@@CONTENT_DIR@@', relContentDir) .replace('@@ASSETS_DIR@@', assetsDir) - .replace('@@REL_ASSETS_DIR', relAssetsDir) .replace('@@ENTRY_GLOB_PATH@@', entryGlob) .replace('@@RENDER_ENTRY_GLOB_PATH@@', entryGlob); diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index f54c02933cd6..e0af4f1aab97 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -215,7 +215,7 @@ describe('astro:image', () => { it('Adds the tags', () => { let $img = $('img'); - expect($img).to.have.a.lengthOf(3); + expect($img).to.have.a.lengthOf(4); }); it('has proper source for directly used image', () => { @@ -237,6 +237,11 @@ describe('astro:image', () => { expect($img.attr('height')).to.equal('243'); expect($img.attr('alt')).to.equal('A penguin!'); }); + + it('properly handles nested images', () => { + let $img = $('#nested-image img'); + expect($img.attr('src').startsWith('/src/')).to.equal(true); + }); }); describe('regular img tag', () => { @@ -330,11 +335,15 @@ describe('astro:image', () => { const $ = cheerio.load(html); let $img = $('img'); - expect($img).to.have.a.lengthOf(1); + expect($img).to.have.a.lengthOf(2); - const src = $img.attr('src'); - const data = await fixture.readFile(src, null); - expect(data).to.be.an.instanceOf(Buffer); + const srcdirect = $('#direct-image img').attr('src'); + const datadirect = await fixture.readFile(srcdirect, null); + expect(datadirect).to.be.an.instanceOf(Buffer); + + const srcnested = $('#nested-image img').attr('src'); + const datanested = await fixture.readFile(srcnested, null); + expect(datanested).to.be.an.instanceOf(Buffer); }); it('quality attribute produces a different file', async () => { 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 00e43a6a214d..88a210b75504 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,6 +1,8 @@ --- title: One image: penguin2.jpg +cover: + image: penguin1.jpg --- # A post diff --git a/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts b/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts index bd101a4aa383..b38ad070e100 100644 --- a/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts +++ b/packages/astro/test/fixtures/core-image-ssg/src/content/config.ts @@ -1,9 +1,12 @@ -import { image, defineCollection, z } from "astro:content"; +import { defineCollection, image, z } from "astro:content"; const blogCollection = defineCollection({ schema: z.object({ title: z.string(), image: image(), + cover: z.object({ + image: image() + }) }), }); diff --git a/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro b/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro index f8191e2b8965..dc25493e854a 100644 --- a/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro +++ b/packages/astro/test/fixtures/core-image-ssg/src/pages/blog/[...slug].astro @@ -20,7 +20,13 @@ const myImage = await getImage(entry.data.image);

Testing

- +
+ +
+ +
+ +
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 00e43a6a214d..88a210b75504 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,6 +1,8 @@ --- title: One image: penguin2.jpg +cover: + image: penguin1.jpg --- # A post diff --git a/packages/astro/test/fixtures/core-image/src/content/config.ts b/packages/astro/test/fixtures/core-image/src/content/config.ts index bd101a4aa383..b38ad070e100 100644 --- a/packages/astro/test/fixtures/core-image/src/content/config.ts +++ b/packages/astro/test/fixtures/core-image/src/content/config.ts @@ -1,9 +1,12 @@ -import { image, defineCollection, z } from "astro:content"; +import { defineCollection, image, z } from "astro:content"; const blogCollection = defineCollection({ schema: z.object({ title: z.string(), image: image(), + cover: z.object({ + image: image() + }) }), }); diff --git a/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro b/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro index 94fbbd6cd7e7..b9667968835f 100644 --- a/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro +++ b/packages/astro/test/fixtures/core-image/src/pages/blog/[...slug].astro @@ -24,6 +24,10 @@ const myImage = await getImage(entry.data.image); +
+ +
+
From 10a7b5a6a101ddf7c0a720b4926233b502d4f458 Mon Sep 17 00:00:00 2001 From: Princesseuh Date: Thu, 9 Mar 2023 18:34:01 +0100 Subject: [PATCH 4/4] chore: changeset --- .changeset/five-coats-tie.md | 5 +++++ 1 file changed, 5 insertions(+) create mode 100644 .changeset/five-coats-tie.md diff --git a/.changeset/five-coats-tie.md b/.changeset/five-coats-tie.md new file mode 100644 index 000000000000..b358aa22c61b --- /dev/null +++ b/.changeset/five-coats-tie.md @@ -0,0 +1,5 @@ +--- +'astro': patch +--- + +Fix images defined in content collections schemas not working