Desenvolvedores web front-end possuem todo um fluxo de trabalho para seus projetos, que envolvem tarefas como compilar CSS de pré-processadores, verificar erros de JavaScript, combinar e minificar assets, otimizar imagens, enfim, tarefas necessárias que fazem parte de qualquer workflow minimamente profissional.
Há anos já existem ferramentas de automatização de tarefas (neste meio, conhecidos como task runners), tais como o já apresentado Grunt. Mas ele não é o único. Recentemente surgiu outro automatizador de tarefas para fazer frente ao Grunt e, como se verá mais à frente, que possui muitas vantagens. Seu nome? Gulp.
Gulp: the streaming build system
Como citado, geralmente este tipo de ferramenta é conhecida como “automatizador de tarefas”, “executor de tarefas”, dentre outros termos do gênero; o Gulp, que também é desta mesma “linha”, se autointitula um build system, algo como um “sistema de construção” ou “sistema de compilação”.
Na prática, seu motivo de existir é o mesmo que do Grunt: ajudar desenvolvedores front-end com tarefas necessárias-repetitivas e, com isso, prover maior velocidade/rapidez no desenvolvimento de um projeto e liberar nossas mentes para focar no que realmente importa. E preste bastante atenção na palavra “velocidade”.
Velocidade. Eficiência. Simplicidade.
Como consta no próprio site oficial do Gulp, estes são os 3 princípios que o norteiam. Caso você já esteja mexendo com Grunt e passar para Gulp (nem que seja para testar), você vai sentir o poder destas 3 palavras na prática!
As características principais do Gulp são:
- Fácil de usar. Ao preferir código ao invés de configuração, Gulp mantém simples o que é simples e faz tarefas complexas mais bem administráveis.
- Eficiente. Gulp usa o poder de streams do Node, o que permite builds muitos mais rápidos e dispensa a necessidade de gravação de arquivos intermediários em disco.
- Alta qualidade. As diretrizes estritas para plugins do Gulp garantem que seus plugins permaneçam simples e trabalhem da maneira que se espera.
- Fácil de aprender. Com uma API mínima, aprende-se a trabalhar com o Gulp quase que na hora!
Código ao invés de configuração (“code over configuration“) significa que realmente é preciso programar, montar scripts. Pare para pensar: um Gruntfile
, por exemplo, é tão-somente um arquivo com um monte de configuração de tarefas, indicando o que estas devem fazer e de que maneira. Com Gulp, o fluxo de tarefas é programado.
A eficiência do Gulp muito se dá em função de este usar Streams do Node. Tecnicamente, Stream é uma interface abstrata implementada por vários objetos, mas pense neles como os pipes de sistemas *NIX, em que é possível jogar a o resultado de um comando diretamente em outro.
Sua alta qualidade e facilidade de aprendizado garantem plugins igualmente eficientes e, devido ao próprio modo como o Gulp funciona, sua facilidade de aprendizado e uso são absurdos; é uma curtíssima (quase inexistente) curva de aprendizado para começar a mexer com uma das mais poderosas ferramentas de desenvolvimento web que surgiram nos últimos tempos!
Como instalar Gulp
Gulp é JavaScript com Node, então, a primeira coisa que você vai precisar é instalar o Node. Tomando por base que você está mexendo num sistema de gente grande, isso é tão simples quando digitar uma linha de comando no Terminal (caso já até não o tenha instalado). Depois disso, instale o Gulp globalmente no sistema com npm install -g gulp
.
Já que estamos lidando com Node, um arquivo package.json
na raiz do projeto se faz necessário para indicar quais módulos serão usados no projeto. É possível que o Node crie esse arquivo automaticamente com npm init
, o que que iniciará um prompt interativo que vai perguntar um monte de coisas (tais como nome do projeto, versão, descrição, licença, autor, etc). Na verdade, para começar a adicionar módulos, tudo o que é preciso é que esse arquivo seja um JSON válido (mais sobre isso no artigo JSON – JavaScript Object Notation), e um JSON válido mínimo não passa de “{}”. Então, se quiser ser mais prático, basta executar echo "{}" > package.json
.
Já com o package.json
na raiz com um JSON válido, execute npm install --save-dev gulp
para instalar o Gulp para o projeto.
Revisando:
npm install -g gulp
echo "{}" > package.json
npm install --save-dev gulp
Depois disso, seu package.json
deve estar assim:
1 2 3 4 5 |
{ "devDependencies": { "gulp": "~3.5.5" } } |
Como você viu, para instalar módulos o comando é npm install --save-dev [MÓDULO]
. Na verdade, a instalação, propriamente dita, dispensa o uso de --save-dev
, mas usar este parâmetro garante com que a definição do módulo seja gravada no package.json
e isso torna as coisas mais fáceis ao se iniciar um projeto que usa Gulp.
node_modules
no controle de versão, já que, ao se clonar um projeto que tenha um package.json
, basta executar npm install
para que ele seja criado automaticamente já com os módulos/dependências que serão usados.gulpfile.js
Agora que o básico para se mexer com Gulp está preparado, é hora do gulpfile.js
. Neste arquivo, que também deve ficar na raiz, é que os scripts das tarefas instaladas constam; é aqui, efetivamente, que os comandos sobre o que fazer e como fazer são passados para o Gulp.
Um boilerplate para o gulpfile.js
poderia ser:
1 2 3 4 5 |
var gulp = require('gulp'); gulp.task('default', function() { // Tarefas }); |
Primeiramente, requere-se o módulo “gulp” (isso deve ser feito com todos módulos que você pretende usar). Depois cria-se uma tarefa default
com as instruções que serão realizadas quando esta tarefa for executada. Do jeito que está, você já pode executar no Terminal: gulp
.
Apesar de ser uma tarefa nada útil, ela já deve retornar algo como:
1 2 3 4 |
[gulp] Using file [...]/gulpfile.js [gulp] Working directory changed to [...] [gulp] Running 'default'... [gulp] Finished 'default' in 85 μs |
Atente-se que a maneira de executar uma tarefa é usar “gulp” seguido do nome da mesma. Por exemplo, se você tivesse criado uma tarefa “concatAssets”, você a executaria com gulp concatAssets
. No caso, funcionou executando só gulp
porque este é um nome de tarefa especial: quando uma tarefa “default” está definida, é ela que será executada caso nenhum outro nome seja passado.
Gulp API
Você já viu que um dos princípios norteadores do Gulp é a simplicidade. Indo ao encontro disso, sua API é extremamente simples e enxuta, limitando-se a 4 funções principais:
src()
. Arquivo(s) que entrará(ão) na sequência de pipes para serem tratados/manipuladostask()
. Define tarefas no Gulpdest()
. Destino(s) do(s) arquivo(s) que passou pelos pipeswatch()
. “Observa” arquivo(s) e faz alguma coisa quando este(s) é(são) alterado(s)
Obviamente cada um tem suas opções, possibilidade e detalhes técnicos, então, apesar de essas breves palavras sobre cada já darem uma noção sobre as respectivas funções, seria interessante olhar a página da API do Gulp – mas as opções mais comuns já poderão ser compreendidas ao se continuar lendo o artigo e ficando atento aos exemplos.
Exemplo de tarefas com Gulp
Basicamente, você já sabe como trabalhar com Gulp! A partir de agora, é usar os módulos Gulp disponíveis (e, quem sabe, até criar alguns) e conhecer as peculiaridades de uso de cada um. Um exemplo vai ajudar a clarear as coisas e fixar o conhecimento.
Então o Gulp, para este exemplo, vai trabalhar com os módulos:
- gulp-ruby-sass (compilar SASS)
- gulp-autoprefixer (prefixos de browsers)
- gulp-minify-css (minificar CSS)
- gulp-livereload (recarrega a página automaticamente quando um arquivo for salvo)
E, usando a função watch()
do Gulp, tudo isso vai acontecer automaticamente ao se salvar algum arquivo SASS.
Instalando módulos Gulp
Para instalar os módulos necessários ao exemplo:
1 |
npm install --save-dev gulp-ruby-sass gulp-autoprefixer gulp-minify-css gulp-livereload tiny-lr |
Lembrando que, para usar o gulp-ruby-sass
– que é um pouquinho mais lento que gulp-sass (imperceptível em exemplos como este), mas possui opções mais interessantes -, é preciso que você tenha Ruby instalado.
Também, que o gulp-livereload
usa tiny-lr
(por isso consta na lista de módulos a serem instalados) e é preciso ter a extensão LiveReload para Chrome.
Depois de rodar o comando, seu package.json
deve estar parecido com:
1 2 3 4 5 6 7 8 9 10 |
{ "devDependencies": { "gulp": "~3.5.5", "gulp-ruby-sass": "~0.7.1", "gulp-autoprefixer": "2.1.0", "gulp-minify-css": "~0.4.3", "gulp-livereload": "~3.6.0", "tiny-lr": "0.1.5" } } |
Estrutura do projeto-exemplo
Para este projeto-exemplo, considere a seguinte estrutura:
1 2 3 4 5 6 7 |
|-- dist | `-- index.html |-- gulpfile.js |-- package.json `-- src |-- _variables.scss `-- style.scss |
1 2 3 4 5 6 7 8 9 10 11 12 |
<!doctype html> <html> <head> <meta charset="utf-8"> <title>Gulp test</title> <link href="style.css" rel="stylesheet"> </head> <body> <p>Texto do teste.</p> </body> </html> |
1 2 |
$backgroundColor: tomato; $defaultTextColor: #fff; |
1 2 3 4 5 6 |
@import 'variables'; body { background-color: $backgroundColor; color: $defaultTextColor; } |
Editar o gulpfile.js
Agora será preciso editar o gulpfile.js
para que fique adequado aos propósitos do projeto-exemplo. Para começar, é preciso requerer os módulos e os atribuir a suas respectivas variáveis:
1 2 3 4 5 6 |
var gulp = require('gulp'), sass = require('gulp-ruby-sass'), prefix = require('gulp-autoprefixer'), minifycss = require('gulp-minify-css'), refresh = require('gulp-livereload'), server = require('tiny-lr')(); |
Repare que, para o gulp-livereload
e tiny-lr
, foram dados nomes de variáveis diferentes. Embora seja uma convenção nomear uma variável com o nome do módulo que ela recebe, já já você vai entender.
Agora, chegou o momento de indicar ao Gulp o que fazer, efetivamente. Lembre-se dos pipes: o(s) arquivos(s) indicado(s) em src()
passa(m) por um comando e o resultado disso é jogado para o próximo e para o próximo e assim por diante.
1 2 3 4 5 6 7 8 9 10 11 12 |
gulp.task('compileStyles', function() { gulp.src('src/style.scss') .pipe(sass({ noCache : true, precision : 4, unixNewlines : true })) .pipe(prefix('last 3 version')) .pipe(minifycss()) .pipe(gulp.dest('dist')) .pipe(refresh(server)); }); |
Perceba que há opções definidas para gulp-ruby-sass
; isso é perfeitamente normal para vários módulos Gulp. Geralmente o que está disponível e quais as opções possíveis são informações disponibilizadas na própria página do módulo. Também, veja o motivo de aquelas variáveis terem recebido nome diferente do nome do módulo: fica mais entendível quando se lê refresh(server)
, concorda?
Finalmente, a parte mágica que automatiza inclusive o recarregar de página, poupando até de ter que dar o foco na janela do navegador e apertar F5 (ou pior: clicar no botão de recarregar).
1 2 3 4 5 6 7 8 9 |
gulp.task('watch', function() { server.listen(35729, function( err ) { if ( err ) { return console.log( err ); } gulp.watch('src/**/*.{sass,scss}', [ 'compileStyles' ]); }); }); |
A tarefa chamada watch
inicia um servidor LiveReload escutando na porta 35729 (a porta padrão desse server) e colocando no console algum acontecimento inesperado. O filé mignon é a parte que indica que, caso qualquer arquivo SASS seja alterado em qualquer parte do diretório src
, a tarefa compileStyles
deve ser executada – e a página recarregada, afinal, é para isso que o LiveReload presta.
O arquivo gulpfile.js
final deve se parecer com:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 |
var gulp = require('gulp'), sass = require('gulp-ruby-sass'), prefix = require('gulp-autoprefixer'), minifycss = require('gulp-minify-css'), refresh = require('gulp-livereload'), server = require('tiny-lr')(); gulp.task('compileStyles', function() { gulp.src('src/style.scss') .pipe(sass({ noCache : true, precision : 4, unixNewlines : true })) .pipe(prefix('last 3 version')) .pipe(minifycss()) .pipe(gulp.dest('dist')) .pipe(refresh(server)); }); gulp.task('watch', function() { server.listen(35729, function( err ) { if ( err ) { return console.log( err ); } gulp.watch('src/**/*.{sass,scss}', [ 'compileStyles' ]); }); }); |
Então, com essas menos de 30 linhas de código, agora é possível abrir index.html
, executar gulp watch
, ativar a extensão LiveReload no navegador e partir pro abraço (leia-se: editar um arquivo SASS em src
). Quase que instantaneamente você vai ver as alterações aparecendo na tela de seu navegador.
Agora você entende aqueles preceitos do Gulp: Velocidade, Eficiência, Simplicidade.
Gulp x Grunt
É completamente comum, natural e até inevitável a comparação Gulp x Grunt, caso você já tenha usado o “porcão” anteriormente. Muito se tem falado a este respeito, apontando que, na verdade, não há uma “disputa” entre ambos e é possível escolher um ou outro, dependendo das preferências do programador e/ou as necessidades do projeto.
A estrondosa-colossal-modafoca diferença de velocidade não pode deixar de ser citada. Até para projetos de pequeno porte, com poucas tarefas, o Grunt costuma levar mais de 1 ou 2 segundos para se virar com todo um fluxo predeterminado. Com Gulp, não raramente se encontra “μ” nos tempos de execução total. Este é o símbolo de microsegundo, que é uma fração 1 milhão de vezes menor que o segundo!
Como “defesa” ao Grunt, é dito que esta comparação não pode ser válida, dado que Grunt e Gulp foram projetados e funcionando usando recursos diferentes. Pessoalmente, discordo, considerando que é um argumento que beira a falácia. Se há duas ferramentas que servem para o mesmo propósito, mas usam tecnologias diferentes e/ou têm funcionamento interno diferente, esta diferença, por si, mesma, deve ser um dos pilares de argumentação!
Mas, não se pode negar, no atual momento o número de módulos para Grunt é maior, dado que ele apareceu primeiro no cenário de desenvolvimento web e… Bem, é só porque ele apareceu primeiro, mesmo.
Para finalizar esta breve comparação, uma tabela com as melhores características de Gulp e Grunt:
Gulp | Grunt | |
---|---|---|
Velocidade | ✔ | |
Flexibilidade | ✔ | |
Facilidade de escrita | ✔ | |
Facilidade de leitura | ✔ | |
Facilidade de manutenção de código | ✔ | |
Quantidade de módulos / Comunidade | ✔ | |
Atrativo a novos “adeptos” | ✔ |
Mas essa é só uma comparação de um cara qualquer que, assumidamente, prefere Gulp. Há gente de peso falando sobre isso e, realmente, é preciso estar atento a opiniões variadas, a quem tem uma posição mais neutra.
Sugestões de módulos Gulp
Existem centenas de módulos/plugins para o Gulp e, a cada dia, mais e mais aparecem pela web. Não seria viável manter uma lista completamente num post, mas, certamente, algumas indicações de módulos úteis para tarefas comuns é bem-vinda:
- gulp-util (funções úteis variadas)
- gulp-ruby-sass (compila SASS)
- gulp-autoprefixer (prefixos de browsers)
- gulp-minify-css (minifica CSS)
- gulp-jshint (detecta erros e problemas potenciais de JavaScript)
- gulp-uglify (minifica arquivos)
- gulp-imagemin (minifica/otimiza imagens)
- gulp-replace (substitui strings em arquivos)
- gulp-concat (concatena arquivos)
- delete-files-folder (remove arquivos e diretórios)
- gulp-cache (faz cache de comandos, melhorando a performance)
- gulp-rename (renomeia arquivos)
- gulp-rev (adiciona hash aleatório em nomes de arquivos)
- gulp-livereload (recarrega a página automaticamente quando um arquivo é salvo)
Conclusão
Kronos é implacável, principalmente quando se trata de desenvolvimento web, e não há como evitar que novas tecnologias apareçam, com novas propostas, solicitando uma nova maneira de pensar e fazer, a fim de tentar sanar problemas já conhecidos. Este é, precisamente, o caso do Gulp: com a intenção de ajudar na automação de tarefas repetitivas e liberar a mente criativa dos desenvolvedores, é uma das melhores e mais eficientes ferramentas para front-end dos últimos anos e, apesar de opiniões (ainda) controversas, veio para substituir seu “irmão mais velho”, Grunt, ao propor mais velocidade, simplicidade e flexibilidade.
Certamente, num só artigo, seria impossível cobrir tudo sobre Gulp; portanto, muitos outros serão escritos, com explicações mais detalhadas sobre o modo de funcionamento do Gulp, em si, e indicações de plugins (tratados de maneira mais aprofundada). Fique ligado.
Mas a verdade é que, cedo ou tarde, algo melhor/mais eficiente que o Gulp vai aparecer. Mais importante que saber mexer com “tal” ou “qual” ferramenta é saber identificar o que o tempo traz de melhor e ter sabedoria para reconhecer o que é bom e saber se adaptar, não ficando pesaroso ao abrir mão do que um dia já foi.
“E o passado é uma roupa que não nos serve mais”.