Laravel Mix et Drupal

Utiliser Laravel Mix dans un thème Drupal

Publié le lun 30/12/2019 - 12:32

Drupal 8

Laravel Mix permet d'utiliser relativement facilement Webpack sans trop entrer dans la configuration qui peut souvent devenir complexe. Voici une façon de l'utiliser dans votre thème Drupal afin de builder vos assets en SASS et ES6, de copier automatiquement les images et polices, de surveiller tous les changements et de synchroniser votre navigateur web pendant le développement.

Nouveau thème

Définissons un nouveau thème, par exemple nommé d8t (comme Drupal 8 theme) :

d8t.info.yml

name: D8t
type
: theme
description
: 'Custom Drupal 8 theme'
core
: 8.x
base theme
: classy
regions
:
  header
: Header # Drupal core, do not remove
  primary_menu
: Primary menu # Drupal core, do not remove
  secondary_menu
: Secondary menu # Drupal core, do not remove
  highlighted
: Highlighted # Drupal core, do not remove
  help
: Help # Drupal core, do not remove
  content
: Content # Drupal core, do not remove
  sidebar_first
: Sidebar first # Drupal core, do not remove
  sidebar_second
: Sidebar second # Drupal core, do not remove
  footer
: Footer # Drupal core, do not remove
  breadcrumb
: Breadcrumb # Drupal core, do not remove
libraries
:
 - d8t/global

Maintenant définissons notre librairie global que nous venons de déclarer. Dans le monde Laravel, on aurait plutôt mis app à la place de global, mais en Drupal un thème peut définir plusieurs librairies. Cette librairie aura les 3 fichiers CSS requis par Drupal ainsi qu'un fichier JavaScript :

d8t.libraries.yml

global:
  version
: VERSION
  css
:
    base
:
      public/css/global/base.css
: {}
    layout
:
      public/css/global/layout.css
: {}
    component
:
      public/css/global/components.css
: {}
  js
:
    public/js/global/global.js
: {}

Jusque là, rien de bien nouveau. Créons la structure des assets images, SASS et JS source :

d8t/resources/images/exemple.jpg
d8t/resources/js/global/global.js
d8t/resources/sass/global/base.scss
d8t/resources/sass/global/components.scss
d8t/resources/sass/global/layout.scss

Laravel Mix

A présent initialisons un package de modules node et ajoutons les dépendances et les scripts de build. Voici le résultat final :

package.json

{
  "name": "d8t",
  "version": "1.0.0",
  "main": "index.js",
  "author": "Guillaume Duveau",
  "license": "MIT",
  "devDependencies": {
    "@fortawesome/fontawesome-free": "^5.12.0",
    "browser-sync": "^2.26.7",
    "browser-sync-webpack-plugin": "^2.0.1",
    "cross-env": "^6.0.3",
    "laravel-mix": "^5.0.0",
    "materialize-css": "^1.0.0",
    "node-sass": "^4.13.0",
    "resolve-url-loader": "^3.1.0",
    "sass-loader": "^8.0.0",
    "vue-template-compiler": "^2.6.10"
  },
  "dependencies": {},
  "scripts": {
    "dev": "npm run development",
    "development": "cross-env NODE_ENV=development node_modules/webpack/bin/webpack.js --progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js",
    "watch": "npm run development -- --watch",
    "hot": "cross-env NODE_ENV=development node_modules/webpack-dev-server/bin/webpack-dev-server.js --inline --hot --config=node_modules/laravel-mix/setup/webpack.config.js",
    "prod": "npm run production",
    "production": "cross-env NODE_ENV=production node_modules/webpack/bin/webpack.js --no-progress --hide-modules --config=node_modules/laravel-mix/setup/webpack.config.js"
  }
}

J'ai tout de suite ajouté Font Awesome et Materialize CSS, nous verrons plus tard comment les inclure. Ils sont bien sûr facultatifs. Tout le reste est indispensable. Pour les scripts, nous utiliserons principalement watch pour dévélopper et production pour générer les assets finaux de production.

Pour finir, nous ajoutons ce fichier de configuration :

webpack.mix.js

const mix = require('laravel-mix')

mix
  .webpackConfig({
    module: {
      rules: [
        {
          test: /\.s[ac]ss$/i,
          use: [
            {
              loader: 'sass-loader',
              options: {
                sassOptions: {
                  includePaths: [
                    'node_modules'
                  ]
                },
              },
            },
          ],
        },
      ],
    }
  })
  .setPublicPath('public')
  .setResourceRoot('../../')
  .js('resources/js/app/app.js', 'public/js/app')
  .sass('resources/sass/app/base.scss', 'public/css/app')
  .sass('resources/sass/app/layout.scss', 'public/css/app')
  .sass('resources/sass/app/components.scss', 'public/css/app')
  .sourceMaps(true, 'source-map')
  .browserSync({
    proxy: 'localhost:8080'
  })
  • Nous demandons à sass-loader d'inclure les modules nodes pour les librairies supplémentaires que nous utilisons (Font Awesome et Materialize CSS), nous verrons plus tard comment concrètement utiliser ceci.
  • setPublicPath('public') indique à Webpack le répertoire où sont les fichiers finaux buildés.
  • setResourceRoot('../../') est une astuce permettant d'utiliser le remplacement à la volée des URLs des images et polices et leur copie automatique.
  • browserSync({ proxy: 'localhost:8080' }) est bien sûr à adapter à votre cas, en mettant l'URL de votre site local.

La configuration pourrait être bien plus complexe mais c'est déjà pas mal.

Librairies externes SASS et JavaScript

Voici enfin comment nous pouvons utiliser les librairies node modules. Ajoutons pour commencer Font Awesome dans les components :

components.scss

@import '~@fortawesome/fontawesome-free/css/all.css';
  • Le ~ indique à webpack d'aller chercher dans le répertoire node_modules.
  • Les polices de Font Awesome (.eot, .svg, .ttf, .woff, .woff2) sont automatiquement copiées dans d8t/public/fonts/. Si on ajoute des images par exemple en background dans le SASS, les fichiers seront aussi copiés.

Utilisons maintenant Materialize CSS. On pourrait juste tout importer :

components.scss

@import "~materialize-css/sass/materialize";

Personnellement, pour réduire la taille des assets et pour pouvoir customizer les variables de Materialize CSS, je préfère importer à la main juste ce qu'il me faut :

components.scss

/**
 * The order of imports must be respected.
 *
 * @see <a href="https://github.com/Dogfalo/materialize/blob/v1-dev/sass/materialize.scss">https://github.com/Dogfalo/materialize/blob/v1-dev/sass/materialize.scss</a>
 */


// We need colors for variables, later.
@import "~materialize-css/sass/components/color-variables";
@import "~materialize-css/sass/components/color-classes";

// We want to override materialize-css variables.
@import "components/variables";

// This is necessary.
@import "~materialize-css/sass/components/normalize";
@import "~materialize-css/sass/components/global";

// Now we import only what we need.
@import "~materialize-css/sass/components/grid";
// We override this one.
@import "components/navbar";
@import "~materialize-css/sass/components/typography";
@import "~materialize-css/sass/components/buttons";
@import "~materialize-css/sass/components/forms/input-fields";
@import "~materialize-css/sass/components/sidenav";
@import "~materialize-css/sass/components/waves";
  • Dans components/_variables.scss j'ai copié et adapté _variables.scss de la librairie.

En dernier, nous allons écrire le JavaScript du thème pour avoir le parallaxe du block titre :

global.js

import { Parallax } from 'materialize-css'

Drupal.behaviors.gd8t = {

  attach: function (context, settings) {
    /**
     * Parallax.
     */

    const parallaxElems = document.querySelectorAll('.parallax')
    const parallaxInstances = M.Parallax.init(parallaxElems)
  }

}

Ca fait du bien, du JS moderne dans un thème Drupal, non ?

Texte brut

  • Aucune balise HTML autorisée.
  • Les lignes et les paragraphes vont à la ligne automatiquement.
  • Les adresses de pages web et les adresses courriel se transforment en liens automatiquement.