diff --git a/core/core.services.yml b/core/core.services.yml
index 62a0f3e..2229e08 100644
--- a/core/core.services.yml
+++ b/core/core.services.yml
@@ -1450,7 +1450,7 @@ services:
     arguments: [ '@state' ]
   asset.css.collection_optimizer:
     class: Drupal\Core\Asset\CssCollectionOptimizer
-    arguments: [ '@asset.css.collection_grouper', '@asset.css.optimizer', '@asset.css.dumper', '@state' ]
+    arguments: [ '@asset.css.collection_grouper', '@asset.css.optimizer', '@theme.manager' ]
   asset.css.optimizer:
     class: Drupal\Core\Asset\CssOptimizer
   asset.css.collection_grouper:
diff --git a/core/lib/Drupal/Core/Asset/AssetDumper.php b/core/lib/Drupal/Core/Asset/AssetDumper.php
index 0504fa4..9e0470b 100644
--- a/core/lib/Drupal/Core/Asset/AssetDumper.php
+++ b/core/lib/Drupal/Core/Asset/AssetDumper.php
@@ -21,13 +21,16 @@ class AssetDumper implements AssetDumperInterface {
    * the aggregated contents of the files in $data. This forces proxies and
    * browsers to download new CSS when the CSS changes.
    */
-  public function dump($data, $file_extension) {
-    // Prefix filename to prevent blocking by firewalls which reject files
-    // starting with "ad*".
-    $filename = $file_extension. '_' . Crypt::hashBase64($data) . '.' . $file_extension;
-    // Create the css/ or js/ path within the files folder.
+  public function dump($data, $file_extension, $uri = NULL) {
     $path = 'public://' . $file_extension;
-    $uri = $path . '/' . $filename;
+    if (!isset($uri)) {
+      // Prefix filename to prevent blocking by firewalls which reject files
+      // starting with "ad*".
+      $filename = $file_extension . '_' . Crypt::hashBase64($data) . '.' . $file_extension;
+      // Create the css/ or js/ path within the files folder.
+      $path = 'public://' . $file_extension;
+      $uri = $path . '/' . $filename;
+    }
     // Create the CSS or JS file.
     file_prepare_directory($path, FILE_CREATE_DIRECTORY);
     if (!file_exists($uri) && !file_unmanaged_save_data($data, $uri, FILE_EXISTS_REPLACE)) {
diff --git a/core/lib/Drupal/Core/Asset/AssetDumperInterface.php b/core/lib/Drupal/Core/Asset/AssetDumperInterface.php
index 5f70aa6..8b997eb 100644
--- a/core/lib/Drupal/Core/Asset/AssetDumperInterface.php
+++ b/core/lib/Drupal/Core/Asset/AssetDumperInterface.php
@@ -19,9 +19,12 @@
    * @param string $file_extension
    *   The file extension of this asset.
    *
+   * @param string $uri
+   *   (optional) The file URI to write to.
+   *
    * @return string
    *   An URI to access the dumped asset.
    */
-  public function dump($data, $file_extension);
+  public function dump($data, $file_extension, $uri);
 
 }
diff --git a/core/lib/Drupal/Core/Asset/AssetResolver.php b/core/lib/Drupal/Core/Asset/AssetResolver.php
index 742cb2c..c05e5f6 100644
--- a/core/lib/Drupal/Core/Asset/AssetResolver.php
+++ b/core/lib/Drupal/Core/Asset/AssetResolver.php
@@ -122,7 +122,24 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) {
     if ($cached = $this->cache->get($cid)) {
       return $cached->data;
     }
+    else {
+      $css = $this->getCssFromLibraries($libraries_to_load, $optimize);
+    }
+    if ($optimize) {
+      $css = \Drupal::service('asset.css.collection_optimizer')->optimize($css);
+    }
+    $this->cache->set($cid, $css, CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
+
+    return $css;
+
+  }
 
+  /**
+   * Get css assets based on a list of libraries.
+   * @todo: interface.
+   */
+  public function getCssFromLibraries($libraries, $optimize) {
+    $theme_info = $this->themeManager->getActiveTheme();
     $css = [];
     $default_options = [
       'type' => 'file',
@@ -133,7 +150,7 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) {
       'browsers' => [],
     ];
 
-    foreach ($libraries_to_load as $library) {
+    foreach ($libraries as $library) {
       list($extension, $name) = explode('/', $library, 2);
       $definition = $this->libraryDiscovery->getLibraryByName($extension, $name);
       if (isset($definition['css'])) {
@@ -152,6 +169,7 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) {
           // Always add a tiny value to the weight, to conserve the insertion
           // order.
           $options['weight'] += count($css) / 1000;
+          $options['library'] = $library;
 
           // CSS files are being keyed by the full path.
           $css[$options['data']] = $options;
@@ -176,11 +194,6 @@ public function getCssAssets(AttachedAssetsInterface $assets, $optimize) {
       }
     }
 
-    if ($optimize) {
-      $css = \Drupal::service('asset.css.collection_optimizer')->optimize($css);
-    }
-    $this->cache->set($cid, $css, CacheBackendInterface::CACHE_PERMANENT, ['library_info']);
-
     return $css;
   }
 
diff --git a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php
index 6cfca51..1c20033 100644
--- a/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php
+++ b/core/lib/Drupal/Core/Asset/CssCollectionOptimizer.php
@@ -8,6 +8,8 @@
 namespace Drupal\Core\Asset;
 
 use Drupal\Core\State\StateInterface;
+use \Drupal\Component\Utility\UrlHelper;
+use \Drupal\Core\Theme\ThemeManagerInterface;
 
 /**
  * Optimizes CSS assets.
@@ -29,18 +31,11 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
   protected $optimizer;
 
   /**
-   * An asset dumper.
+   * The theme manager.
    *
-   * @var \Drupal\Core\Asset\AssetDumper
+   * @var \Drupal\Core\Theme\ThemeManagerInterface
    */
-  protected $dumper;
-
-  /**
-   * The state key/value store.
-   *
-   * @var \Drupal\Core\State\StateInterface
-   */
-  protected $state;
+   protected $themeManager;
 
   /**
    * Constructs a CssCollectionOptimizer.
@@ -49,16 +44,11 @@ class CssCollectionOptimizer implements AssetCollectionOptimizerInterface {
    *   The grouper for CSS assets.
    * @param \Drupal\Core\Asset\AssetOptimizerInterface
    *   The optimizer for a single CSS asset.
-   * @param \Drupal\Core\Asset\AssetDumperInterface
-   *   The dumper for optimized CSS assets.
-   * @param \Drupal\Core\State\StateInterface
-   *   The state key/value store.
    */
-  public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, AssetDumperInterface $dumper, StateInterface $state) {
+  public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptimizerInterface $optimizer, ThemeManagerInterface $theme_manager) {
     $this->grouper = $grouper;
     $this->optimizer = $optimizer;
-    $this->dumper = $dumper;
-    $this->state = $state;
+    $this->themeManager = $theme_manager;
   }
 
   /**
@@ -78,15 +68,10 @@ public function __construct(AssetCollectionGrouperInterface $grouper, AssetOptim
   public function optimize(array $css_assets) {
     // Group the assets.
     $css_groups = $this->grouper->group($css_assets);
+    $key = $this->generateHash($css_groups);
 
-    // Now optimize (concatenate + minify) and dump each asset group, unless
-    // that was already done, in which case it should appear in
-    // drupal_css_cache_files.
-    // Drupal contrib can override this default CSS 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 …).
-    $map = $this->state->get('drupal_css_cache_files') ?: array();
     $css_assets = array();
+    $libraries = [];
     foreach ($css_groups as $order => $css_group) {
       // We have to return a single asset, not a group of assets. It is now up
       // to one of the pieces of code in the switch statement below to set the
@@ -101,38 +86,13 @@ public function optimize(array $css_assets) {
             $uri = $css_group['items'][0]['data'];
             $css_assets[$order]['data'] = $uri;
           }
-          // Preprocess (aggregate), unless the aggregate file already exists.
           else {
-            $key = $this->generateHash($css_group);
-            $uri = '';
-            if (isset($map[$key])) {
-              $uri = $map[$key];
-            }
-            if (empty($uri) || !file_exists($uri)) {
-              // Optimize each asset within the group.
-              $data = '';
-              foreach ($css_group['items'] as $css_asset) {
-                $data .= $this->optimizer->optimize($css_asset);
-              }
-              // Per the W3C specification at
-              // http://www.w3.org/TR/REC-CSS2/cascade.html#at-import, @import
-              // rules must precede any other style, so we move those to the
-              // top.
-              $regexp = '/@import[^;]+;/i';
-              preg_match_all($regexp, $data, $matches);
-              $data = preg_replace($regexp, '', $data);
-              $data = implode('', $matches[0]) . $data;
-              // Dump the optimized CSS for this group into an aggregate file.
-              $uri = $this->dumper->dump($data, 'css');
-              // Set the URI for this group's aggregate file.
-              $css_assets[$order]['data'] = $uri;
-              // Persist the URI for this aggregate file.
-              $map[$key] = $uri;
-              $this->state->set('drupal_css_cache_files', $map);
-            }
-            else {
-              // Use the persisted URI for the optimized CSS file.
-              $css_assets[$order]['data'] = $uri;
+            // To reproduce the full context of assets outside of the request,
+            // we must know the entire set of libraries used to generate all CSS
+            // groups, whether or not files in a group are from a particular
+            // library or not.
+            foreach ($css_group['items'] as $css_asset) {
+              $libraries[$css_asset['library']] = $css_asset['library'];
             }
             $css_assets[$order]['preprocessed'] = TRUE;
           }
@@ -156,6 +116,21 @@ public function optimize(array $css_assets) {
           break;
       }
     }
+    // Generate a URL for the group, but do not process it inline, this is
+    // done by \Drupal\system\controller\CssAssetController
+    $minimal_set = \Drupal::service('library.dependency_resolver')->getMinimalRepresentativeSubset($libraries);
+
+    foreach ($css_assets as $order => $css_asset) {
+      if (!empty($css_asset['preprocessed'])) {
+        $filename = 'css' . '_' . $order . '_' . $key . '.' . 'css';
+        // Create the css/ or js/ path within the files folder.
+        $path = 'public://' . 'css';
+        $uri = $path . '/' . $filename;
+        $theme_name = $this->themeManager->getActiveTheme()->getName();
+        $query = UrlHelper::buildQuery(['libraries' => $minimal_set, 'theme' => $theme_name]);
+        $css_assets[$order]['data'] = file_create_url($uri) . '?' . $query;
+      }
+    }
 
     return $css_assets;
   }
@@ -170,11 +145,13 @@ public function optimize(array $css_assets) {
    *   A hash to uniquely identify the given group of CSS assets.
    */
   protected function generateHash(array $css_group) {
-    $css_data = array();
-    foreach ($css_group['items'] as $css_file) {
-      $css_data[] = $css_file['data'];
+    $normalized = $css_group;
+    foreach ($normalized as $order => $group) {
+      foreach ($group['items'] as $key => $asset) {
+        unset($normalized[$order]['items'][$key]['weight']);
+      }
     }
-    return hash('sha256', serialize($css_data));
+    return hash('sha256', serialize($normalized));
   }
 
   /**
@@ -188,8 +165,6 @@ public function getAll() {
    * {@inheritdoc}
    */
   public function deleteAll() {
-    $this->state->delete('drupal_css_cache_files');
-
     $delete_stale = function($uri) {
       // Default stale file threshold is 30 days.
       if (REQUEST_TIME - filemtime($uri) > \Drupal::config('system.performance')->get('stale_file_threshold')) {
diff --git a/core/modules/system/src/Controller/CssAssetController.php b/core/modules/system/src/Controller/CssAssetController.php
new file mode 100644
index 0000000..e0f158a
--- /dev/null
+++ b/core/modules/system/src/Controller/CssAssetController.php
@@ -0,0 +1,274 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\image\Controller\ImageStyleDownloadController.
+ */
+
+namespace Drupal\system\Controller;
+
+use Drupal\Component\Utility\Crypt;
+use Drupal\Core\Asset\CssCollectionGrouper;
+use Drupal\Core\Asset\CssCollectionOptimizer;
+use Drupal\Core\Theme\ThemeInitializationInterface;
+use Drupal\Core\Theme\ThemeManagerInterface;
+use Drupal\system\FileDownloadController;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\HttpFoundation\BinaryFileResponse;
+use Symfony\Component\HttpFoundation\Request;
+use Symfony\Component\HttpFoundation\Response;
+use Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException;
+use Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException;
+use Symfony\Component\HttpKernel\Exception\BadRequestHttpException;
+
+/**
+ * Defines a controller to serve image styles.
+ */
+class CssAssetController extends FileDownloadController {
+
+  /**
+   * The library dependency resolver.
+   *
+   * @var \Drupal\Core\Asset\LibraryDependencyResolverInterface
+   */
+  protected $libraryDependencyResolver;
+
+  /**
+   * The Asset Resolver.
+   *
+   * @var \Drupal\Core\Asset\AssetResolverInterface
+   */
+  protected $assetResolver;
+
+  /**
+   * The Theme Initialization.
+   *
+   * @var Drupal\Core\Theme\ThemeInitializationInterface;
+   */
+  protected $themeInitialization;
+
+  /**
+   * The theme manager.
+   *
+   * @var Drupal\Core\Theme\ThemeManagerInterface;
+   */
+  protected $themeManager;
+
+  /**
+   * The CSS collection grouper.
+   *
+   * @var Drupal\Core\Asset\CssCollectionGrouper
+   */
+  protected $grouper;
+
+  /**
+   * A CSS asset optimizer.
+   *
+   * @var \Drupal\Core\Asset\CssOptimizer
+   */
+  protected $optimizer;
+
+  /**
+   * An asset dumper.
+   *
+   * @var \Drupal\Core\Asset\AssetDumperInterface
+   */
+  protected $dumper;
+
+  /**
+   * Constructs a CssAssetController object.
+   *
+   * @param \Drupal\Core\Asset\LibraryDependencyResolverInterface
+   *    The library dependency resolver.
+   * @param \Drupal\Core\Asset\AssetResolverInterface
+   *   The Asset resolver.
+   * @param \Drupal\Core\Theme\ThemeInitializationInterface
+   *   The theme initializer.
+   * @param \Drupal\Core\Theme\ThemeManagerInterface
+   *   The theme manager.
+   * @param \Drupal\Core\Asset\AssetCollectionGrouperInterface
+   *   The grouper for CSS assets.
+   * @param \Drupal\Core\Asset\AssetOptimizerInterface
+   *   The optimizer for a single CSS asset.
+   * @param \Drupal\Core\Asset\AssetDumperInterface
+   *   The asset dumper.
+   */
+  public function __construct($library_dependency_resolver, $asset_resolver, $theme_initialization, $theme_manager, $grouper, $optimizer, $dumper) {
+    $this->libraryDependencyResolver = $library_dependency_resolver;
+    $this->assetResolver = $asset_resolver;
+    $this->themeInitialization = $theme_initialization;
+    $this->themeManager = $theme_manager;
+    $this->grouper = $grouper;
+    $this->optimizer = $optimizer;
+    $this->dumper = $dumper;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('library.dependency_resolver'),
+      $container->get('asset.resolver'),
+      $container->get('theme.initialization'),
+      $container->get('theme.manager'),
+      $container->get('asset.css.collection_grouper'),
+      $container->get('asset.css.optimizer'),
+      $container->get('asset.css.dumper')
+    );
+  }
+
+  /**
+   * Generates a derivative, given a style and image path.
+   *
+   * After generating an image, transfer it to the requesting agent.
+   *
+   * @param \Symfony\Component\HttpFoundation\Request $request
+   *   The request object.
+   * @param $file_name
+   *   The file to deliver.
+   *
+   * @return \Symfony\Component\HttpFoundation\BinaryFileResponse|\Symfony\Component\HttpFoundation\Response
+   *   The transferred file as response or some error response.
+   *
+   * @throws \Symfony\Component\HttpKernel\Exception\AccessDeniedHttpException
+   *   Thrown when the user does not have access to the file.
+   * @throws \Symfony\Component\HttpKernel\Exception\ServiceUnavailableHttpException
+   *   Thrown when the file is still being generated.
+   */
+  public function deliver(Request $request, $file_name) {
+    $theme = $request->query->get('theme');
+    $active_theme = $this->themeInitialization->initTheme($theme);
+    $this->themeManager->setActiveTheme($active_theme);
+    $libraries = $this->libraryDependencyResolver->getLibrariesWithDependencies($request->query->get('libraries'));
+    $css_assets = $this->assetResolver->getCssFromLibraries($libraries, TRUE);
+
+    // Group the assets.
+    $css_groups = $this->grouper->group($css_assets);
+
+    // Now optimize (concatenate + minify) and dump each asset group, unless
+    // that was already done, in which case it should appear in
+    // drupal_css_cache_files.
+    // Drupal contrib can override this default CSS 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 …).
+    $css_assets = array();
+    $libraries = [];
+
+    $base_name = basename($file_name, '.css');
+
+    $file_parts = explode('_', $base_name);
+    // The group delta is the second segment of the filename, if it's not there
+    // then  the filename is invalid.
+    if (!isset($file_parts[1]) || !is_numeric($file_parts[1])) {
+      throw new BadRequestHttpException('Invalid filename');
+    }
+    $group_delta = $file_parts[1];
+
+    // The hash is the third segment of the filename.
+    // A non-matching hash does not necessarily mean a bad request, it could
+    // also mean that code is temporarily out of sync between different servers.
+    if (!isset($file_parts[2])) {
+      throw new BadRequestHttpException('Invalid filename');
+    }
+    $hash = $file_parts[2];
+
+    // If the group being requested does not exist, assume an invalid filename.
+    if (!isset($css_groups[$group_delta])) {
+      throw new BadRequestHttpException('Invalid filename');
+    }
+    $css_group = $css_groups[$group_delta];
+
+    // Only groups that are preprocessed will be requested, so don't try to
+    // process ones that aren't.
+    if (!$css_group['preprocess']) {
+      throw new BadRequestHttpException('Invalid filename');
+    }
+    $key = $this->generateHash($css_groups);
+
+
+    // The hash from the library definitions in code may not match the hash from
+    // the URL. This can be for three reasons:
+    // 1. Someone has requested an outdated URL, i.e. from a cached page, which
+    // matches a different version of the code base.
+    // 2. Someone has requrested an outdated URL during a deployment. This is
+    // the same case as #1 but a much shorter window.
+    // 3. Someone is attempting to craft an invalid URL in order to conduct a
+    // denial of service attack on the site.
+    //
+    // @todo: we could potentially hash the library definitions with the secret
+    // key to create an HMAC, so that only valid combinations of libraries are
+    // allowed.
+    // For now treat all of these the same, but if there's no match, don't write
+    // to the filesystem.
+    $match = TRUE;
+
+    $uri = 'public://css/' . $file_name;
+    if ($key !== $hash) {
+      // The file requested may have been written to disk by the time we got
+      // here. If it hasn't, and the hashes don't match, it's possible that a
+      // file matching the code base for this request already exists on disk, so
+      // use the filename matching this code base, not the one that generated
+      // the original filename for the request.
+      if (!file_exists($uri)) {
+        $uri = 'public://css/' . 'css_' . $group_delta . '_' . $hash . '.css';
+      }
+      // Either way, we didn't get a match.
+      $match = FALSE;
+    }
+    $headers = [
+      'Content-Type' => 'text/css',
+      'Cache-control' => 'private, no-store',
+    ];
+
+    if (!file_exists($uri)) {
+      // Optimize each asset within the group.
+      $data = '';
+      foreach ($css_group['items'] as $css_asset) {
+        $data .= $this->optimizer->optimize($css_asset);
+      }
+      // Per the W3C specification at
+      // http://www.w3.org/TR/REC-CSS2/cascade.html#at-import, @import
+      // rules must precede any other style, so we move those to the
+      // top.
+      $regexp = '/@import[^;]+;/i';
+      preg_match_all($regexp, $data, $matches);
+      $data = preg_replace($regexp, '', $data);
+      $data = implode('', $matches[0]) . $data;
+      // Dump the optimized CSS for this group into an aggregate file.
+      if ($match) {
+        $uri = $this->dumper->dump($data, 'css', $uri);
+      }
+      $headers = [
+        'Content-Type' => 'text/css',
+        'Cache-control' => 'private, no-store',
+      ];
+      // Generate response.
+      $response = new Response($data, 200, $headers);
+      return $response;
+    }
+    else {
+      return new BinaryFileResponse($uri, 200, $headers);
+    }
+  }
+
+  /**
+   * Generate a hash for a given group of CSS assets.
+   *
+   * @param array $css_group
+   *   A group of CSS assets.
+   *
+   * @return string
+   *   A hash to uniquely identify the given group of CSS assets.
+   */
+  protected function generateHash(array $css_group) {
+    $normalized = $css_group;
+    foreach ($normalized as $order => $group) {
+      foreach ($group['items'] as $key => $asset) {
+        unset($normalized[$order]['items'][$key]['weight']);
+      }
+    }
+    return hash('sha256', serialize($normalized));
+  }
+
+}
diff --git a/core/modules/system/src/Routing/AssetRoutes.php b/core/modules/system/src/Routing/AssetRoutes.php
new file mode 100644
index 0000000..841fc67
--- /dev/null
+++ b/core/modules/system/src/Routing/AssetRoutes.php
@@ -0,0 +1,71 @@
+<?php
+
+/**
+ * @file
+ * Contains \Drupal\system\Routing\AssetRoutes.
+ */
+
+namespace Drupal\system\Routing;
+
+use Drupal\Core\DependencyInjection\ContainerInjectionInterface;
+use Drupal\Core\StreamWrapper\StreamWrapperManagerInterface;
+use Symfony\Component\DependencyInjection\ContainerInterface;
+use Symfony\Component\Routing\Route;
+
+/**
+ * Defines a routes callback  to register a url for serving assets.
+ */
+class AssetRoutes implements ContainerInjectionInterface {
+
+  /**
+   * The stream wrapper manager service.
+   *
+   * @var \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface
+   */
+  protected $streamWrapperManager;
+
+  /**
+   * Constructs an asset routes object.
+   *
+   * @param \Drupal\Core\StreamWrapper\StreamWrapperManagerInterface $stream_wrapper_manager
+   *   The stream wrapper manager service.
+   */
+  public function __construct(StreamWrapperManagerInterface $stream_wrapper_manager) {
+    $this->streamWrapperManager = $stream_wrapper_manager;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public static function create(ContainerInterface $container) {
+    return new static(
+      $container->get('stream_wrapper_manager')
+    );
+  }
+
+  /**
+   * Returns an array of route objects.
+   *
+   * @return \Symfony\Component\Routing\Route[]
+   *   An array of route objects.
+   */
+  public function routes() {
+    $routes = array();
+    // Generate assets. If clean URLs are disabled image derivatives will always
+    // be served through the routing system. If clean URLs are enabled and the
+    // image derivative already exists, PHP will be bypassed.
+    $directory_path = $this->streamWrapperManager->getViaScheme('public')->getDirectoryPath();
+
+    $routes['system.css_asset'] = new Route(
+      '/' . $directory_path . '/css/{file_name}',
+      array(
+        '_controller' => 'Drupal\system\Controller\CssAssetController::deliver',
+      ),
+      array(
+        '_access' => 'TRUE',
+      )
+    );
+    return $routes;
+  }
+
+}
diff --git a/core/modules/system/system.routing.yml b/core/modules/system/system.routing.yml
index ed111f8..aa2dfe7 100644
--- a/core/modules/system/system.routing.yml
+++ b/core/modules/system/system.routing.yml
@@ -485,3 +485,6 @@ system.entity_autocomplete:
     _controller: '\Drupal\system\Controller\EntityAutocompleteController::handleAutocomplete'
   requirements:
     _access: 'TRUE'
+
+route_callbacks:
+  - '\Drupal\system\Routing\AssetRoutes::routes'
