Grunt és un task runner de JavaScript, una eina utilitzada per realitzar automàticament tasques freqüents com minificació, compilació, proves unitàries i linting.
Utilitza una interfície de línia d’ordres per executar tasques personalitzades definides en un arxiu (conegut com Gruntfile). Grunt es distribueix a través de NPM i compta amb multitud de complements disponibles.
Abans de començar, convé actualitzar NPM (Llibreria de programari, instal·lador i gestor de paquets), amb el comand:
npm update -g npm
Instal·lem el CLI (Command Line Interface) de grunt de forma global:
npm install -g grunt-cli
Ens desplacem a la carpeta del projecte (p.e. cd [nom-del-projecte]), des done preparem el projecte Grunt, creant el fitxer package.json, mitjançant la ordre:
npm init -y
Després instal·lem Grunt, generant les dependències:
npm install grunt --save-dev
En aquest punt, podem instal·lar els complements (tasques) que volem utilitzar en el nostre projecte, podem instal·lar les següents, dependent quines tasques volem utilitzar:
- Eliminar fitxers i carpetes:
npm install grunt-contrib-clean –save-dev - Concatenar fitxers:
npm install grunt-contrib-concat –save-dev - Comprimir fitxers CSS:
npm install grunt-contrib-cssmin –save-dev - Compilació fitxers Sass a CSS:
npm install grunt-contrib-Sass –save-dev - Minificar fitxers JavaScript:
npm install grunt-contrib-uglify –save-dev - Executar tasques predeterminades quan s’afegeixen, modifiquen o eliminen determinats fitxers:
npm install grunt-contrib-watch –save-dev - Minificar imatges de format PNG, JPEG, GIF i SVG:
npm install grunt-contrib-imagemin –save-dev - Validar fitxers amb JSHint:
npm install grunt-contrib-jshint –save-dev - Copia fitxers:
npm install grunt-contrib-copy –save-dev - Prefixar fitxers CSS:
npm install grunt-autoprefixer –save-dev - Transferir fitxers usant FTP:
npm install grunt-ftp-push –save-dev - Sincronitzar l’explorador:
npm install grunt-browser-sync –save-dev
Ara queda definir en el fitxer Gruntfile.js les tasques concretes. En aquest fitxer tenim per una banda les tasques (grunt.initConfig), la càrrega dels complements (grunt.loadNPMTasks) i el registre de tasques (grunt.registerTask).
module.exports = function(grunt) { grunt.initConfig({ sass: { dev: { files: { 'src/style.css': 'src/sass/style.scss' } }, dist: { options: { style: 'compressed', sourcemap: 'none' }, files: [{ expand: true, cwd: 'src/sass', src: ['.scss'], dest: 'src', ext: '.css' }] } }, autoprefixer: { options: { browsers: ['last 2 version','ie 10'], grid: true }, dist: { files: [{ expand: true, cwd: 'src', src: 'style.css', dest: 'src', ext: '.pre.css' }] } }, cssmin: { dist: { src: 'src/style.pre.css', dest: 'dist/style.css' } }, clean: { dist: { src: ['dist/'] }, uploads: { src: ['dist-uploads/'] } }, concat: { options: { separator: ';', }, js: { src: ['src/js/.js','!src/js/built.js'], dest: 'src/js/built.js' } }, uglify: { dist: { files: [{ expand: true, cwd: 'src/', src: 'js/.js', dest: 'dist/', }] } }, imagemin: { dist: { files: [{ expand: true, cwd: 'src/', src: ['/.{png,jpg,gif,svg}'], dest: 'dist/' }] }, uploads: { files: [{ expand: true, cwd: 'uploads/', src: ['/.{png,jpg,gif,svg}'], dest: 'dist-uploads/' }] } }, copy: { dist: { expand: true, cwd: 'src/', src: ['/.php'], dest: 'dist/' }, style: { expand: true, cwd: 'src/', src: ['style.css'], dest: 'dist/' }, localhost: { expand: true, cwd: 'dist/', src: ['/'], dest: 'c:/xampp/htdocs/wordpress/wp-content/themes/proyecto/' } }, ftp_push: { options: { host: 'ftp.proyecto.com', username: 'user', password: 'pass', dest: 'proyecto', }, dist: { files: [{ expand: true, cwd: 'dist/', src: ['/'], dest:'wp-content/themes/proyecto/' }] }, uploads: { files: [{ expand: true, cwd: 'dist-uploads/', src: ['/'], dest:'wp-content/uploads/' }] } }, browserSync: { dev: { bsFiles: { src : ['c:/xampp/htdocs/wordpress/wp-content/themes/proyecto//'] }, options: { watchTask: true, proxy: 'localhost/proyecto', } } }, jshint: { dev: ['src/js/.js'] }, watch: { options: { livereload: true }, sass: { files: ['src/sass/style.scss'], tasks: ['sass:dev'] }, diststyle: { files: ['src/style.css'], tasks: ['clean:dist','copy:style','copy:localhost'] }, js: { files: ['src/js/.js'], tasks: ['jshint:dev'] } }, }); grunt.loadNpmTasks('grunt-contrib-sass'); grunt.loadNpmTasks('grunt-contrib-watch'); grunt.loadNpmTasks('grunt-contrib-clean'); grunt.loadNpmTasks('grunt-contrib-concat'); grunt.loadNpmTasks('grunt-contrib-uglify'); grunt.loadNpmTasks('grunt-contrib-imagemin'); grunt.loadNpmTasks('grunt-contrib-copy'); grunt.loadNpmTasks('grunt-browser-sync'); grunt.loadNpmTasks('grunt-contrib-jshint'); grunt.loadNpmTasks('grunt-contrib-cssmin'); grunt.loadNpmTasks('grunt-ftp-push'); grunt.loadNpmTasks('grunt-autoprefixer'); grunt.registerTask('default',['browserSync:dev','watch:sass','watch:diststyle']); grunt.registerTask('distribute',[ 'clean:dist', 'autoprefixer:dist', 'cssmin:dist', 'uglify:dist', 'imagemin:dist', 'copy:dist' ]); grunt.registerTask('pushweb',['ftp_push:dist']); grunt.registerTask('pushuploads',['clean:uploads','imagemin:uploads','ftp_push:uploads']); grunt.registerTask('pushlocal', ['copy:localhost']); };
Per executar una tasca (p.e., distribute):
grunt distribute
En aquest cas, aquesta tasca realitza el següent:
- Elimina els fitxers de la carpeta dist.
- Autoprefija el fitxer CSS style.css de la carpeta src, generant el fitxer style.pre.css.
- Minimitza el fitxer style.pre.css, generant el fitxer style.css a la carpeta dist.
- Minimitza els arxius js de la carpeta src/js a la carpeta dist/js.
- Minimitza els arxius d’imatge de formats png, jpg, gif i svg de la carpeta src i les seves subcarpetes de la carpeta dist.
- Copia els fitxers de la carpeta dist a la carpeta del nostre projecte c:/xampp/htdocs/wordpress/wp-content/themes/projecte /.
Si executem grunt, es carreguen les tasques per defecte (default), que en aquest cas carrega el sincronitzador de l’explorador i l’observador (watch), que compila els fitxers Sass a CSS.
Si volem executar una tasca concreta, per exemple, pujar el nostre projecte local al nostre servidor web (p.e., ftp.proyecto.com), executem:
grunt pushweb
Si volem que la tasca de compilació es faci sempre que s’observen canvis en els fitxers Sass, executem la ordre:
grunt watch:sass
en el qual hem indicat la tasca i el seu target específic a executar.
Si volem buidar la carpeta dist-uploads:
grunt clean:uploads
Si volem minimitzar les imatges de la carpeta uploads i passar-les a la carpeta dist-uploads:
grunt imagemin:uploads
Modificant el fitxer Gruntfile.js podem generar noves tasques, redefinir i adaptar-les al nostre projecte en concret, de manera que automatitzar tasques repetitives que realitzem durant el desenvolupament del projecte, estalviant temps i millorant la productivitat.