Only file JavaScript assets with preprocessing enabled can be optimized.

Created on 23 January 2024, 10 months ago
Updated 15 August 2024, 3 months ago

Problem/Motivation

Error when tries to load asset from google_tag.
The issue can be fixed using a workaround from https://www.drupal.org/project/google_tag/issues/3413105 πŸ› Only file JavaScript assets with preprocessing enabled can be optimized. Active

The website encountered an unexpected error. Please try again later.

Exception: Only file JavaScript assets with preprocessing enabled can be optimized. in Drupal\Core\Asset\JsOptimizer->optimize() (line 34 of core/lib/Drupal/Core/Asset/JsOptimizer.php).
Drupal\Core\Asset\JsCollectionOptimizerLazy->optimizeGroup() (Line: 183)
Drupal\system\Controller\AssetControllerBase->deliver()
call_user_func_array() (Line: 123)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 592)
Drupal\Core\Render\Renderer->executeInRenderContext() (Line: 124)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->wrapControllerExecutionInRenderContext() (Line: 97)
Drupal\Core\EventSubscriber\EarlyRenderingControllerWrapperSubscriber->Drupal\Core\EventSubscriber\{closure}() (Line: 181)
Symfony\Component\HttpKernel\HttpKernel->handleRaw() (Line: 76)
Symfony\Component\HttpKernel\HttpKernel->handle() (Line: 58)
Drupal\Core\StackMiddleware\Session->handle() (Line: 48)
Drupal\Core\StackMiddleware\KernelPreHandle->handle() (Line: 53)
Asm89\Stack\Cors->handle() (Line: 48)
Drupal\Core\StackMiddleware\ReverseProxyMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\NegotiationMiddleware->handle() (Line: 36)
Drupal\Core\StackMiddleware\AjaxPageState->handle() (Line: 55)
Drupal\http_headers_cleaner\Middleware\HttpHeadersCleanerMiddleware->handle() (Line: 51)
Drupal\Core\StackMiddleware\StackedHttpKernel->handle() (Line: 704)
Drupal\Core\DrupalKernel->handle() (Line: 19)

Why the core forces the assets to be minified?

Steps to reproduce

The problem seems to be
If the asset is not minified then it calls to optimize.
\Drupal\Core\Asset\JsCollectionOptimizer::optimize

                // Optimize this JS file, but only if it's not yet minified.
                if (isset($js_asset['minified']) && $js_asset['minified']) {
                  $data .= file_get_contents($js_asset['data']);
                }
                else {
                  $data .= $this->optimizer->optimize($js_asset);
                }

But if the preprocess is set to false, it throws an error, so the optimizers force the asset to be minified, and it gives a 500 Error when tries to load the asset.

\Drupal\Core\Asset\JsOptimizer::optimize

    if (!$js_asset['preprocess']) {
      throw new \Exception('Only file JavaScript assets with preprocessing enabled can be optimized.');
    }

Example from google_tag.libraries.yml

gtag:
  js:
    js/gtag.js: { preprocess: false }
  drupalSettings:
    gtag:
      tagId: null
      otherIds: []
      events: []
  dependencies:
    - core/drupalSettings
πŸ› Bug report
Status

Needs work

Version

11.0 πŸ”₯

Component
Asset libraryΒ  β†’

Last updated about 5 hours ago

No maintainer
Created by

πŸ‡ͺπŸ‡ΈSpain eduardo morales alberti Spain, πŸ‡ͺπŸ‡Ί

Live updates comments and jobs are added and updated live.
  • Needs tests

    The change is currently missing an automated test that fails when run with the original code, and succeeds when the bug has been fixed.

  • Needs issue summary update

    Issue summaries save everyone time if they are kept up-to-date. See Update issue summary task instructions.

Sign in to follow issues

Merge Requests

Comments & Activities

Not all content is available!

It's likely this issue predates Contrib.social: some issue and comment data are missing.

  • πŸ‡ͺπŸ‡ΈSpain eduardo morales alberti Spain, πŸ‡ͺπŸ‡Ί
  • Status changed to Needs work 10 months ago
  • πŸ‡ͺπŸ‡ΈSpain eduardo morales alberti Spain, πŸ‡ͺπŸ‡Ί
  • πŸ‡ͺπŸ‡ΈSpain eduardo morales alberti Spain, πŸ‡ͺπŸ‡Ί
  • πŸ‡·πŸ‡ΊRussia niklan Russia, Perm

    I'm facing the same issue. I don't understand the current logic. If the library doesn't want to be preprocessed, why is it automatically minified by default? In that case it makes no sense in preprocess: false.

    I believe the issue lies in the logic implemented in two methods: \Drupal\Core\Asset\JsCollectionOptimizerLazy::optimizeGroup and \Drupal\Core\Asset\JsCollectionOptimizer::optimize.

    The \Drupal\Core\Asset\JsCollectionOptimizer::optimize respects asset group preprocess status:

              if (!$js_group['preprocess']) {
                $uri = $js_group['items'][0]['data'];
                $js_assets[$order]['data'] = $uri;
              }
    

    The \Drupal\Core\Asset\JsCollectionOptimizerLazy::optimizeGroup function optimizes the group regardless of any conditions. It doesn't have a condition and simply moves on to the optimization process.

    This method should looks like:

      public function optimizeGroup(array $group): string {
        $data = '';
        $current_license = FALSE;
    
        // No preprocessing, single JS asset: just use the existing URI.
        if ($group['type'] === 'file' && !$group['preprocess']) {
          $data = file_get_contents($group['items'][0]['data']);
        }
        else {
          foreach ($group['items'] as $js_asset) {
            // Ensure license information is available as a comment after
            // optimization.
            if ($js_asset['license'] !== $current_license) {
              $data .= "/* @license " . $js_asset['license']['name'] . " " . $js_asset['license']['url'] . " */\n";
            }
            $current_license = $js_asset['license'];
            // Optimize this JS file, but only if it's not yet minified.
            if (isset($js_asset['minified']) && $js_asset['minified']) {
              $data .= file_get_contents($js_asset['data']);
            }
            else {
              $data .= $this->optimizer->optimize($js_asset);
            }
            // Append a ';' and a newline after each JS file to prevent them from
            // running together.
            $data .= ";\n";
          }
        }
    
        // Remove unwanted JS code that causes issues.
        return $this->optimizer->clean($data);
      }->optimizer->clean($data);
      }
    
  • Status changed to Needs review 5 months ago
  • πŸ‡·πŸ‡ΊRussia niklan Russia, Perm

    I created the MR with the fix and it works with the google_tag module. However, I'm still not sure about this part of the code: $data = file_get_contents($group['items'][0]['data']);. The same code occurs in the methodDrupal\Core\Asset\JsCollectionOptimizer::optimize. It seems that there may be more than one 'item' in the group, and in such a case, some content may be missing. Need some advice here is that safe or not.

  • πŸ‡·πŸ‡ΊRussia niklan Russia, Perm

    It also fails when using libraries with external dependencies, but with a slightly different exception.

    Only file JavaScript assets can be optimized.

    E.g. of such library:

    example:
      version: 1
      remote: https://example.com
      license:
        name: Example
        url: https://example.com/license
        gpl-compatible: true
      js:
        js/init.js: { }
        //example.com/script.js: { preprocess: false }
    

    The suggested solution won't work in this case because the type here is external, which is handled in the method \Drupal\Core\Asset\JsCollectionOptimizer::optimize, but not in the method \Drupal\Core\Asset\JsCollectionOptimizerLazy::optimizeGroup. But for now, I’m out of ideas on how to solve this issue for external libraries. The result of the lazy method should be optimized JavaScript.

    For those who have encountered this problem, I suggest explicitly setting the following in the code: {preprocess: false, minified: true} for such JavaScript files.

    It's also worth mentioning that the solution from MR and Drupal\Core\Asset\JsCollectionOptimizer::optimize does not include injecting library license information.

  • Status changed to Needs work 5 months ago
  • πŸ‡ΊπŸ‡ΈUnited States smustgrave

    Can the issue summary be updated to include any proposed solution and other relevant sections from the issue template.

    Previously was tagged for tests may be good to get those written and may help guide the fix.

  • πŸ‡©πŸ‡ͺGermany Anybody Porta Westfalica

    I can confirm this message keeps on filling our logs on larger projects.

  • πŸ‡ΊπŸ‡ΈUnited States jackfoust

    It appears this is also affecting the Stripe module.

  • πŸ‡ΊπŸ‡ΈUnited States firewaller

    We're seeing this too. Its odd that it would skip "minified" but not "preprocess = false" here if the optimize function is just going to throw an exception for "preprocess = false": https://git.drupalcode.org/project/drupal/-/blob/11.x/core/lib/Drupal/Co...

Production build 0.71.5 2024