10 minutes reading time (1930 words)

Cómo utilizar gulp en el desarrollo de plantillas

Cómo utilizar gulp en el desarrollo de plantillas

Todo desarrollador de plantillas busca siempre ir mejorando su forma de trabajo: optimizar pasos, reducir los tiempos, automatizar acciones.
En los últmos años han aparecido muchas herramientas que nos ayudan en esto. El problema, como siempre, es aprender a usarlas. En este artículo les quiero presentar a gulp, un ejecutador de tareas que podemos integrar en el desarrollo de plantillas.

Introducción

Este artículo está basado en la presentación de Robert Deutz en la conferencia J and Beyond 2015 en Praga (ver sección enlaces al final del artículo).

Para comenzar a optimizar nuestras tareas necesitamos instalar algunas herramientas en nuestro sistema, no importa si trabajamos bajo Windows o Linux, local o en un servidor remoto.
No voy a entrar en detalles con todas las herramientas que necesitamos, pero les voy a dar una pequeña introducción a cada una.

La base que necesitamos para poder instalar el resto es Node.js®, una plataforma creada sobre el entorno de ejecución para JavaScript de Google Chrome. Las funciones que más nos interesan de Node.js es que nos permite correr código JavaScript en el servidor y que trae un manejador de paquetes (npm) que usaremos para instalar las otras herramientas.
Una herramienta adicional que nos ayudará en el desarrollo de plantillas es bower. Bower nos permite instalar paquetes útiles para el desarrollo, como Bootstrap, jQuery, Font Awesome, etc.
Y finalmente gulp.js. Con este sistema de construcción podremos definir nuestras tareas comunes y automatizarlas. Por ejemplo la compilación de archivos less, la minificación de css o JavaScript, la concatenación de archivos y muchas otras tareas.

Primeros pasos

Vamos a comenzar con una instalación de Joomla y la base de la plantilla a desarrollar. En este caso voy a usar la plantilla "simple" de Robert Deutz, que él creó para su presentación en Praga.

Node.js

La primera herramienta que tenemos que instalar es node.js, para después tener acceso al manejo de paquetes npm que nos permitirá instalar las demás herramientas.
En la página de node.js se puede escoger el instalador adecuado. En mi caso el paquete para Windows.

node

 

Ahora que tenemos instalado node.js, podemos acceder al npm usando la consola.
Con el comando

$ npm init

podemos crear un archivo de configuración para nuestro proyecto (package.json).

Gulp

El siguiente paso es instalar gulp:

$ (sudo) npm install -g gulp
$ npm install --save-dev gulp

Con estos comandos instalamos gulp globalmente en nuestro sistema y localmente en nuestro proyecto. Si ahora le hechamos una mirada al archivo package.json que creamos en el paso anterior, vamos a ver que se ha añadido automaticamente un bloque de dependencias con gulp dentro de él:

"devDependencies": {
"gulp": "^3.9.0"
}
Esto ocurre cuando usamos --save-dev en el comando de instalación.

Bower

La siguiente herramienta que vamos a instalar es Bower para obtener los paquetes necesarios para el desarrollo de nuestra plantilla (Bootstrap, jQuery, etc.):

$ (sudo) npm install -g bower
$ npm install --save-dev bower

Para usar Bower necesitamos git y si estamos trabajando en Windows necesitamos instalar correctamente msysgit. Durante la instalación de msysgit tenemos que elegir la opción "Run Git from the Windows Command Prompt".

Bower nos instalará automáticamente los paquetes en la carpeta "bower-components". Si queremos usar otra estructura en nuestro proyecto podemos configurar Bower creando el archivo .bowerrc.
En su presentación Robert cambió la carpeta donde los paquetes de Bower serán guardados:

{
"directory": "assets/bower"
}

Con el comando

$ bower init

se creará un archivo de configuración bower.json y cada vez que instalemos un paquete usando --save-dev se agregará la dependencia en la configuración.

Con Bower podemos buscar paquetes:

$ bower search bootstrap

Este comando nos va a resultar en una lista bastante larga de paquetes. El paquete de Bootstrap que queremos instalar está al principio de la lista y se llama simplemente bootstrap.

$ bower install bootstrap --save-dev

Bower es "inteligente" y nos instala automáticamente los paquetes de dependencia. En el caso de Bootstrap por ejemplo nos instala también jQuery que es necesario para el funcionamiento de Bootstrap.

bootstrap install

Si ahora nos fijamos en la carpeta "assets/bower" vemos que se han creado dos carpetas nuevas: "bootstrap" y "jquery".

Ahora podemos instalar otros paquetes para la plantilla como modernizr y font-awesome:

$ bower install modernizr --save-dev
$ bower install font-awesome --save-dev

Estos paquetes ahora aparecen como dependencias en el archivo bower.json:

"devDependencies": {
"bootstrap": "~3.3.5",
"modernizr": "~2.8.3",
"font-awesome": "~4.3.0"
}

Paquetes

Uno de los objetivos en el desarrollo de nuestra plantilla es que sea compacta, con JavaScript y CSS minificado. Para lograr ello, vamos a crear dos carpetas nuevas dentro de "assets": "less" y "js" (en el caso de la plantilla de nuestro ejemplo, esas carpetas y los archivos necesarios ya vienen creados).

Ahora necesitamos diferentes paquetes de gulp para llevar a cabo nuestras tareas como concatenación y minificación, entre otras.

$ npm install gulp-concat --save-dev
(Lleva a cabo la concatenación de archivos)

$ npm install gulp-less --save-dev
(Compila less en css)

$ npm install gulp-minify-css --save-dev
(Para minificar css)

$ npm install gulp-autoprefixer --save-dev
(Nos agrega los prefijos necesarios para distintos navegadores, por ejemplo nos convertirá este código:
a {
display: flex;
}

en

a {
display: -webkit-box;
display: -webkit-flex;
display: -ms-flexbox;
display: flex
}
Se puede leer más información sobre autoprefixer aquÍ: https://www.npmjs.com/package/autoprefixer)

$ npm install gulp-rimraf --save-dev
(Para hacer limpieza de archivos)

$ npm install gulp-notify --save-dev
(Para mostrar errores)

$ npm install gulp-uglify --save-dev
(Para minificar JavaScript)

$ npm install browser-sync --save-dev
(Nos actualiza el navegador automáticamente cada vez que hacemos un cambio en los archivos de la plantilla)

gulpfile.js

Ahora hemos llegado a la parte más importante del trabajo: tenemos que crear el script para llevar a cabo todas nuestras tareas automaticamente.

Las tareas de gulp se programan en el archivo gulpfile.js. La plantilla "simple" ya viene con el JavaScript listo para usar. Aquí voy a tratar de explicar cada función. En la primera parte del script vamos a definir las variables de acuerdo a las tareas que llevaremos a cabo. Para cada paquete que instalamos, definimos una variable que usa ese paquete:

var gulp = require('gulp');
var concat = require('gulp-concat');
var clean = require('gulp-rimraf');
var less = require('gulp-less');
var minifycss = require('gulp-minify-css');
var autoprefixer = require('gulp-autoprefixer');
var uglify = require('gulp-uglify');
var notify = require('gulp-notify');
var browserSync = require('browser-sync');
var reload = browserSync.reload;

Para seguir facilitándonos las tareas definimos las carpetas que usamos para guardar los diferentes archivos de nuestra plantilla:

/* dirs */
var assetsDir = 'assets';
var lessDir = assetsDir + '/less';
var jsDir = assetsDir + '/js';
var targetCss = 'css';
var targetJs = 'js';
var targetFont = 'fonts';

Y también definimos donde están guardados nuestros JavaScripts:

var scripts = [
assetsDir + '/bower/bootstrap/dist/bootstrap.js',
assetsDir + '/bower/jquery/dist/jquery.js',
assetsDir + '/bower/modernizr/modernizr.js',
jsDir + '/simple.js'
];

Y después empezamos a programar las tareas. La primera tarea es concatenar los JavaScripts. Con gulp.src(scripts) gulp va a buscar los JavaScripts que definimos en el paso anterior en la variable scripts (bootstrap.js, jquery.js, modernizr.js), los va a unir en un sólo JavaScript final (simple.js), los minificará (uglify) y guardará el resultado en la carpeta de destino (targetJs = js).

gulp.task('mergeScripts', function() {
gulp.src(scripts)
.pipe(concat('simple.js'))
.pipe(uglify())
.pipe(gulp.dest(targetJs));
});

El paso siguiente es limpiar nuestras carpetas destino para estar seguros de siempre tener las versiones más actuales de nuestros archivos:

gulp.task('clean', function() {
gulp.src([targetCss + '/*.css', targetJs + '/*.js', targetFont + '/*'], {read:false})
.pipe(clean());
});
Con las siguientes líneas vamos a copiar las fuentes tipográficas:

gulp.task('copyFonts', function(){
gulp.src(assetsDir + '/bower/font-awesome/fonts/*')
.pipe(gulp.dest(targetFont));

gulp.src(assetsDir + '/bower/bootstrap/fonts/*')
.pipe(gulp.dest(targetFont));
});

Ahora viene una de las tareas más importantes, crear el css de la plantilla compilando los archivos less, agregándole los prefijos a las descripciones y guardando el archivo ya minificado en la carpeta de destino. Todo esto en una sóla función de 7 líneas:

gulp.task('css', function(){
return gulp.src('assets/less/simple.less')
.pipe(less())
.pipe(minifycss())
.pipe(autoprefixer('last 20 version'))
.pipe(gulp.dest(targetCss));
});

En el archivo simple.less importamos todos los archivos necesarios para el proyecto: bootstrap.less compilará todos los archivos que pertenecen a Bootstrap, font-awesome.less es la base para la tipografía y en custom.less podemos escribir las definiciones específicas de nuestra plantilla:

@import "../bower/bootstrap/less/bootstrap.less";
@import "../bower/font-awesome/less/font-awesome.less";
@import "custom.less";

Ahora vamos a programar una función un poco más compleja, que durante el desarrollo nos escribe en la consola si ocurren errores durante la compilación de los archivos less:

gulp.task('cssdev', function(){
return gulp.src('assets/less/simple.less')
.pipe(less())
.on('error',function (err) {
console.log(err.toString());
this.emit('end');
})
.pipe(autoprefixer('last 20 version'))
.pipe(notify('cssdev done'))
.pipe(gulp.dest(targetCss))
.pipe(reload({stream:true}));
});

Con las próximas líneas vamos a agregar algo de "magia" en nuestro programa. Con la función "watch" gulp se va a ocupar de controlar cada cambio que hacemos en los archivos less y js. Quiere decir que cada vez que guardamos un cambio en alguno de esos archivos gulp va a llevar a cabo sus tareas (cssdev y mergescripts) y con ayuda de la función "connect" se sincronizará con nuetro navegador y recargará la página para que veamos los cambios hechos:

gulp.task('watch', ['connect'], function() {
gulp.watch(lessDir + '/**/*.less', ['cssdev']);
gulp.watch(jsDir + '/**/*.js', ['mergescripts']);
});

gulp.task('connect', function() {
browserSync({
proxy: "localhost"
});
});

En la definición de "proxy" es importante poner la url correcta para acceder a nuestro proyecto (en mi caso es localhost:8080/cms-joomla):

Durante el desarrollo vamos a usar la función "cssdev" en "watch" para obtener un archivo simple.css sin minificar, así resulta más fácil leerlo y buscar definiciones. Cuando llegamos ya al final del proyecto podemos cambiar a la función "css" para obtener el archivo minificado.

Finalmente definimos una función por defecto, que es la que correrá si sólo escribimos "gulp" en la consola:

gulp.task('default', ['clean'], function(){
gulp.start(['copyFonts', 'css', 'mergeScripts']);
});

Ejemplos

Así se ve la plantilla "simple" cuando comenzamos el proyecto:

simple

 

Después de correr las funciones

$ gulp mergeScripts

mergeScripts

y

$ gulp cssdev

la página ya se ve así (ha cargado todos los css de Bootstrap):

bootstrap

 

Ahora dejamos correr

$ gulp watch

y hacemos un pequeño cambio en nuestro custom.less

body {margin-top: 60px;background-color: red;}

El resultado aparecerá automáticamente en nuestro navegador (gracias a "connect"):

background

 

Más informaciones

En gulp tenemos una multitud de paquetes que nos agregan funcionalidad y facilitan las tareas de desarrollo.
Por ejemplo hay un paquete para minificar HTML (gulp-minify-html) y otro para mapear las funciones JavaScript dentro del archivo minificado (gulp-sourcemaps). Este último paquete puede ser muy útil cuando tenemos muchos archivos js concatenados y minificados y queremos saber de cuál archivo viene una función específica. En el blog de Jair Trejo (http://jairtrejo.mx/blog/2014/11/baby-steps-with-gulp) hay un ejemplo con este paquete.

BrowserSync es un servidor estático que nos permite visitar nuestra página usando diversos dispositivos al mismo tiempo. Si nos fijamos en la consola

watch

 

BrowserSync nos ofrece una url local (localhost:3000/cms-joomla) y una externa (192.168.1.120:3000/cms-joomla). Si vamos a la url externa con nuestro móvil por ejemplo, vamos a ver la misma página sincronizada con nuestro ordenador.
A través de la url localhost:3001 tenemos acceso a la consola de BrowserSync y aquí podemos ver los navegadores conectados y los clicks que hemos hecho en nuestra página.

En la página oficial de gulp hay actualmente 1532 plugins! http://gulpjs.com/plugins/ 

Para obtener más información sobre los paquetes que podemos instalar con npm podemos visitar la página https://www.npmjs.com/

Conclusión

Cada uno tiene su forma de trabajar, que va optimizando con el tiempo y la experiencia. A veces uno está "trabado" en su flujo de trabajo, no está conforme, pero tiene miedo o no tiene tiempo para hacer cambios. En estos casos nos tenemos que dar un empujón y tomarnos el tiempo para aprender a usar nuevas herramientas como node.js, Bower y gulp. Veremos que nuestra forma de trabajar se mejora rapidamente y crearemos una base que podemos ir replicando en nuevos proyectos.

Enlaces

https://www.youtube.com/watch?v=6ihi0KDr-Bs&index=45&list=PLSwFVRVZ3joRlHSiJ8JxKsvI9uWlr1tik

https://github.com/rdeutz/simple

https://nodejs.org/

http://bower.io/

https://git-scm.com/

http://msysgit.github.io/

http://gulpjs.com/

https://github.com/gulpjs/gulp

https://www.npmjs.com/

http://jairtrejo.mx/blog/2014/11/baby-steps-with-gulp

0
Duas joomleiras no J and Beyond em Praga
En attendant Joomla! 3.5
 

Comments

Already Registered? Login Here
No comments made yet. Be the first to submit a comment

By accepting you will be accessing a service provided by a third-party external to https://magazine.joomla.org/