Change record status: 
Project: 
Introduced in branch: 
8.x
Description: 

This only affects (module) developers who wish to override (parts) of Drupal 8's default CSS and JS preprocessing.


Why?

In Drupal 7, the API for this was limited to overridable #aggregate_callback and #group_callback callbacks. While this allowed for *some* flexibility, it was far from enough. Themes and modules attempting to use these would cause conflicts amongst each other. It was impossible for one module to override just plug in a better CSS or JS minifier. Or to just plug in a smarter strategy. You'd always have to override the whole.

New architecture

Now, in Drupal 8, the API for this has been made more explicit, more structured (more lego blocks), while still allowing developers full flexibility to draw outside of the lines (they can use their own structure if they find that to be necessary). The architecture (really just a set of interfaces) looks like this:

  • AssetCollectionOptimizerInterface: optimizes the whole collection of assets, returns a (in our case: smaller because aggregated) set of assets
    1. AssetCollectionGrouperInterface: used/called by AssetCollectionOptimizerInterface, groups a collection of assets into logical groups (e.g. based on media type for CSS, but could also take into account typical user's navigation path)
    2. AssetOptimizerInterface: used/called by AssetCollectionOptimizerInterface, optimizes an individual asset, returns optimized data as string
    3. AssetDumperInterface: used/called by AssetCollectionOptimizerInterface, dumps an (optimized) asset to persistent storage, returns an URI
  • AssetCollectionRendererInterface: can render an asset collection into a render array

So we have "better" aggregation/minification now?

No.

#352951: Make JS & CSS Preprocessing Pluggable transitions all existing CSS and JS aggregation logic to use the above architecture, but it does so while retaining the exact same logic. It's solely refactoring. It does not attempt to improve or change CSS or JS aggregation in any way. (Besides very minor changes where necessary to be able to fit in the existing logic into the above architecture).

So, nothing became better, it only became easier to override parts.

How to override?

We now have a bunch of services, each of which you can individually override — from core.services.yml:

asset.css.collection_renderer:
    class: Drupal\Core\Asset\CssCollectionRenderer
  asset.css.collection_optimizer:
    class: Drupal\Core\Asset\CssCollectionOptimizer
    arguments: [ '@asset.css.collection_grouper', '@asset.css.optimizer', '@asset.css.dumper', '@state' ]
  asset.css.optimizer:
    class: Drupal\Core\Asset\CssOptimizer
  asset.css.collection_grouper:
    class: Drupal\Core\Asset\CssCollectionGrouper
  asset.css.dumper:
    class: Drupal\Core\Asset\AssetDumper
  asset.js.collection_renderer:
    class: Drupal\Core\Asset\JsCollectionRenderer
  asset.js.collection_optimizer:
    class: Drupal\Core\Asset\JsCollectionOptimizer
    arguments: [ '@asset.js.collection_grouper', '@asset.js.optimizer', '@asset.js.dumper', '@state' ]
  asset.js.optimizer:
    class: Drupal\Core\Asset\JsOptimizer
  asset.js.collection_grouper:
    class: Drupal\Core\Asset\JsCollectionGrouper
  asset.js.dumper:
    class: Drupal\Core\Asset\AssetDumper

You can override each individually. You could:

  1. override the asset dumper to not write to Drupal's file system, but to an external server
  2. override just the JS optimizer to swap Drupal 8 core's current default "no-op" minification strategy (unchanged from Drupal 7 currently) to use UglifyJS instead
  3. override the CSS collection optimizer to build a new aggregate also when the mtime of one of the files changes, or to let the aggregate depend on the protocol (HTTP vs. HTTPS) — but other than that, it would still use core's default grouper, optimizer and dumper
  4. override the CSS collection optimizer to not use core's default grouper, optimizer and dumper, but rather to use your asset handling/optimization architecture entirely! (i.e. you're not obligated to use AssetCollectionGrouperInterface, AssetOptimizerInterface and AssetDumperInterface
  5. override the JS collection renderer to use the http://labjs.com/ script loader
Impacts: 
Module developers
Updates Done (doc team, etc.)
Online documentation: 
Not done
Theming guide: 
Not done
Module developer documentation: 
Not done
Examples project: 
Not done
Coder Review: 
Not done
Coder Upgrade: 
Not done
Other: 
Other updates done