Gérer des librairies externes dynamiquement avec Drupal 8

Pages de livre feuilletées

Drupal 8 a revu en profondeur la gestion des librairies et nous permet de gérer très finement les ressources à charger sur les différentes pages d'un site (cf. La gestion des libraries avec Drupal 8). Néanmoins, si nous souhaitons pouvoir gérer une librairie tierce dont nous ne connaissons pas à posteriori l'emplacement, il nous est difficile de pouvoir la déclarer statiquement dans notre fichier .libraries.yml.

C'est le cas typique d'un module qui intègre une librairie tierce, que le site builder va télécharger et installer sur son site. Mais il peut très bien la placer dans le dossier /libraries à la racine du site (emplacement recommandée), ou encore dans le dossier /sites/all/libraries (toujours supporté par Drupal 8), ou encore dans le dossier /sites/[site_name]/libraries s'il s'agit d'une installation multisite, ou même dans le dossier /profiles/[profile_name]/libraries si le module est installé dans un profil d'installation.

Pour gérer ces différents cas de figure, il va falloir gérer dynamiquement cette librairie. Découvrons comment simplement y parvenir avec le module Libraries API.

Note : le module Libraries API est en cours de migration et n'est pas complètement fonctionnel. Les quelques méthodes fournies par ce module que nous allons utiliser sont des méthodes de base, héritées de la version 7, tout à fait opérationnelles. La refonte de ce module, une fois achevée, devrait simplifier encore plus la gestion de librairies tierces que nous allons découvrir.

Déclaration des fichiers attendus de la librairie tierce

Au lieu de déclarer la librairie tierce dans un fichier .libraries.yml (ce qui n'est pas possible puisque nous ne connaissons pas à postériori le chemin du fichier qui sera téléchargé), nous la déclarons en implémentant le hook hook_libraries_info() fourni par Libraries API.

/**
 * Implements hook_libraries_info().
 */
function MYMODULE_libraries_info() {
  $libraries['external-library'] = array(
    'name' => 'External library',
    'vendor url' => 'http://external.library.com',
    'download url' => 'https://external.library.com/master.zip',
    'version arguments' => array(
      'file' => 'external.library.min.js',
      'pattern' => '@version\s+([0-9a-zA-Z\.-]+)@',
      'lines' => 7,
    ),
    'files' => array(
      'js' => array(
        'external.library.min.js',
      ),
    ),
  );

  return $libraries;
}

Nous déclarons une librairie tierce externe dont le nom (machine) est external-library, et spécifions un certain nombre de paramètres, dont le plus important est le nom du fichier attendu. Cette déclaration va nous permettre de trouver dynamiquement le fichier libraries/external-library/external.library.min.js, quelque soit l'emplacement du dossier libraries, au moyen de la méthode libraries_detect().

Il s'agit bien ici de déclarer la librairie tierce attendue au module Libraries API. Nous ne l'avons pas encore déclarée au niveau de Drupal, et donc encore moins chargée.

Déclaration dynamique de la librairie

Nous allons déclarer à Drupal la librairie externe au moyen du hook hook_library_info_build(). Le module Libraries API permet de simplifier cette implémentation en détectant la librairie, et en nous retournant toutes ses informations dont la plus intéressante, le chemin où celle-ci a été installée.

/**
 * Implements hook_library_info_build().
 */
function MYMODULE_library_info_build() {
  $libraries = [];
  $external_library = libraries_detect('external-library');

  if ($external_library['installed']) {

    $libraries['external_library_plugin']['dependencies'] = [
      'core/underscore',
      'core/jquery',
      'core/drupal',
      'core/drupalSettings',
      'core/jquery.once',
    ];

    if (isset($external_library['files']['js'])) {
      $external_library_path = (isset($external_library['library path'])) ? $external_library['library path'] : 'libraries/' . $external_library['machine name'];
      foreach ($external_library['files']['js'] as $external_library_js => $file) {
        $filepath = "/$external_library_path/$external_library_js";
        $libraries['external_library_plugin']['js'][$filepath] = $file;
      }
    }
  }

  return $libraries;
}

La méthode libraries_detect() fait le plus gros du travail, en cherchant la librairie attendue, puis en nous retournant ses informations que nous allons pouvoir utiliser pour déclarer à Drupal la librairie à charger.

Nous déclarons ici la librairie external_library_plugin, nous pouvons lui associer des dépendances, et grâce à la propriété 'library path' nous pouvons reconstruire les chemins des différents fichiers à charger dans notre librairie.

Et voilà. Il ne reste plus qu'à attacher notre librairie où nous en avons besoin. Par exemple

element['#attached']['library'][] = 'MYMODULE/external_library_plugin';

A noter que les librairies ajoutées dynamiquement sont automatiquement préfixées par le module ayant réalisé cette déclaration.

Ajouter un commentaire