Utiliser Grunt et Bower avec WordPress et Bootstrap

Bower Grunt

Je vais présenter aujourd’hui une méthode de travail et des outils permettant aux designers web, intégrateurs et développeurs d’améliorer leur workflow en automatisant des tâches qu’ils doivent répéter à chaque projet d’intégration web. Pour présenter les outils, j’utiliserai un projet “clé-en-main” que j’utilise quand je commence un projet et que j’ai mis à disposition sur Git Hub : grunt-wordpress-theme. Le contexte sera celui d’un début de thème WordPress utilisant Bootstrap mais on verra qu’il peut facilement être utilisé dans le cadre d’une intégration de template HTML5 et CSS ou pour l’intégration d’un thème pour un autre CMS.

Node.js

Les outils principaux que l’on va présenter sont Grunt et Bower. Il est à noter que ces derniers sont open-source et qu’ils s’utilisent via Node.js. Si vous ne connaissez pas cette plateforme basé sur Javascript, allez la télécharger et l’installer, c’est vraiment un excellent outil de développement web, très flexible et utile dans de nombreux cas. Il faudra donc connaître Node.js pour pouvoir suivre le processus. Il vous faudra aussi utiliser l’invite de commande pour l’utiliser mais le temps gagné par la suite sera considérable.

Grunt

Une fois Node.js installé donc, on commence par l’utiliser pour installer Grunt. Pour ça, rendez-vous dans votre dossier de travail via l’invite de commande et lancez simplement :

npm install -g grunt-cli

npm est le gestionnaire de paquet de Node.js, c’est lui qui gère l’installation de nouveau composant (tels que Bower).

Grunt est basiquement un outil d’automatisation de tâches et offre de très nombeuse possibilités. Grâce à lui vous aller pouvoir automatiser la copie de fichiers, l’exports de fichier LESS, SASS ou Coffeescript, la minification, la concaténation de fichiers ou encore l’optimisation d’images…. Le -g dans la ligne de commande vous permet d’installer Bower globalement, il sera disponible partout sur votre poste (et non seulement dans le dossier courant).

Ensuite, pour initialiser un projet Grunt, toujours dans notre dossier de travail, lancez la commande :

npm init

Vous suivez ensuite les instructions pour le paramétrage du fichier package.json, fichier nécessaire à tout projet utilisant npm, le gestionnaire de paquets de Node.js :

{
  "name": "Wordpress",
  "version": "1.0.0",
  "description": "Wordpress theme starter kit",
  "main": "Gruntfile.js",
  "keywords": [
    "Wordpress",
    "LESS",
    "Bower",
    "Grunt"
  ],
  "author": "Hugo Chaume",
  "license": "ISC"
}

Puis, nous aurons donc besoin dans notre projet de Grunt et de plusieurs de ses extensions :

  • “grunt-contrib-concat”: concatenation de fichiers (js et css);
  • “grunt-contrib-less”: compilation LESS;
  • “grunt-contrib-uglify”: minification Javascript;
  • “grunt-contrib-watch”: surveiller les changements dans nos fichiers.

Voici les commandes nécessaires pour ces installations :

npm install grunt --save-dev
npm install grunt-contrib-concat --save-dev
npm install grunt-contrib-less --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-watch --save-dev

Bower

Bower est un gestionnaire de paquet et d’extensions pour le web. C’est-à-dire qu’il s’occupe d’installer pour vous des librairies, frameworks ou plugin tels que Bootstrap, jQuery, Foundation, Backbone.js… Pour installer Bower, très facile, comme avec Grunt, lancez :

npm install -g bower

Maintenant, que nous avons Bower, nous allons l’utiliser pour installer les librairies nécessaires à notre projet. Nous utiliserons Bootstrap, jQuery et Font Awesome. On devra installer simplement installer Bootstrap et Font Awesome. jQuery étant nécessaire au fonctionnement de Bootstrap, il sera installé automatiquement avec Bootstrap.

On commence par créer un fichier bower.json, nécessaire si vous utilisez Bower. Ouvrez-le et inscrivez :

{
  "name": "Wordpress starter kit",
}

Puis, lancez les commandes :

bower install bootstrap -S

et

bower install font-awesome -S

Le -S sert à enregistrer dans le fichier bower.json les noms et versions des librairies, frameworks et dépendances que vous utilisez dans votre projet. Si vous y retournez vous verrez maintenant :

{
  "name": "Wordpress starter kit",
  "dependencies": {
    "bootstrap": "~3.3.5",
    "font-awesome": "~4.4.0"
  }
}

Il vous suffira par la suite de lancer simplement bower install pour réinstaller les dépendances à l’identique. Les dépendances sont installées par défaut dans un dossier bower_components.

À ce point-ci, et avant de commencer à vraiment automatiser nos tâches avec Grunt, voici à quoi ressemble notre arborescence de dossiers :

-/bower_components
 ---/bootstrap
 ---/font-awesome
 ---/jquery
 -/node_modules
 -bower.json
 -package.json

Automatisation de tâches avec Grunt

Commencez par créer un fichier de configuration Gruntfile.js. C’est lui qui contiendra toutes nos commandes pour automatiser nos tâches. Voici la structure basique du fichier :

module.exports = function(grunt) {

  // Initialisation
    grunt.initConfig({

    // Tâches
    less: {
        // compilation des fichiers LESS
    },
    concat: {
      // Concaténation des fichiers JS et CSS
    },
    uglify: {
      // Minification des fichiers JS
    },
    jshint: {
      // Contrôle de la syntaxe des .js, permet de surveiller des erreurs de syntaxe dans votre code
    },
    watch: {
        // Surveillance de modifications sur les fichiers JS et CSS
      }
    });

  // Chargement des extensions Grunt
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-imagemin');

  // Définition de la tâche par défaut
  grunt.registerTask('default', ['watch']);

};

Nous allons maintenant compléter notre arborescence avec un dossier /src et un dossier /public. Le fichier Gruntfile.js ira récupérer dans /src les librairies et nos fichiers JS et LESS pour les compiler, minifier, puis copier dans notre dossier final /public. Voici l’arborescence qu’il faut avoir :

-/bower_components
 ---/bootstrap
 ---/font-awesome
 ---/jquery
-/src
---/assets
---/---/stylesheets
         base.less
         variables.less
         frontdend.less
         ...
---/---/javascript
         frontend.js
         ...
-/public
---/assets
---/---/stylesheets
         main.css
---/---/javascrips
-/node_modules
-bower.json-package.json

Les fichiers LESS sont tout d’abord compilés :

less: {
        development: {
            options: {
              compress: true,  //minifying the result
            },
            files: {
              //compiling frontend.less into main.css
              "./public/assets/stylesheets/main.css":"./src/assets/stylesheets/frontend.less"
            }
        }
    }

Le fichier base.less appelle le fichier LESS de Font Awesome pour inclure la librairie à notre CSS :

// Font Awesome
@import "../../../bower_components/font-awesome/less/font-awesome.less";

Les fichiers Javascript sont concaténés en un seul fichier…

concat: {
      options: {
        separator: ';',
      },
      js_frontend: {
        src: [
          './bower_components/jquery/dist/jquery.js',
          './bower_components/bootstrap/dist/js/bootstrap.js',
          './src/assets/javascript/frontend.js'
        ],
        dest: './public/assets/javascript/frontend.js',
      },
}

…puis minifiés :

uglify: {
      options: {
        mangle: false  // Use if you want the names of your functions and variables unchanged
      },
      frontend: {
        files: {
          './public/assets/javascript/frontend.js': './public/assets/javascript/frontend.js',
        }
      }
}

On utilise JSHint pour débugger basiquement le code en affichant les erreurs de syntaxes de notre code :

jshint: {
            files: ['Gruntfile.js', 'src/**/*.js'],
            options: {
                // options here to override JSHint defaults
                globals: {
                    jQuery: true,
                    console: true,
                    module: true,
                    document: true
                },
                ignores: [
                    // enter paths to ignore here, e.g., 'src/js/jquery.js'
                ]
            }
}

Enfin, on implémente la fonction qui va surveiller les modifications dans nos fichiers et lancer automatiquement l’export de nos fichiers :

watch: {
        js_frontend: {
          files: [
            // fichiers surveillés
            './bower_components/jquery/dist/jquery.js',
            './bower_components/bootstrap/dist/js/bootstrap.js',
            './src/assets/javascript/frontend.js'
            ],   
          tasks: ['concat:js_frontend', 'uglify:frontend','jshint'], // tâches à lancer

        },
        less: {
          files: ['./src/assets/stylesheets/*.less'], // fichiers surveillés
          tasks: ['less'], // tâche à lancer
        },
      }
});

Voici le fichier Gruntfile.js complet :

module.exports = function(grunt) {

  //Initializing the configuration object
    grunt.initConfig({

    // Task configuration
    less: {
        development: {
            options: {
              compress: true,  //minifying the result
            },
            files: {
              //compiling frontend.less into main.css
              "./public/assets/stylesheets/main.css":"./src/assets/stylesheets/frontend.less"
            }
        }
    },
    concat: {
      options: {
        separator: ';',
      },
      js_frontend: {
        src: [
          './bower_components/jquery/dist/jquery.js',
          './bower_components/bootstrap/dist/js/bootstrap.js',
          './src/assets/javascript/frontend.js'
        ],
        dest: './public/assets/javascript/frontend.js',
      },
    },
    uglify: {
      options: {
        mangle: false  // Use if you want the names of your functions and variables unchanged
      },
      frontend: {
        files: {
          './public/assets/javascript/frontend.js': './public/assets/javascript/frontend.js',
        }
      }
    },
    jshint: {
            files: ['Gruntfile.js', 'src/**/*.js'],
            options: {
                // options here to override JSHint defaults
                globals: {
                    jQuery: true,
                    console: true,
                    module: true,
                    document: true
                },
                ignores: [
                    // enter paths to ignore here, e.g., 'src/js/jquery.js'
                ]
            }
    },
    watch: {
        js_frontend: {
          files: [
            //watched files
            './bower_components/jquery/dist/jquery.js',
            './bower_components/bootstrap/dist/js/bootstrap.js',
            './src/assets/javascript/frontend.js'
            ],   
          tasks: ['concat:js_frontend', 'uglify:frontend','jshint'],     //tasks to run
          options: {
            livereload: true                        //reloads the browser
          }
        },
        less: {
          files: ['./src/assets/stylesheets/*.less'],  //watched files
          tasks: ['less'],                          //tasks to run
          options: {
            livereload: true                        //reloads the browser
          }
        },
      }
    });

  // Plugin loading
  grunt.loadNpmTasks('grunt-contrib-concat');
  grunt.loadNpmTasks('grunt-contrib-watch');
  grunt.loadNpmTasks('grunt-contrib-less');
  grunt.loadNpmTasks('grunt-contrib-uglify');
  grunt.loadNpmTasks('grunt-contrib-jshint');
  grunt.loadNpmTasks('grunt-contrib-imagemin');

  // Task definition
  grunt.registerTask('default', ['watch']);

};

Voilà, c’est fait, vous pouvez maintenant lancer la surveillance de votre fichier en utilisant la commande grunt. C’est magique ! Les exports se font tout seul quand on sauvegarde. Vous pouvez aussi regarder du côté de l’extension LiveReload pour que votre navigateur recharge automatiquement la page. Vous devrez installer l’extension et implémenter la fonction dans votre fichier Gruntfile.js.

Pour finaliser, on peux désormais ajouter dans le dossier /public notre feuille de style style.css, nos images, nos fichiers HTML, PHP ou autre includes nécessaires pour la création d’un thème WordPress :

-/bower_components
-/src
-/public
  -index.php
  -header.php
  -footer.php
  -style.css
  -functions.php
  -test.html
  ...
---/assets
---/---/stylesheets
---/---/javascript
---/images
---/includes
-/node_modules
-bower.json
-package.json

N’oubliez pas que vous pouvez récupérer le code complet avec une méthode pour le réutiliser (en anglais) sur GitHub. N’hésitez pas à partager et à soumettre vos questions et remarques pour améliorer cette petite présentation.

Remarque : vous trouverez dans le code dispo sur GitHub une fonction imagemin chargée de compresser les images trouvées dans le dossier /src/images pour ensuite les copier dans /public/images. Je ne l’ai pas inclus dans la présentation mais vous pouvez la décommenter et l’utiliser si besoin.

Archives