Closed (fixed)
Project:
Experience Builder
Version:
0.x-dev
Component:
Theme builder
Priority:
Normal
Category:
Feature request
Assigned:
Unassigned
Issue tags:
Reporter:
Created:
24 Jun 2025 at 11:18 UTC
Updated:
28 Jul 2025 at 13:14 UTC
Jump to comment: Most recent, Most recent file
Comments
Comment #3
balintbrewsComment #4
effulgentsia commentedThis is great! I wonder if the following would be an improvement or not...
What if instead of a wrapper component,
Image from "@/lib/Image", people usednext-image-standalonedirectly, but we gave them a utility function for getting theloaderfunction to pass in? For example:Would the above be more idiomatic in that it would be clearer that people are using essentially the stock Nextjs image component rather than "who knows what else
@/lib/Imagedoes"? Or is the@/lib/Imagewrapper idea better because it gives us room to add other customizations, like adding some defaults to theconfigprop?Comment #5
balintbrews#4: That's a great idea! It's in line with how we chose to provide
@drupal-api-client/json-api-clientandSWRinstead of a custom wrapper. More idiomatic, as you said. For both we add minimal customization and convenience, but we still keep their original names in the module specifiers. So I think we can do the same if we choose to providenext-image-standalonedirectly, as in, we would still have the room to add customizations, such as defaults to theconfigprop, as you point out.The only potential downside is that a
loaderfunction is optional withnext/image: it optimizes images using its own backend by default. I wonder if it could be misleading that we provide something callednext-image-standalone, which may make it sound like aloaderfunction is optional, just as it is withnext/image. Whereas it is required fornext-image-standalone, which is written in its README.So the way I see it, we need to choose how we would like to communicate what it is that we offer:
next/image, but you must provide aloaderfunction. For that we also got you covered, here is a hook that returns aloaderfunction that works with our backend."next/imagedoes."Comment #6
effulgentsia commentedI prefer #5.1 over #5.2 because it's more similar to shadcn's open code approach. It makes the use of
next/image(or thenext-image-standaloneversion of it which is just a way to getnext/imageoutside of a Next.js context) ultimately a decision made by the component author (even if we nudge that decision by providing an example), whereas to me it feels like #5.2 would imply that XB is making that decision more heavy-handedly.Comment #7
effulgentsia commentedIs it reasonable for someone to expect "standalone" (by which is meant: usable outside of Next.js) to have a way of working without providing a loader function? If not, then I don't see anything misleading about it being required in standalone context, even if it's optional in non-standalone context.
Comment #8
balintbrews#6: Love that, let's go with #5.1. It should be straightforward to adjust the MR to that direction.
#7: I think it depends on how much they understand about what
next/imagedoes. What's nice aboutnext/imageis that it's not very necessary to fully understand, it mostly just works. Either way, I'm more than okay to let this thought go, and I'm happy with #5.1, a.k.a. #4.Comment #9
lauriiiNext.js allows configuring the default loader. I believe this is the most common way of configuring this – it doesn't make sense configuring this per instance unless there's something about a specific instance why it needs to use a different loader.
I think the ideal experience would we that we have a default loader which just works within the Drupal environment. There could be additional loaders for example to use CDN from a DAM to load an image, which would then potentially have to be loaded from within a component.
I don't think this goes against the open code approach because this is already an API that the upstream provides, which I also believe is the primary way of configuring this for Next.js applications.
Comment #10
effulgentsia commentedBut where to configure it then? There's no equivalent to
next.config.jsfor code components unless we introduce some new convention for code component global JS config. We have a global CSS tab, so maybe adding a global JS tab makes sense?We could do this per #5's answer about adding defaults to
config. However, the default loader would still require a per-instance prop (srcSetCandidateTemplate) set that isn't part of the next/image set of props. So #4 could be simplified to:However, I don't think
<Image {...{src, alt, width, height, srcSetCandidateTemplate}}/>is any friendlier than<Image {...{src, alt, width, height, loader}}/>.Comment #11
effulgentsia commentedSome minor DX improvements we can make to #10...
srcSetCandidateTemplateis a mouthful. Perhaps this could just besrcTemplate.next/imagethe loader prop (when present) is always a function, perhapsnext-image-standalonecould allow it to be either a function or a string, and if it's a string, convert it to a function that replaces{src},{width}, and{quality}in the string.Doing both of the above would mean the #10 code would become:
Comment #12
lauriiiMaybe we don't have to introduce a configuration at this point so long as we have set the correct default? I would imagine in Drupal this is something that a module may want to change, similar to what the CDN module is doing.
Why do we need
srcSetCandidateTemplateto be passed per instance? Why would I as the user of that component care about it? I would have no idea based on that prop name why it's there and why I'd have to pass it to the function. Tried to look at the code in the MR and in #3515646: Add automated <img srcset> generation but it still wasn't clear what it is.Comment #13
effulgentsia commented@lauriii: I think you'll like #3532718: Improve the front-end DX of `<img srcset>`.
Comment #14
lauriiiProposal on that issue looks great! 👏
Comment #15
effulgentsia commentedTagging as beta blocker for the same reason as #3515646-51: Add automated <img srcset> generation.
Comment #16
wim leersInteresting discussion between @balintbrews & @effulgentsia #4 through #8 🤓
#10: → note that our
AssetLibraryinfrastructure already supports this 😊#11.1: → it is named after the docs at https://developer.mozilla.org/en-US/docs/Web/API/HTMLImageElement/srcset..., specifically the "image candidate string" structure, follow-up for it at #3532718: Improve the front-end DX of `<img srcset>`.
Based on #13 through #15, I think this issue is actionable now that #3515646: Add automated <img srcset> generation landed (on Friday); the
srcSetCandidateTemplatenaming change is out of scope here; that's for #3532718: Improve the front-end DX of `<img srcset>`. AFAICT next steps here is for @balintbrews to respond to #10 and #11.Comment #17
balintbrewsYes, we already make use of it for the Tailwind build. That would make it more complicated to do a new tab right now, plus what had been discussed in this issue would also mean inventing a new configuration format. #3532718: Improve the front-end DX of `<img srcset>` is a fantastic, elegant solution to avoid that.
This issue is indeed actionable, I'll get to it soon.
Comment #18
wim leersDo you mean that it'd be better for this issue to wait for another MR (which one?) to add this tab for the Tailwind build? Or do you mean that the Tailwind build is [going to] just "piggybacking" on that infra and is storing JS in the
globalAssetLibrary, but won't be showing it in the UI?Comment #19
balintbrews#18: The Tailwind build is already piggybacking on that infra since #3516390: Compile Tailwind CSS globally for code components — storing JS in the
globalAssetLibrarywithout showing anything on the UI.In any case, nothing else is needed for this issue, the current MR needs some changes based on the discussion, but nothing major.
Comment #20
wim leers👍
Comment #21
balintbrewsI made the changes based on the discussion, and already future proofed the solution for when #3532718: Improve the front-end DX of `<img srcset>` lands.
Here is how the current DX looks like:
After #3532718: Improve the front-end DX of `<img srcset>` is in, this will be simplified to the following. Everything is already in place for this by the MR in this issue with a few comments pointing at code that we'll be able to remove. (I also extensively tested on top of the current changes in #3532718: Improve the front-end DX of `<img srcset>`.)
Comment #22
larowlanI tested this with the component in #21 against a fresh install with xb_vite running but after running
npm run buildI get the following failure in the console and it doesn't render a preview.
I have run
npm installas wellWhat am I missing?
Comment #23
larowlanCode changes look good to me, just the issue with manual testing per #22
Comment #24
wim leersComment #25
effulgentsia commentedI didn't test this MR, but the code looks great to me! I'd consider it RTBC once #22 is addressed.
Comment #26
balintbrewsI'm very much scratching my head about #22, no idea how Lee managed to hit that. Investigating.
Comment #27
larowlanIf you can't reproduce it, it might just be me doing something wrong
Comment #28
balintbrews#27: The steps you wrote in #22 are all the correct ones. I'll ask others to try as well.
Comment #30
wim leersPaired with @balintbrews & @hooroomoo — turns out that we got the hardcoded widths in
\Drupal\experience_builder\Routing\ParametrizedImageStyleConverter::ALLOWED_WIDTHSandcomponents/image/image.twig(they must be manually set to be in sync until #3533563: Store allowed widths for xb_parametrized_width in third-party settings OR a separate simple config) wrong in #3515646: Add automated <img srcset> generation: we listed only the device sizes, we forgot the image sizes.See https://nextjs.org/docs/pages/api-reference/components/image#imagesizes:
Whoops!
Trivial fix here though :)
Comment #33
balintbrews@lauriii, @hooroomoo, and @justafish helped with testing. We couldn't reproduce #22, but we found smaller issues which were fixed. 🚢
Comment #34
neha_bawankar commentedTested changes on branch
0.x, following scenarios :Scenario
Result
Status
srcsetcandidatetemplatetag is presentsrcsetcandidatetemplatetag is presentsrcsetcandidatetemplatetag is presentsrcsetcandidatetemplatetag is presentsrcsetcandidatetemplateis present which should not beAdd media with dimension as (50x50)
Add media with dimension as (3000x2801)