Linha de comando para desenvolvimento web: automações com o Grunt
() translation by (you can also view the original English article)
No decorrer da série, aprendemos a compilar código, inserir prefix, limpar o código, comprimir e minificar, tudo com algumas palavras (ou comandos). Isso é ótimo, mas e se você precisar executar cada um desses comandos várias vezes em um projeto, um após o outro, toda vez, até completar seu trabalho? Por exemplo:
- Compilar arquivos pré processados para CSS
- Autoprefix CSS
- Clean CSS
- Compilar Jade para HTML
- Concatenar e minificar arquivos JavaScript
Mesmo com apenas algumas palavras por comando, isso logo pode se tornar bem cansativo, mais ainda ao avançar no desenvolvimento do projeto.
Neste momento é que os "task runners" ou "gerenciadores de tarefas" entram em cena para salvar o dia. Com gerenciadores de tarefas você consegue definir, a partir de um único arquivo dentro do projeto, todas as rotinas executadas no projeto e a ordem de execução das mesmas. Nesse mesmo arquivo, você também pode definir comandos para executar as tarefas criadas.
Vamos aprender a configurar um gerenciador de tarefa da maneira que acabamos de descrever, e mais, no processo, vamos utilizar alguns packages do Bower para criar um ambiente de desenvolvimento eficiente com base no gerenciador.
Nota: neste tutorial, exigimos conhecimentos dos tutoriais anteriores da série. Se você ainda não deu uma olhada nos tutoriais anteriores, vale a pena conferir, além de úteis você vai encontrar muita informação relevante para continuar o tutorial.
Os dois principais gerenciadores de tarefas
Existem alguns gerenciadores de tarefas disponíveis hoje, porém, para o nosso tutotrial vamos focar nos dois mais utilizados: o Grunt e o Gulp.
Existem algumas diferenças técnicas básicas entre as duas soluções, mas não vamos analisar isso agora. Também não vou dar palpite em qual dos dois você deve utilizar. Ao invés disso, eu recomendo que você teste as duas soluções e depois decida, com propriedade, qual utilizar.
Criando um projeto de exemplo
Vamos criar um projeto que monitora e compila automaticamente arquivos Jade e Stylus, e otimiza arquivos CSS e JavaScript. Vamos fazer tudo isso utilizando o Grunt, e depois (no próximo tutorial) utilizando o Gulp.
Para começar, vamos criar um projeto de exemplo com alguns arquivos necessários para o gerenciador tarefas operar. Crie uma pasta com o nome "Projeto Grunt", e dentro desta, crie duas pastas, uma com o nome "build" e a outra com nome "source".
Na pasta "source" crie mais duas pastas, uma com o nome "stylus" e a outra, "jade". Crie alguns arquivos de exemplo para cada uma das pastas, Jade e Stylus.
Os arquivos podem conter o código que você desejar, mas se houver algo, você pode ver o processo sendo executado.
Dica: se você não sabe que código adicionar para testar, utilize algum código dos exemplos do Codepen, na parte de projetos com tag Stylus e projetos com tag Jade.
Por exemplo:



Também vamos aproveitar o conhecimento adquirido no tutorial anterior, sobre o Bower, que utilizamos para baixar o pacote do jQuery e Modernizr, e que depois, vamos combinar e comprimir em um único arquivo.
Executando os comandos:
1 |
bower install jquery --save |
1 |
bower install modernizr --save |
Agora, crie uma cópia do pasta do projeto e dê a ela nome de "Gulp Project".
Dessa maneira, você pode testar o Grunt em uma pasta e o Gulp em outra.
Introdução ao Grunt



Instalando o Grunt CLI
Para que os comandos do Grunt funcionem, precisamos primeiro instalar o seu ambiente CLI (interface de linha de comando). Instale o Grunt globalmente com o comando:
1 |
[sudo] npm install -g grunt-cli |
Configurando um projeto para o Grunt
Crie o arquivo package.json
Todo projeto que utiliza o Grunt precisa do arquivo package.json na raiz do projeto.
Ja demos uma olhada em como criar e configurar o arquivo "package.json" através do comando npm init
, no tutorial anterior sobre pacotes de terceiros. Se você se sente perdido aqui e ainda não deu uma olhada no tutorial anterior, pare o que está fazendo e de uma olhada no tutorial anterior.
Instalando pacote do Grunt
Instale o Grunt no seu projeto e salve ele como uma dependência do projeto com o comando:
1 |
npm install grunt --save-dev |
Criando o arquivo Gruntfile
Todo projeto Grunt também precisa, obrigatoriamente, do arquivo Gruntfile na raiz do projeto.
Gruntfile é um arquivo com o nome de "Gruntfile.js", ou se preferir, Gruntfile.coffe para quem utiliza o CoffeeScript. No nosso caso, vamos utilizar JavaScript, então crie um arquivo chamado "Gruntfile.js" (o nome do arquivo obrigatoriamente precisa começar com letra maiúscula) na pasta raiz do seu projeto.
É neste arquivo, o Gruntfile, que definimos quais os comandos e tarefas devem ser executados. Vamos começar incluindo um bloco de código básico no arquivo Gruntfile. O código para denifir as configurações vamos ver mais a frente.
Adicione o seguinte código no seu arquivo Gruntfile.js:
1 |
module.exports = function(grunt) { |
2 |
|
3 |
};
|
Instalando plugins no Grunt
Você deve se lembrar que para utilizar os pacotes do Bower ou npm, você deve busca-los no lugar certo a fim de encontrar a melhor versão para sua necessidade.
A mesma coisa acontece quando utilizamos pacotes no Grunt. Através do Grunt, temos acesso a diversos plugins, que basicamente são ports de pacotes npm vanilla. Esses plugins são disponibilizados via npm, mas são especificos para operar no Grunt
Por exemplo, ao invés de utilizar o pacote npm UglifyJS, no Grunt utilizamos o plugin "grunt-contrib-uglify".
Você pode pesquisar os plugins disponíveis para o Grunt no link http://gruntjs.com/plugins



Para o nosso projeto, vamos instalar seis plugins:
- https://www.npmjs.com/package/grunt-contrib-stylus
- https://www.npmjs.com/package/grunt-autoprefixer
- https://www.npmjs.com/package/grunt-contrib-cssmin
- https://www.npmjs.com/package/grunt-contrib-jade
- https://www.npmjs.com/package/grunt-contrib-uglify
- https://www.npmjs.com/package/grunt-contrib-watch
Cada um deles vai ser instalado na sub pasta "node_modules", na raiz do projeto, e serão salvos como dependências de desenvolvimento.
Execute, por vez, cada um dos seguintes comandos, com o terminal apontando para pasta do projeto de exemplo (Gulp Project):
1 |
npm install grunt-contrib-stylus --save-dev |
1 |
npm install grunt-autoprefixer --save-dev |
1 |
npm install grunt-contrib-cssmin --save-dev |
1 |
npm install grunt-contrib-jade --save-dev |
1 |
npm install grunt-contrib-uglify --save-dev |
1 |
npm install grunt-contrib-watch --save-dev |
Após executar os comandos, as seguintes pastas devem estar disponíveis na pasta "node_modules":



Ativando os plugins através do Gruntfile
Agora vamos utilizar o método grunt.loadNpmTasks
para ativar nossos plugins.
Agora, vamos popular o bloco de código que criamos no Gruntfile. Vamos adicionar seis linhas de código, uma para cada plugin, conforme o exemplo abaixo:
1 |
module.exports = function(grunt) { |
2 |
|
3 |
// Load grunt plugins.
|
4 |
grunt.loadNpmTasks('grunt-contrib-stylus'); |
5 |
grunt.loadNpmTasks('grunt-autoprefixer'); |
6 |
grunt.loadNpmTasks('grunt-contrib-cssmin'); |
7 |
grunt.loadNpmTasks('grunt-contrib-jade'); |
8 |
grunt.loadNpmTasks('grunt-contrib-uglify'); |
9 |
grunt.loadNpmTasks('grunt-contrib-watch'); |
10 |
|
11 |
};
|
Esse comando registra o nome da cada plugin como um comando do Grunt, permitindo utilizar este para executar determinada tarefa. Por exemplo, utilizamos o comando grunt stylus
para executar a tarefa de compilar o código Stylus, e o comando grunt autoprefixer
para executar a tarefa de prefix do autoprefixer, e assim por diante.
Configurando tarefas no Gruntfile
Os plugins estão instalados e os comandos estão configurados, mas se executarmos algum deles, nada vai acontecer. A razão disso é que precisamos definir algumas configurações para determinar qual tarefa de fato é executada.
Isso é feito com o método grunt.initConfig
no arquivo Gruntfile, onde incluimos as informações de execução de cada tarefa.
Primeiro, vamos adicionar o método grunt.initConfig
logo após as linhas que acabamos de incluir para ativar os plugins:
1 |
grunt.initConfig(); |
Agora, deixamos um espaço para declarar as informações das tarefas. Dentro das chaves, deixe algumas linhas em branco:
1 |
grunt.initConfig({ |
2 |
|
3 |
});
|
Agora podemos seguir e adicionar as configurações de cada plugin que instalamos.
Todo o plugin tem suas próprias configurações, e essas opções geralmente estão detalhadas na seção "install grunt plugins".
Você também pode conferir a documentação oficial do Grunt sobre tarefas no link: http://gruntjs.com/configuring-tasks
Exemplo de configuração de tarefa no Grunt: Stylus
Vamos começar adicionando as configurações de tarefa do stylus
.
Entre as chaves do método grunt.initConfig, no espaço que deixamos em branco, adicione o bloco de código abaixo:
1 |
stylus: { |
2 |
compile: { |
3 |
options: { |
4 |
compress: false, |
5 |
paths: ['source/stylus'] |
6 |
},
|
7 |
files: { |
8 |
'build/style.css': 'source/stylus/main.styl' |
9 |
}
|
10 |
}
|
11 |
},
|
Seu arquivo Gruntfile agora deve estar parecido com o exemplo:
1 |
module.exports = function(grunt) { |
2 |
|
3 |
grunt.initConfig({ |
4 |
|
5 |
stylus: { |
6 |
compile: { |
7 |
options: { |
8 |
compress: false, |
9 |
paths: ['source/stylus'] |
10 |
},
|
11 |
files: { |
12 |
'build/style.css': 'source/stylus/main.styl' |
13 |
}
|
14 |
}
|
15 |
},
|
16 |
|
17 |
});
|
18 |
|
19 |
// Load grunt plugins.
|
20 |
grunt.loadNpmTasks('grunt-contrib-stylus'); |
21 |
grunt.loadNpmTasks('grunt-autoprefixer'); |
22 |
grunt.loadNpmTasks('grunt-contrib-cssmin'); |
23 |
grunt.loadNpmTasks('grunt-contrib-jade'); |
24 |
grunt.loadNpmTasks('grunt-contrib-uglify'); |
25 |
grunt.loadNpmTasks('grunt-contrib-watch'); |
26 |
|
27 |
};
|
Vamos dividir esse código em partes para entender o que acontece aqui. Não vamos analisar cada uma das tarefas, mas uma olhada nesta já pode dar uma ideia da sintaxe utilizada para configurar tarefas no Grunt.
Como mencionado anteriormente, cada plugin possui configurações diferentes, então, quando for testar um novo plugin, dê sempre uma olhada nas instruções de uso.
A primeira coisa que fizemos foi adicionar uma entrada para as configurações do Stylus
com o código:
1 |
stylus: { |
2 |
|
3 |
}, |
Dentro, adicionamos a entrada compile
, para controlar o que vai acontecer durante a compilação do arquivo:
1 |
stylus: { |
2 |
compile: { |
3 |
|
4 |
} |
5 |
}, |
Dentro do compile
, criamos uma entrada chamada options
, para definir as opções do recurso.
Vamos utilizar essa parte para definir o compress
para false
, pois vamos comprimir o arquivo apenas no final da execução de outras tarefas.
Também definimos as opções de paths
para o caminho ["source/stylus"]
, assim caso o Stylus encontre uma diretiva @import
, ele pode e deve procurar referências no caminho "source/stylus":
1 |
stylus: { |
2 |
compile: { |
3 |
options: { |
4 |
compress: false, |
5 |
paths: ['source/stylus'] |
6 |
} |
7 |
} |
8 |
}, |
Então, depois da entrada options
, adicionamos uma entrada chamada files
para definir o caminho de saída do arquivo e nome do mesmo, assim como os arquivos de entrada.
Definimos o caminho de saída para o arquivo CSS compilado na pasta "build/style.css"
, enquanto o arquivo a ser compilado está no caminho "source/stylus/main.styl"
.
1 |
stylus: { |
2 |
compile: { |
3 |
options: { |
4 |
compress: false, |
5 |
paths: ['source/stylus'] |
6 |
}, |
7 |
files: { |
8 |
'build/style.css': 'source/stylus/main.styl' |
9 |
} |
10 |
} |
11 |
}, |
Agora, com o terminal apontando para a pasta raiz do projeto, execute o seguinte comando:
1 |
grunt stylus |
Agora dê uma olhada na pasta "build", que agora deve conter o arquivo compilado "style.css".
Configurando as demais tarefas
Agora vamos definir as configurações das demais tarefas. Insira cada bloco de código, referente a cada tarefa, uma após a outra no Gruntfile.
Autoprefixer
Adicione o seguinte código:
1 |
autoprefixer: { |
2 |
compile: { |
3 |
files: { |
4 |
'build/style.css': 'build/style.css' |
5 |
},
|
6 |
},
|
7 |
},
|
Execute a tarefa do autoprefixer com o comando:
1 |
grunt autoprefixer |
Se você der uma olhada no arquivo "build/style.css" você vai notar que foram adicionados os prefix onde havia a necessidade.
cssmin
Adicione o código:
1 |
cssmin: { |
2 |
clean: { |
3 |
files: { |
4 |
'build/style.css': 'build/style.css' |
5 |
}
|
6 |
}
|
7 |
},
|
Execute a tarefa do cssmin com o comando:
1 |
grunt cssmin |
Se você der uma olhada no arquivo "build/style.css" agora, vai notar que o arquivo está bem limpo e comprimido.
Jade
Adicione o código:
1 |
jade: { |
2 |
compile: { |
3 |
files: [{ |
4 |
expand: true, |
5 |
cwd: "source/jade", |
6 |
src: "*.jade", |
7 |
dest: "build", |
8 |
ext: ".html" |
9 |
}]
|
10 |
}
|
11 |
},
|
Execute a tarefa do Jade com o comando:
1 |
grunt jade |
Se você der uma olhada agora na pasta "build", você vai notar que foi criado um arquivo HTML para cada arquivo Jade presente na pasta "source/jade".
Uglify
Adicione o seguinte código:
1 |
uglify: { |
2 |
bower_js_files: { |
3 |
files: { |
4 |
'build/output.min.js': [ |
5 |
'bower_components/jquery/dist/jquery.js', |
6 |
'bower_components/modernizr/modernizr.js' |
7 |
]
|
8 |
}
|
9 |
}
|
10 |
},
|
Neste exemplo você pode notar que apontamos o local onde ficam os componentes do Bower, que instalamos anteriormente.
Com essa tarefa,pegamos os arquivos completo do jQuery e Modernizr nas pasta "bower_components", concatemos e minificamos o código, gerando o arquivo "output.min.js". Essa é uma ótima maneira de gerenciar scripts com o Bower.
Execute a tarefa do Uglify com o comando:
1 |
grunt uglify |
Agora deve ter um arquivo chamado "output.min.js" na pasta "build" do projeto.
Criando a tarefa "watch"
Até agora, parece que apenas substituímos alguns parâmetros para executar determinada tarefa com outro comando, mas o que estamos fazendo até agora é preparar o terreno para as verdadeiras funcionalidades do Grunt.
O segredo é a habilidade do Grunt de executar uma tarefa após a outra, automaticamente. Agora, vamos configurar uma tarefa chamada watch
, que monitora mudanças em determinados arquivos, e então executa as tarefas stylus
e jade
automaticamente para nós.
Adicione o seguinte código:
1 |
watch: { |
2 |
stylus: { |
3 |
files: [ 'source/stylus/*.styl' ], |
4 |
tasks: ['stylus', 'autoprefixer', 'cssmin'] |
5 |
},
|
6 |
jade: { |
7 |
files: [ 'source/jade/*.jade' ], |
8 |
tasks: ['jade'] |
9 |
}
|
10 |
},
|
Primeiro adicionamos a tarefa watch
, depois dentro dela, configuramos o stylus
e jade
.
A opção files
em cada uma das tarefas determina que arquivos serão monitorados. A opção tasks
define quais tarefas devem ser executadas quando houver mudança nos arquivos especificados.
Para o stylus
, configuramos a tarefa watch que monitora mudanças em qualquer arquivo com a extensão ".styl" na pasta "source/stylus", e então executa as tarefas stylus
, autoprefixer
e cssmin
, exatamente nesta ordem.
Agora, enquanto a tarefa watch estiver em execução, tudo que precisamos fazer é salvar um arquivo Stylus após sua edição e o Grunt automaticamente vai compilar, aplicar os prefix e otimizar o arquivo CSS na pasta "build".
A mesma coisa foi feita com arquivos jade
, monitoramos qualquer arquivo com a extensão ".jade" na pasta "source/jade", e qualque alteração sofrida, automaticamente são gerados os arquivos HTML referentes para a pasta "build".
Execute a tarefa watch com o comando:
1 |
grunt watch |
Para parar de executar a tarefa você pode:
- Fechar o terminal
- Pressionar as teclas CTRL + C
Criando a tarefa "default"
Neste ponto você deve estar pensando o que vamos fazer com a tarefa Uglify.
A razão pela qual não adicionamos essa tarefa dentro da tarefa watch
é porque não vamos fazer alterações nos arquivos do jQuery e Modernizr, o que não implica em executar a tarefa Uglify a todo momento. Então, como a tarefa watch
apenas responde a mudanças de arquivos, a tarefa nunca seria executada (já que não vamos fazer alteração nos arquivos JS).
Ao invés disso, vamos utilizar uma tarefa chamado default
que pode ser configurada no arquivo Gruntfile. Essa tarefa vai ser executada caso você execute o comando grunt
sozinho.
Logo após a ultima linha grunt.loadNpmTasks
, antes do };
, adicione a seguinte linha:
1 |
grunt.registerTask('default', ['stylus', 'autoprefixer', 'cssmin', 'jade', 'uglify']); |
Isso define que a tarefa default
vai executar as terefas stylus
, autoprefixer
, cssmin
, jade
e depois a uglify
.
Agora, se você executar o comando grunt
sozinho, ele vai recriar todo o seu projeto com base em cada uma das tarefas, inclusive para o JavaScript.
No próximo tutorial
No próximo tutorial vamos repetir todo esse processo, mas utilizando o Grunt para executar as tarefas, ao invés do Grunt.
Seja o primeiro a saber sobre novas traduções–siga @tutsplus_pt no Twitter!