Gérer vos RIA JavaScript avec Grunt.js

Aujourd’hui, de plus en plus d’applications web sont de véritables RIA (Rich Internet Application) écrites en JavaScript, utilisant des frameworks tels que Backbone.js ou AngularJS et interrogeant des web services REST+JSON. Ces applications sont constituées de simples fichiers statiques (HTML, CSS, JavaScript et images) qui sont la plupart du temps intégrés dans les projets Maven, packagés dans le WAR et déployés sur un Tomcat (enfin dans le meilleur des cas).

Cependant c’est loin d’être idéal.

Tout d’abord l’application web et les web services devraient être séparés avec un côté client et un côté serveur : ils sont inter-dépendants mais ont leur propre cycle de développement.

Cette séparation permet plusieurs optimisations : les fichiers statiques peuvent être servis séparément par un serveur web tel que Apache ou Nginx permettant ainsi de meilleures performances. Il est aussi facile de rajouter un CDN (Content Delivery Network) et/ou un cache : nos fichiers sont statiques, c’est la cible idéale ! Enfin, on peut effectuer de nombreux traitements sur ces fichiers comme la minification du code JavaScript ou CSS.

Jeune padawan : “Bon ok, j’ai mes web services dans un projet Maven, Play, Grails, ça je sais faire. Et pour mon client JavaScript, je fais quoi ? je gère à la main ?”

Maitre Yoda : “Grunt.js tu utilisera !”

Grunt.js : The JavaScript Task Runner

Grunt.js va permettre d’automatiser toutes les tâches qu’on peut rencontrer sur ce genre de projet, à savoir :

  • minification,
  • compilation,
  • execution des tests unitaires,
  • validation syntaxique,
  • serveur de développement,
  • le café

Comme beaucoup d’outils du monde JavaScript, Grunt.js est écrit en ….. JavaScript (ça pour une surprise !) et utilise Node.js pour fonctionner. Il est notamment utilisé par AngularJS.

Comment l’utiliser ?

Pour montrer son utilisation, on va transformer l’application Phonecat du tutorial AngularJS en projet Grunt.js. Le résultat est disponible sur mon Github.

Installation des outils

Comme je l’ai dit tout à l’heure, il faut installer Node.js avant toutes choses (voir documentation de votre distribution Linux préférée). Ensuite, il suffit d’exécuter :

$ npm install -g grunt-cli

Création de l’application

On commence par récupérer l’application Phonecat :

$ git clone git://github.com/angular/angular-phonecat.git

Puis dans le répertoire créé, on va initialiser la création d’un package Node.js (un projet Grunt.js n’est autre qu’un package Node.js déguisé) :

$ npm init

Plusieurs questions vous seront posées comme le nom du projet, la version, l’entry point (pas utile dans notre cas, mais mettez Gruntfile.js pour le principe).

Ensuite il faut rajouter la dépendance à Grunt.js à notre package :

$ npm install grunt --save-dev

Gruntfile.js

Le fichier Gruntfile.js c’est le pom.xml de Grunt.js. C’est dans ce fichier que l’on va définir les plugins à utiliser, les tâches à exécuter et leur configuration. Voici une version minimale du fichier :

1
2
3
4
5
6
7
8
9
10
11
module.exports = function(grunt) {
    // Permet de configurer les plugins et tâches
    grunt.initConfig({
        pkg: grunt.file.readJSON('package.json')
    });

    // Crée la tâche 'default' qui sera exécutée si on ne spécifie
    // aucune tâche
    // Le 2e paramètre indique les tâches qui seront exécutées
    grunt.registerTask('default', []);
};

Il est aussi possible de l’écrire en CoffeeScript en nommant le ficher Gruntfile.coffee. Pour le reste de l’article je continuerai en JavaScript mais personnellement j’ai un petit faible pour le CoffeeScript.

Il ne reste plus qu’à lancer :

$ grunt

Et paf ! Ça ne fait rien ! La plupart d’entre vous l’avait déjà deviné, le Gruntfile.js étant quasi-vide.

Exemple de plugin : minification du JavaScript

On va maintenant ajouter un plugin qui va minifier notre JavaScript grâce à UglifyJS2.

Pour information, la minification de code JavaScript va supprimer tous les caractères inutiles, supprimer le code mort et remplacer les identifiants par des noms courts (et incompréhensibles par la même occasion). L’objectif étant de réduire la taille du fichier. Par exemple, la librairie jQuery (en version 2.0.2) fait 238Kio contre seulement 82Kio après minification.

Tout d’abord, on ajoute la dépendance au package Node.js :

$ npm install grunt-contrib-uglify --save-dev

Ensuite, dans le Gruntfile.js, on charge les tâches du plugin :

1
2
3
4
5
6
7
8
module.exports = function(grunt) {
    ...

    // On charge les tâches du plugin
    grunt.loadNpmTasks('grunt-contrib-uglify');

    ...
};

On y ajoute la configuration :

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
grunt.initConfig({
    pkg: grunt.file.readJSON('package.json'),

    // Configuration du plugin UglifyJS2
    // Les fichiers .js dans le répertoire app/js seront
    // minifiés et concaténés pour produire le fichier
    // app/js/phonecat.min.js
    uglify: {
        minify: {
            files: [ {
                'app/js/phonecat.min.js': ['app/js/*.js']
            } ]
        }
    }
});

Et on ajoute la tâche à la tâche par défaut :

1
2
3
4
5
module.exports = function(grunt) {
    ...

    grunt.registerTask('default', ['uglify:minify']);
};

Voila, maintenant quand vous lancez la commande grunt, les fichiers JavaScript seront minifiés. Le Gruntfile.js complet est ici.

Un exemple complet

Sur Github j’ai mis un exemple complet et commenté pour avoir un Gruntfile.js plus réaliste.

Dans ce fichier, j’y déclare 2 tâches : dev (appelée par défaut) et prod. La tâche dev permet de :

  1. nettoyer le projet
  2. compiler les fichiers CoffeeScript en JavaScript
  3. compiler les fichiers {less} en CSS
  4. démarrer un serveur qui va servir nos petits fichiers
  5. surveiller si des fichiers ont été modifiés et relancer la tâche qu’il faut si c’est le cas (modification d’un fichier CoffeeScript et paf, ça recompile !)

Et la tâche prod permet de :

  1. nettoyer le projet
  2. compiler les fichiers CoffeeScript en JavaScript
  3. minifier le JavaScript
  4. compiler les fichiers {less} en CSS
  5. minifier le CSS
  6. minifier le HTML

En combinant les plugins, on peut donc définir son propre workflow.

Le sanglier, ça a du bon !

Grunt.js permet d’automatiser pleins de petites tâches et une fois qu’on a commencé, on n’arrête plus ! C’est un outil indispensable pour des projets JavaScripts.

De nombreux plugins sont disponibles pour effectuer pleins de tâches : compilation, minification, exécution de tests unitaires, optimisation d’images, création d’archive, génération de templates, … Tous les plugins sont ici.

Il faut savoir qu’il existe aussi des templates tous faits qui permettent de créer des projets vides rapidement avec les technologies que l’on veut un peu à la manière d’un archetype Maven.

De plus, d’autres outils accompagnent Grunt.js tel que Bower qui permet de télécharger automatiquement en local les librairies utilisées dans le projet (jQuery, RequireJS, …) et d’autres.

Un bon point de départ pour tout néophyte est le projet Yeoman qui explique les outils et le workflow à utiliser pour des projets complètement JavaScript.

Quelques liens

  • Grunt.js : la documentation est bien faite
  • Node.js : la technologie sans quoi rien n’est possible en JS
  • Bower : permet de télécharger des librairies JS et de les ajouter à son projet
  • Yeoman : collection d’outils pour vos projets JavaScript
  • CoffeeScript : le rêve de tout développeur JS
  • {less} : le CSS avec des variables, de l’héritage de style, …
VN:R_U [1.9.22_1171]
Rating: +1 (from 1 vote)
Share
Ce contenu a été publié dans Non classé, avec comme mot(s)-clef(s) , , , , . Vous pouvez le mettre en favoris avec ce permalien.

Laisser un commentaire