Cómo crear y desarrollar sitios web con Gulp
Gulp es una de las pocas herramientas de compilación disponibles en JavaScript, y también están disponibles otras herramientas de compilación no escritas en JavaScript, incluido Rake. ¿Por qué deberías elegirlo? Gulp es un sistema de compilación que puede mejorar la forma de desarrollar sitios web mediante la automatización de tareas comunes, como la compilación de CSS preprocesado. En este artículo, Callum Macrae verá cómo puede utilizar Gulp para cambiar su flujo de trabajo de desarrollo, haciéndolo más rápido y eficiente.
Optimizar los activos de su sitio web y probar su diseño en diferentes navegadores ciertamente no es la parte más divertida del proceso de diseño. Afortunadamente, consta de tareas repetitivas que pueden automatizarse con las herramientas adecuadas para mejorar su eficiencia.
Gulp es un sistema de compilación que puede mejorar la forma de desarrollar sitios web al automatizar tareas comunes, como compilar CSS preprocesado, minimizar JavaScript y recargar el navegador.
En este artículo, veremos cómo puede utilizar Gulp para cambiar su flujo de trabajo de desarrollo , haciéndolo más rápido y eficiente.
¿Qué es el trago?
gulp.js es un sistema de compilación, lo que significa que puedes usarlo para automatizar tareas comunes en el desarrollo de un sitio web. Está construido en Node.js, y tanto el código fuente de Gulp como su archivo Gulp, donde define las tareas, están escritos en JavaScript (o algo como CoffeeScript, si así lo desea). Esto lo hace perfecto si eres un desarrollador front-end: puedes escribir tareas para eliminar tu JavaScript y CSS, analizar tus plantillas y compilar tu LESS cuando el archivo haya cambiado (y estos son solo algunos ejemplos), y en un idioma con el que probablemente ya estés familiarizado.
El sistema por sí solo no hace mucho, pero hay una gran cantidad de complementos disponibles, que puede ver en la página de complementos o buscando gulpplugin
en npm. Por ejemplo, existen complementos para ejecutar JSHint , compilar su CoffeeScript , ejecutar pruebas de Mocha e incluso actualizar su número de versión .
Hay otras herramientas de compilación disponibles, como Grunt y, más recientemente, Broccoli , pero creo que Gulp es superior (consulte la sección "¿Por qué Gulp?" a continuación). He compilado una lista más larga de herramientas de compilación escritas en JavaScript .
Gulp es de código abierto y se puede encontrar en GitHub .
Instalación
La instalación es bastante fácil. Primero, instale el paquete globalmente:
npm install -g gulp
Luego, instálalo en tu proyecto:
npm install --save-dev gulp
Usando
Creemos una tarea para minimizar uno de nuestros archivos JavaScript. Cree un archivo llamado gulpfile.js
. Aquí es donde definirás tus tareas de Gulp, que se ejecutarán usando el gulp
comando.
Coloque lo siguiente en su gulpfile.js
archivo:
var gulp = require('gulp'), uglify = require('gulp-uglify');gulp.task('minify', function () { gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build'))});
Instale gulp-uglify
a través de npm ejecutando npm install –save-dev gulp-uglify
y luego ejecute la tarea ejecutando gulp minify
. Suponiendo que tiene un archivo nombrado app.js
en el js
directorio, app.js
se creará uno nuevo en el directorio de compilación que contiene el contenido minimizado de js/app.js
.
Pero ¿qué pasó realmente aquí?
Estamos haciendo algunas cosas en nuestro gulpfile.js
archivo. Primero, estamos cargando los módulos gulp
y :gulp-uglify
var gulp = require('gulp'), uglify = require('gulp-uglify');
Luego, estamos definiendo una tarea llamada minify
, que, cuando se ejecute, llamará a la función proporcionada como segundo argumento:
gulp.task('minify', function () {});
Finalmente, y aquí es donde la cosa se vuelve complicada, estamos definiendo qué debería hacer realmente nuestra tarea:
gulp.src('js/app.js') .pipe(uglify()) .pipe(gulp.dest('build'))
A menos que esté familiarizado con las transmisiones, algo que la mayoría de los desarrolladores front-end no lo están, el código anterior no significará mucho para usted.
Corrientes
Las transmisiones le permiten pasar algunos datos a través de una serie de funciones generalmente pequeñas, que modificarán los datos y luego pasarán los datos modificados a la siguiente función.
En el ejemplo anterior, la gulp.src()
función toma una cadena que coincide con un archivo o una cantidad de archivos (conocido como "glob") y crea una secuencia de objetos que representan esos archivos. Luego se pasan (o canalizan) a la uglify()
función, que toma los objetos del archivo y devuelve nuevos objetos de archivo con una fuente minimizada. Luego, esa salida se canaliza a la gulp.dest()
función, que guarda los archivos modificados.
En forma de diagrama, esto es lo que sucede:
Cuando solo hay una tarea, la función realmente no hace mucho. Sin embargo, considere el siguiente código:
gulp.task('js', function () { return gulp.src('js/*.js') .pipe(jshint()) .pipe(jshint.reporter('default')) .pipe(uglify()) .pipe(concat('app.js')) .pipe(gulp.dest('build'));});
Para ejecutarlo usted mismo, instale gulp
, gulp-jshint
y gulp-uglify
.gulp-concat
Esta tarea tomará todos los archivos que coincidan js/*.js
(es decir, todos los archivos JavaScript del js
directorio), ejecutará JSHint en ellos e imprimirá el resultado, agrandará cada archivo y luego los concatenará, guardándolos en build/app.js
. En forma de diagrama:
Si estás familiarizado con Grunt, notarás que esto es bastante diferente a cómo lo hace Grunt. Grunt no usa transmisiones; en cambio, toma archivos, ejecuta una sola tarea en ellos y los guarda en archivos nuevos, repitiendo todo el proceso para cada tarea. Esto da como resultado muchos ataques al sistema de archivos, lo que lo hace más lento que Gulp.
Para obtener una lectura más completa sobre las transmisiones, consulte el "Manual de transmisiones".
trago.src()
La gulp.src()
función toma un globo (es decir, una cadena que coincide con uno o más archivos) o una matriz de globos y devuelve una secuencia que se puede canalizar a complementos.
Gulp usa node-glob para obtener los archivos del glob o globs que especifique. Es más fácil de explicar usando ejemplos:
js/app.js
Coincide exactamente con el archivojs/*.js
Coincide únicamente con todos los archivos que terminan en.js
el directoriojs
js/**/*.js
Coincide con todos los archivos que terminan en.js
eljs
directorio y todos los directorios secundarios!js/app.js
Se excluyejs/app.js
de la coincidencia, lo cual es útil si desea hacer coincidir todos los archivos en un directorio excepto un archivo en particular.*.+(js|css)
Coincide con todos los archivos en el directorio raíz que terminan en.js
o.css
Hay otras funciones disponibles, pero no se utilizan habitualmente en Gulp. Consulte la documentación de Minimatch para obtener más información.
Digamos que tenemos un directorio llamado js
que contiene archivos JavaScript, algunos minimizados y otros no, y queremos crear una tarea para minimizar los archivos que aún no están minimizados. Para hacer esto, comparamos todos los archivos JavaScript en el directorio y luego excluimos todos los archivos que terminan en .min.js
:
gulp.src(['js/**/*.js', '!js/**/*.min.js'])
Definición de tareas
Para definir una tarea, utilice la gulp.task()
función. Cuando define una tarea simple, esta función toma dos atributos: el nombre de la tarea y una función para ejecutar.
gulp.task('greet', function () { console.log('Hello world!');});
Al ejecutarlo, gulp greet
se imprimirá "Hola mundo" en la consola.
Una tarea también puede ser una lista de otras tareas. Supongamos que queremos definir una build
tarea que ejecute otras tres tareas css
, js
y imgs
. Podemos hacer esto especificando una serie de tareas, en lugar de la función:
gulp.task('build', ['css', 'js', 'imgs']);
Se ejecutarán de forma asincrónica, por lo que no puede asumir que la css
tarea habrá terminado de ejecutarse cuando js
comience; de hecho, probablemente no será así. Para asegurarse de que una tarea haya terminado de ejecutarse antes de que se ejecute otra, puede especificar dependencias combinando la matriz de tareas con la función. Por ejemplo, para definir una css
tarea que verifique que la greet
tarea haya terminado de ejecutarse antes de ejecutarse, puede hacer esto:
gulp.task('css', ['greet'], function () { // Deal with CSS here});
Ahora, cuando ejecute la css
tarea, Gulp la ejecutará greet
, esperará a que finalice y luego llamará a la función que haya especificado.
Tareas predeterminadas
Puede definir una tarea predeterminada que se ejecute cuando usted simplemente ejecute gulp
. Puede hacerlo definiendo una tarea denominada default
.
gulp.task('default', function () { // Your default task});
Complementos
Puede utilizar varios complementos (de hecho, más de 600) con Gulp. Los encontrará enumerados en la página de complementos o buscando gulpplugin
en npm. Algunos complementos están etiquetados como "gulpfriendly"; Estos no son complementos, pero están diseñados para funcionar bien con Gulp. Tenga en cuenta que cuando busque directamente en npm no podrá ver si un complemento ha sido incluido en la lista negra (al desplazarse hasta la parte inferior de la página de complementos, verá que muchos lo están).
La mayoría de los complementos son bastante fáciles de usar, tienen buena documentación y se ejecutan de la misma manera (conectándoles un flujo de objetos de archivo). Luego, normalmente modificarán los archivos (aunque algunos, como los validadores, no lo harán) y devolverán los archivos nuevos para pasarlos al siguiente complemento.
Ampliemos nuestra js
tarea anterior:
var gulp = require('gulp'), jshint = require('gulp-jshint'), uglify = require('gulp-uglify'), concat = require('gulp-concat');gulp.task('js', function () { return gulp.src('js/*.js') .pipe(jshint()) .pipe(jshint.reporter('default')) .pipe(uglify()) .pipe(concat('app.js')) .pipe(gulp.dest('build'));});
Estamos usando tres complementos aquí, gulp-jshint , gulp-uglify y gulp-concat . Puedes ver en los README
archivos de los complementos que son bastante fáciles de usar; Hay opciones disponibles, pero los valores predeterminados suelen ser lo suficientemente buenos.
Es posible que hayas notado que el complemento JSHint se llama dos veces. Esto se debe a que la primera línea ejecuta JSHint en los archivos, que solo adjunta una jshint
propiedad a los objetos del archivo sin generar nada. Puede leer la jshint
propiedad usted mismo o pasarla al reportero JSHint predeterminado o a otro reportero, como jshint-stylish .
Los otros dos complementos son más claros: la uglify()
función minimiza el código y concat(‘app.js’)
concatena todos los archivos en un solo archivo llamado app.js
.
complementos de carga de trago
Un módulo que encuentro realmente útil es gulp-load-plugins, que carga automáticamente cualquier complemento de Gulp desde su package.json
archivo y lo adjunta a un objeto. Su uso más básico es el siguiente:
var gulpLoadPlugins = require('gulp-load-plugins'), plugins = gulpLoadPlugins();
Puedes poner todo eso en una línea ( var plugins = require(‘gulp-load-plugins’)();
), pero no soy un gran admirador de require
las llamadas en línea.
Después de ejecutar ese código, el plugins
objeto contendrá sus complementos, con sus nombres en mayúsculas (por ejemplo, gulp-ruby-sass
se cargarían en plugins.rubySass
). Luego podrá utilizarlos como si fueran necesarios normalmente. Por ejemplo, nuestra js
tarea de antes se reduciría a lo siguiente:
var gulp = require('gulp'), gulpLoadPlugins = require('gulp-load-plugins'), plugins = gulpLoadPlugins();gulp.task('js', function () { return gulp.src('js/*.js') .pipe(plugins.jshint()) .pipe(plugins.jshint.reporter('default')) .pipe(plugins.uglify()) .pipe(plugins.concat('app.js')) .pipe(gulp.dest('build'));});
Esto supone un package.json
archivo similar al siguiente:
{ "devDependencies": { "gulp-concat": "~2.2.0", "gulp-uglify": "~0.2.1", "gulp-jshint": "~1.5.1", "gulp": "~3.5.6" }}
En este ejemplo, en realidad no es mucho más corto. Sin embargo, con archivos Gulp más largos y complicados, reduce la carga de inclusiones a solo una o dos líneas.
La versión 0.4.0 de gulp-load-plugins, lanzada a principios de marzo, agregó la carga diferida de complementos, lo que mejora el rendimiento. Los complementos no se cargan hasta que los llama, lo que significa que no tiene que preocuparse de que los complementos no utilizados afecten el package.json
rendimiento (aunque probablemente debería limpiarlos de todos modos). En otras palabras, si ejecuta una tarea que requiere solo dos complementos, no cargará todos los complementos que requieren las otras tareas.
Ver archivos
Gulp tiene la capacidad de observar archivos en busca de cambios y luego ejecutar una tarea o tareas cuando se detectan cambios. Esta característica es increíblemente útil (y, para mí, probablemente la más útil de Gulp). Puedes guardar tu archivo LESS y Gulp lo convertirá en CSS y actualizará el navegador sin que tengas que hacer nada.
Para ver un archivo o archivos, use la gulp.watch()
función, que toma un globo o una matriz de globos (igual que gulp.src()
) y una serie de tareas para ejecutar o una devolución de llamada.
Digamos que tenemos una build
tarea que convierte nuestros archivos de plantilla en HTML y queremos definir una watch
tarea que observe nuestros archivos de plantilla en busca de cambios y ejecute la tarea para convertirlos en HTML. Podemos usar la watch
función de la siguiente manera:
gulp.task('watch', function () { gulp.watch('templates/*.tmpl.html', ['build']);});
Ahora, cuando cambiemos un archivo de plantilla, la build
tarea se ejecutará y se generará el HTML.
También puedes darle a la watch
función una devolución de llamada, en lugar de una serie de tareas. En este caso, la devolución de llamada recibiría un event
objeto que contiene información sobre el evento que desencadenó la devolución de llamada:
gulp.watch('templates/*.tmpl.html', function (event) { console.log('Event type: ' + event.type); // added, changed, or deleted console.log('Event path: ' + event.path); // The path of the modified file});
Otra característica interesante gulp.watch()
es que devuelve lo que se conoce como archivo watcher
. Utilice watcher
para escuchar eventos adicionales o para agregar archivos al archivo watch
. Por ejemplo, para ejecutar una lista de tareas y llamar a una función, puede agregar un detector al change
evento en el resultado watcher
:
var watcher = gulp.watch('templates/*.tmpl.html', ['build']);watcher.on('change', function (event) { console.log('Event type: ' + event.type); // added, changed, or deleted console.log('Event path: ' + event.path); // The path of the modified file});
Además del change
evento, puedes escuchar otros eventos:
end
Se activa cuando finaliza el observador (lo que significa que las tareas y devoluciones de llamadas ya no se llamarán cuando se cambien los archivos)error
Se dispara cuando ocurre un errorready
Se activa cuando los archivos han sido encontrados y están siendo observados.nomatch
Se activa cuando el globo no coincide con ningún archivo
El watcher
objeto también contiene algunos métodos que puedes llamar:
watcher.end()
Detienewatcher
(para que no se llamen más tareas o devoluciones de llamada)watcher.files()
Devuelve una lista de archivos que están siendo supervisados por elwatcher
watcher.add(glob)
Agrega archivos quewatcher
coinciden con el glob especificado (además, acepta una devolución de llamada opcional como segundo argumento)watcher.remove(filepath)
Elimina un archivo en particular delwatcher
Puede hacer que Gulp recargue o actualice el navegador cuando usted (o cualquier otra cosa, como una tarea de Gulp) cambia un archivo. Hay dos maneras de hacer esto. El primero es usar el complemento LiveReload y el segundo es usar BrowserSync
recarga en vivo
LiveReload se combina con extensiones del navegador (incluida una extensión de Chrome ) para recargar su navegador cada vez que se detecta un cambio en un archivo. Se puede utilizar con el complemento gulp-watch o con el integrado gulp.watch()
que describí anteriormente. Aquí hay un ejemplo del README
archivo del repositorio gulp-livereload :
var gulp = require('gulp'), less = require('gulp-less'), livereload = require('gulp-livereload'), watch = require('gulp-watch');gulp.task('less', function() { gulp.src('less/*.less') .pipe(watch()) .pipe(less()) .pipe(gulp.dest('css')) .pipe(livereload());});
Esto observará todos los archivos que coincidan less/*.less
en busca de cambios. Cuando se detecta un cambio, generará el CSS, guardará los archivos y recargará el navegador.
Hay disponible una alternativa a LiveReload. BrowserSync es similar en que muestra cambios en el navegador, pero tiene muchas más funciones.
Cuando realiza cambios en el código, BrowserSync recarga la página o, si es CSS, inyecta el CSS, lo que significa que no es necesario actualizar la página. Esto es muy útil si su sitio web no es resistente a las actualizaciones. Suponga que está desarrollando cuatro clics en una aplicación de una sola página y al actualizar la página lo llevará de regreso a la página de inicio. Con LiveReload, deberás hacer clic cuatro veces cada vez que realices un cambio. BrowserSync, sin embargo, simplemente inyectaría los cambios cuando modifique el CSS, por lo que no necesitará volver a hacer clic.
BrowserSync también sincroniza los clics, las acciones de los formularios y la posición de desplazamiento entre navegadores. Puedes abrir un par de navegadores en tu escritorio y otro en un iPhone y luego navegar por el sitio web. Los enlaces se seguirían en todos ellos y, a medida que se desplazara hacia abajo en la página, las páginas de todos los dispositivos se desplazarían hacia abajo (¡normalmente también sin problemas!). Cuando ingresa texto en un formulario, se ingresará en cada ventana. Y cuando no desee este comportamiento, puede desactivarlo.
BrowserSync no requiere un complemento de navegador porque entrega sus archivos por usted (o los representa, si son dinámicos) y proporciona una secuencia de comandos que abre un conector entre el navegador y el servidor. Sin embargo, esto no me ha causado ningún problema en el pasado.
En realidad, no existe un complemento para Gulp porque BrowserSync no manipula archivos, por lo que realmente no funcionaría como tal. Sin embargo, el módulo BrowserSync en npm se puede llamar directamente desde Gulp. Primero, instálelo a través de npm:
npm install --save-dev browser-sync
Luego, lo siguiente gulpfile.js
iniciará BrowserSync y observará algunos archivos:
var gulp = require('gulp'), browserSync = require('browser-sync');gulp.task('browser-sync', function () { var files = [ 'app/**/*.html', 'app/assets/css/**/*.css', 'app/assets/imgs/**/*.png', 'app/assets/js/**/*.js' ]; browserSync.init(files, { server: { baseDir: './app' } });});
La ejecución gulp browser-sync
luego observará los archivos coincidentes en busca de cambios e iniciará un servidor que sirve los archivos en el app
directorio.
El desarrollador de BrowserSync ha escrito sobre otras cosas que puedes hacer en su repositorio BrowserSync + Gulp .
¿Por qué tragar?
Como se mencionó, Gulp es una de las pocas herramientas de compilación disponibles en JavaScript, y también están disponibles otras herramientas de compilación no escritas en JavaScript, incluido Rake. ¿Por qué deberías elegirlo?
Las dos herramientas de compilación más populares en JavaScript son Grunt y Gulp. Grunt fue muy popular en 2013 y cambió por completo la forma en que muchas personas desarrollan sitios web. Hay miles de complementos disponibles para ello, que hacen de todo, desde linting, minificación y concatenación de código hasta instalar paquetes usando Bower e iniciar un servidor Express. Este enfoque es bastante diferente del de Gulp, que sólo tiene complementos para realizar pequeñas tareas individuales que hacen cosas con archivos. Debido a que las tareas son solo JavaScript (a diferencia del objeto grande que usa Grunt), no necesitas un complemento; puede iniciar un servidor Express de la forma habitual.
Las tareas gruñidas tienden a estar sobreconfiguradas, requiriendo un objeto grande que contenga propiedades de las que realmente no querrás preocuparte, mientras que la misma tarea en Gulp puede ocupar solo unas pocas líneas. Veamos un simple gruntfile.js
que define una css
tarea para convertir nuestro LESS a CSS y luego ejecutar Autoprefixer en él:
grunt.initConfig({ less: { development: { files: { "build/tmp/app.css": "assets/app.less" } } }, autoprefixer: { options: { browsers: ['last 2 version', 'ie 8', 'ie 9'] }, multiple_files: { expand: true, flatten: true, src: 'build/tmp/app.css', dest: 'build/' } }});grunt.loadNpmTasks('grunt-contrib-less');grunt.loadNpmTasks('grunt-autoprefixer');grunt.registerTask('css', ['less', 'autoprefixer']);
Compare esto con el gulpfile.js
archivo que hace lo mismo:
var gulp = require('gulp'), less = require('gulp-less'), autoprefix = require('gulp-autoprefixer');gulp.task('css', function () { gulp.src('assets/app.less') .pipe(less()) .pipe(autoprefix('last 2 version', 'ie 8', 'ie 9')) .pipe(gulp.dest('build'));});
La gulpfile.js
versión es considerablemente más legible y más pequeña.
Debido a que Grunt llega al sistema de archivos con mucha más frecuencia que Gulp, que usa flujos, casi siempre es mucho más rápido que Grunt. Para un archivo MENOS pequeño, el gulpfile.js
archivo anterior normalmente tardaría unos 6 milisegundos. Por lo general , esto gruntfile.js
tomaría unos 50 milisegundos, más de ocho veces más. Este es un pequeño ejemplo, pero con archivos más largos, la cantidad de tiempo aumenta significativamente.
Otras lecturas
- Cómo aprovechar las máquinas: ser productivo con los ejecutores de tareas
- Por qué debería dejar de instalar su entorno WebDev localmente
- Uso de un generador de sitios estáticos a escala: lecciones aprendidas
- Creación de software web con Make
(ds, al, ml, mrn)Explora más en
- Codificación
- Herramientas
- Flujo de trabajo
- javascript
- Mejoramiento
Deja un comentario