Images, Image APIs, and Image Components
ChristopherBiscardi opened this issue · 3 comments
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.
- Next RFC: Image Component
<Image src=”/photos/foo.jpg” height=”1400” width=”2000” sizes=”40vw” priority>
- Gatsby PR: new gatsby-plugin-image
import React from "react" import { StaticImage } from "gatsby-plugin-image" export const Dino = () => ( <StaticImage height={100} src="trex.png" alt="T-Rex" /> )
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.
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
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*/})
}
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 🙌