function AssetResolver::getJsAssets

Same name and namespace in other branches
  1. 11.x core/lib/Drupal/Core/Asset/AssetResolver.php \Drupal\Core\Asset\AssetResolver::getJsAssets()
  2. 10 core/lib/Drupal/Core/Asset/AssetResolver.php \Drupal\Core\Asset\AssetResolver::getJsAssets()
  3. 9 core/lib/Drupal/Core/Asset/AssetResolver.php \Drupal\Core\Asset\AssetResolver::getJsAssets()
  4. 8.9.x core/lib/Drupal/Core/Asset/AssetResolver.php \Drupal\Core\Asset\AssetResolver::getJsAssets()

File

core/lib/Drupal/Core/Asset/AssetResolver.php, line 288

Class

AssetResolver
The default asset resolver.

Namespace

Drupal\Core\Asset

Code

public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?LanguageInterface $language = NULL) {
  $asset_settings = $assets->getSettings();
  if (!$assets->getLibraries() && !$asset_settings) {
    return [
      [],
      [],
    ];
  }
  if (!isset($language)) {
    $language = $this->languageManager
      ->getCurrentLanguage();
  }
  $theme_info = $this->themeManager
    ->getActiveTheme();
  // Get the complete list of libraries to load including dependencies.
  $libraries_to_load = $this->getLibrariesToLoad($assets, 'js');
  // Collect all libraries that contain JS assets and are in the header.
  $header_js_libraries = [];
  foreach ($libraries_to_load as $key => $library) {
    [$extension, $name] = explode('/', $library, 2);
    $definition = $this->libraryDiscovery
      ->getLibraryByName($extension, $name);
    if (!empty($definition['header'])) {
      $header_js_libraries[] = $library;
    }
  }
  // If all the libraries to load contained only CSS, there is nothing further
  // to do here, so return early.
  if (!$libraries_to_load && !$asset_settings) {
    return [
      [],
      [],
    ];
  }
  // Add the theme name to the cache key since themes may implement
  // hook_library_info_alter(). Additionally add the current language to
  // support translation of JavaScript files via hook_js_alter().
  $cid = 'js:' . $theme_info->getName() . ':' . $language->getId() . ':' . Crypt::hashBase64(serialize($libraries_to_load)) . ':' . (int) $optimize;
  if ($cached = $this->cache
    ->get($cid)) {
    [$js_assets_header, $js_assets_footer, $settings, $settings_in_header] = $cached->data;
  }
  else {
    $javascript = [];
    $default_options = [
      'type' => 'file',
      'group' => JS_DEFAULT,
      'weight' => 0,
      'cache' => TRUE,
      'preprocess' => TRUE,
      'attributes' => [],
      'version' => NULL,
    ];
    // The current list of header JS libraries are only those libraries that
    // are in the header, but their dependencies must also be loaded for them
    // to function correctly, so update the list with those.
    $header_js_libraries = $this->libraryDependencyResolver
      ->getLibrariesWithDependencies($header_js_libraries);
    foreach ($libraries_to_load as $library) {
      [$extension, $name] = explode('/', $library, 2);
      $definition = $this->libraryDiscovery
        ->getLibraryByName($extension, $name);
      foreach ($definition['js'] as $options) {
        $options += $default_options;
        // Copy the asset library license information to each file.
        $options['license'] = $definition['license'];
        // 'scope' is a calculated option, based on which libraries are
        // marked to be loaded from the header (see above).
        $options['scope'] = in_array($library, $header_js_libraries) ? 'header' : 'footer';
        // Preprocess can only be set if caching is enabled and no
        // attributes are set.
        $options['preprocess'] = $options['cache'] && empty($options['attributes']) ? $options['preprocess'] : FALSE;
        // Always add a tiny value to the weight, to conserve the insertion
        // order.
        $options['weight'] += count($javascript) / 30000;
        // Local and external files must keep their name as the associative
        // key so the same JavaScript file is not added twice.
        $javascript[$options['data']] = $options;
      }
    }
    // Allow modules and themes to alter the JavaScript assets.
    $this->moduleHandler
      ->alter('js', $javascript, $assets, $language);
    $this->themeManager
      ->alter('js', $javascript, $assets, $language);
    // Sort JavaScript assets, so that they appear in the correct order.
    uasort($javascript, [
      static::class,
      'sort',
    ]);
    // Prepare the return value: filter JavaScript assets per scope.
    $js_assets_header = [];
    $js_assets_footer = [];
    foreach ($javascript as $key => $item) {
      if ($item['scope'] == 'header') {
        $js_assets_header[$key] = $item;
      }
      elseif ($item['scope'] == 'footer') {
        $js_assets_footer[$key] = $item;
      }
    }
    if ($optimize) {
      $collection_optimizer = \Drupal::service('asset.js.collection_optimizer');
      $js_assets_header = $collection_optimizer->optimize($js_assets_header, $libraries_to_load);
      $js_assets_footer = $collection_optimizer->optimize($js_assets_footer, $libraries_to_load);
    }
    // Always build settings from js libraries. They may or may not be
    // used later depending on whether the core/drupalSettings library is
    // requested.
    $settings = $this->getJsSettingsAssets($assets);
    // Allow modules to add cached JavaScript settings.
    $this->moduleHandler
      ->invokeAllWith('js_settings_build', function (callable $hook, string $module) use (&$settings, $assets) {
      $hook($settings, $assets);
    });
    $settings_in_header = in_array('core/drupalSettings', $header_js_libraries);
    $this->cache
      ->set($cid, [
      $js_assets_header,
      $js_assets_footer,
      $settings,
      $settings_in_header,
    ], CacheBackendInterface::CACHE_PERMANENT, [
      'library_info',
    ]);
  }
  // If the core/drupalSettings library is being loaded or is already
  // loaded, get the JavaScript settings assets, and convert them into a
  // single "regular" JavaScript asset. But only if there are settings to
  // add. Do the quickest checks first.
  $process_settings = FALSE;
  if (count($libraries_to_load) > 0 || count($asset_settings) > 0) {
    $process_settings = in_array('core/drupalSettings', $libraries_to_load) || in_array('core/drupalSettings', $this->libraryDependencyResolver
      ->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()));
  }
  if ($process_settings) {
    // Attached settings override both library definitions and
    // hook_js_settings_build().
    $settings = NestedArray::mergeDeepArray([
      $settings,
      $asset_settings,
    ], TRUE);
    // Allow modules and themes to alter the JavaScript settings.
    $this->moduleHandler
      ->alter('js_settings', $settings, $assets);
    $this->themeManager
      ->alter('js_settings', $settings, $assets);
    // Update the $assets object accordingly, so that it reflects the final
    // settings.
    $assets->setSettings($settings);
    // Convert ajaxPageState to a compressed string from an array, since it is
    // used by ajax.js to pass to AJAX requests as a query parameter.
    if (isset($settings['ajaxPageState']['libraries'])) {
      $settings['ajaxPageState']['libraries'] = UrlHelper::compressQueryParameter($settings['ajaxPageState']['libraries']);
    }
    $settings_as_inline_javascript = [
      'type' => 'setting',
      'group' => JS_SETTING,
      'weight' => 0,
      'data' => $settings,
    ];
    $settings_js_asset = [
      'drupalSettings' => $settings_as_inline_javascript,
    ];
    // Prepend to the list of JS assets, to render it first. Preferably in
    // the footer, but in the header if necessary.
    if ($settings_in_header) {
      $js_assets_header = $settings_js_asset + $js_assets_header;
    }
    else {
      $js_assets_footer = $settings_js_asset + $js_assets_footer;
    }
  }
  return [
    $js_assets_header,
    $js_assets_footer,
  ];
}

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