Dans l’article précédent, Grunt, premier pas, on a vu comment définir une tâche, combiner des tâches, et les lancer. Maintenant, on va approfondir l’utilisation de Grunt, en cherchant de nouveaux plugins, pour améliorer la création des fichiers optimisés pendant le développement du projet.
Vérification du code javascript
Un plugin apprécié dans le développement de projet est jshint
qui permet de détecter les erreurs et les potentiels problèmes du code javascript, ce qui permettra ensuite de fusionner les sources et minifier le code sans danger. Un exemple est un oubli de point virgule à la fin d’un fichier. Lorsque les fichiers js
seront fusionnés, cela risque de poser un problème entre la fin d’un fichier et le début d’un autre, de même entre deux lignes qui ne seraient pas séparées par un point virgule semicolon.
Recherche du plugin Grunt
Comme dans l’article précédent, on va sur la page https://gruntjs.com/plugins/, et l’on recherche jshint
. Comme ce plugin fait partie de l’un des plus populaires, on le trouve en première page.
Le lien envoie sur la page https://www.npmjs.com/package/grunt-contrib-jshint du site npmjs.com. On obtient la commande pour installer le plugin dans le répertoire du projet, des exemples et les différentes options pour la configuration de Grunt dans le fichier Gruntfile.js
.
Installation de grunt-contrib-jshint
Dans le répertoire du projet, on lance la commande donnée sur la page npm
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
xavier@server:/path/to/project$ npm install grunt-contrib-jshint --save-dev + grunt-contrib-jshint@3.0.0 added 18 packages from 12 contributors and audited 285 packages in 14.879s 9 packages are looking for funding run `npm fund` for details found 0 vulnerabilities xavierbs@sd-97133:~/www/_clionautes/clio-wordpress/wp-content/plugins/clio-search$ npm install grunt-contrib-jshint --save-dev + grunt-contrib-jshint@3.0.0 updated 1 package and audited 285 packages in 10.504s 7 packages are looking for funding run `npm fund` for details found 0 vulnerabilities |
Une nouvelle ligne relative au package grunt-contrib-jshint
est écrite dans le fichier package.json
:
1 2 3 4 5 6 7 8 |
// ... "devDependencies": { "@sailshq/grunt-contrib-uglify": "^3.2.1", "grunt": "^1.3.0", "grunt-contrib-concat": "^1.0.1", "grunt-contrib-jshint": "^3.0.0" } } |
Mise en place uglify
Le fichier Gruntfile.js
se complète avec le chargement du plugin et la définition de la tâche :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
module.exports = function(grunt) { grunt.initConfig({ jshint: { all: ['assets/js/admin/*.js'] }, uglify: { target: { files: { 'assets/js/admin.min.js': ['assets/js/admin/*.js'] } } } }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('@sailshq/grunt-contrib-uglify'); grunt.registerTask('default', ['jshint', 'uglify']); } |
Par rapport à l’article précédent, on enlève la tâche de concaténation, car la contribution uglify
s’en charge. On active jshint
, avant la concaténation et la minification pour vérifier l’intégrité du fichier javascript final.
Lancement de la tâche
Puisque la tâche est définie avec le mot clé default
, qui est la tâche par défaut, il suffit de lancer la commande grunt
dans le répertoire du projet.
1 2 3 4 5 6 7 8 9 10 11 |
xavier@server:/path/to/project$ grunt Running "jshint:all" (jshint) task assets/js/admin/admin-tabs.js 4 |( $ => { ^ 'arrow function syntax (=>)' is only available in ES6 (use 'esversion: 6'). 8 | $tabs = $( '.tabs' ); ^ Expected an assignment or function call and instead saw an expression. 10 | const toggle = function( tab ) { ^ 'const' is available in ES6 (use 'esversion: 6') or Mozilla JS extensions (use moz). ... |
De nombreuses erreurs apparaissent avec jshint
, les avertissements nous invite à utiliser l’option esversion: 6
. Ce que l’on fait en ajoutant l’option à la propriété jshint
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
module.exports = function(grunt) { grunt.initConfig({ jshint: { options: { 'esversion': 6 }, all: ['assets/js/admin/*.js'] }, uglify: { target: { files: { 'assets/js/admin.min.js': ['assets/js/admin/*.js'] } } } }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('@sailshq/grunt-contrib-uglify'); grunt.registerTask('default', ['jshint', 'uglify']); } |
Correction des avertissements et des erreurs
jshint
permet de corriger quelques erreurs et oublis de points virgule semicolon. Les variables globales telles ajaxurl
, pour WordPress ou $
, jQuery
sont à préciser, et plus bizarrement console
. Il ne faut pas utiliser "use strict"
en dehors d’une fonction, cela peut poser des problèmes si l’on fusionne plusieurs fichiers dont certains ne répondent pas aux exigences de cette directive. Sinon on utilise l’option strict
, dont les valeurs peuvent être global
, implied
, false
ou true
. Les options de jshint
deviennent donc :
1 2 3 4 5 6 7 8 9 10 11 12 |
jshint: { options: { 'esversion': 6, 'browser': true, 'globals': { 'console': true, 'CS': true, 'ajaxurl': true } }, all: ['assets/js/admin/*.js'] }, |
CS
est une variable globale. Et cela passe enfin, le fichier minifié est créé.
1 2 3 4 5 6 7 8 |
xavier@server:/path/to/project$ grunt Running "jshint:all" (jshint) task >> 2 files lint free. Running "uglify:target" (uglify) task >> 1 file created 8.1 kB → 4.59 kB Done. |
Une subtilité, si l’on demande d’écrire le fichier minifié dans le même dossier que les sources, est d’ignorer ce fichier. Si l’on avait écrit le fichier admin.min.js
dans le dossier assets/js/admin/
(ce n’est pas le cas, car on l’écrit dans assets/js/
). Dans le cas contraire, on écrit la valeur de jshint.all: ['assets/js/admin/*.js', '!assets/js/admin/admin.min.js']
avec le point d’exclamation pour la non prise en compte du fichier minifié. Si le javascript ne fonctionne pas à l’exécution, cela peut être dû au renommage des variables. En ajoutant l’option mangle: true
, cela évite ce comportement.
Compilation des styles SASS
La recherche de SASS sur la page https://gruntjs.com/plugins/, nous indique le module grunt-contrib-sass
. Ce plugin utilise Ruby et Sass pour compiler les fichiers scss
. Or il est dit sur le site SASS que Ruby Sass était l’implémentation originale de Sass, mais qu’il a atteint la fin de sa vie le 26 Mars 2019, et il faut lui préférer une autre implémentation telle que DartSass ou LibSass. On recherche donc des plugins Grunt qui pourraient convenir. Et l’on trouve grunt-sass
qui compile Sass
en utilisant Dart Sass ou Node Sass. On installe ce module de la même façon que précédemment, en installant également node-sass
.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 |
xavier@server:/path/to/project$ npm install --save-dev node-sass grunt-sass npm WARN deprecated request@2.88.2: request has been deprecated, see https://github.com/request/request/issues/3142 npm WARN deprecated har-validator@5.1.5: this library is no longer supported > node-sass@5.0.0 install /var.../project/node_modules/node-sass > node scripts/install.js Downloading binary from https://github.com/sass/node-sass/releases/download/v5.0.0/linux-x64-72_binding.node Download complete..] - : Binary saved to /var ... /project/node_modules/node-sass/vendor/linux-x64-72/binding.node Caching binary to /var .../.npm/node-sass/5.0.0/linux-x64-72_binding.node > node-sass@5.0.0 postinstall /var .../project/node_modules/node-sass > node scripts/build.js Binary found at /var .../project/node_modules/node-sass/vendor/linux-x64-72/binding.node Testing binary Binary is fine + grunt-sass@3.1.0 + node-sass@5.0.0 added 121 packages from 115 contributors and audited 402 packages in 27.716s |
Puisque l’on nous demande d’installer node-sass
sur la page npm
de grunt-sass
, on le fait. Dans le fichier Gruntfile.js
, il faut faire un require('node-sass')
pour indiquer au module quelle implémentation va être utilisée.
Gruntfile.js
final
On modifie alors le fichier Gruntfile.js
:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 |
module.exports = function(grunt) { const sass = require('node-sass'); grunt.initConfig({ jshint: { options: { 'esversion': 6, 'browser': true, 'globals': { 'console': true, 'CS': true, 'ajaxurl': true } }, all: ['assets/js/admin/*.js'] }, uglify: { target: { files: { 'assets/js/admin.min.js': ['assets/js/admin/*.js'] } } }, sass: { admin: { // Nom de la sous-tâche options: { implementation: sass, outputStyle: 'compressed', sourceMap: true }, files: { 'assets/css/admin/styles.min.css': 'assets/css/admin/scss/styles.scss' } }, front: { options: { implementation: sass, outputStyle: 'compressed', sourceMap: true }, files: { 'assets/css/front/styles.min.css': 'assets/css/front/scss/styles.scss' } } } }); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('@sailshq/grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-sass'); grunt.registerTask('default', ['jshint', 'uglify', 'sass']); grunt.registerTask('sass-compile', ['sass']); } |
J’appelle la tâche sass-compile
, avec deux entrées : admin
et front
. On utilise la variable sass
pour l’implémentation, définie au début de la fonction module.exports()
. Je choisis d’écrire des fichiers source map pour le débogage, bien-sûr l’option peut être retirée. Pour tester, je lance la commande pour la partie admin
:
1 2 3 4 |
xavier@server:/path/to/project$ grunt sass-compile:admin Running "sass:admin" (sass) task Done. |
Et hop, minification et concaténation des fichiers js
, compilation et minification des styles scss
, c’est bien parti. Maintenant, il faut relancer la commande grunt
pour chaque modification de fichiers, ce qui est assez rébarbatif en mode développement. Dans l’article suivant, on va voir la mise en place d’un watcher qui écoutera tout changement des sources pour lancer automatiquement les tâches Grunt, sans avoir à le faire manuellement.