Automatizando o Desenvolvimento com Gulp – Parte 1

Hoje vou mostrar para vocês algumas ferramentas para front-end que facilitam e aceleram o desenvolvimento.

Para começarmos, vamos criar um projeto web simples com NPM e Bower, e então adicionar um automatizador de tarefas para nos ajudar. A medida que o código for crescendo vamos implementando mais funcionalidades no nosso automatizador.

$ npm init
This utility will walk you through creating a package.json file.
 It only covers the most common items, and tries to guess sane defaults.
See `npm help json` for definitive documentation on these fields
 and exactly what they do.
Use `npm install <pkg> --save` afterwards to install a package and
 save it as a dependency in the package.json file.
Press ^C at any time to quit.
 name: (ferramentas)
 version: (1.0.0)
 description:
 entry point: (index.js)
 test command:
 git repository:
 keywords:
 author:
 license: (ISC)
 About to write to c:\workspace\sandbox\ferramentas\package.json:
{
 "name": "ferramentas",
 "version": "1.0.0",
 "description": "",
 "main": "index.js",
 "scripts": {
 "test": "echo \"Error: no test specified\" && exit 1"
 },
 "author": "",
 "license": "ISC"
 }
 Is this ok? (yes)
$ bower init
? name: ferramentas
 ? version: 0.0.0
 ? description:
 ? main file:
 ? what types of modules does this package expose?
 ? keywords:
 ? authors: Fernando Falci
 ? license: MIT
 ? homepage:
 ? set currently installed components as dependencies? Yes
 ? add commonly ignored files to ignore list? Yes
 ? would you like to mark this package as private which prevents it from being ac
 ? would you like to mark this package as private which prevents it from being ac
 cidentally published to the registry? No
{
 name: 'ferramentas',
 version: '0.0.0',
 authors: [
 'Fernando Falci'
 ],
 license: 'MIT',
 ignore: [
 '**/.*',
 'node_modules',
 'bower_components',
 'test',
 'tests'
 ]
 }
? Looks good? Yes

(Problemas com NPM ou Bower? Talvez esse post pode te ajudar)

src e dist

A primeira dica aqui é: separar o código fonte do código “compilado”. Ok, eu sei que o front-end não é compilado, mas mesmo assim teremos algumas ferramentas que irão automatizar nosso código e gerar uma nova versão para distribuição (por isso “dist”).

Então na raiz do projeto criaremos dois diretórios: /src e /dist

$ mkdir src
$ mkdir dist

Continuando, vamos criar o index.html, no diretório /src

<!DOCTYPE html>
<html>
   <head>
     <meta charset="UTF-8">
     <title>Ferramentas para Front-end</title>
   </head>
   <body>
     <h1>Algumas ferramentas</h1>
     <ul>
       <li><span>NPM</span></li>
       <li><span>Bower</span></li>
     </ul>
   </body>
 </html>

Gulp – O canivete suíço

De todas as ferramentas que apresentarei nesse post, esta é sem dúvidas a mais importe. Gulp é uma ferramenta de automação de tarefas feita em JavaScript e rodando em cima do Node.js

Como já temos o NPM instalado, precisamos agora adicionar o Gulp como dependência global:

$ npm install -g gulp
C:\Users\user\AppData\Roaming\npm\gulp -> C:\Users\user\AppData\Roaming\npm\node
 _modules\gulp\bin\gulp.js
 gulp@3.8.11 C:\Users\user\AppData\Roaming\npm\node_modules\gulp
 ├── pretty-hrtime@0.2.2
 ├── deprecated@0.0.1
 ├── archy@1.0.0
 ├── minimist@1.1.1
 ├── semver@4.3.4
 ├── interpret@0.3.10
 ├── tildify@1.0.0 (user-home@1.1.1)
 ├── v8flags@2.0.5 (user-home@1.1.1)
 ├── chalk@0.5.1 (supports-color@0.2.0, escape-string-regexp@1.0.3, ansi-styles@1
 .1.0, has-ansi@0.1.0, strip-ansi@0.3.0)
 ├── orchestrator@0.3.7 (sequencify@0.0.7, stream-consume@0.1.0, end-of-stream@0.
 1.5)
 ├── liftoff@2.1.0 (rechoir@0.6.1, flagged-respawn@0.3.1, extend@2.0.1, resolve@1
 .1.6, findup-sync@0.2.1)
 ├── vinyl-fs@0.3.13 (graceful-fs@3.0.7, mkdirp@0.5.1, strip-bom@1.0.0, defaults@
 1.0.2, vinyl@0.4.6, through2@0.6.5, glob-stream@3.1.18, glob-watcher@0.0.6)
 └── gulp-util@3.0.4 (object-assign@2.0.0, array-differ@1.0.0, replace-ext@0.0.1,
 vinyl@0.4.6, beeper@1.0.0, lodash._reevaluate@3.0.0, lodash._reinterpolate@3.0.
 0, array-uniq@1.0.2, lodash._reescape@3.0.0, through2@0.6.5, chalk@1.0.0, multip
 ipe@0.1.2, lodash.template@3.6.1, dateformat@1.0.11)

Lembrando que esse comando só precisa ser feito uma vez, independente de quantos projetos diferentes você irá usar o Gulp.

Apesar de parecer meio redundante, precisamos adicionar o Gulp como dependência do projeto:

$ npm install --save-dev gulp
gulp@3.8.11 node_modules\gulp
 ├── pretty-hrtime@0.2.2
 ├── interpret@0.3.10
 ├── deprecated@0.0.1
 ├── archy@1.0.0
 ├── minimist@1.1.1
 ├── semver@4.3.4
 ├── tildify@1.0.0 (user-home@1.1.1)
 ├── v8flags@2.0.5 (user-home@1.1.1)
 ├── chalk@0.5.1 (ansi-styles@1.1.0, escape-string-regexp@1.0.3, supports-color@0.2.0, has-ansi@0.1.0, strip-ansi@0.3.0)
 ├── orchestrator@0.3.7 (stream-consume@0.1.0, sequencify@0.0.7, end-of-stream@0.1.5)
 ├── liftoff@2.1.0 (extend@2.0.1, rechoir@0.6.1, flagged-respawn@0.3.1, resolve@1.1.6, findup-sync@0.2.1)
 ├── vinyl-fs@0.3.13 (graceful-fs@3.0.7, mkdirp@0.5.1, strip-bom@1.0.0, vinyl@0.4.6, defaults@1.0.2, through2@0.6.5, glob-stream@3.1.18, glob-watcher@0.0.6)
 └── gulp-util@3.0.4 (array-differ@1.0.0, beeper@1.0.0, object-assign@2.0.0, array-uniq@1.0.2, lodash._reescape@3.0.0, lodash._reinterpolate@3.0.0, lodash._reevaluate@3.0.0, replace-ext@0.0.1, vinyl@0.4.6, chalk@1.0.0, through2@0.6.5, lodash.template@3.6.1, multipipe@0.1.2, dateformat@1.0.11)

Dica: o –save-dev salva a dependência como “desenvolvimento”, afinal o Gulp não precisa estar disponível na versão “dist” do projeto

Configurando o Gulp

Quando executarmos o Gulp pela linha de comando, ele irá procurar pelo arquivo gulpfile.js. Então na raiz do projeto crie um novo arquivo com este nome.

var gulp = require('gulp');

Atenção: o gulpfile.js deve ficar na raiz do projeto, e não dentro de /src ou /dist, ok?.

Não se preocupe com o require. Ele faz parte do Node.JS e está disponível no momento da execução.

O Gulp tem 4 comandos principais que veremos a seguir:

1) gulp.task()

O Gulp trabalha com tasks (tarefas) que fazem pequenas ações. A primeira tarefa que precisamos fazer é copiar os arquivos (por hora apenas 1) do diretório /src para /dist.

A síntaxe do comando task é: gulp.task(nome, dependências (opcional), função). Na prática, nossa primeira tarefa começa assim:

var gulp = require('gulp');
gulp.task('copiar', function(){
 console.log('Fazer a cópia dos arquivos');
});

No código acima criamos uma nova task do Gulp, chamada “copiar” e atribuimos uma função para o Gulp associar a ela.

Bem, é claro que esse comando não vai fazer a cópia dos arquivos ainda, mas já podemos acessar pelo console/terminal e ver se tudo está ok:

$ gulp copiar
 [13:54:24] Using gulpfile c:\workspace\sandbox\ferramentas\gulpfile.js
 [13:54:24] Starting 'copiar'...
 Fazer a cópia dos arquivos
 [13:54:24] Finished 'copiar' after 852 µs

2) gulp.src()

Vamos implementar essa tarefa de copiar. Precisamos dizer ao Gulp onde estão os arquivos originais, e para isso temos o método gulp.src().

Claro que precisamos dizer ao gulp.src() onde ele irá encontrar os arquivos. Então o comando ficará assim:

var gulp = require('gulp');
gulp.task('copiar', function(){
  return gulp.src(__dirname + '/src/index.html');
});

Bem, como temos apenas um arquivo, fica fácil. Mas você já deve estar pensando: como eu vou listar todos os arquivos quando a aplicação começar a crescer?

Simples: o gulp.src() aceita arrays e regex, então no futuro podemos passar um parâmetro como:

gulp.src([
  '/src/*.html', // arquivos .html da raiz /src
  'src/**/*.js', // arquivos .js de subdiretórios
  '!src/**/*-spec.js' // ignorar arquivos -spec.js (testes) de subdiretórios
]);

Nota: a variável __dirname também será fornecida pelo Node.JS

3)  .pipe()

O retorno do gulp.src() é um stream que nos disponibiliza o método .pipe().

Mas afinal: o que o .pipe() faz?n

Ele conecta alguma função/plugin ao stream, que deverá ser executada para cada arquivo do .src().

Um exemplo de função de que pode ser plugada é o gulp.dest() que veremos a seguir.

4) gulp.dest()

No método gulp.dest() (destino) é onde dizemos ao Gulp onde devem ficar os arquivos no final da tarefa.

Geralmente este é o ultimo pipe das nossas tarefas.

Finalizando nossa tarefa de cópia, temos o seguinte código:

var gulp = require('gulp');
gulp.task('copiar', function(){
  return gulp.src(__dirname + '/src/index.html')
    .pipe(gulp.dest(__dirname + '/dist'));
});

Vamos testar! Salve o arquivo, e chame esta tarefa no console:

$ gulp copiar
 [14:24:19] Using gulpfile c:\workspace\sandbox\ferramentas\gulpfile.js
 [14:24:19] Starting 'copiar'...
 [14:24:19] Finished 'copiar' after 7.22 ms

Como resultado, podemos verificar que o index.html foi copiado para o diretório dist.

Um coisa que deveriamos fazer antes de copiar os arquivos, seria certificar-se que o diretório de destino está vazio, sem nenhum arquivo da cópia anterior.

Mas como o Gulp é extremamente simples, ele não tem nenhum método para remover arquivos. Neste caso podemos criar uma nova task que execute outro plugin (dependência do NPM) internamente.

O NPM tem uma infinidade de dependências úteis. Então vamos instalar o del:

$ npm install --save-dev del
 del@1.2.0 node_modules\del
 ├── object-assign@2.0.0
 ├── is-path-cwd@1.0.0
 ├── is-path-in-cwd@1.0.0 (is-path-inside@1.0.0)
 ├── each-async@1.1.1 (set-immediate-shim@1.0.1, onetime@1.0.0)
 ├── rimraf@2.3.4 (glob@4.5.3)
 └── globby@2.0.0 (async@0.9.2, array-union@1.0.1, glob@5.0.9)

E agora a task (pode ser adicionada no final do gulpfile.js)

var del = require('del');
gulp.task('limpar', function () {
  del.sync(__dirname + '/dist/**');
});

Ao chamar ‘gulp limpar’ podemos verificar que o diretório está vazio. Opss.. na verdade o diretório todo foi removido. Bem, isso não é um problema, porque a tarefa de cópia irá criar o diretório caso ele não exista.

Bem, não faz muito sentido chamar a tarefa limpar manualmente toda vez. Então vamos adicioná-la como dependência do tarefa de cópia (afinal é ela quem precisa de um diretório limpo).

O nosso gulpfile.js ficará dessa forma:

var gulp = require('gulp')
 del = require('del');  // vamos manter as dependências agrupadas
gulp.task('copiar', ['limpar'], function(){
  return gulp.src(__dirname + '/src/index.html')
    .pipe(gulp.dest(__dirname + '/dist'));
});
gulp.task('limpar', function () {
  del.sync(__dirname + '/dist/**');
});

Apesar de não termos como provar neste momento, o Gulp irá limpar o diretório /dest e então copiar novamente do diretório /src.

Agora já sabemos o básico de como o Gulp se comporta e como criar algumas tarefas.

Na próxima parte deste post, vou trazer uma lista de plugins que impulsionam o desenvolvimento no front-end

Links:

Por FERNANDO FALCI

Postado em: 07 de julho de 2015

Confira outros artigos do nosso blog

Variáveis nativas no CSS: elas existem?

14 de maio de 2018

Patrícia Gomes dos Santos Silva

How-to: Conhecendo o SASS

07 de maio de 2018

Bruno Carvalho

Introdução ao Webpack 2

10 de julho de 2017

Alan Cesar Elias

Começando com Angular 2

09 de fevereiro de 2017

Otávio Felipe do Prado

Deixe seu comentário