Artículo

Una introducción a Gulp para el desarrollador frontend. Parte 1

Gulp es un automatizador de tareas, es decir, se encarga de realizar por nosotros tareas que son tediosas y repetitivas que no aportan nada al desarrollo y nos hacen perder tiempo. Tareas como: concatenar archivos, renombrar archivos, compilar, recargar el navegador, etc. Realmente con Gulp podemos hacer cuanto se nos ocurra. En este artículo trataré de enseñarte lo más esencial de Gulp para que puedes empezar a utilizarlo en tus proyectos.

La filosofía de Gulp es ser muy simple y con una funcionalidad muy básica e ir añadiéndole nuevas funcionalidades a través de plugins. Esto es ideal para que siempre se adapte perfectamente al tipo de proyecto que estamos realizando instalando los plugins necesarios. La mejor manera de ver una herramienta es utilizándola, así que vamos a ello.

Antes que nada es bueno tener instalado en nuestro equipo gulp de forma global.

npm install --global gulp-cli

Creando un proyecto básico

Vamos a empezar creando un proyecto muy básico con la siguiente estructura.

- proyecto-gulp/
    - src/
        - html/
            - index.html
        - js/
            - sumar.js
            - restar.js
    - package.js

estructura

Puedes crearlo manualmente o utilizar la consola como se muestra debajo. Si no sabes usar el terminal tenemos este artículo con lo básico. Lo mismo en este otro artículo para NPM y Bower.

C:\wamp\www
λ mkdir proyecto-gulp

C:\wamp\www
λ cd proyecto-gulp\

C:\wamp\www\proyecto-gulp
λ mkdir src

C:\wamp\www\proyecto-gulp
λ cd src\

C:\wamp\www\proyecto-gulp\src
λ mkdir html js

C:\wamp\www\proyecto-gulp\src
λ touch html\index.html

C:\wamp\www\proyecto-gulp\src
λ touch js\sumar.js js\restar.js

C:\wamp\www\proyecto-gulp\src
λ cd ..

C:\wamp\www\proyecto-gulp
λ npm init
This utility will walk you through creating a package.json file.
It only covers the most common items, and tries to guess sensible defaults.

See `npm help json` for definitive documentation on these fields
and exactly what they do.

Use `npm install  --save` afterwards to install a package and
save it as a dependency in the package.json file.

Press ^C at any time to quit.
name: (proyecto-gulp)
version: (1.0.0)
description: Proyecto de prueba para gulp.
entry point: (index.js)
test command:
git repository:
keywords:
author: Adrián Guerra
license: (ISC)
About to write to C:\wamp\www\proyecto-gulp\package.json:

{
  "name": "proyecto-gulp",
  "version": "1.0.0",
  "description": "Proyecto de prueba para gulp.",
  "main": "index.js",
  "scripts": {
    "test": "echo \"Error: no test specified\" && exit 1"
  },
  "author": "Adrián Guerra",
  "license": "ISC"
}


Is this ok? (yes)

C:\wamp\www\proyecto-gulp  (proyecto-gulp@1.0.0)

Añadimos algo de contenido a nuestros archivos, para que sirvan de ejemplo. Dejo un comentario que no hay que incluir al principio de cara archivo para que se sepa cual es.

<!-- Archivo index.html -->

<!DOCTYPE html>
<html>
<head>
    <meta charset="utf-8">
    <title>Hola Gulp</title>
</head>
<body>
    <h1>Ejemplo de Gulp</h1>

</body>
</html>
// Archivo sumar.js

var sumar = function(a, b) {
    return a + b;
};
// Archivo restar.js

var restar = function(a, b) {
    return a - b;
};

Ahora con toda la estructura básica creada procedemos a instalar Gulp en nuestro proyecto.

npm install -D gulp

Para poder usar gulp necesitamos añadir a nuestro proyecto un archivo gulpfile.js

C:\wamp\www\proyecto-gulp  (proyecto-gulp@1.0.0)
λ touch gulpfile.js

Gulp está basado en tareas. Esto quiere decir que tendremos varias tareas y que cada tarea hace algo concreto. Básicamente lo que hace Gulp es ejecutar tareas definidas en el archivo gulpfile.js.

Ahora vamos a editar nuestro archivo gulpfile.js.

var gulp = require('gulp');

gulp.task('html', function() {
    // Código de la tarea
});

Lo primera línea lo que hace es utilizar require para importar gulp a nuestro archivo. Esto lo debemos hacer también con cada uno de los plugins que utilicemos.

A continuación lo que hacemos es definir una tarea gulp con gulp.task, un método que recibe dos parámetros: Un string con el nombre de la tarea y una función con la tarea a ejecutar.

para ejecutar dicha tarea basta con escribir en el terminal:

C:\wamp\www\proyecto-gulp  (proyecto-gulp@1.0.0)
λ gulp html
[17:19:19] Using gulpfile C:\wamp\www\proyecto-gulp\gulpfile.js
[17:19:19] Starting 'html'...
[17:19:19] Finished 'html' after 57 μs

Como vemos gulp nos indica que archivo gulpfile está usando, cuando empieza a ejecutar la tarea y cuando acaba. Obviamente esta tarea no hace nada ya que está vacía.

Vamos a hacer que nuestra tarea html coja los archivos HTML que se encuentran en la carpeta src y los copie en una carpeta llamada dist.

var gulp = require('gulp');

gulp.task('html', function() {
    gulp.src('src/html/index.html')
        .pipe(gulp.dest('dist'));
});

Ahora nuestra tarea recibe los ficheros de entrada por el método gulp.src y con ello se crea un stream que puede ser usado por otros plugins para operar sobre él o se lo pasamos a gulp.dest para que genere un fichero de salida.

La forma de pasar el stream generado por gulp.src a otros plugins o a gulp.dest es mediante el método pipe.

Probamos a ejecutar nuestra tarea de nuevo.

C:\wamp\www\proyecto-gulp  (proyecto-gulp@1.0.0)
λ gulp html
[17:26:05] Using gulpfile C:\wamp\www\proyecto-gulp\gulpfile.js
[17:26:05] Starting 'html'...
[17:26:05] Finished 'html' after 5.93 ms

Ahora si te fijas se nos habrá creado dentro de nuestro proyecto una directorio llamado dist que contiene el archivo index.html.

tarea

Pero que pasa si tuvieramos más de un archivo html y quisieramos copiarlo. La función gulp.src admite también el paso de arrays.

gulp.task('html', function() {
    gulp.src(['src/html/index.html', 'src/html/otro.html'])
        .pipe(gulp.dest('dist'));
});

Pero la forma más efectiva es usando glob que acepta muchos patrones para añadir archivs masivamente.

gulp.task('html', function() {
    gulp.src('src/html/**/*.html')
        .pipe(gulp.dest('dist'));
});

Con /**/*.html le indicamos que queremos que tome como fichero fuente todos los archivos que acaben en .html del directorio src/html/ y de todos sus subdirectorios.

Utilizando plugins

Hemos visto como crear una tarea gulp y utilizarla para copiar archivos de un directorio a otro, pero la verdadera potencia de gulp está es sus plugins.

Vamos a crear una tarea llamada js que coja todos los archivos con extensión .jsque se encuentren en el directorio src/js/ los concate en un único archivo llamado app.min.js y comprima el código para que ocupe lo menos posible.

Para ello tenemos que instalar los plugins necesarios que son gulp-concat y gulp-uglify.

npm install -D gulp-uglify gulp-concat

Ahora añadimos los require necesarios y creamos la nueva tarea.

var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');

gulp.task('html', function() {
    gulp.src('src/html/**/*.html')
        .pipe(gulp.dest('dist'));
});

gulp.task('js', function() {
    gulp.src('src/js/**/*.js')
        .pipe(concat('app.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'));
});

Esta nueva tarea coge todos los archivos con extensión .js de la carpeta src/js/ y los envía por medio de un pipe al plugin concat que recibe como parámetro el nombre del archivo de salida de todos los archivos concatenados.

Una vez ha terminado su misión el plugin contact le envíamos el resultado al plugin uglify que se encargará de comprimir el archivo.

Por último el resultado se lo enviamos a gulp.dest para que coloque el archivo en el directorio dist/js. Podemos ejecutar la tarea js.

λ gulp js
[20:26:52] Using gulpfile C:\wamp\www\proyecto-gulp\gulpfile.js
[20:26:52] Starting 'js'...
[20:26:52] Finished 'js' after 8.4 ms

Y veremos que nos genera el archivo app.min.js dentro del directorio dist/js/. Si vemos el archivo será algo así:

var restar=function(r,n){return r-n},sumar=function(r,n){return r+n};

Tareas que ejecutan tareas

Una de las ventajas de Gulp es que podemos programar tareas que ejecutan otras tareas. Esto es útil para tener una tarea que nos ejecute todo el set y no tener que ir ejecutando una por una.

gulp.task('default', ['html', 'js']);

La tarea default recibe un array con nombres de otras tareas, en este caso las tareas html y js. Ahora la podemos ejecutar.

C:\wamp\www\proyecto-gulp  (proyecto-gulp@1.0.0)
λ gulp
[20:31:14] Using gulpfile C:\wamp\www\proyecto-gulp\gulpfile.js
[20:31:14] Starting 'html'...
[20:31:14] Finished 'html' after 6.12 ms
[20:31:14] Starting 'js'...
[20:31:14] Finished 'js' after 3.57 ms
[20:31:14] Starting 'default'...
[20:31:14] Finished 'default' after 3.72 μs

Tip: Si te fijas, no hemos usdo gulp default para ejecutar la tarea sino, simplemente gulp. Esto es porque default es una tarea especial de gulp que se ejecuta sin tener que nombrarla.

Como vemos con ejecutar la tarea default esta se encarga de ejecutar las otras dos. Es importante tener en cuenta que cuando una tarea ejecuta otras tareas primero se completan completamente estas y luego se ejecuta nuestra tarea.

En este caso primero se ejecutan las tareas html y js paralelamente y cuando acaban se ejecuta el código de la función default, que en este caso no tiene.

¿Qué pasa si queremos ejecutar las tareas por orden: primero la tarea html luego la tarea js y por último la tarea default. Deberíamos hacer algo como lo siguiente.

var gulp = require('gulp');
var concat = require('gulp-concat');
var uglify = require('gulp-uglify');

gulp.task('html', function() {
    gulp.src('src/html/**/*.html')
        .pipe(gulp.dest('dist'));
});

gulp.task('js', ['html'] ,function() {
    gulp.src('src/js/**/*.js')
        .pipe(concat('app.min.js'))
        .pipe(uglify())
        .pipe(gulp.dest('dist/js'));
});

gulp.task('default', ['js']);

En este caso la tarea default ejecuta primero la tarea js, pero como la tarea js recibe como parámetro la tarea html antes de ejecutarse ejecuta el código de esta.

Como este sistema es algo engorroso y nada claro cuando tenemos muchas tareas existe un plugin llamado run-sequence que perimite hacer esto mucho más fácil. Si quieres más información de todo esto en el libro de AGM Studio se explica su uso con todo detalle.

En la segunda parte de este artículo veremos como vigilar archivos para que se ejecuten tareas sobre la marcha cuando se detecta algún cambio y también como crear un servidor de prueba que recargue nuestra página automáticamente cuando hay cambios.

Actualización: Ya está disponible la segunda parte.

Comentarios