Accueil Le blog ebiznext
Visual Studio et des outils incontournables du Front avec npm, Bower, Grunt et Gulp

Microsoft intègre un ensemble d’outils front de renom pour permettre aux développeurs d’y faire appel de façon naturelle. Certains de ces outils sont :

  • npm et Bower pour la gestion de paquets
  • Grunt et Gulp pour l’automatisation des tâches

Nous allons voir comment tirer parti de ces technologies devenues indispensables avec Visual Studio 2015.

Introduction

Le développement web a subis de profonds changements ces dernières années. Nous sommes passé d’une solution entièrement mises en place par les développeurs, qui devaient réaliser eux-même les javascript et CSS, à des sites construits plus rapidement en utilisant des Frameworks existants, des styles CSS pré-configurés, des librairies JavaScript optimisées et portables, des outils d’automatisation de tâches et bien plus.

Depuis quelques années, la multiplication des outils disponibles a fait prendre conscience à la communauté Web que leurs utilisations devenaient indispensables. Parallèlement, Microsoft, ayant compris les enjeux de telles évolutions, propose son propre gestionnaire de paquets : Nugget. Nugget gère parfaitement l’installation de paquets et des dépendances, mais souffre de la nécessité de la mise à disposition de ces paquets dans le format spécifique Microsoft Nugget. A chaque nouvelle version d’un projet, il est nécessaire à un développeur de mettre à disposition le paquet Nugget correspondant à cette nouvelle version, ce qui entraîne des délais par rapport à la mise à disposition des nouvelles fonctionnalités. Pour éviter ces délais, Microsoft a décidé de faciliter l’installation des outils externes au sein de Visual Studio, en particulier avec Visual Studio 2015. Ce billet va justement s’intéresser à l’intégration de certains de ces outils dans Visual Studio 2015 :

  • npm et Bower pour la gestion de paquets
  • Grunt et Gulp pour l’automatisation de tâches

 

Gestion de paquets avec npm et Bower

npm et Bower sont tous deux des gestionnaires d’installation de paquets dédiés au développement web. Les paquets disponibles se comptent aujourd’hui en dizaine de milliers (plus de 36000 à l’heure où cet article est écrit). Ces paquets peuvent être:

  • Des Frameworks
  • Des fonts
  • Des styles CSS
  • Des librairies JavaScript

Même s’il n’existe pas de consensus à ce sujet, une communauté grandissante de développeurs choisissent :

  • npm pour l’installation des paquets côté serveur
  • Bower pour l’installation des paquets côté clients

 

npm peut cependant être utilisé pour installer des paquets côté clients, et inversement, Bower peut être utilisé pour installer des paquets serveur. Découvrons ce que font ces gestionnaires de paquets avant d’illustrer pourquoi de nombreux développeurs préconisent d’utiliser l’un ou l’autre selon les cas d’usage.

 

npm

Les pré-requis

Sous Visual Studio 2015, de nombreuses ressources sont déjà disponibles. Il faudra cependant télécharger deux produits importants qui ne seront pas spécifiques à Visual Studio : - NodeJS (https://nodejs.org/en/download/): NodeJS installera tous les éléments nécessaires à l’accès aux ressources NodeJS ainsi que l’accès à la console NodeJS, nécessaire à l’installation des paquets via la commande npm. - Git (https://git-scm.com/downloads): il est nécessaire d’installer le client permettant de télécharger les sources des repositories de GitHub. Lors de l’installation de l’outil, pensez à sélectionner l’option permettant d’accéder à la ligne de commande.

L’utilisation

Les deux outils NodeJS et Git étant installés, Visual Studio 2015 est prêt à utiliser un grand nombre de ressources disponibles sur Internet pour le développement web. Pour accéder à la console du gestionnaire de Package NodeJS directement à partir de Visual Studio 2015, cliquer sur Affichage, Autres Fenêtres puis Console du Gestionnaire de Package :

Affichage du gestionnaire de package Faire apparaître la fenêtre de gestionnaire de package

La Console du Gestionnaire de package apparaît en bas de la fenêtre :

console du gestionnaire de package Console du gestionnaire de package

A partir de cette console, il est possible de demander l’installation de package. Installons, par exemple, Bower. La commande d’installation est la suivante :

npm install -g bower

npm est le gestionnaire de paquets de NodeJS. L’option “-g” permet de signaler que l’on souhaite installer bower de façon global, ce qui rendra le package disponible pour toutes les solutions.

Pour installer des dépendances dans le projet uniquement, vous pouvez retirer -g, si vous ne passez pas par Visual Studio. Cependant, Visual Studio 2015 permet de simplifier la gestion des packages qui seront installés dans la solution de façon automatisée via un fichier JSON : package.json. Dans une solution .NET 5, vous pourrez ajouter directement, via l’ajout de nouvel élément, un fichier de configuration npm déjà pré-configuré :

.NET 5 permet d'ajouter un fichier npm pré-configuré Dans les solutions utilisant un Framework plus ancien, il suffira d’ajouter à la solution un fichier JSON vide nommé package.json.

Voici un exemple de fichier package.json :

{
"version": "1.0.0",
"name": "APPLI NAME",
"private": true,
"devDependencies": {
"grunt": "~0.4.5",
"grunt-contrib-clean": "0.6.0",
"grunt-contrib-jshint": "0.11.0",
"grunt-contrib-concat": "0.5.1",
"grunt-contrib-uglify": "0.8.0",
"grunt-contrib-watch": "0.6.1"
}
}
  • Version permet d’identifier la version du programme créé
  • Name identifie le nom de votre application
  • Private permet de signifier que l’application ne doit pas être publiée pour le moment
  • Il est également conseillé de faire apparaître [“private”: true] dans le fichier package.json pour éviter de livrer votre paquet dans le registry officiel de NodeJS lors de vos développements
  • Dependencies (dans notre cas DevDependencies) permet d’identifier les packages NodeJS qui doivent être installés. Comme nous l’avions évoqué, on retrouvera ici les packages qui seront utilisés côté serveur

 

Visual Studio 2015 intègre l’intellisense qui facilite énormément le travail de complétion de ce fichier. Il permet d’identifier les packages ainsi que les versions :

  

  • Si vous souhaitez une version en particulier, choisissez la version sans caractères spéciaux.
  • Si vous souhaitez recevoir automatiquement les nouvelles versions correctives du projet (par exemple ici, les mises à jour de grunt_forever 0.2.X, vous pouvez utiliser la version commençant par ~.
  • Si vous souhaitez recevoir automatiquement les nouvelles versions pour toute la version mineures de ce projet (0.X.X), choisissez l’option commençant par ^.

Il ne vous reste plus qu’à sauvegarder le fichier et voilà ! Les packages s’installent automatiquement dans la solution. Vous pouvez suivre l’avancée des installations dans la fenêtre de sortie de Visual Studio 2015. Les packages téléchargés par NodeJS proviennent par défaut d’un registry officiel.

Dependencies, DevDependencies, BundledDependencies, PeerDependencies ?

Dependencies est utilisé pour installer des paquets qui seront nécessaires pour exécuter l’application. Ce sont donc des packages qui seront livrés lors de la publication de l’application. DevDependencies sont des packages qui ne devront pas être livrés mais qui sont utiles pour le développement. Par exemple, on y retrouvera typiquement les librairies de tests unitaires. Lors des premières phases d’un projet, il arrive souvent que les développeurs préfèrent utiliser DevDependencies pour éviter de copier les fichiers à chaque compilation, et ainsi gagner du temps.

Les BundledDependencies permettent de livrer des fichiers tel un package, mais qui ne font pas parti, en réalité, d’un repository. C’est le cas, par exemple, lorsque vous désirez faire référence à un de vos projets personnels, à un package que vous avez modifié ou encore lorsqu’il n’existe pas de package npm pour le projet. Les PeerDependencies permettent de détecter les erreurs potentielles lors de l’utilisation d’un plugin. Un plugin peut ne fonctionner que pour des versions spécifiques d’un package host. Si vous tentez d’ajouter une version non valide par rapport à ce qui a été déclaré dans le bloc PeerDependencies d’un package, vous obtiendrez une erreur npm.

Bower

Comme nous l’avons évoqué plus tôt, Bower permet de gérer principalement les packages qui seront installés côté clients. Son architecture et mode de fonctionnement est en de nombreux points similaire à celle de NodeJS.

Installation

Une fois NodeJS correctement installé, il est très facile d’installer Bower. Il suffit en effet d’installer Bower dans la liste des packages à installer dans la solution par NodeJS si vous utilisez .NET 4.6 : Ajouter la ligne suivante dans le fichier package.json : “bower”: “^1.7.2” Si vous utilisez .NET 5, bower est installé par défaut dans votre solution. Si le fichier bower.json n’est pas présent dans votre solution, il vous suffit d’en créer un via le menu.

Utilisation L’utilisation de Bower est triviale dès lors que vous avez rencontré npm : le principe de fonctionnement est le même, si ce n’est que les packages sont téléchargés à partir de GitHub directement. Dans Visual Studio 2015, vous pouvez choisir d’accéder directement à la gestion des packages Bower :

Vous pourrez y utiliser la gestion de paquets Bower en utilisant l’interface utilisateur prévue à cet effet:

Si vous développez une solution .NET 5, il est également possible d’ajouter un fichier de configuration Bower déjà préconfiguré :

Sinon, vous pouvez toujours, bien entendu, ajouter un fichier JSON que vous configurerez manuellement. Le format du fichier JSON utilisé par Bower est sensiblement le même que pour NodeJS. Voici un exemple de fichier :

Vous pouvez également ajouter un fichier .bower.rrc qui permettra de configurer bower comme par exemple lui donner le chemin d’installation des packages localement :

Vous pouvez enfin choisir de créer le fichier de configuration via l’aide de bower en utilisant la commande « bower init ». L’installation des packages se produit dès la sauvegarde du fichier bower.json. Il est également possible d’effectuer l’installation via la console de gestionnaire de packages via la commande : bower install

 

Configuration

Les packages téléchargés par bower peuvent parfois être verbeux si vous omettez de télécharger une version minimaliste. Le fichier bower.json permet également de filtrer les informations qui devront être copiés lors de la livraison du projet via l’utilisation de l’attribut ignore. Il est également possible de spécifier le répertoire où les fichiers seront livrés via l’attribut install.

"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"install": {
"path": "lib"
},

Voici un exemple complet de fichier bower.json :

{
"name": "GruntBower",
"description": "GruntBowerTest",
"authors": [
"Ebiznext"
],
"license": "MIT",
"ignore": [
"**/.*",
"node_modules",
"bower_components",
"test",
"tests"
],
"install": {
"path": "lib"
},
"dependencies": {
"bootstrap": "~3.3.6",
"knockout": "~3.4.0",
"jquery": "2.1.4"
}
}

Mais alors, npm ou Bower?

La principale différence entre npm et Bower réside donc dans l’utilisation cible des paquets installés. Ceci est dû au mode de fonctionnement de la résolution des dépendances. La résolution des dépendances pour npm est basée sur la méthode “nested depency tree”. Cela signifie que les dépendances sont téléchargées dans un sous-dossier du paquet installé. Cette technique permet donc d’installer 3 différentes versions d’un même paquet pour gérer au mieux les dépendances. Cependant, il peut s’avérer délicat de réaliser la même chose pour les paquets clients. Imaginez un client devant télécharger 3 fois le même paquet sur Internet. C’est pour cela que la méthode de fonctionnement de Bower correspond plus à une utilisation client. Bower utilisera la technique de “flat dependency tree”, ce qui signifie que les dépendances seront installées dans le dossier racine des paquets. Ceci permet de s’assurer que le client ne télécharge qu’une fois les paquets, mais oblige également le développeur à résoudre les incompatibilités potentielles des dépendances lui-même.

Notes : il arrive parfois qu’avec l’utilisation de npm, le nombre de paquets de dépendances téléchargés soient important (un paquet en nécessitant un autre, qui lui-même nécessite un autre paquet, qui lui-même…). Ceci peut conduire au dépassement, sous Windows, des chemins de plus de 260 caractères, limite pour ce système d’exploitation. Atteindre cette limite empêchera Visual Studio de compiler correctement la solution. Il existe une commande npm pouvant être utilisée afin de réduire le nombre de sous-dossiers si la même dépendance est installée plusieurs fois. Rendez-vous, dans la console de gestionnaire de paquet, dans le dossier de la solution problématique et utilisez la commande “npm dedupe”. Si dedupe n’est pas encore installé, il faudra réaliser un “npm install dedupe -g”.

Grunt

Grunt est un outil permettant l’exécution de tâches automatiques lors de certains événements du cycle de vie de votre application. L’installation de Grunt peut être réalisée simplement via l’installation du paquet npm. Vous pouvez choisir de l’installer via la ligne de commande ou dans le fichier package.json (recommandé). Grunt se base sur un fichier de configuration nommé grunt.js. S’il s’agit d’une application .NET 5, vous pouvez ajouter un nouvel élément « Fichier de configuration Grunt » ou bien simplement ajouter un nouveau fichier JavaScript nommé grunt.js. Le fichier grunt.js doit toujours au minimum définir une méthode pour la méthode exports de l’objet module :

module.exports = function (grunt) {
grunt.initConfig({});
};

Vous l’avez compris, la déclaration des tâches que Grunt pourra exécuter, ainsi que les autres aspects de configuration se feront dans la méthode initConfig. Grunt est basé sur l’utilisation de Plugins. Nous allons en parcourir certains des plus souvent utilisés dans les solutions aujourd’hui. Configuration Prenons un exemple avec Grunt-contrib-concat. Ce plugin permet de fusionner des fichiers JavaScript afin d’optimiser le nombre d’appels du client vers le serveur. Comme pour chaque Plugin Grunt, il faut commencer par l’installer dans la solution, comme on installerait d’importe quel paquet. Ce plugin étant utilisé côté serveur, nous allons utiliser npm, et donc ajouter notre plugin dans la liste des packages dans package.json. Ajoutons la ligne “grunt-contrib-concat”: “0.5.1” dans la section DevDependencies. Une fois le fichier sauvegardé, le plugin s’installe dans la solution et est prêt à être utilisé. Il faut maintenant configurer Grunt pour qu’il puisse utiliser ce plugin. Imaginons que nous ayons placé l’ensemble des fichiers JavaScript que nous souhaitons concaténer dans le dossier ~/javascript Tout d’abord, déclarons l’appel au plugin concat :

module.exports = function (grunt) {
grunt.initConfig({
concat: {/*on déclare l'appel au plugin*/
foo: {/*on définit un nom (on peut choisir build/dist/all/foo/...) */
src: ['TypeScript/*.js'],/*liste des fichiers que l'on va concaténer*/
dest: 'temp/combined.js'/*chemin de destination du fichier concaténé*/
}
}
});
};

Concat est le nom du plugin qui va être utilisé. Foo est le nom donné à cet appel au plugin en particulier. Puisque nous avons décidé d’utiliser le plugin grunt-contrib-concat, il nous faut maintenant le déclarer dans le fichier gruntfile.js afin de chargé les informations nécessaires pour réaliser l’appel au plugin. Ceci est réalisé via la ligne suivante, à ajouter après la méthode initConfig : grunt.loadNpmTasks(‘grunt-contrib-concat’); Le fichier gruntfile.js devrait alors ressembler à ceci :

module.exports = function (grunt) {
grunt.initConfig({
concat: {/*on déclare l'appel au plugin*/
foo: {/*on définit un appel (on peut choisir build/dist/all/foo/...) */
src: ['TypeScript/*.js'],/*liste des fichiers que l'on va concaténer*/
dest: 'temp/combined.js'/*chemin de destination du fichier concaténé*/
}
}
});

grunt.loadNpmTasks('grunt-contrib-concat'); /*déclaration de la tâche*/
};

Il suffit d’enregistrer le fichier pour que les modifications soient prises en compte.

Exécution unitaire de tâches

Vous pouvez voir votre nouvelle tâche apparaître dans l’explorateur d’exécuteur de tâches en suivant les instructions suivantes pour faire apparaître la fenêtre :

La tâche apparaît dans la liste. Pour réaliser la tâche, vous pouvez double cliquer dessus, ou réaliser un clic droit : exécuter. Le résultat s’affichera sur la partie droite de la fenêtre.

Aller plus loin dans la configuration

Voici un fichier grunt.js qui réalise les actions que chaque développeurs web devrait, à mon sens, réaliser avant de livrer un projet :

  • Nettoyer les fichiers temporaires
  • Concaténer les fichiers js gérés localement, en vérifiant le code puis en retirant tous les caractères superflus afin d’améliorer la vitesse de chargement de la page tout en s’assurant d’une qualité optimale
  • Concaténer et nettoyer les fichiers css afin de garder la solution plus rapide à charger pour le client
  • S’assurer que tous les dossiers sont toujours à jours lors de chaque enregistrement de fichiers JavaScript afin de réduire les temps de préparation de la solution
module.exports = function (grunt) {
grunt.initConfig({
clean: ['wwwroot/lib/*.*', 'temp/', 'release/css/site.min.css'], /* nettoyage des fichiers sélectionnés */

concat: {/*concaténation des fichiers JavaScripts*/
dist: {
src: ['TypeScript/*.js'],
dest: 'temp/combined.js'
}
},
jshint: {/*vérification des fichiers JavaScripts*/
files: ['temp/*.js'],
options: {
'-W069': false,
}
},
uglify: {/* On enlève des fichiers JavaScript tous les caractères non utiles (espaces, retour chariot, etc.) et on compresse le fichier */
options: {
compress: true
},
dist: {
src: ['temp/combined.js'],
dest: 'wwwroot/lib/combined.min.js'
}
},
watch: {/* Permet de déclarer un suivi de modification sur les fichiers js. S’ils sont modifiés puis enregistré, la tâche « all » sera alors automatiquement déclenchée */
files: ['TypeScript/*.js', 'css/*.css'],
tasks: ["all"]
},
cssmin: {/* Permet de minimiser tous les fichiers css */
sitecss: {
options: {
banner: '/* Minimisons tous ces fichiers css */'
},
files: {
'release/css/site.min.css': [
'css/*.css']
}
}
}
});

grunt.loadNpmTasks('grunt-contrib-concat');
grunt.loadNpmTasks('grunt-contrib-uglify');
grunt.loadNpmTasks('grunt-contrib-clean');
grunt.loadNpmTasks('grunt-contrib-jshint');
grunt.loadNpmTasks('grunt-contrib-watch');
grunt.loadNpmTasks('grunt-contrib-cssmin');
grunt.registerTask('all', ['clean', 'concat', 'jshint', 'uglify', 'cssmin' ]); /* On enregistre la tâche all comme étant l’ensemble des tâches définies dans le deuxième tableau */
};

Les alias

Notez que la tâche “all” n’est pas définie comme les autres : il s’agit en réalité d’un alias permettant d’exécuter plusieurs tâches en une seule exécution. Elle apparaîtra donc naturellement dans la liste des tâches d’alias :

Associer une tâche à un événement

Si vous souhaitez associer une tâche en particulier à un événement de Visual Studio 2015, il vous suffit de faire un clic droit sur la tâche, et de sélectionner à quel événement correspond le déclenchement de cette tâche :

Les watchers

Ajouter un watcher permet de lancer une tâche lorsqu’une condition prédéfinie. Dans l’exemple précédent, dès qu’un fichier javascript est modifié dans le dossier TypeScript, on relance automatiquement le processus entier (la tâche « all »).

Gulp

De grunt à Gulp

Grunt est un outil d’automatisation performant, principalement basé sur la configuration. C’est d’ailleurs la principale différence avec Gulp, un autre outil d’automatisation principalement basé, lui, sur le code. Tout dans Grunt est une succession de Plugins, exécutés séquentiellement de façon totalement indépendante, à la façon de l’utilisation des pipes Unix (|). Par exemple, comme vous avez pu le voir dans les exemples précédents, pour concaténer les fichiers JavaScript pour réaliser l’offuscation (uglify) du fichier (en le rendant plus léger mais indigeste à lire), Grunt ouvrira de multiple connexions au système de fichiers et les refermera à chaque étape, car chaque étape est indépendante. A chaque étape, Grunt générera un fichier temporaire qui pourra être réutilisé à l’étape suivante, avec les nombreux accès lecture/écriture disque qui sont nécessaires à une telle stratégie. Ceci résultera en des durées d’exécution relativement longue. Gulp est en effet basé sur une approche « pipe and stream » qui permet de chaîner des appels à des méthodes de façon chaînes pour construire sa propre chaîne complexe permettant de réaliser le travail que l’on souhaite, tout cela sans passer par des fichiers temporaires : Gulp se base sur les données brutes des fichiers (en format Node Stream) seront propagées entre les appels aux plugins, appelés de façon chaînée. Les gains de performance sont conséquents. Dans notre exemple, on utilisera le plugin de concaténation, et on utilisera directement la sortie de l’appel pour réaliser l’étape suivante, l’enregistrement dans un fichier, puis on utilisera ce fichier en entrée du plugin d’offuscation.

Configuration de base

Gulp fonctionne avec un fichier de configuration que l’on nomme par convention gulp.js. Dans une solution .NET 5 sous Visual Studio 2015, il est possible de faire un clic droit/ajouter un nouvel élément et de choisir : fichier de configuration Gulp :

Par défaut, le fichier contient uniquement les lignes suivantes :

var gulp = require('gulp');

gulp.task('default', function () { });

La première permet de déclarer la variable permettant de déclarer des tâches, et la seconde contient une définition de tâche :

gulp.task('nom_tache', [dépendances], [fonction_à_exécuter])

Le paramètre nom permet de nommer la tâche. Une fois une tâche déclarée, son nom apparaîtra dans la liste des tâches associées à Gulp (sous Gulpfile.js) dans l’explorateur d’exécuteur des tâches de Visual Studio. Ce nom doit donc être unique. Donner à une tâche le nom de default permet de définir la tâche qui sera lancée si la commande gulp est exécutée sans paramètre. Le paramètre dépendances permet d’identifier les tâches qui devront avoir été exécutées avant que la tâche déclarée ne puisse être exécutée elle-même. Gulp vérifiera, avant de lancer la tâche, que les Ce paramètre est facultatif, si la tâche n’a aucune dépendance, comme dans l’exemple : gulp.task(‘default’, function () { //entrez votre code ici }); Le paramètre fonction définie ce qui sera exécutée lors de l’exécution de la tâche. Ce paramètre est facultatif. Ce paramètre sera par exemple souvent omis lors de la déclaration du default, tâche par défaut exécutée par l’appel de gulp (sans argument), qui permettra souvent de lancer toutes les autres tâches :

gulp.task('task1');
gulp.task('task2');
gulp.task('task3');
gulp.task('default', ['task1', 'task2', 'task3']);

Une fois le fichier enregistré, les tâches sont visibles dans l’explorateur d’exécution des tâches de Visual Studio 2015 :

Voici la sortie d’exécution de cette tâche dans Visual Studio 2015 :

Les tâches sont exécutées parallèlement, ce qui permet d’observer des performances accrues comparé à une solution telle que Grunt. S’il est nécessaire d’introduire un séquencement, il sera nécessaire d’introduire les dépendences lors de la déclaration des tâches.

Autres méthodes de base

En plus de fournir une méthode permettant de déclarer les tâches, Gulp fournit également des méthodes d’accès aux fichiers et de gestion des watchers :

  • Gulp.src permet de définir la source, c’est-à-dire les fichiers que l’on va vouloir traiter. Par exemple, gulp.src(‘TypeScript/*/.js’)
  • Gulp.dest permet de transformer le stream provenant de l’étape précédente et le transformer en un ou plusieurs fichiers dont on donnera la destination cible. Par exemple, gulp.dest(‘wwwroot/lib/combined.min.js’)
  • Gulp.watch permet de définir un watcher sur une liste de fichiers et permet d’appeler, si un évènement survient, soit

  • Une fonction callback
  • Une liste de tâches
  • Nous verrons l’utilisation de gulp.watch plus loin dans nos exemples.

 

Les plugins

Comme pour grunt, si vous souhaitez utiliser des plugins, il faut d’abord les rendre accessibles dans la solution. Pour cela, il suffit de les ajouter dans le fichier package.json :

"gulp": "^3.9.0",
"gulp-concat": "^2.6.0",
"gulp-rename": "^1.2.2",
"gulp-uglify": "^1.5.1",
"gulp-clean": "^0.3.1",
"gulp-jshint": "^2.0.0",
"gulp-cssmin": "^0.1.7"

Pour les utiliser dans le fichier gulp.js, il suffira d’en faire la déclaration au début du fichier gulp.js :

var gulp = require('gulp'),
concat = require('gulp-concat'),
rename = require('gulp-rename'),
clean = require('gulp-clean'),
jshint = require('gulp-jshint'),
cssmin = require('gulp-cssmin'),
uglify = require('gulp-uglify');

Nous pouvons maintenant construire nos appels aux plugins. La première étape consiste à créer le clean qui nettoyer les fichiers dans trois dossiers. Il s’agit d’une opération simple et unitaire ; on sélectionne la source des données, et on applique le plugin clean :

gulp.task('clean', function () {
return gulp.src(['wwwroot/lib/*.*', 'temp/', 'css/site.min.css'])
.pipe(clean());
});

Cette implémentation ne fait pas gagner beaucoup d’étapes, ni de tâche, à cause de sa simplicité.

La véritable force de Gulp est son approche de type “pipe” que nous allons découvrir grâce à la prochaine étape : la gestion des fichiers JavaScript du précédent chapitre. Nous réalisions plusieurs étapes :

  • La concaténation des fichiers JavaScript contenu dans le dossier TypeScript
  • La vérification du code
  • L’offuscation et l’optimisation
  • La sauvegarde dans le fichier de livraison wwwroot/lib/

Toutes ces étapes peuvent être réalisées dans une seule tâche Gulp. Chaque ligne renverra un stream ou un fichier qui pourra être utilisé par la ligne suivante :

gulp.task('js-min', function () {
return gulp.src('TypeScript/*.js')
.pipe(concat('Temp/combined2.js'))
.pipe(jshint())
.pipe(uglify())
.pipe(rename('combined2.min.js'))
.pipe(gulp.dest('wwwroot/lib'));
});

Notez qu’il est nécessaire de commencer par donner un nom (rename) à un fichier, puis de choisir la destination. Le plugin rename peut également être utilisé avec un chemin (/lib/combined2.min.js) qui viendra compléter le chemin spécifié dans la destination (dest(wwwroot)).

Mais alors, Grunt ou Gulp ?

Gulp est sur le papier, pour un développeur ASP.NET chevronné, le choix idéal. Son approche syntaxique se rapproche des langages de programmations habituels, ses performances sont meilleures que celles de Grunt et Gulp est aujourd’hui parfaitement intégré à Visual Studio 2015. Cependant, Grunt est une solution qui fonctionne à merveille pour une très grande communauté de développeurs. Il propose aujourd’hui de nombreux plugins qui ne sont pas encore disponible par Gulp. De plus, ses moins bonnes performances n’affectent en rien son utilisabilité, étant donné que le temps d’exécution des tâches dépasse rarement une dizaine de seconde pour les plus gros projets. Dans la majorité des cas, les temps d’exécution ne dépassent que rarement la seconde. En somme, les deux outils remplissent à merveille leurs tâches. Si vous êtes un utilisateur de longue date de Grunt, mieux vaudrait rester sur Grunt pour avoir accès à la totalité des plugins que vous utilisez. Gulp devrait cependant très rapidement rattraper son retard au fur et à mesure que des utilisateurs le choisissent et font gonfler la communauté et les plugins disponibles, et son approche programmatique sera certainement appréciée des utilisateurs. Il faut cependant noter que Gulp aujourd’hui est en pleine expansion, tirant parti d’une communauté de développeurs grandissante. De plus, Microsoft semble vouloir signifier aux développeurs que Gulp sera considéré comme la solution d’automatisation par défaut ; ainsi, si l’on créée une nouvelle application web .NET 5, Microsoft suggère directement de se tourner vers ce moteur comme en témoigne la page par défaut des applications web :

 

npm et les tâches

Je vous avais dit qu’npm était le système de gestion de package de Node. Si cela reste vrai, npm peut cependant également être utilisé comme un outil de build, tel que Grunt et Gulp. Moins versatile et lisible, il permet cependant de réaliser des actions automatiques, déclarées dans le fichier package.json. Des tâches peuvent en effet être déclarées dans le bloc « script » de package.json de la manière suivante :

{
"version": "1.0.0",
"name": "ASP.NET",
"private": true,
"devDependencies": {
"jshint": "^2.9.1"
},
"scripts": {
"jshintTask": "jshint . --exclude node_modules"
}
}

Pour exécuter la tâche, il faudra aller dans la console du gestionnaire de package et taper la ligne :

npm run jshintTask

Notez que ces tâches ne seront pas accessibles par l’explorateur d’exécution des tâches.

 

Conclusion

Il est certain que Microsoft a fait de réels efforts pour intégrer des outils puissants basés sur des technologies du web devenues incontournables. Etant donnée l’ouverture de Microsoft vers ces technologies du Web et l’apparition d’une très forte communauté Open Source, il y a fort à parier que de nombreuses avancées soient encore réalisées et que les développeurs de la communauté Microsoft deviennent des acteurs encore plus influents sur l’ensemble des technologies Web dans le futur.