withastro / astro

The web framework for content-driven websites. ⭐️ Star to support our work!
https://astro.build
Other
43.84k stars 2.28k forks source link

Inconsistencies with image optimizations with Vercel Adaptor #11320

Closed mikeburgh closed 1 day ago

mikeburgh commented 5 days ago

Astro Info

Astro                    v4.11.0
Node                     v18.20.2
System                   macOS (arm64)
Package Manager          npm
Output                   hybrid
Adapter                  @astrojs/vercel/serverless
Integrations             @astrojs/tailwind
                         @astrojs/lit
                         @astrojs/sitemap
                         astro-expressive-code
                         @astrojs/mdx
                         pagefind
                         astro-icon
                         astro-compress

If this issue only occurs in one browser, which browser is a problem?

No response

Describe the Bug

I am sorry if this is not the right place, but I have not been able to find an existing solution to these issues, and not sure if it's Astro or the Vercel adaptor where the issue is.

There are a number of edge cases with image optimization on Vercel.

Image component

Using the import(variable) approach:

 <Image
            class="group-hover:scale-110 duration-300 aspect-[2/1] object-cover"
            loading="lazy"
            width="560"
            src={import(image)}
            alt={imageAlt}
/>

Fails to build with Vercel adaptor (locally or deployed on Vercel) with the following error:

Cannot find module '/src/images/content/blog/article/screenshot-partial.png' imported from /vercel/path0/.vercel/output/_functions/chunks/index_BuSqNfCn.mjs

It does work if the import is a string and not a variable.

A solution that works for this, is to import all images, and then map the string back to one of those imported images. This can be turned into a component to wrap the Image component.

---
import { Image as OriginalImage } from "astro:assets";

const images = import.meta.glob('/src/images/**');
const props = Astro.props;

if (typeof props.src === 'string') {
  const image = images[props.src]();
  if (image) {
    props.src = image;
  }
}

---
<OriginalImage {...props}/>

Images in Markdown

Is you use regular markdown, Astro only optimizes images that are relative urls:

![New Connection](../../images/content/docs/connect/new-connection.png)
or
![New Connection](./src/images/content/docs/connect/new-connection.png)

If you try to use an absolute reference, Astro in development will not optimize it.

![New Connection](/src/images/content/docs/connect/new-connection.png)

The problem is, if the url is relative, the Vercel adaptor will error:

Could not resolve "./src/images/content/docs/connect/new-connection.png" from "src/content/docs/connect.md"

If it's absolute it does not error, but the url does not get changed, and the resulting image is broken as it it's img src="/src/images/..."

The other issue is if the markdown files are edited using a CMS, they will use absolute urls to the /src folder.

What's the expected result?

Image optimization to work with Vercel for dynamic images, and images used in markdown.

Link to Minimal Reproducible Example

Vercel Deployment based.

Participation

github-actions[bot] commented 5 days ago

Hello @mikeburgh. Please provide a minimal reproduction using a GitHub repository or StackBlitz. Issues marked with needs repro will be closed if they have no activity within 3 days.

Princesseuh commented 5 days ago

All of those limitations are intended, we cannot process dynamic imports like these (you should get a Vite warning when you do it normally)

As for images in Markdown, images starting with a slash are considered to be references to images in the public folder. Paths are relative to the content file, hence why it doesn't work when you do ./src

mikeburgh commented 4 days ago

Thanks for getting back to me..

Looking at this with fresh eyes this morning, would you consider adding some handling around using /src/ in markdown, similar to how /public/ is handled ?

If you use /public/ at the start of a url in markdown, you get a warning, and it's removed from the url so everything still works.

Could you apply the same to /src/ at the start of a url ? provide a warning, and handle it as though it was a relative url and run it through the Image component (in the case of frontmatter import it so it can be passed to the Image component ?)

If that's something you would consider, I can try my hand at a PR for it once I find the logic that wraps that.. This would I assume then work in Vercel, and also allow CMS tools that edit the markdown to use the absolute /src/.