Overview

To enable simple use cases in dynamic code components, we need to expose specific pieces of data to the code components via drupalSettings. This includes information that is usually rendered by blocks like system branding or breadcrumbs, but will now be needed directly in dynamic code components — which will deprecate code overrides (#3505993: Code Components as Block Overrides, step 1).

Proposed resolution

Populate the following data in drupalSettings under a new top-level key xbData (note: not under xb, which is reserved for internal Experience Builder needs):

{
  xbData: {
    baseUrl: 'https://www.example.com',
    branding: {
      homeUrl: '/',
      logo: '/core/misc/logo/drupal-logo.svg',
      siteName: 'My awesome website',
      siteSlogan:
        "<p>This website is the best. It's better than all the rest.</p>",
    },
    breadcrumbs: [
      {
        key: 'front_page',
        text: 'Home',
        url: '/',
      },
      {
        key: 'news',
        text: 'News',
        url: '/news',
      },
      {
        key: 'business',
        text: 'Business',
        url: '/business',
      },
    ],
    pageTitle: 'Home',
  },
}

The data needs to be added everywhere where the astro_island render element (\Drupal\experience_builder\Element\AstroIsland) is rendered, so not only on the XB UI.

The proposed shape follows what we previously introduced in #3505993: Code Components as Block Overrides, step 1 — see /experimental/js-components-as-block-overrides/example-data/.

These settings will need to be attached in 2 places:

  1. For the actual live site and the preview inside the XB UI: Since this is intended to provide information for >=1 ComponentSources (currently only the js one), this belongs in \Drupal\experience_builder\Hook\ComponentSourceHooks::pageAttachments().
  2. For the previews of components in the component list ("component hover"): update \Drupal\experience_builder\Entity\Component::normalizeForClientSide()
Command icon Show commands

Start within a Git clone of the project using the version control instructions.

Or, if you do not have SSH keys set up on git.drupalcode.org:

Comments

isholgueras created an issue. See original summary.

balintbrews’s picture

Title: Populate data to drupalSettings to enable Dynamic Code Components » Populate data in `drupalSettings` to enable simple use cases in dynamic code components
Component: Code » Theme builder
Assigned: Unassigned » isholgueras
Issue summary: View changes
Related issues: +#3505993: Code Components as Block Overrides, step 1, +#3530429: Make drupalSettings available in code editor preview

I added more details and what I propose as the data shape.

wim leers’s picture

Issue summary: View changes
Issue tags: +beta blocker, +Needs tests

Added some implementation guidance.

balintbrews’s picture

#3: We need the page title in drupalSettings.xbData regardless of that. #3502371: Make "Page title block" work A) also outside regions, B) on the only routes XB currently supports: content entity routes will enable the page title block to work, but we would like to support building a dynamic code component where users can access the raw page title and add custom markup around it. It was amongst our original goals for #3505993: Code Components as Block Overrides, step 1, but we dropped it due to the challenges with page title block. Or maybe what you're saying is that we need #3502371: Make "Page title block" work A) also outside regions, B) on the only routes XB currently supports: content entity routes even to be able to populate it in drupalSettings.xbData here? 🙂

Edit: Yes, after re-reading your comment, that's what you were saying, sorry! 🙈

isholgueras’s picture

Assigned: isholgueras » wim leers
Status: Active » Needs review

I think it's ready for the first review round

wim leers’s picture

Assigned: wim leers » Unassigned
Issue tags: +front-end performance, +scalability

Nice work here!

I'm missing three key things:

  1. JavaScriptComponent config entities should at minimum declare that they depend on drupalSettings
  2. JavaScriptComponent config entities should ideally declare that they depend on specific data in drupalSettings — especially breadcrumbs data, because it massively worsens cacheability
  3. a strategy for avoiding worsened cacheability and scalability (see MR comments for details)

I'm fine with a @todo + stable-blocking follow-up issue to address the dependency information, but shipping a 1.0 like this is a no-go.

isholgueras’s picture

Assigned: Unassigned » isholgueras
Status: Needs review » Needs work
isholgueras’s picture

There is only one thing left to do. How are the code component going to require that it depends on... breadcrumbs for example?

I still missing how, if I'm creating a code component, I'm going to depend on breadcrumb or pageTitle.

I mean, in the whole process as a user or XB user, I click in Add new, I get the editor and... where I define what features I will require?

I was playing around with a new schema Choice property, drupalSettings, similar to a blockOverride and list there all the options allowing developers to add it to the yaml files, maybe in the future adding them to the UI, but that's very much out of scope here.

Any thoughts here?

wim leers’s picture

Assigned: isholgueras » wim leers
wim leers’s picture

  1. 👍 The current MR is based on the simple on/off presence of preg_match('/drupalSettings\.xbData/', $component->getJs(). I agree with the pragmatism until such a time we can use explicit import statements.
  2. 👎 While better than when I reviewed it in #8 late last week, it still has too much of a negative impact on cacheability and hence scalability. See my analysis and rough proposal, and my implementation outline. That outline partially works. Next step: debug why \Drupal\experience_builder\Hook\ComponentSourceHooks::jsSettingsAlter() is not being called.
  3. 👎 The problem with the absence of explicit import statements for specific subsets of data is that this de facto becomes an API we can not ever evolve nor change. So, I think it should be tweaked slightly, similar to what we did with XB's internal HTTP API at #3471884: Rename all XB internal HTTP API routes from `/xb/api/…` to `/xb/api/v0/…`: we should version it.

    So instead of:

    drupalSettings?.xbData?.branding?.homeUrl
    

    it should become
    drupalSettings?.xbData?.v0?.branding?.homeUrl

    … which will allow for evolvability, backwards compatibility layers, deprecation warnings etc.

  4. 🐛 This currently contains a race condition, because it inspects ::getJs(), which is the saved JS, not the auto-save JS. This needs to reflect either. In fact, it probably makes sense to ALWAYS load all drupalSettings.xbData for draft components, just to avoid race conditions: if I'd add drupalSettings while editing the code in the code editor, they wouldn't be populated yet? See #3529677: `JavaScriptComponent`'s CSS library (prod/draft) should depend on global `AssetLibrary`'s asset library (prod/draft) for inspiration.
wim leers’s picture

Issue tags: +AI-accelerated

Oh, a crucial bit I forgot:

In Drupal 11, how does the cacheability for `drupalSettings` get associated with the response?

— I

  • Settings added in system_js_settings_build() are cached and reused
  • Settings added in system_js_settings_alter() are regenerated on every request

— Claude

This is why in the commit I pushed, I used hook_js_settings_alter(). XB doesn't create any new problem/challenge then, but just piggybacks on what Drupal core does 👍

wim leers’s picture

Paired with @isholgueras to get #12.2 working. Got it working, but not in the way I liked. So I dug deeper. Turns out we're running into a core bug: #3533354: `AssetResolver::getJsSettingsAssets()` calls `::getLibrariesToLoad()` with wrong asset type. Worked around it in https://git.drupalcode.org/project/experience_builder/-/merge_requests/1... 👍

Over to @isholgueras to address the remaining feedback — we're on the same page 🥳

wim leers’s picture

Assigned: isholgueras » Unassigned
Status: Needs work » Reviewed & tested by the community
Issue tags: -Needs tests

Much better! 🤩

wim leers’s picture

Status: Reviewed & tested by the community » Fixed

isholgueras’s picture

Assigned: Unassigned » isholgueras
Status: Fixed » Needs work

After chatting with @balintbrews, the resolution for this issue is not correct.

drupalSettings.xbData should be in global scope and appear only once. This branch does too much and it has some errors:
- The preview (top right) doesn't work. When users create code, the client is not yet talking to the backend.
- The non-compiled code wont work.

The front-end API will consume this settings with methods (not decided yet) like getPageData() (for title and breadcrumb) and getSiteData() (for base URL and branding).

effulgentsia’s picture

Assigned: isholgueras » Unassigned
Status: Needs work » Fixed

From chatting with @balintbrews, as I understand it there's only two problems with what got merged here:

  1. #3533458: Change CodeComponentDataProvider::getRequiredXbDataLibraries() to base its logic on information provided by the front-end rather than on naive string/regex matching (that issue had already been opened previously, I just now re-titled it).
  2. #3533535: Attach `xbData.*` asset library when loading XB UI, for use by the code component editor (I just now filed that issue).

Assuming it's only those two problems, let's handle them there, and I'm moving this one back to Fixed.

Status: Fixed » Closed (fixed)

Automatically closed - issue fixed for 2 weeks with no activity.