diff --git a/.changeset/giant-spies-type.md b/.changeset/giant-spies-type.md new file mode 100644 index 000000000000..97018591a63f --- /dev/null +++ b/.changeset/giant-spies-type.md @@ -0,0 +1,6 @@ +--- +"@astrojs/markdoc": patch +"astro": patch +--- + +Fixes original images sometimes being kept / deleted when they shouldn't in both MDX and Markdoc diff --git a/packages/astro/package.json b/packages/astro/package.json index 731033eeb384..36a0483cf54e 100644 --- a/packages/astro/package.json +++ b/packages/astro/package.json @@ -108,6 +108,7 @@ "dev": "astro-scripts dev --copy-wasm --prebuild \"src/runtime/server/astro-island.ts\" --prebuild \"src/runtime/client/{idle,load,media,only,visible}.ts\" \"src/**/*.{ts,js}\"", "postbuild": "astro-scripts copy \"src/**/*.astro\" && astro-scripts copy \"src/**/*.wasm\"", "test": "pnpm run test:node", + "test:match": "pnpm run test:node --match", "test:e2e": "playwright test", "test:e2e:match": "playwright test -g", "test:node": "astro-scripts test \"test/**/*.test.js\"" diff --git a/packages/astro/src/assets/build/generate.ts b/packages/astro/src/assets/build/generate.ts index 1c73c1592cd8..496dc1e6e4a7 100644 --- a/packages/astro/src/assets/build/generate.ts +++ b/packages/astro/src/assets/build/generate.ts @@ -119,7 +119,13 @@ export async function generateImagesForPath( !globalThis.astroAsset.referencedImages?.has(transformsAndPath.originalSrcPath) ) { try { - await fs.promises.unlink(getFullImagePath(originalFilePath, env)); + if (transformsAndPath.originalSrcPath) { + env.logger.debug( + 'assets', + `Deleting ${originalFilePath} as it's not referenced outside of image processing.` + ); + await fs.promises.unlink(getFullImagePath(originalFilePath, env)); + } } catch (e) { /* No-op, it's okay if we fail to delete one of the file, we're not too picky. */ } diff --git a/packages/astro/src/assets/utils/proxy.ts b/packages/astro/src/assets/utils/proxy.ts index 2b4389e4d142..e5c7ce7a094d 100644 --- a/packages/astro/src/assets/utils/proxy.ts +++ b/packages/astro/src/assets/utils/proxy.ts @@ -11,7 +11,11 @@ export function getProxyCode(options: ImageMetadata, isSSR: boolean): string { if (name === 'fsPath') { return ${stringifiedFSPath}; } - ${!isSSR ? `globalThis.astroAsset.referencedImages.add(${stringifiedFSPath});` : ''} + ${ + !isSSR + ? `if (target[name] !== undefined) globalThis.astroAsset.referencedImages.add(${stringifiedFSPath});` + : '' + } return target[name]; } }) diff --git a/packages/astro/src/core/logger/core.ts b/packages/astro/src/core/logger/core.ts index 3f9c9f4177b5..45ab41ec92ce 100644 --- a/packages/astro/src/core/logger/core.ts +++ b/packages/astro/src/core/logger/core.ts @@ -28,6 +28,7 @@ export type LoggerLabel = | 'preferences' | 'redirects' | 'toolbar' + | 'assets' // SKIP_FORMAT: A special label that tells the logger not to apply any formatting. // Useful for messages that are already formatted, like the server start message. | 'SKIP_FORMAT'; diff --git a/packages/astro/test/fixtures/core-image-deletion/astro.config.mjs b/packages/astro/test/fixtures/core-image-deletion/astro.config.mjs new file mode 100644 index 000000000000..e39cf9fc68fc --- /dev/null +++ b/packages/astro/test/fixtures/core-image-deletion/astro.config.mjs @@ -0,0 +1,7 @@ +import mdx from '@astrojs/mdx'; +import markdoc from '@astrojs/markdoc'; +import { defineConfig } from 'astro/config'; + +export default defineConfig({ + integrations: [mdx(), markdoc()], +}); diff --git a/packages/astro/test/fixtures/core-image-deletion/package.json b/packages/astro/test/fixtures/core-image-deletion/package.json index 40a2ee1a64b1..e55fc847dce8 100644 --- a/packages/astro/test/fixtures/core-image-deletion/package.json +++ b/packages/astro/test/fixtures/core-image-deletion/package.json @@ -3,7 +3,9 @@ "version": "0.0.0", "private": true, "dependencies": { - "astro": "workspace:*" + "astro": "workspace:*", + "@astrojs/mdx": "workspace:*", + "@astrojs/markdoc": "workspace:*" }, "scripts": { "dev": "astro dev" diff --git a/packages/astro/test/fixtures/core-image-deletion/src/assets/markdocStillExists.jpg b/packages/astro/test/fixtures/core-image-deletion/src/assets/markdocStillExists.jpg new file mode 100644 index 000000000000..8e38327233fc Binary files /dev/null and b/packages/astro/test/fixtures/core-image-deletion/src/assets/markdocStillExists.jpg differ diff --git a/packages/astro/test/fixtures/core-image-deletion/src/assets/mdxDontExist.jpg b/packages/astro/test/fixtures/core-image-deletion/src/assets/mdxDontExist.jpg new file mode 100644 index 000000000000..8c5ba062c2f0 Binary files /dev/null and b/packages/astro/test/fixtures/core-image-deletion/src/assets/mdxDontExist.jpg differ diff --git a/packages/astro/test/fixtures/core-image-deletion/src/content/blog/markdoc.mdoc b/packages/astro/test/fixtures/core-image-deletion/src/content/blog/markdoc.mdoc new file mode 100644 index 000000000000..41119a9e7a53 --- /dev/null +++ b/packages/astro/test/fixtures/core-image-deletion/src/content/blog/markdoc.mdoc @@ -0,0 +1,7 @@ +--- +title: "Markdoc" +--- + +There is an image below + +![A penguin](../../assets/markdocStillExists.jpg) diff --git a/packages/astro/test/fixtures/core-image-deletion/src/content/blog/mdx.mdx b/packages/astro/test/fixtures/core-image-deletion/src/content/blog/mdx.mdx new file mode 100644 index 000000000000..3de8bda4ffe6 --- /dev/null +++ b/packages/astro/test/fixtures/core-image-deletion/src/content/blog/mdx.mdx @@ -0,0 +1,7 @@ +--- +title: "MDX" +--- + +There is an image below + +![A penguin](../../assets/mdxDontExist.jpg) diff --git a/packages/astro/test/fixtures/core-image-deletion/src/content/config.ts b/packages/astro/test/fixtures/core-image-deletion/src/content/config.ts new file mode 100644 index 000000000000..1c0eae662372 --- /dev/null +++ b/packages/astro/test/fixtures/core-image-deletion/src/content/config.ts @@ -0,0 +1,12 @@ +import { defineCollection, z } from 'astro:content'; + +const blog = defineCollection({ + type: 'content', + schema: z.object({ + title: z.string(), + }) +}); + +export const collections = { + blog: blog, +}; diff --git a/packages/astro/test/fixtures/core-image-deletion/src/pages/blog/[slug].astro b/packages/astro/test/fixtures/core-image-deletion/src/pages/blog/[slug].astro new file mode 100644 index 000000000000..418d449bb64c --- /dev/null +++ b/packages/astro/test/fixtures/core-image-deletion/src/pages/blog/[slug].astro @@ -0,0 +1,22 @@ +--- +import type { GetStaticPaths } from "astro"; +import { getCollection } from "astro:content"; + +export const getStaticPaths = (async () => { + const blog = await getCollection("blog"); + return blog.map((post) => ({ + params: { + slug: post.slug, + }, + props: { + post + } + })); +}) satisfies GetStaticPaths; + +const { post } = Astro.props; + +const { Content } = await post.render(); +--- + + diff --git a/packages/astro/test/image-deletion.test.js b/packages/astro/test/image-deletion.test.js index 4283e8c06f3b..cb4b464bf6aa 100644 --- a/packages/astro/test/image-deletion.test.js +++ b/packages/astro/test/image-deletion.test.js @@ -3,7 +3,7 @@ import { before, describe, it } from 'node:test'; import { testImageService } from './test-image-service.js'; import { loadFixture } from './test-utils.js'; -describe('astro:assets - delete images that are unused', () => { +describe('astro:assets - delete images that are unused zzz', () => { /** @type {import('./test-utils.js').Fixture} */ let fixture; @@ -33,5 +33,15 @@ describe('astro:assets - delete images that are unused', () => { const imagesUsedElsewhere = await fixture.glob('_astro/url.*.*'); assert.equal(imagesUsedElsewhere.length, 2); }); + + it('should delete MDX images only used for optimization', async () => { + const imagesOnlyOptimized = await fixture.glob('_astro/mdxDontExist.*.*'); + assert.equal(imagesOnlyOptimized.length, 1); + }); + + it('should always keep Markdoc images', async () => { + const imagesUsedElsewhere = await fixture.glob('_astro/markdocStillExists.*.*'); + assert.equal(imagesUsedElsewhere.length, 2); + }); }); }); diff --git a/packages/integrations/markdoc/src/content-entry-type.ts b/packages/integrations/markdoc/src/content-entry-type.ts index fe15d03b01ea..89f9f9e8687b 100644 --- a/packages/integrations/markdoc/src/content-entry-type.ts +++ b/packages/integrations/markdoc/src/content-entry-type.ts @@ -196,7 +196,19 @@ async function emitOptimizedImages( ctx.pluginContext.meta.watchMode, ctx.pluginContext.emitFile ); - node.attributes[attributeName] = src; + + const fsPath = resolved.id; + + if (src) { + // We cannot track images in Markdoc, Markdoc rendering always strips out the proxy. As such, we'll always + // assume that the image is referenced elsewhere, to be on safer side. + if (ctx.astroConfig.output === 'static') { + if (globalThis.astroAsset.referencedImages) + globalThis.astroAsset.referencedImages.add(fsPath); + } + + node.attributes[attributeName] = { ...src, fsPath }; + } } else { throw new MarkdocError({ message: `Could not resolve image ${JSON.stringify( diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9e35467d7405..62588e2fc44c 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -2516,6 +2516,12 @@ importers: packages/astro/test/fixtures/core-image-deletion: dependencies: + '@astrojs/markdoc': + specifier: workspace:* + version: link:../../../../integrations/markdoc + '@astrojs/mdx': + specifier: workspace:* + version: link:../../../../integrations/mdx astro: specifier: workspace:* version: link:../../..