diff --git a/core/lib/Drupal/Core/Asset/AssetResolver.php b/core/lib/Drupal/Core/Asset/AssetResolver.php
index 251b9036f3a5de4bb265531c5b461f5d9b28fbbf..4c6875b000ff6aa511cbd08fa9431ede3c0d7b11 100644
--- a/core/lib/Drupal/Core/Asset/AssetResolver.php
+++ b/core/lib/Drupal/Core/Asset/AssetResolver.php
@@ -143,10 +143,10 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, Languag
       'preprocess' => TRUE,
     ];
 
-    foreach ($libraries_to_load as $library) {
+    foreach ($libraries_to_load as $key => $library) {
       [$extension, $name] = explode('/', $library, 2);
       $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
-      if (isset($definition['css'])) {
+      if (!empty($definition['css'])) {
         foreach ($definition['css'] as $options) {
           $options += $default_options;
           // Copy the asset library license information to each file.
@@ -165,6 +165,9 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, Languag
           $css[$options['data']] = $options;
         }
       }
+      else {
+        unset($libraries_to_load[$key]);
+      }
     }
 
     // Allow modules and themes to alter the CSS assets.
@@ -176,7 +179,7 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize, Languag
       uasort($css, [static::class, 'sort']);
 
       if ($optimize) {
-        $css = \Drupal::service('asset.css.collection_optimizer')->optimize($css, $libraries_to_load, $language);
+        $css = \Drupal::service('asset.css.collection_optimizer')->optimize($css, array_values($libraries_to_load), $language);
       }
     }
     $this->cache->set($cid, $css, CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
@@ -240,14 +243,20 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, Language
       ];
 
       // Collect all libraries that contain JS assets and are in the header.
+      // Also remove any libraries with no JavaScript from the libraries to
+      // load.
       $header_js_libraries = [];
-      foreach ($libraries_to_load as $library) {
+      foreach ($libraries_to_load as $key => $library) {
         [$extension, $name] = explode('/', $library, 2);
         $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
         if (isset($definition['js']) && !empty($definition['header'])) {
           $header_js_libraries[] = $library;
         }
+        if (empty($definition['js'])) {
+          unset($libraries_to_load[$key]);
+        }
       }
+      $libraries_to_load = array_values($libraries_to_load);
       // 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.
@@ -256,28 +265,26 @@ public function getJsAssets(AttachedAssetsInterface $assets, $optimize, Language
       foreach ($libraries_to_load as $library) {
         [$extension, $name] = explode('/', $library, 2);
         $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
-        if (isset($definition['js'])) {
-          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;
-          }
+        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;
         }
       }