Overview
Currently, the image prop type consists of 4 properties: src
, alt
, width
, and height
.
This means a (Twig) SDC can render an image prop like this:
<img src="{{ image.src }}" alt="{{ image.alt }}" width="{{ image.width }}" height="{{ image.height }}" />
And a (JS) Code Component can render it like this:
export default function({ image }) {
return (
<img src={ image.src } alt={ image.alt } width={ image.width } height={ image.height } />
)
}
Or, taking advantage of JSX prop spreading, like this:
export default function({ image }) {
const { src, alt, width, height } = image;
return (
<img { ...{src, alt, width, height} } />
)
}
In
āØ
Add automated image optimization to image component
Active
, we're working on adding a 5th property: srcsetCandidateTemplate
. That name is still a work in progress. For the purpose of this issue, let's simplify it to scaledSrc
. The idea is that src
would be the original image, or possibly one with an image style applied for visual effect (color shifting, watermarking, cropping, etc.), but not for size optimization. Meanwhile, scaledSrc
would be the URL template for scaling to one of several widths. For example:
src = '/sites/default/files/foo.jpg'
scaledSrc = '/sites/default/files/styles/xb_parameterized_width--{width}/public/foo.jpg.webp?itok=1Rl59WAb'
Assuming we add a toSrcSet
filter, this would allow a Twig SDC to do this:
<img src="{{ image.src }}" alt="{{ image.alt }}" width="{{ image.width }}" height="{{ image.height }}" srcset="{{ image.scaledSrc|toSrcSet }}" sizes="auto 100vw" />
It would allow a JS code component to do something similar, but where JS components really shine is in the ability to use the JS ecosystem, such as next/image (or a version of it that can be used on its own without Next.js: next-image-standalone). So, for example:
import Image from "next-image-standalone";
export default function({ image }) {
const { src, alt, width, height, scaledSrc } = image;
const loader = ({ width }) => scaledSrc.replace('{width}', width);
return (
<Image { ...{src, alt, width, height, loader} } />
)
}
The above is nice and enables the code component to use various other nice features from next/image
by passing the appropriate props. But one thing that's annoying about the above is the need to pass in an explicit loader
prop. Although it's possible to configure a centralized loader, so long as it's relying on scaledSrc
, the code component has to pass along scaledSrc
somehow, just like the Twig version earlier.
I discussed this with @lauriii and he's been pushing back on this, asking: is it possible to let component authors just deal with standard <img>
concepts like src, alt, width, and height, and not introduce any Drupalisms like a scaledSrc
property?
Proposed resolution
What if instead of separate src
and scaledSrc
properties we combined both into src
like this:
src = '/sites/default/files/foo.jpg?alternateWidths=%2Fsites%2Fdefault%2Ffiles%2Fstyles%2Fxb_parameterized_width--%7Bwidth%7D%2Fpublic%2Ffoo.jpg.webp%3Fitok%3D1Rl59WAb'
In other words, instead of a scaledSrc
property we add it as a query parameter to src
. This query parameter wouldn't affect the response if the browser requests this src
(especially if foo.jpg is already on disk in which case query parameters do nothing), but it would allow the Twig SDC to do this:
<img src="{{ image.src }}" alt="{{ image.alt }}" width="{{ image.width }}" height="{{ image.height }}" srcset="{{ image.src|toSrcSet }}" sizes="auto 100vw" />
And more importantly, it would allow a JS code component to do this:
import Image from "next-image-standalone";
export default function({ image }) {
const { src, alt, width, height } = image;
return (
<Image { ...{src, alt, width, height} } />
)
}
Where a default loader
function could be configured completely invisibly and from the perspective of the component author, they're using next/image
completely idiomatically.