 cdn.module                               |  7 ++++
 cdn.services.yml                         |  7 ++++
 src/Asset/CssOptimizer.php               | 64 ++++++++++++++++++++++++++++++++
 src/EventSubscriber/ConfigSubscriber.php | 30 +--------------
 4 files changed, 79 insertions(+), 29 deletions(-)

diff --git a/cdn.module b/cdn.module
index 0e337e2..a15a711 100644
--- a/cdn.module
+++ b/cdn.module
@@ -9,6 +9,13 @@ function cdn_file_url_alter(&$uri) {
     return;
   }
 
+  // Don't alter file URLs while processing a CSS file.
+  // @see \Drupal\cdn\Asset\CssOptimizer
+  global $cdn_in_css_file;
+  if ($cdn_in_css_file) {
+    return;
+  }
+
   $result = \Drupal::service('cdn.file_url_generator')->generate($uri);
   if ($result) {
     $uri = $result;
diff --git a/cdn.services.yml b/cdn.services.yml
index 2560a0f..f9b2ad3 100644
--- a/cdn.services.yml
+++ b/cdn.services.yml
@@ -29,3 +29,10 @@ services:
     class: Drupal\cdn\PathProcessor\CdnFarfuturePathProcessor
     tags:
       - { name: path_processor_inbound }
+
+  # Decorators.
+  cdn.asset.css.optimizer:
+    public: false
+    class: Drupal\cdn\Asset\CssOptimizer
+    decorates: asset.css.optimizer
+    arguments: ['@cdn.asset.css.optimizer.inner']
diff --git a/src/Asset/CssOptimizer.php b/src/Asset/CssOptimizer.php
new file mode 100644
index 0000000..6599a2b
--- /dev/null
+++ b/src/Asset/CssOptimizer.php
@@ -0,0 +1,64 @@
+<?php
+
+namespace Drupal\cdn\Asset;
+
+use Drupal\Core\Asset\AssetOptimizerInterface;
+
+/**
+ * Decorates CSS asset optimizer: ensures file URLs are rewritten to the CDN.
+ *
+ * @see cdn_file_url_alter()
+ */
+class CssOptimizer implements AssetOptimizerInterface {
+
+  /**
+   * The decorated CSS asset optimizer service.
+   *
+   * @var \Drupal\Core\Asset\AssetOptimizerInterface
+   */
+  protected $decoratedCssOptimizer;
+
+  /**
+   * @param \Drupal\Core\Asset\AssetOptimizerInterface $decorated_css_optimizer
+   *   The decorated CSS asset optimizer service.
+   */
+  public function __construct(AssetOptimizerInterface $decorated_css_optimizer) {
+    $this->decoratedCssOptimizer = $decorated_css_optimizer;
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function optimize(array $css_asset) {
+    return $this->runWithoutCdnFileAlteration(function () use ($css_asset) {
+      return $this->decoratedCssOptimizer->optimize($css_asset);
+    });
+  }
+
+  /**
+   * {@inheritdoc}
+   */
+  public function clean($contents) {
+    return $this->runWithoutCdnFileAlteration(function () use ($contents) {
+      return $this->decoratedCssOptimizer->optimize($contents);
+    });
+  }
+
+  /**
+   * Wraps callable in an environment where the global $cdn_in_css_file===FALSE.
+   *
+   * @param callable $callable
+   *   A callable.
+   *
+   * @return mixed
+   *   The result of the callable.
+   */
+  protected function runWithoutCdnFileAlteration(callable $callable) {
+    global $cdn_in_css_file;
+    $cdn_in_css_file = TRUE;
+    $result = $callable();
+    $cdn_in_css_file = FALSE;
+    return $result;
+  }
+
+}
diff --git a/src/EventSubscriber/ConfigSubscriber.php b/src/EventSubscriber/ConfigSubscriber.php
index 625b858..53f2914 100644
--- a/src/EventSubscriber/ConfigSubscriber.php
+++ b/src/EventSubscriber/ConfigSubscriber.php
@@ -5,7 +5,6 @@ namespace Drupal\cdn\EventSubscriber;
 use Drupal\Core\Cache\CacheTagsInvalidatorInterface;
 use Drupal\Core\Config\ConfigCrudEvent;
 use Drupal\Core\Config\ConfigEvents;
-use Drupal\Core\Config\ConfigFactoryInterface;
 use Drupal\Core\DrupalKernelInterface;
 use Drupal\Core\StringTranslation\StringTranslationTrait;
 use Symfony\Component\EventDispatcher\EventSubscriberInterface;
@@ -31,13 +30,6 @@ class ConfigSubscriber implements EventSubscriberInterface {
    */
   protected $drupalKernel;
 
-  /**
-   * The config factory.
-   *
-   * @var \Drupal\Core\Config\ConfigFactoryInterface
-   */
-  protected $configFactory;
-
   /**
    * Constructs a ConfigSubscriber object.
    *
@@ -45,13 +37,10 @@ class ConfigSubscriber implements EventSubscriberInterface {
    *   The cache tags invalidator.
    * @param \Drupal\Core\DrupalKernelInterface $drupal_kernel
    *   The Drupal kernel.
-   * @param \Drupal\Core\Config\ConfigFactoryInterface $config_factory
-   *   A config factory for retrieving config objects.
    */
-  public function __construct(CacheTagsInvalidatorInterface $cache_tags_invalidator, DrupalKernelInterface $drupal_kernel, ConfigFactoryInterface $config_factory) {
+  public function __construct(CacheTagsInvalidatorInterface $cache_tags_invalidator, DrupalKernelInterface $drupal_kernel) {
     $this->cacheTagsInvalidator = $cache_tags_invalidator;
     $this->drupalKernel = $drupal_kernel;
-    $this->configFactory = $config_factory;
   }
 
   /**
@@ -62,26 +51,9 @@ class ConfigSubscriber implements EventSubscriberInterface {
    */
   public function onSave(ConfigCrudEvent $event) {
     if ($event->getConfig()->getName() === 'cdn.settings') {
-      // If farfuture was just enabled, then we must enable CSS aggregation.
-      // Otherwise files referenced by the CSS (images, fonts …) will fail to
-      // load, because they will reuse the security token of the referencing CSS
-      // file. By enabling CSS aggregation, referenced files will be passed
-      // through file_create_url(), giving them their own security tokens.
-      if ($event->getConfig()->get('farfuture.status') === TRUE && $event->isChanged('farfuture.status') && !$this->configFactory->get('system.performance')->get('css.preprocess')) {
-        $this->configFactory->getEditable('system.performance')
-          ->set('css.preprocess', TRUE)
-          ->save();
-        drupal_set_message($this->t('Automatically enabled the <q>@css-aggregation-label</q> setting: this is required for the <q>@farfuture-label</q> functionality.', [
-          '@css-aggregation-label' => $this->t('Aggregate CSS files'),
-          '@farfuture-label' => $this->t('Forever cacheable files'),
-        ]), 'warning');
-      }
-
       $this->cacheTagsInvalidator->invalidateTags([
         // Rendered output that is cached. (HTML containing URLs.)
         'rendered',
-        // Processed assets that are cached. (CSS aggregates containing URLs).
-        'library_info',
       ]);
 
       // Rebuild the container whenever the 'status' configuration changes.
