Overview

If I have a code component with CSS using a variable defined in global CSS, it isn't available. That's because the AssetLibrary CSS library is one o the last stylesheets added.

Proposed resolution

Make all code component libraries depend on the global AssetLibrary's asset library.

User interface changes

None.

CommentFileSizeAuthor
#4 image (2).png13.71 KBlibbna
#4 image (1).png25.06 KBlibbna
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

mglaman created an issue. See original summary.

libbna’s picture

Assigned: Unassigned » libbna

Giving it a try on this.

libbna’s picture

Hi @mglaman,

Could you please share the steps to reproduce this issue?

Below are the steps I followed—please let me know if they are correct or if I’m missing something. The CSS appears to be getting applied, but I’m not sure if I’m approaching it the right way. I’d appreciate your guidance on this.

Thanks!

  1. I created a new component in the XB page - Test Component
  2. Added a Title prop of type text
  3. In the code editor - global css - I declared a variable
    :root {
      --brand-color: #0074D9;
    }
  4. In css section and used the variable as text color
    .test-box {
        color: var(--brand-color);
      }
  5. last, I used the .test-box is js code.
libbna’s picture

StatusFileSize
new25.06 KB
new13.71 KB

I again tried but couldn't reproduce the issue. In the last comment I forgot to attach the screenshot so I have attached it now!

wim leers’s picture

The problem/challenge here is that it's possible that both the code component (JavaScriptComponent config entity)'s and the AssetLibrary config entity (only a single one allowed for now, with the ID global) can have a draft (auto-saved) version.

So dependencies don't quite end up working, because it depends on the context which should be loaded:

  private static function shouldLoadAssetFromAutoSave(AutoSaveData $autoSave, bool $isPreview) : bool {
    return $isPreview && !$autoSave->isEmpty();
  }

which is then used by \Drupal\experience_builder\Entity\JavaScriptComponent::getCssLibrary():

  public function getCssLibrary(AutoSaveData $autoSave, bool $isPreview): ?string {
    // @see \Drupal\experience_builder\Hook\LibraryHooks::libraryInfoBuild()
    $css_library = 'experience_builder/astro_island.' . $this->id();
    $has_css = $this->hasCss();
    if (self::shouldLoadAssetFromAutoSave($autoSave, $isPreview)) {
      $css_library .= '.draft';
      \assert($autoSave->data !== NULL);
      $has_css = self::forAutoSavePreview($autoSave->data)->hasCss();
    }
    return $has_css ? $css_library : NULL;
  }

isPreview will be true when editing inside XB, not outside of it, and an auto-save entry can (dis)appear at any time. Similar thing for the global asset library:

    // Load the auto-save/draft version of the global asset library in the XB UI.
    $global_asset_library = AssetLibrary::load(AssetLibrary::GLOBAL_ID);
    assert($global_asset_library instanceof AssetLibrary);

    $auto_saved_global_asset_library = NULL;
    $auto_save = $this->autoSaveManager->getAutoSaveData($global_asset_library);
    if (!$auto_save->isEmpty()) {
      \assert($auto_save->data !== NULL);
      $auto_saved_global_asset_library = $global_asset_library->forAutoSavePreview($auto_save->data);
    }
    $page['#cache']['tags'][] = AutoSaveManager::CACHE_TAG;
    $page['#attached']['library'][] = $auto_saved_global_asset_library !== NULL ?
      'experience_builder/asset_library.' . AssetLibrary::GLOBAL_ID . '.draft' :
      'experience_builder/asset_library.' . AssetLibrary::GLOBAL_ID;

\Drupal\experience_builder\Hook\ComponentSourceHooks::pageAttachments()

libbna’s picture

Assigned: libbna » Unassigned
wim leers’s picture

Title: JavaScriptComponent CSS libraries should depend on AssetLibrary libraries » `JavaScriptComponent`'s CSS library (prod/draft) should depend on global `AssetLibrary`'s asset library (prod/draft)
Assigned: Unassigned » mglaman
Status: Active » Needs review

However … the work I did on #3508922: Regression after #3500386: import map scope mismatch when previewed code component's JS is a 307 due to it not having an auto-save/draft gave me an idea:

  1. let ApiConfigAutoSaveControllers::getCss() and ApiConfigAutoSaveControllers::getJs() do the disambiguation: return auto-save data if it exists, return stored/live data if not
  2. always load the "draft" inside XB, even if no auto-save entry exists
  3. … which means I can create a "draft" asset library for the code component, which can always depend on the "draft" asset library for the global asset library
  4. This should work?

Can you test this, @mglaman? Quick manual test suggests it works fine. 😊

larowlan’s picture

Just a couple of minor nits about the use of the verbose match for booleans

wim leers’s picture

Assigned: mglaman » Unassigned
Status: Needs review » Reviewed & tested by the community

All tests are passing, the tests are pretty detailed, manual testing reveals no regressions and … this really does simplify the "asset loading" logic of config-defined CSS/JS a lot. It makes all this much easier to reason about.

Only +1s from @larowlan, so going ahead and RTBC'ing even ahead of @mglaman's manual testing.

wim leers’s picture

Issue summary: View changes

  • wim leers committed 76c8b0f7 on 0.x
    Issue #3529677 by wim leers, mglaman, larowlan: `JavaScriptComponent`'s...
wim leers’s picture

Status: Reviewed & tested by the community » Fixed

Status: Fixed » Closed (fixed)

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