diff --git a/core/core.services.yml b/core/core.services.yml index 6ac951f..d73f6b5 100644 --- a/core/core.services.yml +++ b/core/core.services.yml @@ -1535,7 +1535,7 @@ services: arguments: ['@library.discovery'] asset.resolver: class: Drupal\Core\Asset\AssetResolver - arguments: ['@library.discovery', '@library.dependency_resolver', '@module_handler', '@theme.manager', '@language_manager', '@cache.data', '@asset.css.collection_optimizer', '@asset.js.collection_optimizer'] + arguments: ['@library.discovery', '@library.dependency_resolver', '@module_handler', '@theme.manager', '@language_manager', '@cache.data'] info_parser: class: Drupal\Core\Extension\InfoParser twig: diff --git a/core/lib/Drupal/Core/Asset/AssetGroupSetHashTrait.php b/core/lib/Drupal/Core/Asset/AssetGroupSetHashTrait.php new file mode 100644 index 0000000..e9f41cd --- /dev/null +++ b/core/lib/Drupal/Core/Asset/AssetGroupSetHashTrait.php @@ -0,0 +1,28 @@ + $group) { + foreach ($group['items'] as $key => $asset) { + unset($normalized[$order]['items'][$key]['weight']); + } + } + return hash('sha256', serialize($normalized)); + } +} diff --git a/core/lib/Drupal/Core/Asset/AssetResolver.php b/core/lib/Drupal/Core/Asset/AssetResolver.php index 003d88c..3ffd7a9 100644 --- a/core/lib/Drupal/Core/Asset/AssetResolver.php +++ b/core/lib/Drupal/Core/Asset/AssetResolver.php @@ -285,7 +285,7 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) { $js_assets_header = []; $js_assets_footer = []; foreach ($javascript as $key => $item) { - if ($item['scope'] == 'header') { + if ($item['scope'] == 'header' && $item['type'] !== 'setting') { $js_assets_header[$key] = $item; } elseif ($item['scope'] == 'footer') { @@ -295,7 +295,9 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize) { if ($optimize) { $collection_optimizer = \Drupal::service('asset.js.collection_optimizer'); - $js_assets_header = $collection_optimizer->optimize($js_assets_header); + if ($js_assets_header) { + $js_assets_header = $collection_optimizer->optimize($js_assets_header); + } $js_assets_footer = $collection_optimizer->optimize($js_assets_footer); } diff --git a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php index 59ad098..125240a 100644 --- a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php +++ b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php @@ -9,6 +9,7 @@ * Optimizes CSS assets. */ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface { + use AssetGroupSetHashTrait; /** * A CSS asset grouper. @@ -114,25 +115,6 @@ public function optimize(array $css_assets) { } /** - * Generate a hash for a given group of assets. - * - * @param array $group - * A group of assets. - * - * @return string - * A hash to uniquely identify the given group of assets. - */ - protected function generateHash(array $group) { - $normalized = $group; - foreach ($normalized as $order => $group) { - foreach ($group['items'] as $key => $asset) { - unset($normalized[$order]['items'][$key]['weight']); - } - } - return hash('sha256', serialize($normalized)); - } - - /** * {@inheritdoc} */ public function getAll() { diff --git a/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php b/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php index c35dd7b..d636a4d 100644 --- a/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php +++ b/core/lib/Drupal/Core/Asset/JsCollectionOptimizer.php @@ -50,13 +50,8 @@ public function __construct(AssetCollectionGrouperInterface $grouper, ThemeManag public function optimize(array $js_assets) { // Group the assets. $js_groups = $this->grouper->group($js_assets); + $key = $this->generateHash($js_groups); - // Now optimize (concatenate, not minify) and dump each asset group, unless - // that was already done, in which case it should appear in - // system.js_cache_files. - // Drupal contrib can override this default JS aggregator to keep the same - // grouping, optimizing and dumping, but change the strategy that is used to - // determine when the aggregate should be rebuilt (e.g. mtime, HTTPS …). $js_assets = array(); foreach ($js_groups as $order => $js_group) { // We have to return a single asset, not a group of assets. It is now up @@ -92,23 +87,24 @@ public function optimize(array $js_assets) { break; } } - - // Generate a URL for the group, but do not process it inline, this is - // done by \Drupal\system\controller\JsAssetController - $minimal_set = \Drupal::service('library.dependency_resolver')->getMinimalRepresentativeSubset($libraries); - $theme_name = $this->themeManager->getActiveTheme()->getName(); - $ajax_page_state = \Drupal::request()->get('ajax_page_state'); - $already_loaded = isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : []; - $minimal_already_loaded_set = \Drupal::service('library.dependency_resolver')->getMinimalRepresentativeSubset($already_loaded); - $header_query = UrlHelper::buildQuery(['libraries' => $minimal_set, 'theme' => $theme_name, 'already_loaded' => $minimal_already_loaded_set, 'scope' => 'header']); - $footer_query = UrlHelper::buildQuery(['libraries' => $minimal_set, 'theme' => $theme_name, 'already_loaded' => $minimal_already_loaded_set, 'scope' => 'footer']); - $path = 'public://' . 'js'; - foreach ($js_assets as $order => $js_asset) { - if (!empty($js_asset['preprocessed'])) { - $query = $js_asset['scope'] == 'header' ? $header_query : $footer_query; - $filename = 'js' . '_' . $order . '_' . $key . '.' . 'js'; - $uri = $path . '/' . $filename; - $js_assets[$order]['data'] = file_create_url($uri) . '?' . $query; + if ($libraries) { + // Generate a URL for the group, but do not process it inline, this is + // done by \Drupal\system\controller\JsAssetController + $minimal_set = \Drupal::service('library.dependency_resolver')->getMinimalRepresentativeSubset($libraries); + $theme_name = $this->themeManager->getActiveTheme()->getName(); + $ajax_page_state = \Drupal::request()->get('ajax_page_state'); + $already_loaded = isset($ajax_page_state) ? explode(',', $ajax_page_state['libraries']) : []; + $minimal_already_loaded_set = \Drupal::service('library.dependency_resolver')->getMinimalRepresentativeSubset($already_loaded); + $header_query = UrlHelper::buildQuery(['libraries' => $minimal_set, 'theme' => $theme_name, 'already_loaded' => $minimal_already_loaded_set, 'scope' => 'header']); + $footer_query = UrlHelper::buildQuery(['libraries' => $minimal_set, 'theme' => $theme_name, 'already_loaded' => $minimal_already_loaded_set, 'scope' => 'footer']); + $path = 'public://' . 'js'; + foreach ($js_assets as $order => $js_asset) { + if (!empty($js_asset['preprocessed'])) { + $query = $js_asset['scope'] == 'header' ? $header_query : $footer_query; + $filename = 'js' . '_' . $order . '_' . $key . '.' . 'js'; + $uri = $path . '/' . $filename; + $js_assets[$order]['data'] = file_create_url($uri) . '?' . $query; + } } } @@ -116,20 +112,22 @@ public function optimize(array $js_assets) { } /** - * Generate a hash for a given group of JavaScript assets. + * Generate a hash for a given group of assets. * - * @param array $js_group - * A group of JavaScript assets. + * @param array $groups + * A group of assets. * * @return string - * A hash to uniquely identify the given group of JavaScript assets. + * A hash to uniquely identify the given group of assets. */ - protected function generateHash(array $js_group) { - $js_data = array(); - foreach ($js_group['items'] as $js_file) { - $js_data[] = $js_file['data']; + protected function generateHash(array $groups) { + $normalized = $groups; + foreach ($normalized as $order => $group) { + foreach ($group['items'] as $key => $asset) { + unset($normalized[$order]['items'][$key]['weight']); + } } - return hash('sha256', serialize($js_data)); + return hash('sha256', serialize($normalized)); } /** diff --git a/core/modules/system/src/Controller/AssetControllerBase.php b/core/modules/system/src/Controller/AssetControllerBase.php index 1128485..b2a32fa 100644 --- a/core/modules/system/src/Controller/AssetControllerBase.php +++ b/core/modules/system/src/Controller/AssetControllerBase.php @@ -77,26 +77,24 @@ protected $assetType; /** - * The asset aggregate mimetype. + * The aggregate file extension. * * @var string */ - protected $mimeType; + protected $fileExtension; /** - * The aggregate file extension. + * The asset aggregate content type to send as Content-Type header. * * @var string */ - protected $fileExtension; + protected $contentType; /** * The cache control header to use. */ protected $cacheControl = 'private, no-store'; - - /** * Constructs a CssAssetController object. * @@ -218,7 +216,7 @@ public function deliver(Request $request, $file_name) { $uri = $this->dumper->dump($data, $this->assetType, $uri); } $headers = [ - 'Content-Type' => $this->mimeType, + 'Content-Type' => $this->contentType, 'Cache-control' => $this->cacheControl, ]; // Generate response. @@ -231,25 +229,6 @@ public function deliver(Request $request, $file_name) { } /** - * Generate a hash for a given group of assets. - * - * @param array $asset_group - * A group of assets. - * - * @return string - * A hash to uniquely identify the given group of assets. - */ - protected function generateHash(array $asset_group) { - $normalized = $asset_group; - foreach ($normalized as $order => $group) { - foreach ($group['items'] as $key => $asset) { - unset($normalized[$order]['items'][$key]['weight']); - } - } - return hash('sha256', serialize($normalized)); - } - - /** * Get assets of a certain type given attached assets. * * @param AttachedAssetsInterface $attached_assets diff --git a/core/modules/system/src/Controller/CssAssetController.php b/core/modules/system/src/Controller/CssAssetController.php index 6102521..8796880 100644 --- a/core/modules/system/src/Controller/CssAssetController.php +++ b/core/modules/system/src/Controller/CssAssetController.php @@ -5,13 +5,14 @@ use Symfony\Component\DependencyInjection\ContainerInterface; use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; - use Drupal\Core\Asset\AttachedAssetsInterface; +use Drupal\Core\Asset\AssetGroupSetHashTrait; /** * Defines a controller to serve CSS aggregates. */ class CssAssetController extends AssetControllerBase { + use AssetGroupSetHashTrait; /** * {@inheritdoc} diff --git a/core/modules/system/src/Controller/JsAssetController.php b/core/modules/system/src/Controller/JsAssetController.php index b44ef1b..de6a142 100644 --- a/core/modules/system/src/Controller/JsAssetController.php +++ b/core/modules/system/src/Controller/JsAssetController.php @@ -6,17 +6,20 @@ use Symfony\Component\HttpKernel\Exception\BadRequestHttpException; use Drupal\Core\Asset\AttachedAssetsInterface; +use Drupal\Core\Asset\AssetGroupSetHashTrait; /** * Defines a controller to serve Javascript aggregates. */ class JsAssetController extends AssetControllerBase { + use AssetGroupSetHashTrait; + /** * {@inheritdoc} */ public function __construct($library_dependency_resolver, $asset_resolver, $theme_initialization, $theme_manager, $grouper, $optimizer, $dumper) { - $this->mimeType = 'application/javascript'; + $this->contentType = 'application/javascript'; $this->assetType = 'js'; parent::__construct($library_dependency_resolver, $asset_resolver, $theme_initialization, $theme_manager, $grouper, $optimizer, $dumper); } @@ -49,6 +52,13 @@ protected function getKeyAndGroup(AttachedAssetsInterface $attached_assets, $gro throw new BadRequestHttpException('The URL must have a scope query argument.'); } $assets = $scope == 'header' ? $js_assets_header : $js_assets_footer; + // While the asset resolver will find setting, these are never aggregated, + // so filter them out. Settings are always in the header. + if ($scope == 'header') { + $assets = array_filter($assets, function($item) { + return $item['type'] !== 'setting'; + }); + } // Group the assets. $groups = $this->grouper->group($assets); if (!isset($groups[$group_delta]['preprocess'])) { @@ -60,8 +70,6 @@ protected function getKeyAndGroup(AttachedAssetsInterface $attached_assets, $gro 'group' => $group, 'key' => $key, ]; - - return []; } /**