Rajouter du code JS ou CSS à un module Drupal

Drupal 8

Rajouter du code JS ou CSS à un module Drupal

Soumis par Antoine le dim 12/04/2020 - 14:37

Dans ce tuto pour Drupal, nous allons voir comment ajouter des fichiers CSS et JS à vos modules. De cette manière vous pourrez modifier l'apparence de vos modules et y ajouter des fonctionnalités comme des animations.

Principes

  • Créer les répertoire CSS et JS et y placer les fichiers
  • Déclarer la libraires dans le fichier nommodule.libraries.yml
  • Charger la librairie

Créer les répertoire CSS et JS et y placer les fichiers

A la racine du module, créez un dossier CSS et un dossier JS dans lequel vous placez vos différents fichiers CSS et JS. Vous pouvez faire des sous dossiers si nécessaire.

Déclarer la librairies dans le fichier nommodule.libraries.yml

Créer un fichier nommodule.libraries.yml à la racine du dossier. Le fichier comportera une entrée par librairie, et liste les fichiers css et/ou js qu'elle utilise comme dans les exemples ci-dessous :

Nom de la libraire qui utilise que css:
  version: 8.x
  css:
    theme:
      css/fichier1.css: {}
      css/fichier2.css: {}
      css/Fichier3.css: {}
Nom de la librairie qui utilise que du js:
  version: 1.x
  js: 
    js/fichier.js: {}  
Nom de la libraire qui utilise du css et du js:
  version: 1.x
  css:
    theme:
      css/fichier.css: {}
  js: 
    js/fichier.js: {}  
  dependencies: 
    - core/jquery

Les fichiers de libraries sont traduits par la fonction  LibraryDiscoveryParser::parseLibraryInfo. En lisant cette doc, on apprend que la clé d'une entrée correspond au nom machine de la librairie. Chaque entrée peut avoir les sous clés suivantes :

La clé css

L'objectif de la clé "css" et de lister les fichiers css à charger. Mais, afin de permettre le respect des spécificités SMACSS, les fichiers sont regroupés dans des catégories qui indiquent l'importance des fichiers. Ces catégories doivent être choisie parmi :

  • Base — CSS reset/normalize et les styles des éléments HTML. Poids : -200
  • Layout — découpage de l’architecture de votre site en sections principales. On y retrouve les grilles. Poids : -100
  • Component — un élément d'une page qui est réutilisable comme une liste ou un bouton. Poids : -0
  • State — des classes pour des états particulier d'un élément. Par exemple l'aspect actif ou inactif d'un élément Poids : 100
  • Theme — aspect purement visuel d'un élément Poids : 200

Vous trouverez une description de chaque catégorie en français à cette adresse.

Chaque catégorie contient une liste des fichiers css. Dans cette liste, chaque chemin d'accès (local ou url) est la clé d'un objet qui permet d'indiquer des caractéristiques au fichier comme :

  • des attributs html de la balise <script> (avec la clé attributes), 
  • la désactivation du preprocess (avec preprocess:false...). 
  • si elle est externe type:external
  • si elle est minifiée

Si vous ne devez donner aucune caractéristique au fichier, vous devez tout de même mettre un objet vide.

Règle générale

malibrairie:
  css:
    nom_categorie:
      chemin_access1:{ attributes:{attr1:value, attr2:value} }
      chemin_access2:{ }

Exemple

librairieglobale:
  css:
    base:
      css/base.css:{ attributes:{defer:true} }
      url:{type:external}
    Layout:
      css/grille.css:{}

La clé js

L'objectif de la clé "js" et de lister les fichiers js à charger. Contrairement au css, il n'y a pas de catégorie, et il est possible de lister directement les fichiers. Comme pour le css, chaque chemin d'accès (local ou url) est la clé d'un objet qui permet d'indiquer des caractéristiques au fichier. Il ne faut pas oublier de préciser que le type est external si le chemin d'accès est une url.

Règle générale :

malibrairie:
  js:
    chemin_accès1:{}
    chemin_accès2:{ attributes:{attr1:value, attr2:value} }

 Exemple :

malibrairie:
  js:
    js/fiche.js:{ attributes:{defer:true} }
    js/fichier2.js:{}
    url:{type:external}

La clé dependencies

Cette clé liste dans un tableau les librairies qu'il faut charger avant celle-ci. Les dépendances s’appellent en indiquant le nom de la librairie préfixée du module ou du thème qui l’a implémenté et séparé par un /. Dans l'exemple ci-dessous, on voit que jquery est fourni par le cœur de Drupal.

global:
  css:
    theme:
      css/fichier.css: {}
  js: 
    js/fichier.js: {}  
  dependencies: 
    core/jquery

La clé version :

Cette clé permet d'indiquer la version du noyau de drupal pour laquelle la version est prévue

La clé header 

Par défaut, Drupal charge les librairies tout en bas du html. Avec cette clé, il est possible d'indiquer à Drupal que la librairie doit être chargée dans le header. C'est nécessaire pour des scripts comme celui de Google Analytics

La clé minified

Cette clé permet d'indiquer que le fichier est déjà minifié et que Drupal ne doit pas le refaire.

La clé remote

Si le fichier est stocké sur un serveur externe comme un cdn, cette clé permet d'indiquer le dépot utilisé (repository)

La clé license

permet d'indiquer à l'aide de trois sous clés (name, url, gpl-compatible) le nom de la licence, l'adresse où elle est décrite, et si elle est GPL compatible.

Charger la librairie

En principe, une librairie devrait être chargée uniquement quand cela est nécessaire. C'est ce que permet Drupal en chargeant les libraires en fonction de ce qui est affiché plutôt qu'en fonction de la page qui est chargée. 

Attacher une librairie à toutes les instances d'un type de render array

Imaginons que vous souhaitez que sur votre site, tous les tableaux utilisent la librairie datatables.net . En rattachant une librairies au render array de type '#table', vous vous assurez que la librairie ne soit chargée que sur les pages ou un tableau est affiché. Pour cela, il faut utiliser le hook "hook_element_info_alter".

function nommodule_element_info_alter(array &$types) {
  if (isset($types['table'])) {
    $types['table']['#attached']['library'][] = 'nommodule/nomlibrairie';
  }
}

Si vous ne savez pas ce qu'est un hook ou comment l'implanter, vous pouvez lire les articles "Qu'est ce qu'un hook" et "Utiliser un hook dans un module"

Attacher une librairie à une instance d'un type de render array

Imaginons que sur votre site, certains tableaux utilisent la libraire datatables.net mais pas tous. Il faut alors attacher la librairie au render array de certaines tables. Pour cela, on rajoutera au render array les tableaux  imbriqués ["#attached"]|"library"] auquel on rajoutera une clé numérique "nommodule/nomlibrairie"

Soit vous avez accès au render array après qu'il ait été conçus (comme dans un hook) :

$build['element']['#attached']['library'][] = 'nommodule/nomlibrairie';

Soit vous êtes en train de le construire :

//Déclaration de la table
    $variable['table'] = [
      '#type' => 'table',
      '#attributes' => [
        'class' => ['table-class'],
      ],
      '#header' => $header,
      '#rows' => $rows,
      '#attached' => [
        'library' => [
          'nom_module/nom_librairie'
        ]
      ]
    ];

Les blocs et les formulaires sont des render array. Il est possible de leur attacher des librairies soit dans leur méthode build, soit grâce à des hooks.

Attacher des librairies à des pages

Soit on utilise le hook "hook_page_attachment" pour attacher la libraire à toutes les pages

function hook_page_attachments(array &$attachments) {
  // Attacher une librairie à toutes les pages
  $attachments['#attached']['library'][] = 'module/librairie';

  // Attacher une librairie à toutes les pages en fonction de certaines condition : ici si l'utilisateur à certains droits
  if (!\Drupal::currentUser()
    ->hasPermission('ma permission')) {
    $attachments['#attached']['library'][] = 'module/librairie';
  }
}

Soit on utilise une fonction preprocess du type nommodule_preprocess_page(&$variables). Dans l'exemple ci-dessous on cible la page front

function nommodule_preprocess_page__front(&$variables){
$variables['#attached']['library'][] = 'nommodule/nomlibrairie';
}

Attacher une librairie à un type de nœud

On utilise la fonction preprocess du type nommodule_preprocess_node__nommachinenode(&$variables). Dans l'exemple ci-dessous on cible les articles

function nommodule_preprocess_node__article(&$variables)
{
  $variables['#attached']['library'][] = 'nommodule/nomlibrairie';
}

Attacher des libraires à un gabarit twig

Comme lors du theming, on peut utilise la fonction twig :

{{ attach_library('your_module/library_name') }}

 

Version