Loading core/core.libraries.yml +53 −58 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ internal.backbone: url: https://raw.githubusercontent.com/jashkenas/backbone/1.6.1/LICENSE gpl-compatible: true js: assets/vendor/backbone/backbone-min.js: { weight: -19, minified: true, preprocess: false } assets/vendor/backbone/backbone-min.js: { minified: true, preprocess: false } dependencies: - core/internal.underscore Loading Loading @@ -356,8 +356,8 @@ drupal: js: 'drupal' version: VERSION js: misc/drupal.js: { weight: -18 } misc/drupal.init.js: { weight: -17 } misc/drupal.js: {} misc/drupal.init.js: {} dependencies: - core/drupalSettings drupalSettings: Loading @@ -368,9 +368,7 @@ drupalSettings: js: 'drupal' version: VERSION js: # Need to specify a negative weight like drupal.js until # https://www.drupal.org/node/1945262 is resolved. misc/drupalSettingsLoader.js: { weight: -18 } misc/drupalSettingsLoader.js: {} drupalSettings: # These placeholder values will be set by system_js_settings_alter(). path: Loading Loading @@ -440,44 +438,44 @@ loadjs: internal.jquery_ui: version: VERSION js: # All weights are based on the requirements defined within each file. assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/data-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/jquery-patch-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/scroll-parent-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/unique-id-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/focusable-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/keycode-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/plugin-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/widget-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/version-min.js: { weight: -11.9, minified: true } # These JavaScript assets previously came from core/jquery.ui, a deprecated # library. # @todo replace with solution in https://drupal.org/node/3076171 assets/vendor/jquery.ui/ui/version-min.js: { minified: true } assets/vendor/jquery.ui/ui/data-min.js: { minified: true } assets/vendor/jquery.ui/ui/disable-selection-min.js: { minified: true } assets/vendor/jquery.ui/ui/focusable-min.js: { minified: true } assets/vendor/jquery.ui/ui/jquery-patch-min.js: { minified: true } assets/vendor/jquery.ui/ui/keycode-min.js: { minified: true } assets/vendor/jquery.ui/ui/plugin-min.js: { minified: true } assets/vendor/jquery.ui/ui/scroll-parent-min.js: { minified: true } assets/vendor/jquery.ui/ui/widget-min.js: { minified: true } assets/vendor/jquery.ui/ui/unique-id-min.js: { minified: true } assets/vendor/jquery.ui/ui/labels-min.js: { minified: true } css: component: assets/vendor/jquery.ui/themes/base/core.css: { weight: -11.8 } assets/vendor/jquery.ui/themes/base/core.css: {} theme: assets/vendor/jquery.ui/themes/base/theme.css: { weight: -11.8 } assets/vendor/jquery.ui/themes/base/theme.css: {} dependencies: - core/jquery drupal.autocomplete: version: VERSION js: misc/autocomplete.js: { weight: -1 } # The remaining JavaScript assets previously came from core/jquery.ui, a # deprecated library. # All weights are based on the requirements defined within each file. # @todo replace with solution in https://drupal.org/node/3076171 assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/widgets/menu-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/widgets/menu-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js: { minified: true } misc/autocomplete.js: {} # All CSS assets previously came from core/jquery.ui, a deprecated library. # @todo replace with solution found in https://drupal.org/node/3076171 css: component: assets/vendor/jquery.ui/themes/base/autocomplete.css: { weight: -11.7 } assets/vendor/jquery.ui/themes/base/menu.css: { weight: -11.7 } misc/components/autocomplete-loading.module.css: { weight: -10 } assets/vendor/jquery.ui/themes/base/menu.css: {} assets/vendor/jquery.ui/themes/base/autocomplete.css: {} misc/components/autocomplete-loading.module.css: {} dependencies: - core/jquery - core/internal.jquery_ui Loading Loading @@ -530,31 +528,29 @@ drupal.dialog: version: VERSION js: misc/dialog/dialog-deprecation.js: {} # The remaining JavaScript assets previously came from core/jquery.ui, a # deprecated library. assets/vendor/tua-body-scroll-lock/tua-bsl.umd.min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js: { minified: true } assets/vendor/jquery.ui/ui/form-reset-mixin-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/mouse-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/draggable-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/resizable-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/checkboxradio-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/button-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/dialog-min.js: { minified: true } misc/dialog/dialog.js: {} misc/dialog/dialog.position.js: {} misc/dialog/dialog.jquery-ui.js: {} # The remaining JavaScript assets previously came from core/jquery.ui, a # deprecated library. # All weights are based on the requirements defined within each file. # @todo replace with solution in https://drupal.org/node/2158943 assets/vendor/jquery.ui/ui/widgets/dialog-min.js: { weight: -11.4, minified: true } assets/vendor/jquery.ui/ui/widgets/button-min.js: { weight: -11.5, minified: true } assets/vendor/jquery.ui/ui/widgets/checkboxradio-min.js: { weight: -11.6, minified: true } assets/vendor/jquery.ui/ui/widgets/draggable-min.js: { weight: -11.6, minified: true } assets/vendor/jquery.ui/ui/widgets/resizable-min.js: { weight: -11.6, minified: true } assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/form-reset-mixin-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/widgets/mouse-min.js: { weight: -11.7, minified: true } assets/vendor/tua-body-scroll-lock/tua-bsl.umd.min.js: { weight: -1, minified: true } # All CSS assets previously came from core/jquery.ui, a deprecated library. # @todo replace with solution found in https://drupal.org/node/2158943 css: component: assets/vendor/jquery.ui/themes/base/dialog.css: { weight: -11.4 } assets/vendor/jquery.ui/themes/base/button.css: { weight: -11.5 } assets/vendor/jquery.ui/themes/base/checkboxradio.css: { weight: -11.6 } assets/vendor/jquery.ui/themes/base/resizable.css: { weight: -11.6 } assets/vendor/jquery.ui/themes/base/controlgroup.css: { weight: -11.7 } assets/vendor/jquery.ui/themes/base/dialog.css: {} assets/vendor/jquery.ui/themes/base/button.css: {} assets/vendor/jquery.ui/themes/base/controlgroup.css: {} assets/vendor/jquery.ui/themes/base/checkboxradio.css: {} assets/vendor/jquery.ui/themes/base/resizable.css: {} dependencies: - core/jquery - core/internal.jquery_ui Loading Loading @@ -753,12 +749,11 @@ drupal.tabbingmanager: drupal.tabledrag: version: VERSION js: misc/tabledrag.js: { weight: -1 } misc/tabledrag.js: {} css: component: misc/components/tabledrag.module.css: {} misc/components/tree-child.module.css: {} dependencies: - core/jquery - core/drupal Loading Loading @@ -835,7 +830,7 @@ drupal.touchevents-test: header: true version: VERSION js: misc/touchevents-test.js: { weight: -21 } misc/touchevents-test.js: {} drupal.vertical-tabs: version: VERSION Loading @@ -850,9 +845,10 @@ drupal.vertical-tabs: - core/drupal - core/drupalSettings - core/drupal.form before: - core/drupal.collapse htmx: aggregate_target: js: 'htmx' remote: https://github.com/bigskysoftware/htmx version: "2.0.4" license: Loading @@ -860,7 +856,7 @@ htmx: url: https://raw.githubusercontent.com/bigskysoftware/htmx/refs/tags/v2.0.4/LICENSE gpl-compatible: true js: assets/vendor/htmx/htmx.min.js: { minified: true } assets/vendor/htmx/htmx.min.js: { minified: true, preprocess: false } internal.floating-ui: aggregate_target: Loading Loading @@ -888,7 +884,7 @@ jquery: # across different aggregates which can include different combinations of # libraries that depend on jQuery, so that it is only downloaded once per # browser instead of potentially multiple times from different pages. assets/vendor/jquery/jquery.min.js: { preprocess: false, minified: true, weight: -20 } assets/vendor/jquery/jquery.min.js: { preprocess: false, minified: true } internal.jquery.form: # Internal library. Do not depend on it outside core nor add new core usage. Loading Loading @@ -921,7 +917,7 @@ normalize: gpl-compatible: true css: base: assets/vendor/normalize-css/normalize.css: { weight: -20 } assets/vendor/normalize-css/normalize.css: {} once: remote: https://git.drupalcode.org/project/once Loading @@ -931,7 +927,7 @@ once: url: https://git.drupalcode.org/project/once/-/raw/v1.0.1/LICENSE.md gpl-compatible: true js: assets/vendor/once/once.min.js: { weight: -19, minified: true, preprocess: false } assets/vendor/once/once.min.js: { minified: true, preprocess: false } sortable: remote: https://github.com/SortableJS/Sortable Loading @@ -951,7 +947,7 @@ tabbable: url: https://raw.githubusercontent.com/focus-trap/tabbable/v6.3.0/LICENSE gpl-compatible: true js: assets/vendor/tabbable/index.umd.min.js: { weight: -1, minified: true, preprocess: false } assets/vendor/tabbable/index.umd.min.js: { minified: true, preprocess: false } transliteration: remote: https://github.com/dzcpy/transliteration Loading @@ -977,8 +973,7 @@ internal.underscore: url: https://raw.githubusercontent.com/jashkenas/underscore/1.13.8/LICENSE gpl-compatible: true js: assets/vendor/underscore/underscore-min.js: { weight: -20, minified: true, preprocess: false } assets/vendor/underscore/underscore-min.js: { minified: true, preprocess: false } drupal.dialog.off_canvas: version: VERSION Loading core/lib/Drupal/Core/Asset/AssetResolver.php +22 −11 Original line number Diff line number Diff line Loading @@ -262,6 +262,17 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, ?Langua [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name); foreach ($definition['css'] as $options) { // Libraries are loaded based on dependencies, then their attaching // order. Individual asset files are ordered how they are defined within // the library itself. // Re-adding an asset file will rewrite the resulting array leading to // an incorrect order of asset files, i.e. the last occurrence of the // particular asset will win, but the desired behavior is the opposite - // the first occurrence must win. // So, let's skip processing of already added asset files. if (array_key_exists($options['data'], $css)) { continue; } $options += $default_options; // Copy the asset library license information to each file. $options['license'] = $definition['license']; Loading @@ -270,11 +281,6 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, ?Langua if ($options['type'] === 'file' && $options['preprocess'] && str_contains($options['data'], '?')) { $options['preprocess'] = FALSE; } // Always add a tiny value to the weight, to conserve the insertion // order. $options['weight'] += count($css) / 30000; $options['library'] = $library; $options['aggregate_target'] = $definition['aggregate_target'] ?? ['js' => FALSE, 'css' => FALSE]; Loading Loading @@ -392,6 +398,17 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?Languag [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name); foreach ($definition['js'] as $options) { // Libraries are loaded based on dependencies, then their attaching // order. Individual asset files are ordered how they are defined // within the library itself. // Re-adding an asset file will rewrite the resulting array leading to // an incorrect order of asset files, i.e. the last occurrence of the // particular asset will win, but the desired behavior is the opposite // - the first occurrence must win. // So, let's skip processing of already added asset files. if (array_key_exists($options['data'], $javascript)) { continue; } $options += $default_options; // Copy the asset library license information to each file. $options['license'] = $definition['license']; Loading @@ -404,13 +421,8 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?Languag // 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; $options['library'] = $library; $options['aggregate_target'] = $definition['aggregate_target'] ?? ['js' => FALSE, 'css' => FALSE]; // 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; Loading Loading @@ -480,7 +492,6 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?Languag $settings_as_inline_javascript = [ 'type' => 'setting', 'group' => JS_SETTING, 'weight' => 0, 'data' => $settings, ]; $settings_js_asset = ['drupalSettings' => $settings_as_inline_javascript]; Loading core/lib/Drupal/Core/Asset/LibraryDependencyResolver.php +71 −33 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ namespace Drupal\Core\Asset; use Drupal\Component\Graph\Graph; /** * Resolves the dependencies of asset (CSS/JavaScript) libraries. */ Loading @@ -14,13 +16,6 @@ class LibraryDependencyResolver implements LibraryDependencyResolverInterface { */ protected $libraryDiscovery; /** * The libraries dependencies. * * @var array */ protected $librariesDependencies = []; /** * Constructs a new LibraryDependencyResolver instance. * Loading @@ -35,14 +30,20 @@ public function __construct(LibraryDiscoveryInterface $library_discovery) { * {@inheritdoc} */ public function getLibrariesWithDependencies(array $libraries) { $return = []; foreach ($libraries as $library) { if (!isset($this->librariesDependencies[$library])) { $this->librariesDependencies[$library] = $this->doGetDependencies([$library]); } $return += $this->librariesDependencies[$library]; $libraries_graph = $this->doGetDependencies($libraries); $libraries_graph = $this->doProcessBeforeAfter($libraries_graph); $graph_object = new Graph($libraries_graph); $graph = $graph_object->searchAndSort(); uasort($graph, function ($a, $b) { if ($a['weight'] == $b['weight']) { return 0; } return array_values($return); return ($a['weight'] < $b['weight']) ? 1 : -1; }); return array_keys($graph); } /** Loading @@ -50,29 +51,67 @@ public function getLibrariesWithDependencies(array $libraries) { * * Helper method for ::getLibrariesWithDependencies(). * * @param string[] $libraries_with_unresolved_dependencies * A list of libraries, with unresolved dependencies, in the order they * should be loaded. * @param string[] $final_libraries * The final list of libraries (the return value) that is being built * recursively. * @param string[] $libraries * A list of libraries in the order they should be loaded. * @param array $graph * The graph of libraries that is being built recursively. * * @return string[] * A list of libraries, in the order they should be loaded, including their * dependencies. */ protected function doGetDependencies(array $libraries_with_unresolved_dependencies, array $final_libraries = []) { foreach ($libraries_with_unresolved_dependencies as $library) { if (!isset($final_libraries[$library])) { protected function doGetDependencies(array $libraries, array $graph = []) { foreach ($libraries as $library) { if (!isset($graph[$library])) { [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name); if ($definition) { $graph[$library]['edges'] = []; } if (!empty($definition['dependencies'])) { $final_libraries = $this->doGetDependencies($definition['dependencies'], $final_libraries); foreach ($definition['dependencies'] as $dependency) { $graph[$library]['edges'][$dependency] = $dependency; } $graph = $this->doGetDependencies($definition['dependencies'], $graph); } } $final_libraries[$library] = $library; } return $graph; } /** * Processes before and after settings for the libraries graph. * * @param array $graph * The libraries graph array. * * @return array * The libraries graph with before and after processed. */ protected function doProcessBeforeAfter($graph): array { foreach ($graph as $library => $data) { [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name) + [ 'after' => [], 'before' => [], ]; foreach ($definition['after'] as $after) { if (isset($graph[$after])) { $graph[$library]['edges'][$after] = $after; } return $final_libraries; } foreach ($definition['before'] as $before) { if (isset($graph[$before])) { $graph[$before]['edges'][$library] = $library; } } } return $graph; } /** Loading @@ -81,15 +120,14 @@ protected function doGetDependencies(array $libraries_with_unresolved_dependenci public function getMinimalRepresentativeSubset(array $libraries) { assert(count($libraries) === count(array_unique($libraries)), '$libraries can\'t contain duplicate items.'); // Determine each library's dependencies. $all_dependencies = []; foreach ($libraries as $library) { $with_deps = $this->getLibrariesWithDependencies([$library]); // We don't need library itself listed in the dependencies. $all_dependencies = array_unique(array_merge($all_dependencies, array_diff($with_deps, [$library]))); $graph = $this->doGetDependencies($libraries); $libraries_to_exclude = []; foreach ($graph as $vertex) { $libraries_to_exclude += $vertex['edges']; } return array_values(array_diff($libraries, array_intersect($all_dependencies, $libraries))); return array_values(array_diff($libraries, $libraries_to_exclude)); } } core/modules/ckeditor5/src/Hook/Ckeditor5Hooks.php +6 −33 Original line number Diff line number Diff line Loading @@ -352,41 +352,14 @@ public function jsAlter(&$javascript, AttachedAssetsInterface $assets, LanguageI $translations_library = 'core/ckeditor5.translations'; if (in_array($translations_library, $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getLibraries()), TRUE) || in_array($translations_library, $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()), TRUE)) { // This file is used to get a weight that will make it possible to // aggregate all translation files in a single aggregate. $ckeditor_dll_file = 'core/assets/vendor/ckeditor5/ckeditor5-dll/ckeditor5-dll.js'; // Use the placeholder file weight to set all the translations files // weights so they can be aggregated together as expected. Account for // requests where the library is not loaded such as when during an AJAX // request when it was already loaded via the main request. In these cases // it is unlikely that multiple JavaScript aggregates will be created // anyway since AJAX requests generally result in very few libraries being // loaded. $default_weight = $javascript[$placeholder_file]['weight'] ?? 0; if (isset($javascript[$ckeditor_dll_file])) { $default_weight = $javascript[$ckeditor_dll_file]['weight']; } $ckeditor5_language = $this->languageMapper->getMapping($language->getId()); // Remove all CKEditor 5 translations files that are not in the current // language. foreach ($javascript as $index => &$item) { // This is not a CKEditor 5 translation file, skip it. if (empty($item['ckeditor5_langcode'])) { continue; } // This file is the correct translation for this page. if ($item['ckeditor5_langcode'] === $ckeditor5_language) { // Set the weight for the translation file to be able to have the // translation files aggregated. $item['weight'] = $default_weight; } else { // Remove files that don't match the language requested. unset($javascript[$index]); } } $ckeditor5_language = $this->languageMapper->getMapping($language->getId()); $javascript = array_filter($javascript, function ($item) use ($ckeditor5_language) { // Skip files that are not CKEditor5 translation files. Remove files // that don't match the language requested. return empty($item['ckeditor5_langcode']) || $item['ckeditor5_langcode'] === $ckeditor5_language; }); } // The placeholder file is not a real file, remove it from the list. unset($javascript[$placeholder_file]); Loading core/modules/ckeditor5/tests/src/Unit/CKEditor5Test.php +1 −9 Original line number Diff line number Diff line Loading @@ -125,7 +125,6 @@ public static function providerPathsToFormNames(): array { * @legacy-covers \Drupal\ckeditor5\Hook\Ckeditor5Hooks::jsAlter */ public function testJsAlterHook(): void { $placeholder_file = 'core/assets/vendor/ckeditor5/translation.js'; $language_mapper = $this->createMock(LanguageMapper::class); $language_mapper->expects($this->any()) ->method('getMapping') Loading Loading @@ -167,7 +166,6 @@ public function testJsAlterHook(): void { $expected_javascript = [ 'keep_this' => [ 'ckeditor5_langcode' => 'en', 'weight' => 5, ], 'keep_this_too' => [], ]; Loading @@ -179,11 +177,7 @@ public function testJsAlterHook(): void { \Drupal::setContainer($container); // First check that it filters when the placeholder script is present. $javascript = $original_javascript + [ $placeholder_file => [ 'weight' => 5, ], ]; $javascript = $original_javascript; $hooks->jsAlter($javascript, $assets, $language); $this->assertEquals($expected_javascript, $javascript); Loading @@ -199,8 +193,6 @@ public function testJsAlterHook(): void { ]); $javascript = $original_javascript; $hooks->jsAlter($javascript, $assets, $language); // There was no placeholder to get the weight from. $expected_javascript['keep_this']['weight'] = 0; $this->assertEquals($expected_javascript, $javascript); } Loading Loading
core/core.libraries.yml +53 −58 Original line number Diff line number Diff line Loading @@ -13,7 +13,7 @@ internal.backbone: url: https://raw.githubusercontent.com/jashkenas/backbone/1.6.1/LICENSE gpl-compatible: true js: assets/vendor/backbone/backbone-min.js: { weight: -19, minified: true, preprocess: false } assets/vendor/backbone/backbone-min.js: { minified: true, preprocess: false } dependencies: - core/internal.underscore Loading Loading @@ -356,8 +356,8 @@ drupal: js: 'drupal' version: VERSION js: misc/drupal.js: { weight: -18 } misc/drupal.init.js: { weight: -17 } misc/drupal.js: {} misc/drupal.init.js: {} dependencies: - core/drupalSettings drupalSettings: Loading @@ -368,9 +368,7 @@ drupalSettings: js: 'drupal' version: VERSION js: # Need to specify a negative weight like drupal.js until # https://www.drupal.org/node/1945262 is resolved. misc/drupalSettingsLoader.js: { weight: -18 } misc/drupalSettingsLoader.js: {} drupalSettings: # These placeholder values will be set by system_js_settings_alter(). path: Loading Loading @@ -440,44 +438,44 @@ loadjs: internal.jquery_ui: version: VERSION js: # All weights are based on the requirements defined within each file. assets/vendor/jquery.ui/ui/labels-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/data-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/disable-selection-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/jquery-patch-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/scroll-parent-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/unique-id-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/focusable-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/keycode-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/plugin-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/widget-min.js: { weight: -11.8, minified: true } assets/vendor/jquery.ui/ui/version-min.js: { weight: -11.9, minified: true } # These JavaScript assets previously came from core/jquery.ui, a deprecated # library. # @todo replace with solution in https://drupal.org/node/3076171 assets/vendor/jquery.ui/ui/version-min.js: { minified: true } assets/vendor/jquery.ui/ui/data-min.js: { minified: true } assets/vendor/jquery.ui/ui/disable-selection-min.js: { minified: true } assets/vendor/jquery.ui/ui/focusable-min.js: { minified: true } assets/vendor/jquery.ui/ui/jquery-patch-min.js: { minified: true } assets/vendor/jquery.ui/ui/keycode-min.js: { minified: true } assets/vendor/jquery.ui/ui/plugin-min.js: { minified: true } assets/vendor/jquery.ui/ui/scroll-parent-min.js: { minified: true } assets/vendor/jquery.ui/ui/widget-min.js: { minified: true } assets/vendor/jquery.ui/ui/unique-id-min.js: { minified: true } assets/vendor/jquery.ui/ui/labels-min.js: { minified: true } css: component: assets/vendor/jquery.ui/themes/base/core.css: { weight: -11.8 } assets/vendor/jquery.ui/themes/base/core.css: {} theme: assets/vendor/jquery.ui/themes/base/theme.css: { weight: -11.8 } assets/vendor/jquery.ui/themes/base/theme.css: {} dependencies: - core/jquery drupal.autocomplete: version: VERSION js: misc/autocomplete.js: { weight: -1 } # The remaining JavaScript assets previously came from core/jquery.ui, a # deprecated library. # All weights are based on the requirements defined within each file. # @todo replace with solution in https://drupal.org/node/3076171 assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/widgets/menu-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/widgets/menu-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/autocomplete-min.js: { minified: true } misc/autocomplete.js: {} # All CSS assets previously came from core/jquery.ui, a deprecated library. # @todo replace with solution found in https://drupal.org/node/3076171 css: component: assets/vendor/jquery.ui/themes/base/autocomplete.css: { weight: -11.7 } assets/vendor/jquery.ui/themes/base/menu.css: { weight: -11.7 } misc/components/autocomplete-loading.module.css: { weight: -10 } assets/vendor/jquery.ui/themes/base/menu.css: {} assets/vendor/jquery.ui/themes/base/autocomplete.css: {} misc/components/autocomplete-loading.module.css: {} dependencies: - core/jquery - core/internal.jquery_ui Loading Loading @@ -530,31 +528,29 @@ drupal.dialog: version: VERSION js: misc/dialog/dialog-deprecation.js: {} # The remaining JavaScript assets previously came from core/jquery.ui, a # deprecated library. assets/vendor/tua-body-scroll-lock/tua-bsl.umd.min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js: { minified: true } assets/vendor/jquery.ui/ui/form-reset-mixin-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/mouse-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/draggable-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/resizable-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/checkboxradio-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/button-min.js: { minified: true } assets/vendor/jquery.ui/ui/widgets/dialog-min.js: { minified: true } misc/dialog/dialog.js: {} misc/dialog/dialog.position.js: {} misc/dialog/dialog.jquery-ui.js: {} # The remaining JavaScript assets previously came from core/jquery.ui, a # deprecated library. # All weights are based on the requirements defined within each file. # @todo replace with solution in https://drupal.org/node/2158943 assets/vendor/jquery.ui/ui/widgets/dialog-min.js: { weight: -11.4, minified: true } assets/vendor/jquery.ui/ui/widgets/button-min.js: { weight: -11.5, minified: true } assets/vendor/jquery.ui/ui/widgets/checkboxradio-min.js: { weight: -11.6, minified: true } assets/vendor/jquery.ui/ui/widgets/draggable-min.js: { weight: -11.6, minified: true } assets/vendor/jquery.ui/ui/widgets/resizable-min.js: { weight: -11.6, minified: true } assets/vendor/jquery.ui/ui/widgets/controlgroup-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/form-reset-mixin-min.js: { weight: -11.7, minified: true } assets/vendor/jquery.ui/ui/widgets/mouse-min.js: { weight: -11.7, minified: true } assets/vendor/tua-body-scroll-lock/tua-bsl.umd.min.js: { weight: -1, minified: true } # All CSS assets previously came from core/jquery.ui, a deprecated library. # @todo replace with solution found in https://drupal.org/node/2158943 css: component: assets/vendor/jquery.ui/themes/base/dialog.css: { weight: -11.4 } assets/vendor/jquery.ui/themes/base/button.css: { weight: -11.5 } assets/vendor/jquery.ui/themes/base/checkboxradio.css: { weight: -11.6 } assets/vendor/jquery.ui/themes/base/resizable.css: { weight: -11.6 } assets/vendor/jquery.ui/themes/base/controlgroup.css: { weight: -11.7 } assets/vendor/jquery.ui/themes/base/dialog.css: {} assets/vendor/jquery.ui/themes/base/button.css: {} assets/vendor/jquery.ui/themes/base/controlgroup.css: {} assets/vendor/jquery.ui/themes/base/checkboxradio.css: {} assets/vendor/jquery.ui/themes/base/resizable.css: {} dependencies: - core/jquery - core/internal.jquery_ui Loading Loading @@ -753,12 +749,11 @@ drupal.tabbingmanager: drupal.tabledrag: version: VERSION js: misc/tabledrag.js: { weight: -1 } misc/tabledrag.js: {} css: component: misc/components/tabledrag.module.css: {} misc/components/tree-child.module.css: {} dependencies: - core/jquery - core/drupal Loading Loading @@ -835,7 +830,7 @@ drupal.touchevents-test: header: true version: VERSION js: misc/touchevents-test.js: { weight: -21 } misc/touchevents-test.js: {} drupal.vertical-tabs: version: VERSION Loading @@ -850,9 +845,10 @@ drupal.vertical-tabs: - core/drupal - core/drupalSettings - core/drupal.form before: - core/drupal.collapse htmx: aggregate_target: js: 'htmx' remote: https://github.com/bigskysoftware/htmx version: "2.0.4" license: Loading @@ -860,7 +856,7 @@ htmx: url: https://raw.githubusercontent.com/bigskysoftware/htmx/refs/tags/v2.0.4/LICENSE gpl-compatible: true js: assets/vendor/htmx/htmx.min.js: { minified: true } assets/vendor/htmx/htmx.min.js: { minified: true, preprocess: false } internal.floating-ui: aggregate_target: Loading Loading @@ -888,7 +884,7 @@ jquery: # across different aggregates which can include different combinations of # libraries that depend on jQuery, so that it is only downloaded once per # browser instead of potentially multiple times from different pages. assets/vendor/jquery/jquery.min.js: { preprocess: false, minified: true, weight: -20 } assets/vendor/jquery/jquery.min.js: { preprocess: false, minified: true } internal.jquery.form: # Internal library. Do not depend on it outside core nor add new core usage. Loading Loading @@ -921,7 +917,7 @@ normalize: gpl-compatible: true css: base: assets/vendor/normalize-css/normalize.css: { weight: -20 } assets/vendor/normalize-css/normalize.css: {} once: remote: https://git.drupalcode.org/project/once Loading @@ -931,7 +927,7 @@ once: url: https://git.drupalcode.org/project/once/-/raw/v1.0.1/LICENSE.md gpl-compatible: true js: assets/vendor/once/once.min.js: { weight: -19, minified: true, preprocess: false } assets/vendor/once/once.min.js: { minified: true, preprocess: false } sortable: remote: https://github.com/SortableJS/Sortable Loading @@ -951,7 +947,7 @@ tabbable: url: https://raw.githubusercontent.com/focus-trap/tabbable/v6.3.0/LICENSE gpl-compatible: true js: assets/vendor/tabbable/index.umd.min.js: { weight: -1, minified: true, preprocess: false } assets/vendor/tabbable/index.umd.min.js: { minified: true, preprocess: false } transliteration: remote: https://github.com/dzcpy/transliteration Loading @@ -977,8 +973,7 @@ internal.underscore: url: https://raw.githubusercontent.com/jashkenas/underscore/1.13.8/LICENSE gpl-compatible: true js: assets/vendor/underscore/underscore-min.js: { weight: -20, minified: true, preprocess: false } assets/vendor/underscore/underscore-min.js: { minified: true, preprocess: false } drupal.dialog.off_canvas: version: VERSION Loading
core/lib/Drupal/Core/Asset/AssetResolver.php +22 −11 Original line number Diff line number Diff line Loading @@ -262,6 +262,17 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, ?Langua [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name); foreach ($definition['css'] as $options) { // Libraries are loaded based on dependencies, then their attaching // order. Individual asset files are ordered how they are defined within // the library itself. // Re-adding an asset file will rewrite the resulting array leading to // an incorrect order of asset files, i.e. the last occurrence of the // particular asset will win, but the desired behavior is the opposite - // the first occurrence must win. // So, let's skip processing of already added asset files. if (array_key_exists($options['data'], $css)) { continue; } $options += $default_options; // Copy the asset library license information to each file. $options['license'] = $definition['license']; Loading @@ -270,11 +281,6 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, ?Langua if ($options['type'] === 'file' && $options['preprocess'] && str_contains($options['data'], '?')) { $options['preprocess'] = FALSE; } // Always add a tiny value to the weight, to conserve the insertion // order. $options['weight'] += count($css) / 30000; $options['library'] = $library; $options['aggregate_target'] = $definition['aggregate_target'] ?? ['js' => FALSE, 'css' => FALSE]; Loading Loading @@ -392,6 +398,17 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?Languag [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name); foreach ($definition['js'] as $options) { // Libraries are loaded based on dependencies, then their attaching // order. Individual asset files are ordered how they are defined // within the library itself. // Re-adding an asset file will rewrite the resulting array leading to // an incorrect order of asset files, i.e. the last occurrence of the // particular asset will win, but the desired behavior is the opposite // - the first occurrence must win. // So, let's skip processing of already added asset files. if (array_key_exists($options['data'], $javascript)) { continue; } $options += $default_options; // Copy the asset library license information to each file. $options['license'] = $definition['license']; Loading @@ -404,13 +421,8 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?Languag // 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; $options['library'] = $library; $options['aggregate_target'] = $definition['aggregate_target'] ?? ['js' => FALSE, 'css' => FALSE]; // 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; Loading Loading @@ -480,7 +492,6 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, ?Languag $settings_as_inline_javascript = [ 'type' => 'setting', 'group' => JS_SETTING, 'weight' => 0, 'data' => $settings, ]; $settings_js_asset = ['drupalSettings' => $settings_as_inline_javascript]; Loading
core/lib/Drupal/Core/Asset/LibraryDependencyResolver.php +71 −33 Original line number Diff line number Diff line Loading @@ -2,6 +2,8 @@ namespace Drupal\Core\Asset; use Drupal\Component\Graph\Graph; /** * Resolves the dependencies of asset (CSS/JavaScript) libraries. */ Loading @@ -14,13 +16,6 @@ class LibraryDependencyResolver implements LibraryDependencyResolverInterface { */ protected $libraryDiscovery; /** * The libraries dependencies. * * @var array */ protected $librariesDependencies = []; /** * Constructs a new LibraryDependencyResolver instance. * Loading @@ -35,14 +30,20 @@ public function __construct(LibraryDiscoveryInterface $library_discovery) { * {@inheritdoc} */ public function getLibrariesWithDependencies(array $libraries) { $return = []; foreach ($libraries as $library) { if (!isset($this->librariesDependencies[$library])) { $this->librariesDependencies[$library] = $this->doGetDependencies([$library]); } $return += $this->librariesDependencies[$library]; $libraries_graph = $this->doGetDependencies($libraries); $libraries_graph = $this->doProcessBeforeAfter($libraries_graph); $graph_object = new Graph($libraries_graph); $graph = $graph_object->searchAndSort(); uasort($graph, function ($a, $b) { if ($a['weight'] == $b['weight']) { return 0; } return array_values($return); return ($a['weight'] < $b['weight']) ? 1 : -1; }); return array_keys($graph); } /** Loading @@ -50,29 +51,67 @@ public function getLibrariesWithDependencies(array $libraries) { * * Helper method for ::getLibrariesWithDependencies(). * * @param string[] $libraries_with_unresolved_dependencies * A list of libraries, with unresolved dependencies, in the order they * should be loaded. * @param string[] $final_libraries * The final list of libraries (the return value) that is being built * recursively. * @param string[] $libraries * A list of libraries in the order they should be loaded. * @param array $graph * The graph of libraries that is being built recursively. * * @return string[] * A list of libraries, in the order they should be loaded, including their * dependencies. */ protected function doGetDependencies(array $libraries_with_unresolved_dependencies, array $final_libraries = []) { foreach ($libraries_with_unresolved_dependencies as $library) { if (!isset($final_libraries[$library])) { protected function doGetDependencies(array $libraries, array $graph = []) { foreach ($libraries as $library) { if (!isset($graph[$library])) { [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name); if ($definition) { $graph[$library]['edges'] = []; } if (!empty($definition['dependencies'])) { $final_libraries = $this->doGetDependencies($definition['dependencies'], $final_libraries); foreach ($definition['dependencies'] as $dependency) { $graph[$library]['edges'][$dependency] = $dependency; } $graph = $this->doGetDependencies($definition['dependencies'], $graph); } } $final_libraries[$library] = $library; } return $graph; } /** * Processes before and after settings for the libraries graph. * * @param array $graph * The libraries graph array. * * @return array * The libraries graph with before and after processed. */ protected function doProcessBeforeAfter($graph): array { foreach ($graph as $library => $data) { [$extension, $name] = explode('/', $library, 2); $definition = $this->libraryDiscovery->getLibraryByName($extension, $name) + [ 'after' => [], 'before' => [], ]; foreach ($definition['after'] as $after) { if (isset($graph[$after])) { $graph[$library]['edges'][$after] = $after; } return $final_libraries; } foreach ($definition['before'] as $before) { if (isset($graph[$before])) { $graph[$before]['edges'][$library] = $library; } } } return $graph; } /** Loading @@ -81,15 +120,14 @@ protected function doGetDependencies(array $libraries_with_unresolved_dependenci public function getMinimalRepresentativeSubset(array $libraries) { assert(count($libraries) === count(array_unique($libraries)), '$libraries can\'t contain duplicate items.'); // Determine each library's dependencies. $all_dependencies = []; foreach ($libraries as $library) { $with_deps = $this->getLibrariesWithDependencies([$library]); // We don't need library itself listed in the dependencies. $all_dependencies = array_unique(array_merge($all_dependencies, array_diff($with_deps, [$library]))); $graph = $this->doGetDependencies($libraries); $libraries_to_exclude = []; foreach ($graph as $vertex) { $libraries_to_exclude += $vertex['edges']; } return array_values(array_diff($libraries, array_intersect($all_dependencies, $libraries))); return array_values(array_diff($libraries, $libraries_to_exclude)); } }
core/modules/ckeditor5/src/Hook/Ckeditor5Hooks.php +6 −33 Original line number Diff line number Diff line Loading @@ -352,41 +352,14 @@ public function jsAlter(&$javascript, AttachedAssetsInterface $assets, LanguageI $translations_library = 'core/ckeditor5.translations'; if (in_array($translations_library, $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getLibraries()), TRUE) || in_array($translations_library, $this->libraryDependencyResolver->getLibrariesWithDependencies($assets->getAlreadyLoadedLibraries()), TRUE)) { // This file is used to get a weight that will make it possible to // aggregate all translation files in a single aggregate. $ckeditor_dll_file = 'core/assets/vendor/ckeditor5/ckeditor5-dll/ckeditor5-dll.js'; // Use the placeholder file weight to set all the translations files // weights so they can be aggregated together as expected. Account for // requests where the library is not loaded such as when during an AJAX // request when it was already loaded via the main request. In these cases // it is unlikely that multiple JavaScript aggregates will be created // anyway since AJAX requests generally result in very few libraries being // loaded. $default_weight = $javascript[$placeholder_file]['weight'] ?? 0; if (isset($javascript[$ckeditor_dll_file])) { $default_weight = $javascript[$ckeditor_dll_file]['weight']; } $ckeditor5_language = $this->languageMapper->getMapping($language->getId()); // Remove all CKEditor 5 translations files that are not in the current // language. foreach ($javascript as $index => &$item) { // This is not a CKEditor 5 translation file, skip it. if (empty($item['ckeditor5_langcode'])) { continue; } // This file is the correct translation for this page. if ($item['ckeditor5_langcode'] === $ckeditor5_language) { // Set the weight for the translation file to be able to have the // translation files aggregated. $item['weight'] = $default_weight; } else { // Remove files that don't match the language requested. unset($javascript[$index]); } } $ckeditor5_language = $this->languageMapper->getMapping($language->getId()); $javascript = array_filter($javascript, function ($item) use ($ckeditor5_language) { // Skip files that are not CKEditor5 translation files. Remove files // that don't match the language requested. return empty($item['ckeditor5_langcode']) || $item['ckeditor5_langcode'] === $ckeditor5_language; }); } // The placeholder file is not a real file, remove it from the list. unset($javascript[$placeholder_file]); Loading
core/modules/ckeditor5/tests/src/Unit/CKEditor5Test.php +1 −9 Original line number Diff line number Diff line Loading @@ -125,7 +125,6 @@ public static function providerPathsToFormNames(): array { * @legacy-covers \Drupal\ckeditor5\Hook\Ckeditor5Hooks::jsAlter */ public function testJsAlterHook(): void { $placeholder_file = 'core/assets/vendor/ckeditor5/translation.js'; $language_mapper = $this->createMock(LanguageMapper::class); $language_mapper->expects($this->any()) ->method('getMapping') Loading Loading @@ -167,7 +166,6 @@ public function testJsAlterHook(): void { $expected_javascript = [ 'keep_this' => [ 'ckeditor5_langcode' => 'en', 'weight' => 5, ], 'keep_this_too' => [], ]; Loading @@ -179,11 +177,7 @@ public function testJsAlterHook(): void { \Drupal::setContainer($container); // First check that it filters when the placeholder script is present. $javascript = $original_javascript + [ $placeholder_file => [ 'weight' => 5, ], ]; $javascript = $original_javascript; $hooks->jsAlter($javascript, $assets, $language); $this->assertEquals($expected_javascript, $javascript); Loading @@ -199,8 +193,6 @@ public function testJsAlterHook(): void { ]); $javascript = $original_javascript; $hooks->jsAlter($javascript, $assets, $language); // There was no placeholder to get the weight from. $expected_javascript['keep_this']['weight'] = 0; $this->assertEquals($expected_javascript, $javascript); } Loading