Problem/Motivation

It is currently up to any user of the library.discovery service (\Drupal\Core\Asset\LibraryDiscovery) to invoke hook_library-alter().

(Not to be confused with hook_library_info_alter(), which does get invoked by the responsible service.)

This is bad for:

  1. DX — it's annoying to do, unlike anything else, and fragile (if it's forgotten, then hook_library_alter() won't be invoked, with bad consequences…)
  2. performance — the results of hook_library_alter() are not statically cached as they should be and could hence result in the same hook being invoked multiple times (it should be called by any consumer of the library.discovery service)

On top of that, there currently is zero test coverage for hook_library_alter()!

Proposed resolution

Let LibraryDiscovery call it.

Remaining tasks

Review.

User interface changes

None.

API changes

None.

Comments

wim leers’s picture

Assigned: wim leers » Unassigned
Issue summary: View changes
Status: Active » Needs review
StatusFileSize
new7.33 KB

Status: Needs review » Needs work

The last submitted patch, 1: fix_hook_library_alter-2378263-1.patch, failed testing.

wim leers’s picture

Basically every test is failing on testbot… but not locally. Something fishy is going on with testbot. Retesting.

dawehner’s picture

Status: Needs work » Needs review

Patch looks fine!

  1. +++ b/core/lib/Drupal/Core/Asset/LibraryDiscovery.php
    @@ -22,22 +23,51 @@ class LibraryDiscovery implements LibraryDiscoveryInterface {
        * @param \Drupal\Core\Extension\ModuleHandlerInterface $module_handler
        *   The module handler.
    ...
    +  public function __construct(CacheCollectorInterface $library_discovery_collector, ModuleHandlerInterface $module_handler) {
    

    HAHA

  2. +++ b/core/lib/Drupal/Core/Asset/LibraryDiscovery.php
    @@ -22,22 +23,51 @@ class LibraryDiscovery implements LibraryDiscoveryInterface {
    -    return $this->collector->get($extension);
    +    if (!isset($this->libraryDefinitions[$extension])) {
    +      $libraries = $this->collector->get($extension);
    +      $this->libraryDefinitions[$extension] = [];
    +      foreach ($libraries as $name => $definition) {
    +        // Allow modules and themes to dynamically attach request and context
    +        // specific data for this library; e.g., localization.
    +        $this->moduleHandler->alter('library', $definition, $name);
    +        $this->libraryDefinitions[$extension][$name] = $definition;
    +      }
    +    }
    +
    +    return $this->libraryDefinitions[$extension];
       }
    

    I know its "out of scope" but can we think about not executing an alter hook for each library but rather once for all? What bout a follow up for both the static and dynamic alter hook?

Status: Needs review » Needs work

The last submitted patch, 1: fix_hook_library_alter-2378263-1.patch, failed testing.

hampercm’s picture

I attempted to test the patch submitted in #1 to see what was up. Applying the patch to an existing install of 8.0.x immediately broke the site. My attempts to recover by following the procedure at https://www.drupal.org/documentation/rebuild were unsuccessful, as well as attempts to perform a new install after zapping the database, settings.php, etc.

Browsing to /core/install.php at this point gave the following output:

Additional uncaught exception thrown while handling exception.

Original

LogicException: A stray drupal_render() invocation with $is_root_call = TRUE is causing bubbling of attached assets to break. in drupal_render() (line 2857 of /var/www/8.0.x/core/includes/common.inc).

drupal_render(Array, 1)
drupal_render_root(Array)
Drupal\Core\Render\BareHtmlPageRenderer->renderBarePage(Array, 'Error', Array, Array, 'install_page')
Drupal\Core\Render\BareHtmlPageRenderer->renderInstallPage(Array, 'Error', Array)
install_display_output(Array, Array)
_drupal_log_error(Array, 1)
_drupal_error_handler_real(4096, 'Argument 2 passed to Drupal\Core\Asset\LibraryDiscovery::__construct() must implement interface Drupal\Core\Extension\ModuleHandlerInterface, none given', '/var/www/8.0.x/core/lib/Drupal/Core/Asset/LibraryDiscovery.php', 50, Array)
_drupal_error_handler(4096, 'Argument 2 passed to Drupal\Core\Asset\LibraryDiscovery::__construct() must implement interface Drupal\Core\Extension\ModuleHandlerInterface, none given', '/var/www/8.0.x/core/lib/Drupal/Core/Asset/LibraryDiscovery.php', 50, Array)
Drupal\Core\Asset\LibraryDiscovery->__construct(Object)
ReflectionClass->newInstanceArgs(Array)
Symfony\Component\DependencyInjection\ContainerBuilder->createService(Object, 'library.discovery')
Symfony\Component\DependencyInjection\ContainerBuilder->get('library.discovery', 1)
Drupal\Core\DependencyInjection\ContainerBuilder->get('library.discovery')
Drupal::service('library.discovery')
_drupal_add_library('core/html5shiv')
drupal_process_attached(Array)
template_preprocess_html(Array, 'html', Array)
_theme('html', Array)
Drupal\Core\Theme\ThemeManager->render('html', Array)
drupal_render(Array)
Drupal\Core\Render\BareHtmlPageRenderer->renderBarePage(Array, 'Choose language', Array, Array, 'install_page')
Drupal\Core\Render\BareHtmlPageRenderer->renderInstallPage(Array, 'Choose language', Array)
install_display_output(Array, Array)
install_drupal()

Additional

LogicException: A stray drupal_render() invocation with $is_root_call = TRUE is causing bubbling of attached assets to break. in drupal_render() (line 2857 of /var/www/8.0.x/core/includes/common.inc).

drupal_render(Array, 1)
drupal_render_root(Array)
Drupal\Core\Render\BareHtmlPageRenderer->renderBarePage(Array, 'Error', Array, Array, 'install_page')
Drupal\Core\Render\BareHtmlPageRenderer->renderInstallPage(Array, 'Error', Array)
install_display_output(Array, Array)
_drupal_log_error(Array, 1)
_drupal_exception_handler(Object)

Running the patch through simplytest.me produced similar output. I'm guessing the patch that was submitted is in some way incomplete/incorrect.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new7.95 KB
new651 bytes

#4

  1. :)
  2. That's a good point. But indeed out of scope. Issue opened: #2378737: Consider not executing hook_library_(info)_alter() *per* library, but once for all

#7: thanks for confirming the bug :)


Fixed the patch. I forgot to include the hunk that updates core.services.yml… /facepalm!

Status: Needs review » Needs work

The last submitted patch, 8: fix_hook_library_alter-2378263-8.patch, failed testing.

wim leers’s picture

Status: Needs work » Needs review
StatusFileSize
new10.52 KB
new2.77 KB

Ok, so thanks to the implicit test coverage of hook_library_alter() for Color module and Locale module (which has a test for hook_library_alter(), but pretends it for hook_library_alter()… fixed!), I found a pretty crucial oversight in the patch, causing those 3 failures!

dawehner’s picture

Status: Needs review » Reviewed & tested by the community

Alright!

alexpott’s picture

Status: Reviewed & tested by the community » Fixed

This issue addresses a critical bug and is allowed per https://www.drupal.org/core/beta-changes. Committed 7d36a7c and pushed to 8.0.x. Thanks!

  • alexpott committed 7d36a7c on 8.0.x
    Issue #2378263 by Wim Leers: hook_library_alter() must be manually...

Status: Fixed » Closed (fixed)

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