Drupal 10 : Gestion des librairies, Point sur le monde JS

Précédemment porté par un module contribué, les librairies font leur apparition de le cœur.

Cet article a été initialement rédigé pour Drupal 8 mais son contenu est toujours d'actualité pour Drupal 9 et Drupal 10.

N'hésitez pas à nous contacter ou à vous inscrire à notre formation «Drupal pour les développeurs et développeuses» pour en savoir plus !

Le gros changement dans Drupal 8 au niveau Javascript se situe principalement dans la façon dont on va importer les fichiers Javascript.

En Drupal 7, on devait directement définir les fichiers Javascript à importer dans le fichier *.info d’un thème, d’un module ou via drupal_add_js() ou via l’attribut #attached d’un render array. Drupal 8 systématise l’usage de librairies qui existaient déjà dans Drupal 7. Cela permet de déclarer un groupe de fichiers Javascript ou CSS et de les injecter ensemble là où c’est nécessaire dans le site. Les librairies sont créées dans un fichier *.libraries.yml se plaçant à la racine du thème ou du module.

# block.libraries.yml

drupal.block:
  version: VERSION
  js:
    js/block.js: {}
  dependencies:
    - core/jquery
    - core/drupal

drupal.block.admin:
  version: VERSION
  js:
    js/block.admin.js: {}
  css:
    theme:
      css/block.admin.css: {}
  dependencies:
    - core/jquery
    - core/drupal
    - core/drupal.ajax

Un des avantages majeurs de ce nouveau système est la possibilité de définir des dépendances. Ici, lorsque la librairie drupal.block sera incluse, elle importera automatiquement jQuery et la librairie core de Drupal.

Ce que cela sous-entend et qui est une énorme évolution dans Drupal, c’est que jQuery, par exemple, n'est plus importé par défaut dans les pages.
Ainsi, un Drupal standard en mode anonyme est complément libre de tout javascript. C’est une sacrée amélioration pour les performances d’affichage !

L’utilisation des librairies dans le code passe par “l’attachement” de celles-ci à l’élément où le code est nécessaire. Pour cela, nous pourrons nous appuyer sur plusieurs mécanismes en fonction de la situation. La philosophie de Drupal 10 est d’essayer de cibler spécifiquement l’élément (la page, le contenu, le bloc, la table, etc.) pour que le code ne soit chargé que lorsque cela est vraiment nécessaire.

L’attachement de la librairie utilise l’attribut #attached, déjà présent en Drupal 7.

Attacher ses librairies

…à un type d’élément

Nous avons vu précédemment l’API de rendu et la notion de type. Il est possible de cibler un type particulier pour que la librairie lui soit toujours attachée. Pour cela, il faut utiliser le hook_element_info_alter() permettant me modifier le render array par défaut de ces types.

# module_name.module
function module_name_element_info_alter(array &$types) {
  if (isset($types['table'])) {
    $types['table']['#attached']['library'][] = 'module_name/jslib';
  }
}

…à une entité

Pour cibler une entité en particulier on peut passer par le hook_entity_view_alter().

# module_name.module
function module_name_entity_view_alter(&$build, $type) {
  if ($build['#entity_type'] == 'node') {
    $build['#attached']['library'][] = 'module_name/jslib';
  }
}

…à la page complète

Cette fois on vise la page complète et donc potentiellement toutes les pages via le hook_page_attachments_alter().

# module_name.module
function module_name_page_attachments_alter(array &$attachments) {
  $attachments['#attached']['library'][] = 'module_name/jslib';
}

…dans un template Twig

Twig propose une méthode pour attacher directement une librairie dans un template.

# stuff.html.twig:
{{ attach_library('module_name/jslib') }}

Écrire du javascript

L’écriture de code Javascript ne change fondamentalement pas. Drupal 8 permet toujours d'utiliser jQuery (version 2.1.4), le code est toujours à inclure dans une closure et les Drupal Behaviors sont toujours à utiliser pour permettre à notre code de réagir à chaque requête. En nouveauté, on voit apparaître l’utilisation fortement conseillée du use strict; facilitant l’écriture de code Javascript correct et sécurisé. Il devient par exemple impossible d’utiliser une variable non déclarée préalablement.

La version de jQuery disponible est régulièrement mise à jour avec l'évolution du cœur. Voici un petit tableau récapitulatif :

Version de Drupal Version de jQuery
8.4.0 3.2.1
8.8.0 3.4.1
8.9.0 3.5.1
9.5.0 3.6.3

# file.js

(function ($, Drupal, drupalSettings) { // closure
  'use strict';
  Drupal.behaviors.awesome = { // behaviors
    attach: function(context) {
    },
    detach: function (context, trigger) {
    }
  };
}(jQuery, Drupal, drupalSettings));

Concernant la liaison entre une action et un objet du DOM, il est conseillé d’utiliser des attributs data- HTML 5 quand cela est possible ou bien de préfixer les classes utilisées par js- quand cela est possible. L’idée est de créer une frontière entre le monde CSS et JS pour limiter les régressions en cas de modification d’une classe par exemple.

Ce travail est encore en cours dans Drupal 8 : https://www.drupal.org/node/2431671

Passer des paramètres du back au front

Si vous souhaitez passer des paramètres à votre script, il faut ajouter une dépendance sur core/drupalSettings à votre librairie et l’injecter dans votre closure (voir exemple ci-dessus). Enfin, si nécessaire, on peut passer les paramètres de la façon suivante lors de l’attachement :

# module_name.module
function module_name_page_attachments_alter(array &$attachments) {
  $attachments['#attached']['library'][] = 'module_name/jslib';
  $attachments['#attached']['drupalSettings']['some']['var']['name'] = 'bar';
}

On accédera alors dans le code javascript à la variable drupalSettings.some.var.name

Mettre en forme le contenu en Javascript

Drupal permet toujours de déclarer des fonctions de thème en Javascript :

# file.js
Drupal.theme.hello = function () {
  var markup = 'Hello world!';
  return markup;
};

Drupal.theme.helloYou = function (name) {
  var markup = 'Hello ' + name '!';
  return markup;
};

var example = Drupal.theme('hello'); // Hello world!
var another_example = Drupal.theme('helloYou', 'Dries'); // Hello Dries!

Pensez à utiliser $.extend() pour déclarer plusieurs fonctions d’un coup :

# file.js
$.extend(Drupal.theme, {
  hello: function () { return 'Hello world!'; },
  helloYou: function (name) { return 'Hello ' + name '!'; }
});

Se passer de jQuery

Pour le développement de votre thème sur mesure c'est totalement possible et même recommandé de ne pas utiliser jQuery. En effet, l'intérêt principal de cette librairies était initialement de simplifier le développement Javascript pour tous les navigateurs du marché. Désormais, ces derniers ont évolué et jQuery n'est plus nécessaire à moins de vouloir rester compatible avec d'antiques versions plus supportées depuis longtemps.

Si vous voulez vous lancer, vous trouverez quelques pistes sur notre article de veille Remplacer son code jQuery par du code natif "vanilla".

Après jQuery, voici Backbone.js

Une autre nouveauté concernant le monde Javascript dans Drupal 8 est l’intégration de Backbone.js (et sa dépendance underscore.js) dans le core.

C’est une librairie permettant la création structurée d’applications javascript facilitant la mise en place d’interface riche (utilisée par Foursquare, Disqus, Trello). Elle apporte un cadre composé (entre autres) de :

  • modèles (Model) qui sont une représentation des données via un système interne de clés/valeurs qui lance des évènements spécifiques lors des changements de valeurs.
  • vues (View) qui est la partie gérant l’affichage d’un modèle, a l’écoute des évènements et qui envoi des données au modèle.
  • collections (Collection) qui proposent une API pour gérer des groupes de modèles, s’occupant de leur chargement et de leur sauvegarde.

Backbone est désormais utilisé dans Drupal pour gérer la toolbar ou la fonctionnalité d’édition en ligne rapide. Pour l’utiliser dans vos scripts il suffit de le mettre en dépendance de votre librairie.

# foo.libraries.yml
foo-lib:
  version: VERSION
  js:
    js/foo-lib.js: {}
  dependencies:
    - core/backbone

Ressources associées

Votre commentaire

Le contenu de ce champ sera maintenu privé et ne sera pas affiché publiquement.
Votre adresse servira à afficher un Gravatar et à vous notifier des réponses. Votre commentaire sera anonymisé si ce billet est dépublié pendant plus de 3 mois.
Pour lutter contre le spam notre système enregistre votre adresse IP et votre adresse e-mail si vous la partagez.
Nous vous invitons à consulter notre politique de confidentialité pour comprendre les traitements faits de ces données et comment les rectifier.

À propos de Julien

Co-fondateur - Scrum master & Expert technique

Utilisateur de Drupal depuis 2008, j’ai fait mes armes comme développeur chez Commerce Guys puis me suis mis à encadrer les nouveaux arrivants avant de donner des formations, participer aux avant ventes et accompagner les équipes au passage à Scrum.

Je suis impliqué dans la communauté française de Drupal depuis 2009, j’ai été tour à tour président puis vice-président de l’association Drupal France et francophonie entre 2011 et 2013.