JsCollectionOptimizerLazy.php

Same filename in other branches
  1. 11.x core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php

Namespace

Drupal\Core\Asset

File

core/lib/Drupal/Core/Asset/JsCollectionOptimizerLazy.php

View source
<?php

namespace Drupal\Core\Asset;

use Drupal\Component\Datetime\TimeInterface;
use Drupal\Component\Utility\UrlHelper;
use Drupal\Core\Config\ConfigFactoryInterface;
use Drupal\Core\File\FileSystemInterface;
use Drupal\Core\File\FileUrlGeneratorInterface;
use Drupal\Core\Language\LanguageManagerInterface;
use Drupal\Core\Theme\ThemeManagerInterface;
use Symfony\Component\HttpFoundation\RequestStack;

/**
 * Optimizes JavaScript assets.
 */
class JsCollectionOptimizerLazy implements AssetCollectionGroupOptimizerInterface {
    use AssetGroupSetHashTrait;
    
    /**
     * Constructs a JsCollectionOptimizerLazy.
     *
     * @param \Drupal\Core\Asset\AssetCollectionGrouperInterface $grouper
     *   The grouper for JS assets.
     * @param \Drupal\Core\Asset\AssetOptimizerInterface $optimizer
     *   The asset optimizer.
     * @param \Drupal\Core\Theme\ThemeManagerInterface $themeManager
     *   The theme manager.
     * @param \Drupal\Core\Asset\LibraryDependencyResolverInterface $dependencyResolver
     *   The library dependency resolver.
     * @param \Symfony\Component\HttpFoundation\RequestStack $requestStack
     *   The request stack.
     * @param \Drupal\Core\File\FileSystemInterface $fileSystem
     *   The file system service.
     * @param \Drupal\Core\Config\ConfigFactoryInterface $configFactory
     *   The config factory.
     * @param \Drupal\Core\File\FileUrlGeneratorInterface $fileUrlGenerator
     *   The file URL generator.
     * @param \Drupal\Component\Datetime\TimeInterface $time
     *   The time service.
     * @param \Drupal\Core\Language\LanguageManagerInterface $languageManager
     *   The language manager.
     */
    public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, ThemeManagerInterface $themeManager, LibraryDependencyResolverInterface $dependencyResolver, RequestStack $requestStack, FileSystemInterface $fileSystem, ConfigFactoryInterface $configFactory, FileUrlGeneratorInterface $fileUrlGenerator, TimeInterface $time, LanguageManagerInterface $languageManager) {
    }
    
    /**
     * {@inheritdoc}
     */
    public function optimize(array $js_assets, array $libraries) {
        // File names are generated based on library/asset definitions. This
        // includes a hash of the assets and the group index. Additionally, the full
        // set of libraries, already loaded libraries and theme are sent as query
        // parameters to allow a PHP controller to generate a valid file with
        // sufficient information. Files are not generated by this method since
        // they're assumed to be successfully returned from the URL created whether
        // on disk or not.
        // Group the assets.
        $js_groups = $this->grouper
            ->group($js_assets);
        $js_assets = [];
        foreach ($js_groups as $order => $js_group) {
            // We have to return a single asset, not a group of assets. It is now up
            // to one of the pieces of code in the switch statement below to set the
            // 'data' property to the appropriate value.
            $js_assets[$order] = $js_group;
            switch ($js_group['type']) {
                case 'file':
                    // No preprocessing, single JS asset: just use the existing URI.
                    if (!$js_group['preprocess']) {
                        $uri = $js_group['items'][0]['data'];
                        $js_assets[$order]['data'] = $uri;
                    }
                    else {
                        // To reproduce the full context of assets outside of the request,
                        // we must know the entire set of libraries used to generate all CSS
                        // groups, whether or not files in a group are from a particular
                        // library or not.
                        $js_assets[$order]['preprocessed'] = TRUE;
                    }
                    break;
                case 'external':
                    // We don't do any aggregation and hence also no caching for external
                    // JS assets.
                    $uri = $js_group['items'][0]['data'];
                    $js_assets[$order]['data'] = $uri;
                    break;
                case 'setting':
                    $js_assets[$order]['data'] = $js_group['data'];
                    break;
            }
        }
        if ($libraries) {
            // All group URLs have the same query arguments apart from the delta and
            // scope, so prepare them in advance.
            $language = $this->languageManager
                ->getCurrentLanguage()
                ->getId();
            $query_args = [
                'language' => $language,
                'theme' => $this->themeManager
                    ->getActiveTheme()
                    ->getName(),
                'include' => UrlHelper::compressQueryParameter(implode(',', $this->dependencyResolver
                    ->getMinimalRepresentativeSubset($libraries))),
            ];
            $ajax_page_state = $this->requestStack
                ->getCurrentRequest()
                ->get('ajax_page_state');
            $already_loaded = isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : [];
            if ($already_loaded) {
                $query_args['exclude'] = UrlHelper::compressQueryParameter(implode(',', $this->dependencyResolver
                    ->getMinimalRepresentativeSubset($already_loaded)));
            }
            // Generate a URL for the group, but do not process it inline, this is
            // done by \Drupal\system\controller\JsAssetController.
            foreach ($js_assets as $order => $js_asset) {
                if (!empty($js_asset['preprocessed'])) {
                    $query = [
                        'scope' => $js_asset['scope'] === 'header' ? 'header' : 'footer',
                        'delta' => "{$order}",
                    ] + $query_args;
                    // Add a filename prefix to mitigate ad blockers which can block
                    // any script beginning with 'ad'.
                    $filename = 'js_' . $this->generateHash($js_asset) . '.js';
                    $uri = 'assets://js/' . $filename;
                    $js_assets[$order]['data'] = $this->fileUrlGenerator
                        ->generateString($uri) . '?' . UrlHelper::buildQuery($query);
                }
                unset($js_assets[$order]['items']);
            }
        }
        return $js_assets;
    }
    
    /**
     * {@inheritdoc}
     */
    public function getAll() {
        @trigger_error(__METHOD__ . ' is deprecated in drupal:10.2.0 and is removed from drupal:11.0.0. There is no replacement. See https://www.drupal.org/node/3301744', E_USER_DEPRECATED);
        return [];
    }
    
    /**
     * {@inheritdoc}
     */
    public function deleteAll() {
        $this->fileSystem
            ->deleteRecursive('assets://js');
    }
    
    /**
     * {@inheritdoc}
     */
    public function optimizeGroup(array $group) : string {
        $data = '';
        $current_license = FALSE;
        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);
    }

}

Classes

Title Deprecated Summary
JsCollectionOptimizerLazy Optimizes JavaScript assets.

Buggy or inaccurate documentation? Please file an issue. Need support? Need help programming? Connect with the Drupal community.