Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Adapter Vercel Image Optimizations #8561

Open
hartwm opened this issue Jan 17, 2023 · 13 comments · Fixed by #8667
Open

Adapter Vercel Image Optimizations #8561

hartwm opened this issue Jan 17, 2023 · 13 comments · Fixed by #8667
Labels
pkg:adapter-vercel Pertaining to the Vercel adapter

Comments

@hartwm
Copy link

hartwm commented Jan 17, 2023

Describe the problem

Would be really awesome if adapter-vercel package accepted images option for using Vercel's native image optimization. It only requires simple addition of images object to build config file .vercel/output/config.json. I would submit a pull request but I am sure the options, naming conventions, etc would not be as the team would desire. Given it is such a straightforward task it probably wouldn't prove helpful.

Describe the proposed solution

Here are the options

type ImageFormat = 'image/avif' | 'image/webp';

type RemotePattern = {
  protocol?: 'http' | 'https';
  hostname: string;
  port?: string;
  pathname?: string;
};

type ImagesConfig = {
  sizes: number[];
  domains: string[];
  remotePatterns?: RemotePattern[];
  minimumCacheTTL?: number; // seconds
  formats?: ImageFormat[];
  dangerouslyAllowSVG?: boolean;
  contentSecurityPolicy?: string;
};

https://vercel.com/docs/concepts/image-optimization
https://vercel.com/docs/build-output-api/v3#build-output-configuration/supported-properties/images

Alternatives considered

No response

Importance

nice to have

Additional Information

No response

@dummdidumm dummdidumm added the pkg:adapter-vercel Pertaining to the Vercel adapter label Jan 17, 2023
@dummdidumm
Copy link
Member

I'm not sure just adding the options is enough, there's also work involved to create a specific image component I guess? Related to #241

@hartwm
Copy link
Author

hartwm commented Jan 17, 2023

I'm not sure just adding the options is enough, there's also work involved to create a specific image component I guess? Related to #241

you can leave that to the community, because thats more subjective and that would be separate from an adapter package anyway, but without the ability to put these options in the build config then you can't use it, so this shouldn't be the breakpoint of using features

@hartwm
Copy link
Author

hartwm commented Jan 17, 2023

Also all the solutions I have seen are for local images, not remote images.

@lettucebowler
Copy link
Contributor

I'm not sure just adding the options is enough, there's also work involved to create a specific image component I guess? Related to #241

Next and Nuxt have supported image components, but from my understanding once enabled you could also just update your image srcs manually from eg /public/images/logo.png to /_vercel/image?url=/public/image/logo.png?w=320&q=80. A fancy image component could come later if the community wants it, but just enabling this would be a great enhancement IMO

@hartwm
Copy link
Author

hartwm commented Jan 20, 2023

Next and Nuxt have supported image components, but from my understanding once enabled you could also just update your image srcs manually from eg /public/images/logo.png to /_vercel/image?url=/public/image/logo.png?w=320&q=80. A fancy image component could come later if the community wants it, but just enabling this would be a great enhancement IMO

Exactly

@izznat
Copy link

izznat commented Jan 23, 2023

@lettucebowler has made a PR for this #8667.

@benmccann
Copy link
Member

benmccann commented Jan 31, 2023

Example usage as of today shared on Discord by OP:

// Image.svelte

<script lang="ts">  
  import { dev } from '$app/environment'; 

  let className = ""
  export { className as class };
  export let image:WpImage
  export let showTitle = false
  export let lazy = true
  export let height  = 1280
  export let quality = 70
  export let width = 720
  export let unoptimized = false 
 
  const sizeArr = [640, 768, 1024, 1280, 1536, 2048]  
  
  const vercelImg = (sourceUrl:string,size:number) => 
  (`/_vercel/image?url=${encodeURIComponent(sourceUrl)}&w=${size}&q=${quality} ${size}w`)
  
  $:({ srcSet, sourceUrl, title, altText} = image) 
  $: vercelSrcSet = sizeArr.map(size=>vercelImg(image?.sourceUrl,size)).join(',') 
    
  // dyanmic srcset only for optimized (w/vercel) 
  $: imageSrcSet = (unoptimized || dev) ? srcSet : vercelSrcSet

  let element 
</script>

<img   
  {width}
  {height}
  title={showTitle ? title : undefined}
  srcset={imageSrcSet}
  src={sourceUrl}
  alt={altText ?? title} 
  class={className ?? undefined}
  loading={lazy ? 'lazy' : 'eager'}
  {...$$restProps} 
  bind:this={element}
/>
// scripts/vercel-images.js
import fs from 'node:fs';
import dotenv from 'dotenv'
dotenv.config()
// sizes should be shared variable with Image component
import {sizes} from './theme.cjs'
    
    
const file = '.vercel/output/config.json';

const config = {
  ...JSON.parse(fs.readFileSync(file, 'utf-8')),
        images: {
                "sizes": sizes,
                "domains": [],
                "minimumCacheTTL": 60,
                "formats": ["image/avif", "image/webp"],
                "remotePatterns": [ 
                        { 
                            "hostname": "yourcdn\\.cloudfront\\.net$"
                        }, 
                ]
            }
};

fs.writeFileSync(file, JSON.stringify(config, null, 2));
// package.json

"build": "vite build && node scripts/vercel-images",

@aakash14goplani
Copy link

aakash14goplani commented Mar 8, 2023

@hartwm @benmccann do you have working example hoisted anywhere (e.g. GitHub, Code sandbox etc. ). I wanted to see the configuration details. Thanks.

@hartwm
Copy link
Author

hartwm commented Mar 8, 2023

@hartwm @benmccann do you have working example hoisted anywhere (e.g. GitHub, Code sandbox etc. ). I wanted to see the configuration details. Thanks.

https://github.com/hartwm/vercel-images-sveltekit
https://vercel-images-sveltekit.vercel.app/

@benmccann
Copy link
Member

benmccann commented Oct 6, 2023

There are a couple PRs out for this:

@benmccann
Copy link
Member

Hi @hartwm, thanks so much for providing these examples! I do have one question I wonder if anyone knows the answer to.

Vite lets you import images like this:

<script>
	import logo from '$images/example.png';
</script>

That means that a hash gets put in their name so that they can be cached forever. Is it possible to use such an image with the Vercel image solution?

When I go to https://vercel-images-sveltekit.vercel.app/ I notice that the local image can't be cached as strongly as the Vite processed images we have today. If you hit the page a second time, it returns a 304 response as opposed to avoiding the request entirely. I wonder if it's possible to use an imported image so that Vite processes the request before Vercel takes over possibly allowing us to skip the request entirely still. If it's possible, it'd be a great example to add to https://github.com/hartwm/vercel-images-sveltekit

@leoj3n
Copy link
Contributor

leoj3n commented Feb 29, 2024

@benmccann You can set Cache-Control headers with Vercel...

https://github.com/leoj3n/svelte-vercel-optimized-images?tab=readme-ov-file#avoiding-304-network-requests

It looks like you merged #8667 (review) which relates to the OP... Considering the ability to set Cache-Control with Vercel, your remaining question may be answered, and so you might now be able to close this open issue.

@leoj3n
Copy link
Contributor

leoj3n commented Feb 29, 2024

@benmccann Regarding "Vite processes the request before Vercel takes over"...

It kind of defeats the purpose of using Vercel to send the correct image type (avif/webp) based on headers sent from the browser, as well as the (pre-defined) dynamic image sizes. If you circumvent Vercel you would have to generate all those permutations ahead of time yourself which could be prohibitive for user uploaded images, as mentioned.

I do believe Next.js implements their own code that emulates what the Vercel image optimization endpoint does, so it may be possible to add such functionality to SvelteKit itself, but you probably will have a very similar approach.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
pkg:adapter-vercel Pertaining to the Vercel adapter
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants