Setup Menus in Admin Panel

School.Dataninja.it

Applicazioni web: automatizzare le operazioni ripetitive con Grunt

Durante lo sviluppo di un'applicazione ti troverai spesso a ripetere operazioni sui file di progetto: l'uso di gestori automatici di task permette di risparmiare tempo, evitare errori e ottenere applicazioni più robuste, semplice e veloci.

Lo sviluppo software in ambito web si fa sostanzialmente scrivendo file di testo, ma quando si va anche solo di poco oltre singole istruzioni (dette anche script) è necessario strutturare bene il processo e l’ambiente di lavoro e scegliere gli strumenti giusti. Nelle unità precedenti hai visto come Git permette di mantenere e gestire uno storico del progetto e Bower di sfruttare facilmente le infinite librerie riusabili disponibili. Visti da vicino, questi strumenti specializzati automatizzano tutta una serie di operazioni ripetitive, nascondendone la complessità sotto il cofano: tu sviluppatore dici a Bower di installare una libreria, Bower in silenzio la cerca, la verifica, la scarica, la copia nella cartella giusta, ne controlla le dipendenze, installa eventualmente anche quelle, ecc. Tutte operazioni che puoi fare a mano, ma che non avrebbe senso fare una volta che c’è uno strumento sviluppato apposta.

Grunt, The JavaScript Task Runner

L’idea di automatizzare processi predeterminati e ripetitivi viene affrontata in senso generale da strumenti noti come task manager, ovvero gestori di compiti. L’utente li istruisce opportunamente con un linguaggio di alto livello (copia quello che trovi qui, verifica che ci siano queste condizioni, concatena e comprimi questi file in uno nuovo) e loro si occupano del lavoro sporco. In poche frazioni di secondo, naturalmente. Grunt è uno dei task manager per javascript più famosi, ma ce ne sono altri, come per esempio Gulp (sì, si diventa mattacchioni scrivendo codice) oppure Webpack.

Installare Grunt

Grunt è un’applicazione di Nodejs, per cui devi prima installare quest’ultimo, insieme al gestore dei pacchetti npm. Se queste dipendenze di sistema sono soddisfatte, come tutti i pacchetti npm da un terminale devi solo eseguire il comando: npm install -g grunt-cli  (probabilmente da super utente se sei su un sistema Linux). Trovi maggiori dettagli sul funzionamento della Common Line Interface (CLI) di Grunt nella guida ufficiale.

Ora hai a disposizione il nuovo comando grunt globalmente (grazie all’opzione -g), con cui puoi automatizzare le operazioni sui file di ogni tuo progetto. Di per sé, però, Grunt fa ben poco, perché serve per gestire task (eseguirli, concatenarli, ecc.), non definisce alcun task. Gli elementi che eseguono le operazioni di basso livello (spostare materialmente un file da una cartella all’altra, per esempio) sono rilasciati come plugin a parte, installabili a piacere a seconda delle necessità specifiche, in un approccio modulare molto efficace.

Per essere usato al meglio, Grunt richiede che il progetto sia corredato del file package.json in cui sono descritte le dipendenze del progetto, sia in produzione che in fase di sviluppo. Le librerie installate con Bower per esempio sono dipendenze di produzione (servono all’applicazione per funzionare!), mentre i plugin di Grunt sono tipicamente dipendenze di sviluppo (una volta terminata, l’applicazione non ne ha bisogno per funzionare).

Installare i plugin di Grunt

I plugin di Grunt sono applicazioni di Nodejs come tutte le altre. Devono essere installate mediante npm e Grunt deve sapere dove trovarle per utilizzarle quando serve. Come esempio prendiamo uno dei plugin più semplici e utili, quello che permette di copiare file da una cartella all’altra: grunt-contrib-copy. Mettiti nella cartella del tuo progetto dove è localizzato il file package.json e installa il plugin con il comando npm install grunt-contrib-copy --save-dev . L’opzione –save-dev salva questa dipendenza nel file package.json come dipendenza di sviluppo, esattamente come –save salvava le librerie installate con Bower come dipendenze di produzione. I file necessari al plugin sono scaricati nella cartella node_modules/ del tuo progetto (non saranno disponibili globalmente, infatti nel comando di installazione manca l’opzione -g).

Inizializzare il progetto: il Gruntfile.js

Quando lanci il comando grunt, Grunt si aspetta di leggere le operazioni da compiere in un file chiamato Gruntfile.js, che a tutti gli effetti è un pezzo di un’applicazione javascript. È qui che descriverai i task da compiere secondo le logiche richieste dal tuo progetto. A prima vista il Gruntfile ti apparirà abbastanza incomprensibile, ma solo perché usa molte convenzioni che bisogna conoscere prima. Per fortuna non è necessario cominciare da zero: ecco per esempio come dovrebbe apparire il tuo Gruntfile.js nel caso tu voglia copiare automaticamente i file delle librerie necessarie al tuo progetto dalla cartella di Bower (bower_components/vendor/) a quella di produzione (lib/).

Se il tuo progetto è corredato con il package.json visto nell’unità sulla struttura di file e cartelle, probabilmente l’esecuzione di grunt con questo Gruntfile non eseguirà nulla o produrrà un errore. Questo perché fai riferimento all’attributo pkg.files letto dal package.json che non esiste. Apri dunque il file package.json e aggiungi i file di libreria da cui il tuo progetto effettivamente dipende.

Eseguire un task

Ricapitolando: con Bower hai installato la libreria d3js che ora si trova nella cartella bower_components/d3/. Nel file package.json hai indicato che il tuo progetto ha bisogno del solo file d3.min.js della libreria, l’unico che includerai con un tag script nel file index.html. Quando leggerà il file package.json, ora Grunt saprà quali file andare a prendere e dove (tutti quelli nella lista files sotto la cartella bower_components/) e li copierà nella cartella lib/ mantenendo inalterata la struttura delle sotto cartelle: da bower_components/d3/d3.min.js a lib/d3/d3.min.js. Per farlo materialmente è sufficiente il comando grunt (che esegue il task di default).

In questo modo nella cartella lib/ ci saranno tutti e solo i file strettamente necessari alla tua applicazione. Sarà da qui che includerai i file js e css nel file index.html. E con Git potrai tenere traccia solo della cartella lib/ e dei file bower.json, package.json e Gruntfile.js e ignorare completamente le cartelle bower_components/ e node_modules/, utili solo alla fase di sviluppo e ricostruibili in pochi secondi con i comandi bower install (si basa su bower.json), npm install (si basa su package.json), grunt (si basa su Gruntfile.js e package.json).

Per far sì che Git ignori sistematicamente file e cartelle specifici, crea un file .gitignore (il punto iniziale!) nella cartella del tuo progetto e scrivi un file o cartella per riga. Per esempio “bower_components/” e “node_modules/” su due righe. Ricordati poi di aggiungerlo e inserirlo nel prossimo commit: git add .gitignore && git commit 

Comporre più task

Una volta capita la struttura del Gruntfile e la logica con cui Grunt gestisce i task, definire ed eseguire operazioni complicate a piacere è solo questione di trovare e installare i plugin giusti, comprenderne le funzionalità e i parametri che puoi personalizzare e concatenarne l’esecuzione opportunamente. Tanto per fare un esempio, c’è un plugin che gestisce proprio la copia di librerie gestite da Bower: grunt-bower-task. Nella documentazione ufficiale ci sono molti esempi su come definire e comporre task, mentre per cercare il plugin che fa per te c’è un comodo motore di ricerca. Non dimenticare poi che nel Gruntfile c’è puro e semplice javascript, quindi puoi scrivere ed eseguire tutte le funzioni e le operazioni che vuoi, accedendo e manipolando le informazioni contenute nel package.json o le opzioni su cui si basano i vari plugin.

Nella prossima unità, quella conclusiva, metterai in pratica tutto ciò che hai visto nel corso costruendo da zero un’applicazione completa di visualizzazione di dati e facendo uso di Git, Bower e Grunt.

Letture: 552