Component libraries are prioritized over theme ones

Created on 23 November 2024, 4 months ago

Problem/Motivation

All component libraries are registered with the “core” extension and the “components.[component-id]” library name. This causes problems because such libraries are treated by the LibraryDiscoveryParser as the “default group” (CSS_AGGREGATE_DEFAULT) even if the component is defined and only exists in the theme. However, libraries defined by the theme are forced into the “theme group” (CSS_AGGREGATE_THEME). This results in a broken sorting in \Drupal\Core\Asset\AssetResolver::sort. Since CSS_AGGREGATE_DEFAULT has priority over CSS_AGGREGATE_THEME, and everything else is ignored, even properly made dependencies are not considered.

This heavily breaks the CSS flow, because styles from components are always loaded before those from the theme. And if your styles rely on this (implying that components should override them, not define), it is broken. A simple example is CSS layers, which simply don't work in this workflow, because layer definitions should come first, and only then can they be used. However, since theme CSS with layer definitions is loaded after components, you cannot use them there.

Altering component libraries and adding the theme library as a dependency, which should come first, also won’t work because of library groups.

Steps to reproduce

Try to load CSS files from the theme before the component libraries are loaded on the page in any way. Something like this:

<link rel="stylesheet" media="all" href="/themes/custom/themename/css/layer.css">
<link rel="stylesheet" media="all" href="/core/../themes/custom/themename/components/foo/foo.css">

Proposed resolution

  1. The component libraries should be forced into the CSS_AGGREGATE_THEME group.
  2. Allow CSS libraries from the theme override group. This can be done in \Drupal\Core\Asset\LibraryDiscoveryParser::buildByExtension.
  3. Improve components documentation with a mention that “not a bug, but a feature” and how to workaround it.

Workaround

This workaround will change the group for the theme CSS file [theme]/css/layers.css to CSS_AGGREGATE_DEFAULT group, which, with a proper weight, will load it before component styles.

/**
 * Implements hook_css_alter().
 */
function MYTHEME_css_alter(array &$css, AttachedAssetsInterface $assets, LanguageInterface $language): void {
  $active_theme = \Drupal::service(ThemeManagerInterface::class)->getActiveTheme();
  $layers_path = $active_theme->getPath() . '/css/layer.css';

  if (array_key_exists($layers_path, $css)) {
    $css[$layers_path]['group'] = CSS_AGGREGATE_DEFAULT;
  }
}

Remaining tasks

Decide which way to go.

🐛 Bug report
Status

Active

Version

11.0 🔥

Component

single-directory components

Created by

🇷🇺Russia niklan Russia, Perm

Live updates comments and jobs are added and updated live.
Sign in to follow issues

Comments & Activities

Production build 0.71.5 2024