Universitat Oberta de Catalunya

Bienvenidos

Cambiar de idioma:

gulp-build-system

A continuación mostramos el flujo de trabajo habitual con Gulp, para la creación y configuración de un proyecto, y posterior trabajo sobre los ficheros del mismo.

Dado que el fichero gulpfile.js hace uso de la API incluida en Gulp, es importante revisar el material de la asignatura en el punto 3.4.4 Build Systems, y más concretamente la parte destinada a Gulp, además de la propia documentación sobre la API de comandos básicos.

Partimos de un escenario en el que ya se encuentra disponible una instalación de nodeJS y de npm en nuestro equipo y tenemos una carpeta dentro del directorio de trabajo del servidor web (en caso de XAMPP por defecto en la carpeta htdocs, aunque es algo que se puede cambiar en el fichero httpd.conf de apache modificando la ruta asignada a DocumentRoot) que en su interior contiene la estructura de carpetas que muestra la imagen:

Estructura proyecto web básico

1) Instalación del CLI de Gulp de forma global

El siguiente paso es acceder a la consola de comandos o al terminal para instalar «CLI» (Command Line Interface) de Gulp de forma global. Esto lo logramos a través de npm, con el comando habitual de instalación de un paquete:

npm install --global gulp-cli

En el caso de realizar la instalación en OSX, puede ser que nos de arroje errores de permisos, en cuyo caso habría que lanzar esa misma linea precedida de sudo.

2) Instalación de Gulp en el proyecto local

Una vez tenemos el CLI instalado, podemos instalar ahora Gulp como dependencia del proyecto con el que queremos trabajar, de manera que además quede registrado en el fichero package.json que previamente hemos creado.

npm install gulp --save-dev

Con este paso en nuestro proyecto se nos ha generado una carpeta node_modules que guarda los paquetes necesarios para los plugins que iremos añadiendo al entorno de trabajo, y que NO debería formar parte del repositorio (por lo tanto se debería excluir con git ignore)

Estructura de carpetas con gulp ya incluido

3) Instalación de plugins

A continuación, instalamos todos los plugins que deseemos usar en nuestro proyecto. Esto podemos lograrlo instalando cada uno de ellos desde línea de comandos (3A) o bien editando el fichero package.json que teníamos creado en la carpeta raíz de nuestro proyecto, para que éste se use como base para la instalación completa de todas las dependencias que indica en su interior (3B).

Los plugins que vamos a usar en este tutorial son:

  • del: utilidad para borrar ficheros.
  • gulp-sasspara el trabajo con el preprocesador CSS Sass.
  • gulp-jshint: para evaluación de código JavaScript.
  • jshint-stylish: para estilizar los mensajes de JSHint.
  • gulp-concat: para concatenar ficheros.
  • gulp-uglify: para compactar ficheros.
  • gulp-sourcemaps: para poder depurar en el navegador en los fuentes a partir de los compilados o minificados.
  • gulp-imagemin: para comprimir imágenes.
  • browser-sync: para testeo en navegador y dispositivos de forma sincronizada.

3A) Instalación individual de plugins

Hacemos uso repetido del comando npm install nombre-plugin –save-dev que además de instalar el paquete del plugin correspondiente actualiza el fichero package.json (se le indica con el –save-dev).

Por ejemplo en el caso de gulp-sass escribiríamos:

npm install gulp-sass --save-dev

Una forma de agilizar este proceso, que en el caso de este tutorial se tendría que repetir 6 veces (una por cada plugin) es hacer la instalación en una sola línea, que sería totalmente equivalente a esto:

npm install gulp del gulp-sass gulp-jshint jshint-stylish gulp-concat gulp-uglify gulp-sourcemaps gulp-imagemin browser-sync --save-dev

3B) Instalación a través de package.json

La alternativa a la instalación individual sería contar con la identificación como dependencias del proyecto de los paquetes que queremos en el fichero package.json, del cual tenemos un recurso en la red muy ilustrativo sobre la anatomía de dicho fichero.

En nuestro caso tendríamos:

{
 "name": "gulp-basics",
 "version": "0.0.1",
 "description": "Ejemplo básico de entorno de desarrollo front-end con Gulp",
 "author": "Marcos Gonzalez <mgonzalezsancho@uoc.edu>",
 "devDependencies": {
 "browser-sync": "^2.11.1",
 "del": "^2.2.0",
 "gulp": "^3.9.1",
 "gulp-concat": "^2.6.0",
 "gulp-imagemin": "^2.4.0",
 "gulp-jshint": "^2.0.0",
 "gulp-sass": "^2.2.0",
 "gulp-sourcemaps": "^1.6.0",
 "gulp-uglify": "^1.5.3",
 "jshint": "^2.9.1",
 "jshint-stylish": "^2.1.0"
 }
}

A partir del mismo se podrían instalar todos los plugins indicados como devDependencies en nuestro directorio de proyecto ejecutando la siguiente instrucción, una vez nos encontramos dentro de la carpeta raíz del proyecto, es decir al mismo nivel que el fichero package.json:

npm install

Esta instrucción lanza un proceso secuencial que descarga todos los paquetes necesarios para contar con esos plugins en nuestro proyecto. Esta característica es la que hace importante incluir este fichero en el repositorio, para que cualquier miembro del equipo o nosotros mismos descargándonos el contenido del repositorio, estemos a un simple comando de obtener todos los paquetes necesarios.

4) Añadir plugins posteriormente

Si se quisiera añadir algún plugin adicional posteriormente y no se desea añadirlo manualmente editando el fichero package.json, se pueden hacer la instalación con el formato visto en el punto 3A.

npm install nombre-paquete --save-dev

Lo que instalará dicho paquete en nuestro proyecto (bajo la carpeta node_modules) y además añadirá ese plugin a las dependencias fichero package.json (al incluir el –save-dev)

5) Creación del fichero gulpfile.js

El otro fichero clave para montar este entorno de trabajo es el denominado gulpfile.js, que será el que especifique cómo queremos usar esos plugins en nuestro proyecto, nos permita crear las diferentes tareas, combinarlas, etc. El contenido del fichero gulpfile empleado en este tutorial es:

var gulp        = require('gulp'),
    del         = require('del'),
    browserSync = require('browser-sync').create(),
    concat      = require('gulp-concat'),
    imagemin    = require('gulp-imagemin'),
    jshint      = require('gulp-jshint'),
    stylish     = require('jshint-stylish'),
    sass        = require('gulp-sass'),
    sourcemaps  = require('gulp-sourcemaps'),
    uglify      = require('gulp-uglify');


// Definición de direcotrios origen
var srcPaths = {
    images:   'src/img/',
    scripts:  'src/js/',
    styles:   'src/sass/',
    files:    'src/'
};


// Definición de directorios destino
var distPaths = {
    images:   'dist/img/',
    scripts:  'dist/js/',
    styles:   'dist/css/',
    files:    'dist/'
};


// Limpieza del directorio dist
gulp.task('clean', function(cb) {
  del([ distPaths.files+'*.html', distPaths.images+'**/*', distPaths.scripts+'*.js', distPaths.styles+'*.css'], cb);
});


// Copia de los cambios en los ficheros html en el directorio dist.
gulp.task('html', function() {
    return gulp.src([srcPaths.files+'*.html'])
        .pipe(gulp.dest(distPaths.files))
        .pipe(browserSync.stream());
});


/* 
* Procesamiento de imágenes para comprimir / optimizar las mismas.
*/ 
gulp.task('imagemin', function() {
    return gulp.src([srcPaths.images+'**/*'])        
        .pipe(imagemin({
            progressive: true,
            interlaced: true,
            svgoPlugins: [{removeUnknownsAndDefaults: false}, {cleanupIDs: false}]
        }))
        .pipe(gulp.dest(distPaths.images))
        .pipe(browserSync.stream());
});


/* 
* Procesamiento de ficheros SCSS para la generación de los ficheros
* CSS correspondientes. Los sourcemaps en este caso se generan dentro 
* del propio fichero.
*/ 
gulp.task('css', function() {
    return gulp.src([srcPaths.styles+'**/*.scss'])
        .pipe(sourcemaps.init())
            .pipe(sass())
        .pipe(sourcemaps.write())
        .pipe(gulp.dest(distPaths.styles))
        .pipe(browserSync.stream());
});


/* 
* Procesamiento de ficheros JS mediante JSHint para detección de errores.
* Este proceso es previo al tratamiento de los ficheros JS para la 
* obtención del fichero concatenado y minificado.
*/ 
gulp.task('lint', function() {
  return gulp.src([srcPaths.scripts+'**/*.js'])
    .pipe(jshint())
    .pipe(jshint.reporter(stylish));
});


/* 
* Procesamiento de ficheros JS para la generación de un fichero 
* final único y minificado. Los sourcemaps se generan en una 
* carpeta independiente en vez de en el propio fichero.
*/ 
gulp.task('js', ['lint'], function() {
    return gulp.src([srcPaths.scripts+'main.js', srcPaths.scripts+'extra.js'])                            
        .pipe(sourcemaps.init())
            .pipe(concat('all.min.js'))        
            .pipe(uglify())
        .pipe(sourcemaps.write('maps'))
        .pipe(gulp.dest(distPaths.scripts))
        .pipe(browserSync.stream());
});


/*
* Tarea para lanzar el proceso de servidor mediante BrowserSync.
* Antes de comenzar la propia tarea ejecuta las tareas de las que tiene
* dependencia: html, imagemin, css y js necesarias para disponer
* del proyecto en dist, ya que cada vez que se lanza gulp, se hace una
* limpieza de dicho directorio.
*
* En este caso se trabaja con un servidor local mediante un proxy
* y se define la ruta de partida, así como los navegadores a lanzar
* en caso de estar disponibles en el equipo.
*
* Adicionalmente se crean los watchers para procesar los cambios que se
* puedan producir en los archivos sensibles para el proyecto.
*/
gulp.task('serve', ['html', 'imagemin', 'css', 'js'], function() {
    browserSync.init({
        logLevel: "info",
        browser: ["google chrome", "Firefox"],
        proxy: "localhost:80",
        startPath: "/gulp-basics/dist/"
    });

    gulp.watch(srcPaths.files+'*.html', ['html']);
    gulp.watch(srcPaths.images+'**/*', ['imagemin']);   
    gulp.watch(srcPaths.styles+'**/*.scss', ['css']);
    gulp.watch(srcPaths.scripts+'**/*.js', ['js']);
});

/* 
* Definción de la tarea por defecto que en este caso limpia el directorio destino
* y lanza la tarea de servidor.
*/
gulp.task('default', ['clean', 'serve'], function() {});

 

Se puede apreciar en este fichero una de las mayores diferencias con respectoa Grunt, que es que en vez de tener que realizar importantes esfuerzos configurando cada plugin, en este caso se configuran tareas de una forma mucho más intuitiva mediante el encadenamiento de acciones sobre los ficheros procesados.

Con Gulp podemos crear tantas tareas como queramos y combinarlas de forma compleja, incluso aplicando lógica mediante JavaScript.

6) Arranque y testeo

El último paso es lanzar Gulp para que el entorno empiece a funcionar, y podamos comprobar como editando un fichero sass, o un fichero js, o modificando el contenido HTML de nuestra página podemos ver los cambios en el equipo de trabajo e incluso en otros equipos y dispositivos conectados a través de browsersync.

Para ello simplemente, en el terminal o línea de comandos, una vez estemos en la carpeta del proyecto, ejecutamos la instrucción gulp indicando la acción que queremos ejecutar… como en este caso hemos preparado la acción por defecto vinculándola a las tareas de limpieza y lanzamiento de BrowserSync junto con la monitorización de ficheros, nos valdría con simplemente poner en la consola o terminal:

gulp

Con esto se mostrarían los correspondientes mensajes de ejecución de las tareas y si todo va bien se lanzaría BrowserSync en los navegadores indicados con la página de salida abierta, tras la ejecución de todas las tareas asociadas a la ejecución de la tarea «serve»

 

Últimos artículos

  • Uso de handlebars

    En esta pequeño tutorial veremos un ejemplo básico del uso de handlebars, que nos permita descubrir y entender las principales partes implicadas en el trabajo con este motor de plantillas del lado cliente, que se caracteriza por no añadir prácticamente lógica funcional a las plantillas, centrándose en al semántica. Los principales elementos en el trabajo con […]

  • Uso básico de AngularJS

    En este pequeño ejemplo, veremos el uso más básico y reducido que se le puede dar a AngularJS, para simplemente poder comprobar una de las características más interesantes y potentes con las que cuenta este framework que es el trabajo con el concepto de «data-binding«. El ejemplo está recogido en el repositorio: https://gitlab.com/qmarcos/angularjs-basics.git Como se […]

  • Uso básico de gulp

    A continuación mostramos el flujo de trabajo habitual con Gulp, para la creación y configuración de un proyecto, y posterior trabajo sobre los ficheros del mismo. Dado que el fichero gulpfile.js hace uso de la API incluida en Gulp, es importante revisar el material de la asignatura en el punto 3.4.4 Build Systems, y más […]