diff --git a/core/lib/Drupal/Core/Asset/AssetResolver.php b/core/lib/Drupal/Core/Asset/AssetResolver.php index 35d6608256..6945011b08 100644 --- a/core/lib/Drupal/Core/Asset/AssetResolver.php +++ b/core/lib/Drupal/Core/Asset/AssetResolver.php @@ -259,7 +259,7 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, Language // Always add a tiny value to the weight, to conserve the insertion // order. - $options['weight'] += count($javascript) / 1000; + $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. diff --git a/core/modules/system/tests/modules/jqueryui_library_assets_test/jqueryui_library_assets_test.routing.yml b/core/modules/system/tests/modules/jqueryui_library_assets_test/jqueryui_library_assets_test.routing.yml index cb2ad14524..5a8a815d1e 100644 --- a/core/modules/system/tests/modules/jqueryui_library_assets_test/jqueryui_library_assets_test.routing.yml +++ b/core/modules/system/tests/modules/jqueryui_library_assets_test/jqueryui_library_assets_test.routing.yml @@ -1,7 +1,15 @@ jqueryui_library_asset_test_page: - path: '/jqueryui_library_assets_test/{library}' + path: '/jqueryui_library_assets_test' defaults: _controller: '\Drupal\jqueryui_library_assets_test\Controller\JqueryUiTestAssetsController::build' _title: 'Test jQuery UI asset loading order' requirements: _access: 'TRUE' + +jqueryui_library_asset_test_external: + path: '/jqueryui_library_assets_test_large' + defaults: + _controller: '\Drupal\jqueryui_library_assets_test\Controller\JqueryUiTestAssetsController::largeJavascriptDependencies' + _title: 'Test jQuery UI asset loading order with lots of intermediate assets' + requirements: + _access: 'TRUE' diff --git a/core/modules/system/tests/modules/jqueryui_library_assets_test/src/Controller/JqueryUiTestAssetsController.php b/core/modules/system/tests/modules/jqueryui_library_assets_test/src/Controller/JqueryUiTestAssetsController.php index 2db6550c68..4befade8f8 100644 --- a/core/modules/system/tests/modules/jqueryui_library_assets_test/src/Controller/JqueryUiTestAssetsController.php +++ b/core/modules/system/tests/modules/jqueryui_library_assets_test/src/Controller/JqueryUiTestAssetsController.php @@ -3,6 +3,7 @@ namespace Drupal\jqueryui_library_assets_test\Controller; use Drupal\Core\Controller\ControllerBase; +use Symfony\Component\HttpFoundation\Request; /** * Controller for testing jQuery UI asset loading order. @@ -12,23 +13,31 @@ class JqueryUiTestAssetsController extends ControllerBase { /** * Provides a page that loads a library. * - * @param string $library - * A pipe delimited list of library names. + * @param \Symfony\Component\HttpFoundation\Request $request + * The current request object, typically containing "library" query + * containing a pipe delimited list of library names. * * @return array * The render array. */ - public function build($library) { + public function build(Request $request) { + // @see https://www.drupal.org/project/drupal/issues/2741939 + $library = $request->query->get('library', ''); // If there are pipes in $library, they are separating multiple library // names. if (strpos($library, '|') !== FALSE) { $library = explode('|', $library); $library = array_map(function ($item) { - return "core/$item"; + if (strpos($item, '/') === FALSE) { + return "core/$item"; + } + return $item; }, $library); } else { - $library = "core/$library"; + if (strpos($library, '/') === FALSE) { + $library = "core/$library"; + } } return [ @@ -36,6 +45,35 @@ public function build($library) { '#attached' => [ 'library' => $library, ], + '#cache' => [ + 'max-age' => 0, + 'contexts' => [ + 'url.path', + 'url.query_args:library', + ], + ], + ]; + } + + /** + * Provides a page that loads jQuery UI as a library. + * + * With a large third party library in the middle of two other jquery.ui + * dependents. + * + * @return array + * The render array. + */ + public function largeJavascriptDependencies() { + return [ + '#markup' => 'I am a page for testing jQuery UI asset loading order when large asset dependencies are involved between two jquery.ui dependents.', + '#attached' => [ + 'library' => [ + 'core/drupal.dialog', + 'jqueryui_library_assets_test/many-dependencies', + 'core/drupal.autocomplete', + ], + ], ]; } diff --git a/core/tests/Drupal/FunctionalTests/Libraries/JqueryUiLibraryAssetsTest.php b/core/tests/Drupal/FunctionalTests/Libraries/JqueryUiLibraryAssetsTest.php index f92fd3c535..02d42f4fcc 100644 --- a/core/tests/Drupal/FunctionalTests/Libraries/JqueryUiLibraryAssetsTest.php +++ b/core/tests/Drupal/FunctionalTests/Libraries/JqueryUiLibraryAssetsTest.php @@ -216,7 +216,7 @@ protected function trimFilePath($path) { * @dataProvider providerTestAssetLoading */ public function testLibraryAssetLoadingOrder($library) { - $this->drupalGet("jqueryui_library_assets_test/$library"); + $this->drupalGet('jqueryui_library_assets_test', ['query' => ['library' => $library]]); $this->assertSession()->statusCodeEquals(200); // A pipe character in $libraries is delimiting multiple library names. @@ -227,6 +227,10 @@ public function testLibraryAssetLoadingOrder($library) { // libraries being tested. This will be used to confirm the configured // assets actually load on the test page. foreach ($libraries as $library_name) { + if (strpos($library_name, '/') !== FALSE) { + // Ignore if it's an external library. + continue; + } foreach (['css', 'js'] as $type) { $assets = $this->coreLibrariesWithJqueryUiAssets[$library_name][$type]; foreach ($assets as $asset) { @@ -297,7 +301,7 @@ public function testLibraryAssetLoadingOrder($library) { * @dataProvider providerTestAssetLoading */ public function testAssetLoadingUnchanged($library, array $expected_css, array $expected_js) { - $this->drupalGet("jqueryui_library_assets_test/$library"); + $this->drupalGet('jqueryui_library_assets_test', ['query' => ['library' => $library]]); $this->assertSession()->statusCodeEquals(200); // Find all jQuery UI CSS files loaded to the page. @@ -345,6 +349,90 @@ public function testAssetLoadingUnchanged($library, array $expected_css, array $ */ public function providerTestAssetLoading() { return [ + 'drupal.dialog|drupal.autocomplete' => [ + 'library' => 'drupal.dialog|drupal.autocomplete', + 'expected_css' => [ + 'core/assets/vendor/jquery.ui/themes/base/core.css', + 'core/assets/vendor/jquery.ui/themes/base/controlgroup.css', + 'core/assets/vendor/jquery.ui/themes/base/autocomplete.css', + 'core/assets/vendor/jquery.ui/themes/base/menu.css', + 'core/assets/vendor/jquery.ui/themes/base/checkboxradio.css', + 'core/assets/vendor/jquery.ui/themes/base/resizable.css', + 'core/assets/vendor/jquery.ui/themes/base/button.css', + 'core/assets/vendor/jquery.ui/themes/base/dialog.css', + 'core/assets/vendor/jquery.ui/themes/base/theme.css', + ], + 'expected_js' => [ + 'core/assets/vendor/jquery.ui/ui/data-min.js', + 'core/assets/vendor/jquery.ui/ui/disable-selection-min.js', + 'core/assets/vendor/jquery.ui/ui/escape-selector-min.js', + 'core/assets/vendor/jquery.ui/ui/focusable-min.js', + 'core/assets/vendor/jquery.ui/ui/form-min.js', + 'core/assets/vendor/jquery.ui/ui/form-reset-mixin-min.js', + 'core/assets/vendor/jquery.ui/ui/ie-min.js', + 'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js', + 'core/assets/vendor/jquery.ui/ui/keycode-min.js', + 'core/assets/vendor/jquery.ui/ui/labels-min.js', + 'core/assets/vendor/jquery.ui/ui/plugin-min.js', + 'core/assets/vendor/jquery.ui/ui/safe-active-element-min.js', + 'core/assets/vendor/jquery.ui/ui/safe-blur-min.js', + 'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js', + 'core/assets/vendor/jquery.ui/ui/unique-id-min.js', + 'core/assets/vendor/jquery.ui/ui/version-min.js', + 'core/assets/vendor/jquery.ui/ui/widget-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/button-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/checkboxradio-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/dialog-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/draggable-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/menu-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/mouse-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/resizable-min.js', + ], + ], + 'drupal.dialog|jqueryui_library_assets_test/many-dependencies|drupal.autocomplete' => [ + 'library' => 'drupal.dialog|jqueryui_library_assets_test/many-dependencies|drupal.autocomplete', + 'expected_css' => [ + 'core/assets/vendor/jquery.ui/themes/base/core.css', + 'core/assets/vendor/jquery.ui/themes/base/controlgroup.css', + 'core/assets/vendor/jquery.ui/themes/base/autocomplete.css', + 'core/assets/vendor/jquery.ui/themes/base/menu.css', + 'core/assets/vendor/jquery.ui/themes/base/checkboxradio.css', + 'core/assets/vendor/jquery.ui/themes/base/resizable.css', + 'core/assets/vendor/jquery.ui/themes/base/button.css', + 'core/assets/vendor/jquery.ui/themes/base/dialog.css', + 'core/assets/vendor/jquery.ui/themes/base/theme.css', + ], + 'expected_js' => [ + 'core/assets/vendor/jquery.ui/ui/data-min.js', + 'core/assets/vendor/jquery.ui/ui/disable-selection-min.js', + 'core/assets/vendor/jquery.ui/ui/escape-selector-min.js', + 'core/assets/vendor/jquery.ui/ui/focusable-min.js', + 'core/assets/vendor/jquery.ui/ui/form-min.js', + 'core/assets/vendor/jquery.ui/ui/form-reset-mixin-min.js', + 'core/assets/vendor/jquery.ui/ui/ie-min.js', + 'core/assets/vendor/jquery.ui/ui/jquery-1-7-min.js', + 'core/assets/vendor/jquery.ui/ui/keycode-min.js', + 'core/assets/vendor/jquery.ui/ui/labels-min.js', + 'core/assets/vendor/jquery.ui/ui/plugin-min.js', + 'core/assets/vendor/jquery.ui/ui/safe-active-element-min.js', + 'core/assets/vendor/jquery.ui/ui/safe-blur-min.js', + 'core/assets/vendor/jquery.ui/ui/scroll-parent-min.js', + 'core/assets/vendor/jquery.ui/ui/unique-id-min.js', + 'core/assets/vendor/jquery.ui/ui/version-min.js', + 'core/assets/vendor/jquery.ui/ui/widget-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/button-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/checkboxradio-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/dialog-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/draggable-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/menu-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/mouse-min.js', + 'core/assets/vendor/jquery.ui/ui/widgets/resizable-min.js', + ], + ], 'drupal.autocomplete' => [ 'library' => 'drupal.autocomplete', 'expected_css' => [