New to Drupal 8 is the asset management system. The asset management system allows modules and themes to register libraries. Libraries define CSS stylesheets and JavaScript files that need to be loaded with the page. Drupal 8 takes this approach for the frontend performance. Rather than loading all CSS or JavaScript assets, only those required for the current page in the specified libraries will be loaded.
In this recipe, we will define a libraries.yml
file that will define a CSS stylesheet and JavaScript file provided by a custom theme.
This recipe assumes that you have a custom theme created, such as the one you created in the first recipe. When you see mytheme
, use the machine name of the theme that you have created.
css
in your themes
base directory.css
folder, add a style.css
file that will hold the theme's CSS declarations. For demonstration purposes, add the following CSS declaration to style.css
:body { background: cornflowerblue; }
js
folder, and add a scripts.js
file that will hold the themes
JavaScript items.mytheme.libraries.yml
file and edit it, as shown in the following screenshot:
YAML
text to define the global-styling
library for your theme that will load the CSS file and JavaScript file:global-styling: version: VERSION css: theme: css/style.css: {} js: js/scripts.js: {}
global-styling
library. You have the ability to specify a library version and use the VERSION
defaults for your themes. It also defines the css/styles.css
stylesheet as part of the library under the theme
group.mytheme.info.yml
, and we need to add the declaration to our global-styling
library:libraries: - mytheme/global-styling
libraries
key that defines the libraries that should always be loaded. This YAML
array lists libraries to be loaded for each page.global-styling
library will be loaded and the page's background color will be styled appropriately:Drupal aggregates all the available library.yml
files and passes them to the library.discovery.parser
service. The default
class for this service provider is DrupalCoreAssetLibraryDiscoveryParser
. This service reads the library definition from each library.yml
and returns its value to the system. Before parsing the file, the parser allows themes to provide overrides and extensions to the library.
Libraries are enqueuers as they are attached to rendered elements. Themes have the ability to generically add libraries through their info.yml
files via the libraries
key. These libraries will always be loaded on the page when the theme is active.
CSS stylesheets are added to the data, which will build the head tag of the page. JavaScript resources, by default, are rendered in the footer of the page for performance reasons.
We will explore the options surrounding libraries in Drupal 8 in more detail.
With libraries, you have the ability to specify CSS by different groups. Drupal's asset management system provides the following CSS groups:
base
layout
component
state
theme
Stylesheets are loaded in the order in which the groups are listed. Each one of them relates to a PHP constant defined in /core/includes/common.inc
. This allows separation of concerns when working with stylesheets. Drupal 8's CSS architecture borrows concepts from the SMACSS system to organize CSS declarations.
Library assets can have configuration data attached to them. If there are no configuration items provided, a simple set of empty brackets is added. This is why, in each example, files end with {}
.
The following example, taken from core.libraries.yml
, adds HTML5shiv
:
assets/vendor/html5shiv/html5shiv.min.js: { weight: -22, browsers: { IE: 'lte IE 8', '!IE': false }, minified: true }
Let's take a look at the attributes of html5shiv.min.js
:
weight
key ensures that the script is rendered earlier than other librariesbrowser
tag allows you to specify conditional rules to load the scriptingminified
as true
if the asset has already been minifiedFor CSS assets, you can pass a media option to specify a media query for the asset. Reviewing classes which implement DrupalCoreAssetAssetCollectionRendererInterface
.
Libraries have the ability to specify other libraries as dependencies. This allows Drupal to provide a minimum footprint on the frontend performance.
jQuery is only loaded if a JavaScript library specifies it as a dependency. Refer to https://www.drupal.org/node/1541860.
Here's an example from the Quick Edit module's libraries.yml
file:
quickedit: version: VERSION js: ... css: ... dependencies: - core/jquery - core/jquery.once - core/underscore - core/backbone - core/jquery.form - core/jquery.ui.position - core/drupal - core/drupal.displace - core/drupal.form - core/drupal.ajax - core/drupal.debounce - core/drupalSettings - core/drupal.dialog
The Quick Edit module defines jQuery, the jQuery Once plugin, Underscore, and Backbone, and selects other defined libraries as dependencies. Drupal will ensure that these are present whenever the quickedit/quickedit
library is attached to a page.
A complete list of the default libraries provided by Drupal core can be found in core.libraries.yml
, which is in core/core.libraries.yml
.
Themes have the ability to override libraries using the libraries-override
and libraries-extend
keys in their info.yml
. This allows themes to easily customize the existing libraries without having to add the logic for conditionally removing or adding their assets when a particular library has been attached to a page.
The libraries-override
key can be used to replace an entire library, replace selected files in a library, remove an asset from a library, or disable an entire library. The following code will allow a theme to provide a custom jQuery UI theme:
libraries-override: core/jquery.ui: css: component: assets/vendor/jquery.ui/themes/base/core.css: false theme: assets/vendor/jquery.ui/themes/base/theme.css: css/jqueryui.css
The override declaration mimics the original configuration. Specifying false
will remove the asset or else a supplied path will replace that asset.
The libraries-extend
key can be used to load additional libraries with an existing library. The following code will allow a theme to associate a CSS stylesheet with selected jQuery UI declaration overrides, without always having them included in the rest of the theme's assets:
libraries-extend: core/jquery.ui: - mytheme/jqueryui-theme
Libraries also work with external resources, such as assets loaded over a CDN. This is done by providing a URL for the file location along with selected file parameters.
Here is an example to add the FontAwesome
font icon library from the BootstrapCDN
provided by MaxCDN:
mytheme.fontawesome: remote: http://fontawesome.io/ version: 4.4.0 license: name: SIL OFL 1.1 url: http://fontawesome.io/license/ gpl-compatible: true css: base: https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css: { type: external, minified: true }
Remote libraries require additional meta information to work properly:
remote: http://fontawesome.io/
The remote
key describes the library as using external resources. While this key is not validated beyond its existence, it is best to define it with the external resource's primary website:
version: 4.4.0
Like all libraries, a version is required. This should match the version of the external resource being added:
license: name: SIL OFL 1.1 url: http://fontawesome.io/license/ gpl-compatible: true
If a library defines the remote
key, it needs to also define the license
key. This defines the license name, the URL for the license, and checks whether it is GPL compatible. If this key is not provided, a DrupalCoreAssetExtensionLibraryDefinitionMissingLicenseException
will be thrown:
css: base: https://maxcdn.bootstrapcdn.com/font-awesome/4.4.0/css/font-awesome.min.css: { type: external, minified: true }
Finally, specific external resources are added as normal. Instead of providing a relative file path, the external URL is provided.
Modules have the ability to provide dynamic library definitions and alter libraries. A module can use the hook_library_info()
hook to provide a library definition. This is not the recommended way to define a library, but it is provided for edge use cases.
Modules do not have the ability to use libraries-override
or libraries-extend
, and need to rely on the hook_library_info_alter()
hook. The hook is documented in core/lib/Drupal/Core/Render/theme.api.php
or at https://api.drupal.org/api/drupal/core!lib!Drupal!Core!Render!theme.api.php/function/hook_library_info_alter/8.
By default, Drupal ensures that JavaScript is placed last on the page. This improves the page, load performance by allowing the critical portions of the page to load first. Placing JavaScript in the header is now an opt-in option.
In order to render a library in the header, you need to add the header: true
key/value pair:
js-library: header: true js: js/myscripts.js: {}
This will load a custom JavaScript library and its dependencies into the header of a page.