Concat & Watch: La leggerezza di utilizzare Grunt come Task Runner

Nello sviluppo delle applicazioni web, mobile, abbiamo spesso la necessità di ripetere delle operazioni che ci aiutino, per esempio, a definire un pacchetto per la distribuzione del software, la creazione di un unico file di stile a partire dai vari file che abbiamo a disposizione o che magari ci permettano di accorgerci che un file è stato modificato ed eseguire le opportune operazioni per la sua gestione.
In un linguaggio come Java ci viene in aiuto Maven che pernmette, appurto, di gestire le dipendenze, compilare i nostri file, spostarli e fare il pacchetto per la distribuzione (si possono fare molte più cose con Maven, ma esulano dagli scopi di questo articolo).
Un potentissimo strumento che possiamo utilizzare coi nostri progetti WEB si chiama Grunt.
Grunt è una libreria npm, quindi possiamo installarlo tramite l’istruzione:

npm install -g grunt-cli

In questo modo viene installata la Command Line Interface che ci permetterà di gestire il nostro progetto con Grunt (l’opzione -g dice che la libreria verrà installata a livello globale in modo che si possa utilizzare nell’intero sistema).

Abbiamo anche la possibilità di installare una specifica versione eseguendo il comando:

npm install grunt@VERSION --save-dev

Dopo aver installato grunt, inizializziamo il progetto facendo creare ad npm il file package.json per noi. Questo file raccoglie le informazioni sul progetto come il nome, la versione e le dipendenze per esempio. Creiamo il file con il comando:

npm init

Schermata 2016-01-12 alle 05.56.58

Il comando lanciato, come evidenziato dall’immagine, è interattivo e quindi ci chiederà se vogliamo modificare il nome del progetto, la sua versione e una serie di altre informazioni. Dopo aver fornito tutte le informazioni che vogliamo ci verrà presentato il contenuto del file che sta per essere creato, se confermato avremo:

Schermata 2016-01-12 alle 06.15.21

Abbiamo così creato il nostro file package.json che viene utilizzato da nodejs per definire tutte le informazioni necessarie per il nostro progetto.
Per installare Grunt nel mio progetto, eseguiamo il comando:

npm install -S grunt

Tale comando avrà il doppio effetto di installare grunt come modulo nodejs:

Schermata 2016-01-12 alle 06.26.22

Vedendo il file system avremo:

Schermata 2016-01-12 alle 06.28.03

e scrivere una nuova informazione all’interno del notro package.json che definisce la dipendenza da Grunt del nostro progetto.

Schermata 2016-01-12 alle 06.30.31

Dopo aver installato grunt procediamo con la creazione del file necessario a Grunt stesso, per eseguire i task:

touch Gruntfile.js

Cominciamo col creare il nostro primo Task che ci permetterà di concatenare il contenuto di più file in modo da averne solo uno per i javascript ed uno per i css.

Andiamo sul sito di Grunt, nella sezione plugin: gruntjs.com/plugins e cerchiamo il plugin che ci interessa (nel nostro caso contrib-concat):

Schermata 2016-01-12 alle 06.48.11

Cliccando sul plugin che ci interessa abbiamo tutte le info necessarie per l’installazione e l’utilizzo del plugin.
Nel terminale scriviamo, quindi:

npm install grunt-contrib-concat --save-dev

Questo comando aggiungerà il plugin tra i moduli nodejs e come dipendenza di sviluppo nel file package.json

Schermata 2016-01-12 alle 06.53.50

La dipendenza verrà utilizzata solo in “sviluppo” perché le operazioni che stiamo eseguendo sono utili solo in questo ambiente.

Nel file Gruntfile.js scriviamo, quindi:

module.exports = function(grunt) {
    
    // Project configuration. 
    grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      concat: {
        css: {
          src: ['css/file1.css', 'css/file2.css'],
          dest: 'build/css/style.css',
        },
        js: {
          src: ['js/file1.js', 'js/file2.js'],
          dest: 'build/js/main.js',
        },
      },
    });
    
    grunt.loadNpmTasks('grunt-contrib-concat');
}

In questo modo, eseguendo il comando:

grunt concat

Verranno creati automaticamente i file style.css e main.js, nelle cartelle specificate, il cui contenuto è la concatenazione dei contenuti dei file specificati dall’attributo src (in css e js).

Schermata 2016-01-12 alle 07.20.53

Facciamo un ulteriore passo avanti, perché siamo un po’ lazy e non ci va di eseguire ogni volta il comando grunt concat. In questo caso utilizzeremo un nuovo plugin denominato contrib-watch che, come dice il nome, si mette a “guardare” i cambiamenti nei file che gli definiremo e quando ne vedrà uno eseguirà il task concat per noi.

Andiamo sempre nella pagina plugins del sito gruntjs.com e vediamo come utilizzare questo plugin.
Dopo averlo installato col comando :

npm install grunt-contrib-watch --save-dev

Il nostro file package.js sarà, quindi:

Schermata 2016-01-12 alle 07.25.48

Come possiamo vedere, nel nostro progetto è ora presente la libreria grunt-contrib-watch, che useremo per implementare un meccanismo di aggiornamento automatico nel caso facessimo delle modifiche nei file “controllati”.
Nel nostro file di configurazione Gruntfile.js scriviamo il blocco:

        watch: {
          css: {
            files: ['css/**/*.css'],
            tasks: ['concat:css'],
          },
          js: {
            files: ['js/**/*.js'],
            tasks: ['concat:js'],
          },
        },

che per essere utilizzato va “importato” tramite l’istruzione:

grunt.loadNpmTasks('grunt-contrib-watch');

A questo punto eseguendo il comando:

grunt watch

Grunt si mette in attesa che vengano effettuate modifiche nei file compresi nell’array definiti con l’attributo files. Se modifichiamo i file e li salviamo Grunt si occuperà in automatico di chiamare il task concat.
Da notare che per definire l’aggiornamento dei file opportuni ho potuto lanciare un sotto-task suddividendo il nome con i due punti :

tasks: ['concat:css']  /* Nel caso dei CSS */
tasks: ['concat:js']  /* Nel caso dei JS */

Facciamo uno sforzo finale, facendo in modo e aggiungiamo un comando per lanciare i nostri task in modo più usabile e senza specificare il nome dei specifici task da eseguire. Inseriamo l’istruzione:

grunt.registerTask('default', ['concat', 'watch']);

Il nostro Gruntfile.js finale sarà, quindi:

module.exports = function(grunt) {
    
    // Project configuration. 
    grunt.initConfig({
      pkg: grunt.file.readJSON('package.json'),
      concat: {
        css: {
          src: ['css/file1.css', 'css/file2.css'],
          dest: 'build/css/style.css',
        },
        js: {
          src: ['js/file1.js', 'js/file2.js'],
          dest: 'build/js/main.js',
        },
      },
        watch: {
          css: {
            files: ['css/**/*.css'],
            tasks: ['concat:css'],
          },
          js: {
            files: ['js/**/*.js'],
            tasks: ['concat:js'],
          },
        },
    });
    
    grunt.loadNpmTasks('grunt-contrib-concat');
    grunt.loadNpmTasks('grunt-contrib-watch');
    
    grunt.registerTask('default', ['concat', 'watch']);
}

In questo modo possiamo scrivere, su linea di comando:

grunt

Che eseguirà prima il task concat creando i file style.css e main.js concatenando i file di partenza e mettendosi in attesa di modifiche sui file per poterli aggiornare.

Schermata 2016-01-13 alle 05.45.02

In altri articoli vedremo in profondità altre funzionalità che questo semplice ma potente strumento ci mette a disposizione.

RSS AngularJob

ddelfio Written by: