From a1a4f45b51a80215fa7598da83bd0d9c5acd20d2 Mon Sep 17 00:00:00 2001 From: Erika <3019731+Princesseuh@users.noreply.github.com> Date: Tue, 4 Apr 2023 10:21:13 +0200 Subject: [PATCH] fix(images): Simpler logic for collecting images in Markdown (#6744) --- .changeset/green-turtles-jump.md | 6 +++++ .../astro/src/vite-plugin-markdown/index.ts | 21 ++++++++-------- packages/astro/test/core-image.test.js | 13 ++++++++++ .../core-image/src/pages/httpImage.md | 2 ++ packages/markdown/remark/src/rehype-images.ts | 25 +------------------ .../remark/src/remark-collect-images.ts | 24 ++++++++++++++---- packages/markdown/remark/src/types.ts | 5 ++-- 7 files changed, 54 insertions(+), 42 deletions(-) create mode 100644 .changeset/green-turtles-jump.md create mode 100644 packages/astro/test/fixtures/core-image/src/pages/httpImage.md diff --git a/.changeset/green-turtles-jump.md b/.changeset/green-turtles-jump.md new file mode 100644 index 000000000000..22c670c17602 --- /dev/null +++ b/.changeset/green-turtles-jump.md @@ -0,0 +1,6 @@ +--- +'astro': patch +'@astrojs/markdown-remark': patch +--- + +Fix remote images in Markdown throwing errors when using `experimental.assets` diff --git a/packages/astro/src/vite-plugin-markdown/index.ts b/packages/astro/src/vite-plugin-markdown/index.ts index ed2779da92a4..1afeca8f7673 100644 --- a/packages/astro/src/vite-plugin-markdown/index.ts +++ b/packages/astro/src/vite-plugin-markdown/index.ts @@ -86,18 +86,17 @@ export default function markdown({ settings, logging }: AstroPluginOptions): Plu let html = renderResult.code; const { headings } = renderResult.metadata; + + // Resolve all the extracted images from the content let imagePaths: { raw: string; resolved: string }[] = []; - if (settings.config.experimental.assets) { - let paths = (renderResult.vfile.data.imagePaths as string[]) ?? []; - imagePaths = await Promise.all( - paths.map(async (imagePath) => { - return { - raw: imagePath, - resolved: - (await this.resolve(imagePath, id))?.id ?? path.join(path.dirname(id), imagePath), - }; - }) - ); + if (settings.config.experimental.assets && renderResult.vfile.data.imagePaths) { + for (let imagePath of renderResult.vfile.data.imagePaths.values()) { + imagePaths.push({ + raw: imagePath, + resolved: + (await this.resolve(imagePath, id))?.id ?? path.join(path.dirname(id), imagePath), + }); + } } const astroData = safelyGetAstroData(renderResult.vfile.data); diff --git a/packages/astro/test/core-image.test.js b/packages/astro/test/core-image.test.js index 7baf8bcb8749..4b444708e2e1 100644 --- a/packages/astro/test/core-image.test.js +++ b/packages/astro/test/core-image.test.js @@ -218,6 +218,19 @@ describe('astro:image', () => { let $img = $('img'); expect($img.attr('src').startsWith('/_image')).to.equal(true); }); + + it('properly handles remote images', async () => { + let res = await fixture.fetch('/httpImage'); + let html = await res.text(); + $ = cheerio.load(html); + + let $img = $('img'); + expect($img).to.have.a.lengthOf(2); + const remoteUrls = ['https://example.com/image.png', '/image.png']; + $img.each((index, element) => { + expect(element.attribs['src']).to.equal(remoteUrls[index]); + }); + }); }); describe('getImage', () => { diff --git a/packages/astro/test/fixtures/core-image/src/pages/httpImage.md b/packages/astro/test/fixtures/core-image/src/pages/httpImage.md new file mode 100644 index 000000000000..441b74f3e842 --- /dev/null +++ b/packages/astro/test/fixtures/core-image/src/pages/httpImage.md @@ -0,0 +1,2 @@ +![Remote image](https://example.com/image.png) +![/public image](/image.png) diff --git a/packages/markdown/remark/src/rehype-images.ts b/packages/markdown/remark/src/rehype-images.ts index 72f4757008d5..fd1e8f70f1cc 100644 --- a/packages/markdown/remark/src/rehype-images.ts +++ b/packages/markdown/remark/src/rehype-images.ts @@ -9,9 +9,7 @@ export function rehypeImages() { if (node.tagName !== 'img') return; if (node.properties?.src) { - if (file.dirname) { - if (!isRelativePath(node.properties.src) && !isAliasedPath(node.properties.src)) return; - + if (file.data.imagePaths?.has(node.properties.src)) { node.properties['__ASTRO_IMAGE_'] = node.properties.src; delete node.properties.src; } @@ -19,24 +17,3 @@ export function rehypeImages() { }); }; } - -function isAliasedPath(path: string) { - return path.startsWith('~/assets'); -} - -function isRelativePath(path: string) { - return startsWithDotDotSlash(path) || startsWithDotSlash(path); -} - -function startsWithDotDotSlash(path: string) { - const c1 = path[0]; - const c2 = path[1]; - const c3 = path[2]; - return c1 === '.' && c2 === '.' && c3 === '/'; -} - -function startsWithDotSlash(path: string) { - const c1 = path[0]; - const c2 = path[1]; - return c1 === '.' && c2 === '/'; -} diff --git a/packages/markdown/remark/src/remark-collect-images.ts b/packages/markdown/remark/src/remark-collect-images.ts index afc61c468dc5..470b770ed5a1 100644 --- a/packages/markdown/remark/src/remark-collect-images.ts +++ b/packages/markdown/remark/src/remark-collect-images.ts @@ -1,17 +1,31 @@ import type { Image } from 'mdast'; import { visit } from 'unist-util-visit'; -import type { VFile } from 'vfile'; +import type { MarkdownVFile } from './types'; export default function toRemarkCollectImages() { return () => - async function (tree: any, vfile: VFile) { + async function (tree: any, vfile: MarkdownVFile) { if (typeof vfile?.path !== 'string') return; const imagePaths = new Set(); - visit(tree, 'image', function raiseError(node: Image) { - imagePaths.add(node.url); + visit(tree, 'image', (node: Image) => { + if (shouldOptimizeImage(node.url)) imagePaths.add(node.url); }); - vfile.data.imagePaths = Array.from(imagePaths); + vfile.data.imagePaths = imagePaths; }; } + +function shouldOptimizeImage(src: string) { + // Optimize anything that is NOT external or an absolute path to `public/` + return !isValidUrl(src) && !src.startsWith('/'); +} + +function isValidUrl(str: string): boolean { + try { + new URL(str); + return true; + } catch { + return false; + } +} diff --git a/packages/markdown/remark/src/types.ts b/packages/markdown/remark/src/types.ts index dc3bbce32ff8..2f2d36de7431 100644 --- a/packages/markdown/remark/src/types.ts +++ b/packages/markdown/remark/src/types.ts @@ -1,8 +1,8 @@ import type * as hast from 'hast'; import type * as mdast from 'mdast'; import type { - all as Handlers, one as Handler, + all as Handlers, Options as RemarkRehypeOptions, } from 'remark-rehype'; import type { ILanguageRegistration, IThemeRegistration, Theme } from 'shiki'; @@ -85,11 +85,12 @@ export interface MarkdownMetadata { export interface MarkdownVFile extends VFile { data: { __astroHeadings?: MarkdownHeading[]; + imagePaths?: Set; }; } export interface MarkdownRenderingResult { metadata: MarkdownMetadata; - vfile: VFile; + vfile: MarkdownVFile; code: string; }