Gulp.js en español – tutorial básico y primeros pasos

En este artículo, vamos a aprender a utilizar Gulp.js para mejorar y acelerar nuestro flujo de trabajo al desarrollar y tratar de entender su funcionamiento.

¿Qué es Gulp.js?

Gulp.js es un build system(sistema de construcción) que permite automatizar tareas comunes de desarrollo, tales como la minificación de código JavaScript, recarga del navegador, compresión de imágenes, validación de sintaxis de código y un sin fin de tareas más.

Como verás no importa si eres un desarrollador Front-End, Back-End ó los dos a la vez. Si hoy en día no quieres perder tiempo realizando tareas comunes “manualmente”, es momento de que aprendas a usar un automatizador como Gulp.js.

Adicionalmente Gulp.js está construído con Javascript, funciona sobre Node.js y es Open Source, así que su código fuente lo puedes encontrar en github.

¿Por qué te debería interesar usar Gulp.js?

Porque hoy en día el flujo de trabajo de un desarrollador se ha vuelto más complejo, usamos muchas herramientas de desarrollo, por lo cual configurar cada tarea y ejecutarla “manualmente” y por separado requiere demasiado tiempo.

Porque Gulp.js no sólo soluciona este problema sino que le aporta mejoras, convirtiendose en una herramienta que tiene prácticamente todo en uno, así mismo nos permite administrar y controlar todas esas tareas en un solo lugar.

Porque Gulp.js prefiere el código sobre la configuración, esto no sólo lo hace muy fácil para escribir tareas, sino también lo hace más simple de leer y mantener.

Porque Gulp.js tiene directrices estrictas para la creación de sus plugins, lo cual asegura que estos sean simples y que funcionen como se espera.

Solo por mencionarlo, una de las directrices es la siguiente: “Un plugin sólo debe hacer una cosa y hacerla bien”. Esta directriz ha sido muy positiva para los usuarios de Gulp.js, lo comprobaremos más adelante cuando veamos como configurar una tarea con Gulp.js.

¿Cómo funciona Gulp.js?

Gulp.js utiliza el módulo Stream de Node.js, lo cual lo hace más rápido para construir, a diferencia de Grunt.js.

Gulp.js no necesita escribir archivos y/o carpetas temporales en el disco duro, lo cual supone que realizará las mismas tareas que Grunt.js pero en menor tiempo.

Gulp.js utiliza el método pipe(), este método obtiene todos los datos de un Stream legible(readable) y lo escribe en destino que le indiquemos ó de lo contrario lo entrega o sirve hacia otro pipe.

En la siguiente imagen veremos como Grunt.js manipula los archivos al realizar sus tareas:

grunt-file-manipulation

Y en esta veremos como Gulp.js manipula los archivos al realizar sus tareas:

gulp-file-manipulation

Como podemos ver, aunque los 2 hicieron la misma tarea Gulp.js no escribió archivos temporales en el disco duro. Gulp.js realizó 4 operaciones y en cambio Grunt.js realizó 8 operaciones.

Gulp.js utiliza el poder del paquete Node.js vinyl-fs para leer y escribir Streams.

Gulp.js también utiliza un paquete Node.js para la secuenciación, ejecución de tareas y dependencias en máxima concurrencia, llamado Orchestrator.

Más adelante veremos con mayor detalle como trabajan los Streams de Node.js.

¿Cómo instalar Gulp.js?

Para instalar Gulp.js el único requisito es tener instalado Node.js. si usas Linux Ubuntu y aún no lo tienes instalado este post te puede servir.

Instalando Gulp.js de forma global en nuestro sistema


npm install -g gulp

Si estás usando Linux o Mac, tal vez necesites anteponer la palabra sudo para poder ejecutar este comando con los permisos de administrador, así:


sudo npm install -g gulp

Verificamos que Gulp.js ha sido instalado correctamente.


gulp -v

Si lo tenemos instalado correctamente, nos mostrará lo siguiente:


CLI version 3.8.6
Local version undefined

Donde CLI version es la versión de Gulp.js instalada en nuestro sistema y Local version es la versión de Gulp.js instalada en nuestro proyecto local, pero como aún no hemos creado nuestro proyecto nos saldrá undefined.

¿Cómo usar Gulp.js?

Una vez instalado en nuestro sistema estamos listos para crear nuestro primer proyecto usando Gulp.js, nuestro pequeño proyecto concatenará dos archivos .js en uno solo y luego lo minificará. Así que configuraremos 2 tareas(concatenar y minificar), todo esto contenido en una tarea llamada “demo”.

Creamos una carpeta llamada: gulp-primeros-pasos, ingresamos a esa carpeta mediante terminal.

Luego allí dentro creamos nuestro archivo: gulpfile.js, que es el archivo que Gulp.js necesita para saber que tareas realizará y de momento no le podremos ningún contenido.

Luego escribimos lo siguiente(en este punto suponemos que tenemos instalado Node.js):


npm init

Npm nos pedirá los datos de nuestro proyecto, ya que en esta ocasión sólo estamos haciendo un demo. Simplemente presionaremos Enter a todas las preguntas.

Con esto, Npm nos debe haber creado un archivo llamado: package.json, que contendrá algo parecido a lo siguiente:


{
  "name": "gulp-primeros-pasos",
  "version": "0.0.1",
  "description": "Gulp: Primeros pasos",
  "main": "gulpfile.js",
  "author": "jansanchez",
  "license": "MIT"
}

Ahora agregaremos las dependencias de desarrollo a nuestro proyecto, la primera a instalar será: gulp, así que escribimos lo siguiente en nuestra terminal:


npm install --save-dev gulp

Luego instalamos: gulp-concat


npm install --save-dev gulp-concat

Y finalmente instalamos: gulp-uglify


npm install --save-dev gulp-uglify

Tengamos en cuenta que sí no agregamos el parámetro: –save-dev, entonces Npm no agregará este paquete como una dependencia de desarrollo de nuestro proyecto y mucho menos lo agregará a nuestro archivo package.json.

Como podremos observar, nuestro archivo package.json a cambiado y debería contener algo parecido a lo siguiente:


{
  "name": "gulp-primeros-pasos",
  "version": "0.0.1",
  "description": "Gulp: Primeros pasos",
  "main": "gulpfile.js",
  "author": "jansanchez",
  "license": "MIT",
  "devDependencies": {
    "gulp": "^3.8.7",
    "gulp-concat": "^2.3.4",
    "gulp-uglify": "^0.3.1"
  }
}

Como vemos, se agregó la clave devDependencies y en su interior se comienzan a guardar nuestras dependencias de desarrollo y la versión que hemos instalado localmente.

Luego vamos a crear las siguientes carpetas y archivos:

Creamos la carpeta js y dentro de esta carpeta crearemos la carpeta source.

Dentro de la carpeta source crearemos el archivo 1.js y le agregaremos el siguiente contenido:


// contenido del archivo 1.js

var sumar = function (a, b){
  return a + b;
};

Nuevamente dentro de la carpeta source crearemos el archivo 2.js y le agregaremos el siguiente contenido:


// contenido del archivo 2.js

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

Ahora vamos a poner el siguiente contenido a nuestro archivo gulpfile.js:


/*
* Dependencias
*/
var gulp = require('gulp'),
  concat = require('gulp-concat'),
  uglify = require('gulp-uglify');

/*
* Configuración de la tarea 'demo'
*/
gulp.task('demo', function () {
  gulp.src('js/source/*.js')
  .pipe(concat('todo.js'))
  .pipe(uglify())
  .pipe(gulp.dest('js/build/'))
});

Con esto ya tenemos todo configurado, así que para ponerlo a prueba en nuestra terminal escribimos lo siguiente:


gulp demo

Y si todo anda bien, nos dará el siguiente mensaje:


[11:23:09] Using gulpfile ~/htdocs/gulp-primeros-pasos/gulpfile.js
[11:23:09] Starting 'demo'...
[11:23:09] Finished 'demo' after 9 ms

El cual nos indica que la tarea demo se ejecutó con éxito en 9 milisegundos.

Para comprobar si se ejecutaron las 2 tareas requeridas, nos dirigimos a la carpeta js/build y abrimos el archivo todo.js y nos debe mostrar el siguiente contenido:


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

Como vemos, con unas simples y limpias lineas de código hemos realizado 2 tareas de desarrollo comunes(concatenar y minificar archivos .js).

Para esto usamos 2 plugins de Gulp.js, la buena noticia es que actualmente existen más de 1800 plugins para Gulp.js, así que imagínate todo lo que puedes automatizar en tu flujo de trabajo con Gulp.js.

Analizando el gulpfile.js

Ahora vamos a analizar el código que escribimos en nuestro gulpfile.js para entender un
poco más como funciona Gulp.js.

Primero para llevar a cabo las tareas que deseamos, requerimos los siguientes paquetes: gulp, gulp-concat y gulp-uglify, así:


/*
* Dependencias
*/
var gulp = require('gulp'),
  concat = require('gulp-concat'),
  uglify = require('gulp-uglify');

API

Gulp.js tiene una pequeña API, esto te permitirá aprender Gulp.js rápidamente.

gulp.task()

Con el método gulp.task() definimos una tarea, este método toma 3 argumentos: el nombre de la tarea, la ó las tareas de las que depende esta tarea y la función que ejecutará al llamar esta tarea.

En nuestro ejemplo sólo usamos 2 parámetros: el nombre y la función, así:


/*
* Configuración de la tarea 'demo'
*/
gulp.task('demo', function () {
  // Contenido de la tarea 'demo'
});

Con lo cual declaramos “demo” como nombre de la tarea y dentro escribimos lo que deseamos que haga nuestra tarea.

Así que si queremos llamar esta tarea tan solo escribimos en nuestra terminal:


gulp demo

Lista de tareas

Una tarea también puede actuar como una lista de tareas, supongamos que queremos definir una tarea que corra otras 3 tareas por ejemplo: imágenes, css y js. Entonces escribiríamos lo siguiente:


gulp.task('estaticos', ['imagenes', 'css', 'js']);

Lo que quiere decir que al ejecutar la tarea “estaticos” con el comando gulp estaticos se ejecutarán estas 3 tareas.

El detalle es que estas tareas correran asíncronamente, osea que correrán todas juntas al mismo tiempo sin ningún orden de ejecución.

Tareas como dependencia

Si deseamos que una tarea se ejecute sí y solo sí otra tarea haya terminado antes, entonces podemos hacer lo siguiente:


gulp.task('css', ['imagenes'], function () {
  /*
  * Aquí iría el contenido de mi tarea 'css'
  * Que se ejecutará solo cuando la tarea
  * 'imagenes' haya terminado.
  */
});

Entonces, cuando corramos la tarea “css”, Gulp.js ejecutará primero la tarea “imagenes”, esperará a que esta tarea termine y luego recién ejecutará la tarea “css”.

Tarea por defecto(default)

Gulp.js nos permite definir una tarea por defecto, que corra tan solo al escribir el comando gulp. Esto se puede hacer tan solo poniendole a la tarea el nombre de default, así:


gulp.task('default', function () {
  /*
  * Código de nuestra tarea por defecto.
  */
});

Y claro, también puedes hacer que tu tarea por defecto sea una lista de tareas, así:


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

Esta tarea ejecutará las tarea ‘css’ y ‘js’, tan solo escribiendo en nuestra terminal:


gulp

gulp.src()

El método gulp.src() toma como parámetro un valor glob es decir, una cadena que coincida con uno o más archivos usando los patrones que usa el intérprete de comandos de unix(shell) y retorna un stream que puede ser “pipeado” a un plugin adicional ó hacia el método gulp.dest().

Este parámetro puede ser una cadena o una colección(Array) de valores glob.

Gulp.js usa el paquete de Node.js node-glob para obtener los archivos especificados en él ó los globs ingresados.

Ejemplos de globs

  • js/source/1.js coincide exactamente con el archivo.
  • js/source/*.js coincide con los archivos que terminen en .js dentro de la carpeta js/source.
  • js/**/*.js coincide con los archivos que terminen en .js dentro de la carpeta js y dentro de todas sus sub-carpetas.
  • !js/source/3.js Excluye especificamente el archivo 3.js.
  • static/*.+(js|css) coincide con los archivos que terminen en .js ó .css dentro de la carpeta static/

Existen más patrones, los puedes revisar desde la documentación de la librería minimatch.

Así que tienes la oportunidad de realizar todas las combinaciones posibles, según lo necesites.

Como en nuestra demo, necesitabamos encontrar todos los archivos que terminen en .js dentro de la carpeta js/source, así:


gulp.src('js/source/*.js')

Cada vez que Gulp.js encuentre un archivo que coincida con nuestro patrón, lo irá metiendo dentro de un Stream, que será como una colección de archivos. Claro, respetando las propiedades de cada archivo(ruta, etc).

Entonces podemos decir que tendremos todos esos archivos con sus respectivas propiedades dentro de un Stream, Este Stream puede ser manipulado por Gulp.js.

el método pipe() de Node.js

El método pipe() puede leer, ayudar a transformar y grabar los datos de un Stream.

Es por eso que en nuestro ejemplo usamos el método pipe() 3 veces.

La primera vez lo usamos para leer el Stream y se lo pasamos al plugin “concat” para que este realize la concatenación y así transforme los datos del Stream, así:


.pipe(concat('todo.js'))

La segunda vez lo usamos para leer los datos actuales(js concatenado) y se lo pasamos al plugin “uglify”, para que realize la minificación del archivo concatenado. Todo esto sin escribir en el disco ningún archivo temporal, así:


.pipe(uglify())

La tercera vez se lo pasamos a el método gulp.dest(), así que veamos que hace este método.

gulp.dest()

Canaliza y escribe archivos desde un Stream, por lo que puede canalizar a varias carpetas. Creará las carpetas que no existan y retornará el Stream, por si deseamos realizar alguna acción más.

En pocas palabras, sirve para escribir los datos actuales de un Stream.

Y en nuestro ejemplo lo usamos así:


.pipe(gulp.dest('js/build/'))

Con lo cual escribimos los datos resultantes del Stream dentro de la carpeta js/build/.

El código final nos quedó así:


/*
* Dependencias
*/
var gulp = require('gulp'),
  concat = require('gulp-concat'),
  uglify = require('gulp-uglify');

/*
* Configuración de la tarea 'demo'
*/
gulp.task('demo', function () {
  gulp.src('js/source/*.js')
  .pipe(concat('todo.js'))
  .pipe(uglify())
  .pipe(gulp.dest('js/build/'))
});

Así como realizé 2 tareas consecutivas, con Gulp.js se pueden realizar muchas más.

gulp.watch()

Ver archivos y hacer algo cuando se modifique un archivo. Esto siempre devuelve un EventEmitter que emite los eventos de cambio.

Tiene 2 formas de usar:

gulp.watch(glob, tareas) ó gulp.watch(glob, callback).


gulp.watch('js/source/*.js', ['js']);

Con lo cual, cada vez que se modifique un archivo .js que se encuentre dentro de la carpeta js/source/ automáticamente se ejecutará la tarea js.


gulp.watch('js/source/*.js', function(){
  /*
  * Aquí iría el código de la acción que deseas realizar,
  * Cuando hayan cambios en dichos archivos.
  *
  * También podrías ejecutar una tarea mediante el método
  * gulp.start('js')
  *
  * Pero este método no es oficial, le pertenece al
  * paquete 'Orchestrator' ya que Gulp hereda los 
  * métodos de 'Orchestrator'.
  */  
});

Con esto ya podemos usar el API de Gulp.js con mucha facilidad.

Plugins

Como dije anteriormente Gulp.js tiene alrededor de 1800 plugins “oficiales” y otros cuantos no-oficiales, los plugins “oficiales” los puedes encontrar en la página de plugins de Gulp.js o buscando con la palabra clave gulpplugin en npm.

Actualmente existen plugins para casí todo lo que se necesita al desarrollar, si deseas puedes pasar por nuestro post sobre los plugins más usados de Gulp.js y sus configuraciones básicas.

La mayoría de los plugins son bastante fáciles de usar, tienen una buena documentación y se ejecutan de la misma forma (mediante la canalización de un Stream de objetos de archivo). Estos plugins normalmente modifican los archivos (aunque algunos, como validadores, no lo harán) y devuelven los archivos nuevos que se pasarán al siguiente plugin en un Stream.

Por ejemplo digamos que en ejemplo que teníamos quiero agregarle la funcionalidad de validación de sintaxis, entonces haríamos lo siguiente:


npm install --save-dev gulp-jshint

Y luego nuestro gulpfile.js quedaría así:


/*
* Dependencias
*/
var gulp = require('gulp'),
  jshint = require('gulp-jshint'),
  concat = require('gulp-concat'),
  uglify = require('gulp-uglify');

/*
* Configuración de la tarea 'demo'
*/
gulp.task('demo', function () {
  gulp.src('js/source/*.js')
    .pipe(jshint())
    .pipe(jshint.reporter('default'))
    .pipe(concat('todo.js'))
    .pipe(uglify())
    .pipe(gulp.dest('js/build/'))
});

Solo agregé 3 lineas especificas a mi gulpfile.js y ya estoy realizando otra tarea más sobre los mismos archivos, es por eso que es más simple que Grunt.js, donde no puedes codificar sino que tienes que poner en el objeto JSON tu configuración, lo cual te limita mucho y hace que generes un archivo de configuración muy grande y siempre llega a verse muy desordenado.

Dejo en github el repositorio del ejemplo que trabajamos en este artículo.

Sobre los Pipes en unix

Para entender aun más el proceso Gulp.js a continuación veamos como funcionan los pipes en Unix.

En unix, los comandos bash pueden “pipear” o “canalizar” la salida de otro comando bash, permitiendo operar esa información antes de ser devuelta, veamos un ejemplo práctico.

Por ejemplo si deseamos averiguar nuestra MAC address en unix ejecutamos el siguiente comando:


ifconfig

Lo cual nos devuelve toda esta información:


eth0
  inet addr:192.111.77.27  Bcast:192.111.77.255
  Link encap:Ethernet  HWaddr 00:1b:00:bb:1c:ab
  Mask:255.255.255.0 Scope:Link
  collisions:0 txqueuelen:1000

Pero nosotros no queremos toda esa información, sino solamente nuestra MAC address, entonces aquí podemos utilizar el poder de los pipes para lograr esto con el siguiente código.


ifconfig | grep "HWaddr"

Ahora sí obtuvimos especificamente lo que necesitabamos:


HWaddr 00:1b:00:bb:1c:ab Link encap:Ethernet

Aclaraciones

  • El comando ifconfig, nos devuelve toda la información de red en nuestro ordenador.
  • El comando grep, busca las líneas que contengan una coincidencia con un patrón que le pasemos.
  • pipe = |

Explicación del proceso

El proceso fue el siguiente:

  1. El comando ifconfig generó una respuesta.
  2. Antes que sea escrita “canalizamos” esa respuesta usando un pipe.
  3. A esa respuesta le aplicamos el comando grep con el patrón: “HWaddr”.
  4. Y finalmente nos devuelve sólo la MAC address.

Todo esto se hizo directamente sobre la respuesta inicial y sin almacenarla, ni escribirla en disco de manera temporal.

De la misma forma trabaja Gulp.js, canalizando el stream resultante de una función o plugin y pasando esa respuesta para ser operada por una nueva función y así sucesivamente.

¿Existen otros sistemas de construcción hechos con Javascript?

Claro que sí, a continuación listaré los que me parecen más interesantes:

Si ya se animaron a usar Gulp.js entonces les recomiendo leer nuestro artículo Plugins más usados de Gulp.js y sus configuraciones básicas. Para crear tareas en Gulp.js, comenzar a automatizar sus proyectos y empezar a ahorrar tiempo.

Espero que este artículo les haya servido para conocer Gulp.js, si tienen alguna duda, consulta ó aclaración solo háganla dejando sus comentarios, que estaremos prestos a ayudarlos.

Aquí en Frontend Labs estamos dispuestos a compartir el conocimiento, a enseñar y aprender!.

Si el artículo les gustó, por favor compartanlo en las redes sociales. De esa manera nos ayudan muchísimo! las opciones para compartir se encuentran aquí abajo, muchas gracias.

  • Alex Arriaga

    Muy buen artículo Jan, como retroalimentación estas son algunas de las tareas que yo uso:

    // 1. Transform LESS file to CSS (place CSS files into dev/css folder)
    gulp.task(‘less’, function() {
    console.log(“Running LESS task…”);
    return gulp.src(paths.dev + paths.less)
    .pipe(less())
    .pipe(minifyCSS(minifyCSSOptions))
    .pipe(gulp.dest(paths.dev + ‘css’));
    });

    // 2. Compress CSS (it will run after ‘less’ task finishes
    gulp.task(‘compress-css’,['less'], function() {
    console.log(“Running compressing CSS task…”);
    return gulp.src(paths.css)
    .pipe(concat(‘all-styles.css’))
    .pipe(gulp.dest(paths.prod + ‘css’))
    .pipe(rename(‘all-styles.min.css’))
    .pipe(minifyCSS(minifyCSSOptions))
    .pipe(gulp.dest(paths.prod + ‘css’));
    });

    // 3. Compress JavaScript files and place them into production folder
    gulp.task(‘compress-js’, function() {
    console.log(“Running compressing JavaScript task…”);
    return gulp.src(paths.scripts)
    .pipe(concat(‘all-scripts.js’))
    .pipe(gulp.dest(paths.prod + ‘js’))
    .pipe(rename(‘all-scripts.min.js’))
    .pipe(uglify())
    .pipe(gulp.dest(paths.prod + ‘js’));
    });

    // 4. Copy images and fonts
    gulp.task(‘copy-static-resources’, function() {
    // console.log(“Copy images from:” + (paths.dev+paths.images));
    console.log(“Copying static resources task…”);
    gulp.src(paths.images)
    .pipe(imagemin({
    progressive: true,
    optimizationLevel: 6,
    svgoPlugins: [{ removeViewBox: false }],
    use: [pngcrush({ reduce: true })]
    }))
    .pipe(gulp.dest(paths.prod + ‘img’));
    gulp.src(paths.dev+paths.fonts)
    .pipe(gulp.dest(paths.prod + ‘fonts’));
    });

  • Frontend Labs

    Estimados, estamos preparando el post de las configuraciones mas usadas de Gulp.js. sale en unos días :)

  • http://www.aprendiendoando.com/ yan arlex vallejo

    Buenas tardes, excelente articulo sobre Gulp , tengo un pequeño problema , resulta que tengo en mi directorio una carpeta llamada dev/stylus/ el cual tengo otras carpetas de component, modules , layout , y cada uno contiene algunos archivos stylus, y en mi carpeta raíz tengo el archivo style.styl el cual importo los archivos que están en la carpeta mencionada, ahora bien tengo mi tarea llamada stylus y cuando edito los archivos que están dentro de la carpeta dev/stylus/ y hago el gulp stylus me funcionan los cambios en el destino public_html/css/style.css , pero cuando hago un gulp watch, y edito los archivos de stylus no hace nada, alguna configuración especial que se deba hacer para que me funcione, Saludos

    • http://frontendlabs.io/ Jan Sanchez

      Hola Yan, al parecer el watcher si funciona pero para que ejecute la tarea correctamente deberías enviar como primer parámetro un glob más general y no el que has puesto “./style.styl”. Porque en ese caso el watcher solo observará los cambios en ese archivo. Prueba con por ejemplo este path:


      gulp.watch('./stylus/**/*.styl'); // buscará en todas las subdirectorios

      Puedes revisar más a detalle en este post la sección: “Ejemplos de globs” para que encuentres la combinación exacta para tu glob.

      • http://aprendiendoando.com/ Yan Arlex Vallejo

        Hola buenos dias, Si señor esa era la razon por la cual no funcionaba, ahora estoy trabajando perfectamente , Saludos desde Colombia.

  • http://gorka.co/ Gorka P

    Pues menuda maravilla. Estaba empezando con Grunt y aunque muy potente me parecía un poco lío. Sobre todo comparando cómo se añaden las gemas en Bundler, y ahora resulta que con Gulp es todo mucho más fácil. ¡Muchas gracias!

  • Albert Gracia

    Hola; excelente articulo, muchas gracias!!!.
    Ahora una pregunta, lo he configurado y todo muy bien, pero al reiniciar el pc, tengo que volver a abril el promt y ejecutar gulp de nuevo para que los directorios vuelvan a estar monitorizados, hay alguna forma de hacer que esto se haga automatico?

  • aridiodesign

    Saludos, soy diseñador front-end, sé casi nada de programación, intenté instalar el Gulp pero al insertar el comando npm install -g gulp en la consola me sale este error: npm should be run outside of the node repl, in your normal shell.

    No tengo ni la menor idea, si creen que sea una tarea no apta para un diseñador y solo para un programador por favor díganmelo para saber, gracias.

    • Frontend Labs

      Hola, claro que puedes!. Al parecer como estas usando windows y de seguro bajaste node.js pero de este tipo: Windows Binary (.exe). Lo ideal es que lo bajes desde aquí http://nodejs.org/download/ el instalador que dice Windows Installer (.msi), dependiendo si tu sistema es de 32 bits o de 64. Con esto descargarás un archivo instalador con extensión .msi. Ejemplo: node-v0.10.33-x86.msi. Es preferible que instales node.js desde un archivo como este, suerte!.

      • aridiodesign

        Muchas gracias por aclararme el tema de la instalación, espero lograrlo!

  • Doc Kodam

    Excelente guia

  • Julio Sotomayor O.

    Gracias por la información, pensaba que Grunt era lo máximo, ahora veo que no era así.

  • victor

    buenas tardes!
    alguien podria decirme como funciona grunt? no lo encuentro por ningun sitio =(
    solo encuentro que gulp es mejor por utilizar las “tuberias”.
    muchas gracias!

    • Frontend Labs

      Grunt en su momento fue una buena idea, pasar los scripts como rake, make, etc. a la ejecución de tareas mediante un archivo de configuración en formato JSON. Según lo poco que ví, Grunt simplemente lee un archivo de configuración y ejecuta las tareas de forma secuencial(sincrona) en Grunt no puedes ejecutar tareas al mismo tiempo porque tiene una gran dependencia de su archivo de configuración(tiene que leer una y terminarla para pasar a la siguiente). Grunt también tiene un manejo de tareas bastante simple ya que usa lo básico de node.js al leer, modificar y escribir archivos.

      De esos puntos débiles se preocupo Gulp.js para hacerle un buen benchmark y crear un automatizador con codigo sobre configuracion y usando streams para no estar escribiendo archivos temporales y poder usar siempre el contenido de una tarea.

      http://frontendlabs.io/146–grunt-js-espanol-tutorial-basico-primeros-pasos

  • https://twitter.com/cricarba Cristian Carvajal

    Muchas gracias, me sirvió mucho.

  • Oky

    Impresionante post, muy bueno y claro.

  • Diego

    Ame el post, muy comprensible, muy didáctico, muy claro y concreto, y sobre todo no solo enseñas lo básico de Gulp, sino temas relacionados como los pipes en Unix y das links para que sigamos el hilo. Muchas gracias.

  • Elbert Castañeda

    Muy buen post

  • Bruno Alfaro

    Excelente explicación, estaba usando un tutorial en el que ocupaban Gulp sin explicarlo, y con este articulo… QUEDA TODO CLARO! gracias.

  • Christian Valencia

    excelente

  • Pablo Sanz

    Interesante artículo. Tanto que he decidido probar Gulp y si me convence substituir mi sistema de automatizaciones. He seguido los pasos uno por uno, pero cuando lanzo ‘gulp demo’ obtengo un error:

    psanz@psanz-HP-ProBook-4530s:~/proyectos/gulp/gulp-primeros-pasos$ gulp demo
    [18:44:00] Using gulpfile ~/proyectos/gulp/gulp-primeros-pasos/gulpfile.js
    [18:44:00] Starting ‘demo’…
    [18:44:00] Finished ‘demo’ after 8.98 ms

    events.js:72
    throw er; // Unhandled ‘error’ event

    ^

    Error

    at new JS_Parse_Error (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1507:18)

    at js_error (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1515:11)

    at parse_error (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1625:9)

    at eval (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1853:36)

    at handle_slash (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1827:20)

    at Object.next_token [as input] (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1880:27)

    at next (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :1993:25)

    at semicolon (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :2040:30)

    at eval (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :2175:38)

    at eval (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:24:4), :2054:24)

    psanz@psanz-HP-ProBook-4530s:~/proyectos/gulp/gulp-primeros-pasos$

    Teía la versión 1.3.11 de node/npm y la he actualizado a la última versión 3.3.6 y me sigue dando el error. Alguien sabe a qué se debe?

    Gracias

    • Frontend Labs

      Hola Pablo probaste primero instalar las dependencias del proyecto? ósea hacer un:


      sudo npm install

      Prueba eso y luego ejecuta la tarea “gulp demo”, acabo de probarlo y funciona, todo ok, si tienes problemas no dudes en comentárnoslos.

      Saludos

      • Pablo

        Pues lo siento. Después del sudo esto es lo que recibo

        psanz@psanz-HP-ProBook-4530s:~/proyectos/gulp/gulp-primeros-pasos$ sudo npm install

        npm WARN EPACKAGEJSON gulp-primeros-pasos@0.0.0 No description
        npm WARN EPACKAGEJSON gulp-primeros-pasos@0.0.0 No repository field.

        Luego del gulp demo me sigue dando error aunque cambia la línea

        [20:53:36] Using gulpfile ~/proyectos/gulp/gulp-primeros-pasos/gulpfile.js

        [20:53:36] Starting ‘demo’…

        [20:53:36] Finished ‘demo’ after 14 ms

        events.js:141

        throw er; // Unhandled ‘error’ event

        ^

        Error

        at new JS_Parse_Error (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1508:18)

        at js_error (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1516:11)

        at parse_error (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1626:9)

        at eval (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1854:36)

        at handle_slash (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1828:20)

        at Object.next_token [as input] (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1881:27)

        at next (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :1994:25)

        at semicolon (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :2041:30)

        at eval (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :2176:38)

        at eval (eval at (/home/psanz/proyectos/gulp/gulp-primeros-pasos/node_modules/gulp-uglify/node_modules/uglify-js/tools/node.js:22:1), :2055:24)

        • Frontend Labs

          Al parecer es por la dependencia de jshint, la dependencia a sido separada individualmente, quedando asi:

          “devDependencies”: {
          “gulp”: “^3.9.0″,
          “gulp-concat”: “^2.6.0″,
          “gulp-jshint”: “^2.0.0″,
          “gulp-uglify”: “^1.5.1″,
          “jshint”: “^2.8.0″
          }

          Hemos actualizado el repositorio de primeros pasos con gulp, prueba clonando nuevamente e instalandolo.

  • Martin

    muy buen artículo, gracias

  • Alejandro García

    buen artículo, tengo un error que ocurre con la dependencia jshint, al instalarla me marcar estos 2 warnings:
    npm WARN EPEERINVALID gulp-jshint@2.0.0 requires a peer of jshint@2.x but none was installed.
    npm WARN EPACKAGEJSON gulp@1.0.0 No repository field.

    y al ejecutar gulp demo me da el siguiente error:

    module.js:340
    throw err;
    ^

    Error: Cannot find module ‘jshint/src/cli’
    at Function.Module._resolveFilename (module.js:338:15)
    at Function.Module._load (module.js:289:25)
    at Module.require (module.js:366:17)
    at require (module.js:385:17)
    at Object. (/Library/WebServer/Documents/gulp/node_modules/gulp-jshint/src/extract.js:1:79)
    at Module._compile (module.js:425:26)
    at Object.Module._extensions..js (module.js:432:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:313:12)
    at Module.require (module.js:366:17)
    at require (module.js:385:17)

    que supongo ha de ser por los warnings que indican que no tengo instalado algo, o a que se debe el error.

    Saludos

    • Frontend Labs

      Estimados, las dependencias de gulp-jshint cambiaron un poco, asi que hemos actualizado el repositorio para que no tengan ningun problema con las actualizaciones.
      Los requerimientos son: node: v0.12.0, npm: 2.5.1, gulp: 3.9.0
      Simplemente clonen nuevamente el proyecto e instalenlo y funcionara correctamente.

      • Alejandro García

        gracias, ya quedo solucionado

  • Andrés Pinilla

    Gracias, excelente tuturial muy concreto.

  • MangaPowerZero

    Excelente tutorial! He pasado de no saber nada de nada de Gulp a no solo entenderlo sino quererlo en mi vida <3
    En fin, muchas gracias!

  • http://guatejazz.com Alejandro Reyna

    Amigo, que tal?
    Espero todo esté re bien en tus ocupaciones.
    Fíjate que tengo un problema, al parecer gulp-concat no me está funcionando, y pensé que quizá el paquete estaba descontinuado pero no veo señales de que así sea.

    Estoy trabajando con node 5.0, gulp 3.9.1 y al parecer gulp-concat está usando su versión 2.6, coloqué las tareas por aparte para probarlas sin resultados favorables. Crees que sea por la versión de node o gulp?

    Espero tu respuesta, saludos y éxitos en todo! ( :

    • Frontend Labs

      Buenos días estimado, probamos con las siguientes especificaciones: node -v: v5.0.0, npm -v: 3.3.6, gulp -v: CLI version 3.9.0, gulp -v: 3.9.1 y no hemos tenido inconvenientes.

      Podrías indicarnos el SO y la version exacta de node js que estas usando?
      Saludos

  • guli

    Graciasss, muy buena data

  • Jorge

    Hola Tengo un problema en // Concat & Minify JS, me sale este error:

    [12:33:26] Starting ‘scripts’…
    Running compressing JavaScript task…

    events.js:160
    throw er; // Unhandled ‘error’ event
    ^
    Error
    at new JS_Parse_Error (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :1526:18)
    at js_error (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :1534:11)
    at croak (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :2026:9)
    at token_error (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :2034:9)
    at expect_token (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :2047:9)
    at expect (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :2050:36)
    at expr_atom (eval at (/Users/xbust3r/Desktop/Learn Gulp/html/node_modules/uglify-js/tools/node.js:22:1), :2535:17)
    sh-3.2#

    Mi script, todo funciona bien, menos gulp.task(‘scripts’)

    /*
    * Dependencias
    */

    var gulp = require(‘gulp’),
    concat = require(‘gulp-concat’),
    rename = require(‘gulp-rename’),
    uglify = require(‘gulp-uglify’),
    jade = require(‘gulp-jade’),
    imagemin = require(‘gulp-imagemin’),
    minifyCSS = require(‘gulp-minify-css’),
    sass = require(‘gulp-sass’),
    browserSync = require(‘browser-sync’).create();

    var gutil = require(‘gulp-util’);
    var UglifyJS = require(“uglify-js”);

    gulp.task(‘jade’, function() {
    gulp.src(‘jade/vistas/*.jade’)
    .pipe(jade({
    pretty: true //compile expanded html
    }))
    .pipe(browserSync.reload({
    stream: true //reload browser html
    }))
    .pipe(gulp.dest(”))
    });

    gulp.task(‘sass’, function() {
    gulp.src(‘scss/main.scss’)
    //output styles : nested, expanded, compact, compressed
    .pipe(sass({ outputStyle: ‘nested’ }).on(‘error’, sass.logError))
    .pipe(gulp.dest(‘./css/’))
    .pipe(browserSync.reload({
    stream: true //reload browser css
    }))
    });

    //Minify PNG, JPEG, GIF and SVG images
    gulp.task(‘imagemin’, function () {
    return gulp.src(['images/*.*'])
    .pipe(imagemin({
    progressive: true
    }))
    .pipe(gulp.dest(‘images/min’));
    });

    //minify css (alternative)

    gulp.task(‘mincss’, function() {
    gulp.src(‘./css/*.css’)
    .pipe(minifyCSS())
    .pipe(gulp.dest(‘./css/min/’))
    });

    // Concat & Minify JS //script paths

    var jsFiles = ‘componentes/*.js’,
    jsDest = ‘js';

    gulp.task(‘scripts’, function() {
    console.log(“Running compressing JavaScript task…”);
    return gulp.src(jsFiles)
    .pipe(concat(‘scripts.js’))
    .pipe(gulp.dest(jsDest))
    .pipe(rename(‘scripts.min.js’))
    .pipe(uglify())
    .pipe(gulp.dest(jsDest));
    });

    gulp.task(‘jsmin’, function() {
    return gulp.src(‘js/recursos.js’)
    .pipe(uglify(‘recursos.min.js’))
    .pipe( gulp.dest(‘js/scripts/’));
    });

    //minifyjs
    gulp.task(‘minjs’, function () {
    gulp.src(‘js/main.js’)
    .pipe(gulp.dest(‘js/min/’))
    });

    //browser-sync
    gulp.task(‘browserSync’, function() {
    browserSync.init({
    server: {
    baseDir: ”
    },
    })
    })

    //watch
    gulp.task(‘watch’, ['browserSync', 'jade', 'minjs', 'mincss'], function (){
    //gulp src (origgen)
    gulp.watch(‘scss/*.scss’, ['sass']);
    gulp.watch(‘jade/vistas/*.jade’,['jade']);

    gulp.watch(‘js/*.js’, ['minjs']);
    //gulp.watch(‘css/*.css’,['mincss']);
    })

    • Jorge

      a alguien le ha pasado algo similar?, me comentan gracias

      • Frontend Labs

        Buenas tardes Jorge, realizé el ejemplo con esa porción de tu código pero no obtengo el error que comentas, hice este gist para que los pruebes, solo cambie de posicion un poco las lineas de los pipes, y lo demas lo deje igual (de todas maneras no obtuve el error, revisa las versiones de gulp y node que estas usando, tal vez va por alli el problema), tambien puedes probar con esta modificacion. Te recomiendo separar solo el codigo de las tareas Javascript, para que asi puedas depurar mas facilmente donde puede encontrarse el error.

        https://gist.github.com/jansanchez/440149d84f4d83e87f64829fb08f7691

        • Jorge

          Hola Jan, ahora si me funciona con los mismos códigos, que raro, tengo otra consulta sobre compilación con jade

          Cuando ejecuto gulp watch y luego edito el archivo index.jade, realiza el cambio en el index.html y refresca en pantalla, todo OK

          pero cuando edito page.jade, realiza el cambio en el page.html y no refresca en pantalla inmediatamente, tengo que darle f5 para que muestre los cambios.

          eso a que se debe?, adjunto mi repo: https://github.com/jlcallalle/gulp

          Gracias! por la ayuda

          pd: te conocí en una entrevista de trabajo de orvis :)

          Saludos

          • Jan Sanchez

            Hola Jorge que tal, el problema es que tu gulp watch ejecutará la tarea ‘jade’, cuando escuche cambios en la ruta ‘jade/vistas/*.jade’.

            Entonces si tu deseas que escuche todos los cambios en los archivos .jade, segun tu estructura deberias cambiar el watcher de ‘gulp.watch(‘jade/vistas/*.jade’,['jade']);’ a ‘gulp.watch(‘jade/**/*.jade’,['jade']);’

            Exitos!

          • Jorge

            Hola Jan, la estructura de mi jade es:
            jade
            – includes
            header.jade
            footer.jade
            – plantillas
            plantilla-principal.jade
            – vistas
            index.jade (tiene extends ../plantillas/plantilla-principal y en plantillas-principal tiene header y footer)
            page.jade (tiene extends ../plantillas/plantilla-principal y en plantillas-principal tiene header y footer)

            al aplicar tu sugerencia, me sale el mismo problema, ya que esta compilando el index.jade y utlizando el extends.

            saludos