toastdotdev / toast

The best place to stack your JAM. Toast is a Jamstack framework
153 stars 13 forks source link

Images, Image APIs, and Image Components #28

Open ChristopherBiscardi opened 3 years ago

ChristopherBiscardi commented 3 years ago

There's plenty of work going on in the world of "Image Components" and optimization. This is quite a large area, so I'll just start this issue by linking to prior art and ongoing state of the art in other frameworks.

other comments

Image processing is typically one of the slowest pieces of SSG build pipelines. At the scale that Toast can support, it is likely that image processing becomes such a large issue that using third party services is critical to build performance. For this reason I like the idea of using third-party services like cloudinary as defaults, with people opting-in to local processing if they want it and understand the tradeoff.

In the past Toast has allowed you to use plugins like rehype-local-image-to-cloudinary. Perhaps that sort of behavior should be built-in.

Modern formats include webp and avif, so if we do local processing these should be the target formats afaict.

jlengstorf commented 3 years ago

I just had Maya Shavin on LWJ and she covered the Cloudinary Nuxt plugin, which was a pretty nice API that might be worth looking over for inspiration

on a separate galaxy brain note: here are some Thoughts™ that you're welcome to entirely ignore, but that seem promising from the flexibility/"optimize for deletion" angle

I love the idea of making this a processing pipeline that defaults to something scalable like Cloudinary and letting people opt into other processors. this opens the door for Mux, Sharp, jimp, etc. to all be dropped in without changing the image markup at all — this is especially interesting because it means that someone could swap late without making any client code changes 👀

// default, maybe
export const toastPipelines = {
  image: (img) => cloudinary(img)
}

// custom
export const toastPipelines = {
  image: (img) => {
    // pipelines could allow arbitrary local code
    const watermarked = myCustomWatermarkFn(img);

    // pipelines would be pure, so they could be composed
    return sharp(watermarked);
  }
}

I think that would work in parallel, and that could open up a pattern for other asset processing pipelines

mdarrik commented 3 years ago

Speaking of Maya Shavin, she mentioned a Nuxt Image component that was in the works. It might be worth looking at here: https://image.nuxtjs.org/ . It's a lot of like what Jason suggests here. It supports provider options and lets you write your own where necessary. It also has setup for some configuration, but a lot of that is related to Nuxt's conventions which aren't really transposable to Toast at the moment.

I also think a config could just look like this for Jason's example:

export const toastPipelines = {
           image: (img) => cloudinary(img, { /*config options go here*/})
}
domitriusclark commented 3 years ago

I'd love to lob use-cloudinary in the ring here for defaults.

Since swapping to a strictly URL generation focused model, I've been able to drop the lib to 8KB (for now).

This includes intersection-observer for lazy-loading out of the box and surfaced through the useImage API

Building out @mdnext/components's Image with this, could be a good spot check for a base to what you wanna build here (probably without the dependency on Chakra)

Would be happy to discuss this further though 🙌