Loading core/lib/Drupal/Core/Asset/AssetGroupSetHashTrait.php +6 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,12 @@ protected function generateHash(array $group): string { ]; foreach ($group['items'] as $key => $asset) { $normalized['asset_group']['items'][$key] = array_diff_key($asset, $group_keys, $omit_keys); // If the version is set to -1, this means there is no version in the // library definition. To ensure unique hashes when unversioned files // change, replace the version with a hash of the file contents. if ($asset['version'] === -1) { $normalized['asset_group']['items'][$key]['version'] = hash('xxh64', file_get_contents($asset['data'])); } } // The asset array ensures that a valid hash can only be generated via the // same code base. Additionally use the hash salt to ensure that hashes are Loading core/modules/system/tests/modules/unversioned_assets_test/unversioned_assets_test.info.yml 0 → 100644 +5 −0 Original line number Diff line number Diff line name: 'Unversioned assets test' type: module description: 'Tests that aggregates change when unversioned assets change' package: Testing version: VERSION core/modules/system/tests/modules/unversioned_assets_test/unversioned_assets_test.module 0 → 100644 +18 −0 Original line number Diff line number Diff line <?php /** * @file * Helper module for unversioned asset test. */ /** * Implements hook_library_info_build(). */ function unversioned_assets_test_library_info_alter(&$libraries, $extension) { if ($extension === 'system') { // Remove the version and provide an additional CSS file we can alter the // contents of . unset($libraries['base']['version']); $libraries['base']['css']['component']['public://test.css'] = ['weight' => -10]; } } core/tests/Drupal/FunctionalTests/Asset/UnversionedAssetTest.php 0 → 100644 +102 −0 Original line number Diff line number Diff line <?php namespace Drupal\FunctionalTests\Asset; use Drupal\Tests\BrowserTestBase; /** * Tests asset aggregation. * * @group asset */ class UnversionedAssetTest extends BrowserTestBase { /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * The file assets path settings value. */ protected $fileAssetsPath; /** * {@inheritdoc} */ protected static $modules = ['system', 'unversioned_assets_test']; /** * Tests that unversioned assets cause a new filename when changed. */ public function testUnversionedAssets(): void { $this->fileAssetsPath = $this->publicFilesDirectory; file_put_contents('public://test.css', '.original-content{display:none;}'); // Test aggregation with a custom file_assets_path. $this->config('system.performance')->set('css', [ 'preprocess' => TRUE, 'gzip' => TRUE, ])->save(); $this->config('system.performance')->set('js', [ 'preprocess' => TRUE, 'gzip' => TRUE, ])->save(); // Ensure that the library discovery cache is empty before the page is // requested and that updated asset URLs are rendered. \Drupal::service('cache.data')->deleteAll(); \Drupal::service('cache.page')->deleteAll(); $this->drupalGet('<front>'); $session = $this->getSession(); $page = $session->getPage(); $style_elements = $page->findAll('xpath', '//link[@rel="stylesheet"]'); $this->assertNotEmpty($style_elements); $href = NULL; foreach ($style_elements as $element) { if ($element->hasAttribute('href')) { $href = $element->getAttribute('href'); $url = $this->getAbsoluteUrl($href); // Not every script or style on a page is aggregated. if (!str_contains($url, $this->fileAssetsPath)) { continue; } $session = $this->getSession(); $session->visit($url); $this->assertSession()->statusCodeEquals(200); $aggregate = $session = $session->getPage()->getContent(); $this->assertStringContainsString('original-content', $aggregate); $this->assertStringNotContainsString('extra-stuff', $aggregate); } } $file = file_get_contents('public://test.css') . '.extra-stuff{display:none;}'; file_put_contents('public://test.css', $file); // Clear the library discovery and page caches again so that new URLs are // generated. \Drupal::service('cache.data')->deleteAll(); \Drupal::service('cache.page')->deleteAll(); $this->drupalGet('<front>'); $session = $this->getSession(); $page = $session->getPage(); $style_elements = $page->findAll('xpath', '//link[@rel="stylesheet"]'); $this->assertNotEmpty($style_elements); foreach ($style_elements as $element) { if ($element->hasAttribute('href')) { $new_href = $element->getAttribute('href'); $this->assertNotSame($new_href, $href); $url = $this->getAbsoluteUrl($new_href); // Not every script or style on a page is aggregated. if (!str_contains($url, $this->fileAssetsPath)) { continue; } $session = $this->getSession(); $session->visit($url); $this->assertSession()->statusCodeEquals(200); $aggregate = $session = $session->getPage()->getContent(); $this->assertStringContainsString('original-content', $aggregate); $this->assertStringContainsString('extra-stuff', $aggregate); } } } } Loading
core/lib/Drupal/Core/Asset/AssetGroupSetHashTrait.php +6 −0 Original line number Diff line number Diff line Loading @@ -36,6 +36,12 @@ protected function generateHash(array $group): string { ]; foreach ($group['items'] as $key => $asset) { $normalized['asset_group']['items'][$key] = array_diff_key($asset, $group_keys, $omit_keys); // If the version is set to -1, this means there is no version in the // library definition. To ensure unique hashes when unversioned files // change, replace the version with a hash of the file contents. if ($asset['version'] === -1) { $normalized['asset_group']['items'][$key]['version'] = hash('xxh64', file_get_contents($asset['data'])); } } // The asset array ensures that a valid hash can only be generated via the // same code base. Additionally use the hash salt to ensure that hashes are Loading
core/modules/system/tests/modules/unversioned_assets_test/unversioned_assets_test.info.yml 0 → 100644 +5 −0 Original line number Diff line number Diff line name: 'Unversioned assets test' type: module description: 'Tests that aggregates change when unversioned assets change' package: Testing version: VERSION
core/modules/system/tests/modules/unversioned_assets_test/unversioned_assets_test.module 0 → 100644 +18 −0 Original line number Diff line number Diff line <?php /** * @file * Helper module for unversioned asset test. */ /** * Implements hook_library_info_build(). */ function unversioned_assets_test_library_info_alter(&$libraries, $extension) { if ($extension === 'system') { // Remove the version and provide an additional CSS file we can alter the // contents of . unset($libraries['base']['version']); $libraries['base']['css']['component']['public://test.css'] = ['weight' => -10]; } }
core/tests/Drupal/FunctionalTests/Asset/UnversionedAssetTest.php 0 → 100644 +102 −0 Original line number Diff line number Diff line <?php namespace Drupal\FunctionalTests\Asset; use Drupal\Tests\BrowserTestBase; /** * Tests asset aggregation. * * @group asset */ class UnversionedAssetTest extends BrowserTestBase { /** * {@inheritdoc} */ protected $defaultTheme = 'stark'; /** * The file assets path settings value. */ protected $fileAssetsPath; /** * {@inheritdoc} */ protected static $modules = ['system', 'unversioned_assets_test']; /** * Tests that unversioned assets cause a new filename when changed. */ public function testUnversionedAssets(): void { $this->fileAssetsPath = $this->publicFilesDirectory; file_put_contents('public://test.css', '.original-content{display:none;}'); // Test aggregation with a custom file_assets_path. $this->config('system.performance')->set('css', [ 'preprocess' => TRUE, 'gzip' => TRUE, ])->save(); $this->config('system.performance')->set('js', [ 'preprocess' => TRUE, 'gzip' => TRUE, ])->save(); // Ensure that the library discovery cache is empty before the page is // requested and that updated asset URLs are rendered. \Drupal::service('cache.data')->deleteAll(); \Drupal::service('cache.page')->deleteAll(); $this->drupalGet('<front>'); $session = $this->getSession(); $page = $session->getPage(); $style_elements = $page->findAll('xpath', '//link[@rel="stylesheet"]'); $this->assertNotEmpty($style_elements); $href = NULL; foreach ($style_elements as $element) { if ($element->hasAttribute('href')) { $href = $element->getAttribute('href'); $url = $this->getAbsoluteUrl($href); // Not every script or style on a page is aggregated. if (!str_contains($url, $this->fileAssetsPath)) { continue; } $session = $this->getSession(); $session->visit($url); $this->assertSession()->statusCodeEquals(200); $aggregate = $session = $session->getPage()->getContent(); $this->assertStringContainsString('original-content', $aggregate); $this->assertStringNotContainsString('extra-stuff', $aggregate); } } $file = file_get_contents('public://test.css') . '.extra-stuff{display:none;}'; file_put_contents('public://test.css', $file); // Clear the library discovery and page caches again so that new URLs are // generated. \Drupal::service('cache.data')->deleteAll(); \Drupal::service('cache.page')->deleteAll(); $this->drupalGet('<front>'); $session = $this->getSession(); $page = $session->getPage(); $style_elements = $page->findAll('xpath', '//link[@rel="stylesheet"]'); $this->assertNotEmpty($style_elements); foreach ($style_elements as $element) { if ($element->hasAttribute('href')) { $new_href = $element->getAttribute('href'); $this->assertNotSame($new_href, $href); $url = $this->getAbsoluteUrl($new_href); // Not every script or style on a page is aggregated. if (!str_contains($url, $this->fileAssetsPath)) { continue; } $session = $this->getSession(); $session->visit($url); $this->assertSession()->statusCodeEquals(200); $aggregate = $session = $session->getPage()->getContent(); $this->assertStringContainsString('original-content', $aggregate); $this->assertStringContainsString('extra-stuff', $aggregate); } } } }