Automação de build de front-end com Grunt.js

Ferramentas de build é o que não falta no mercado atual – desde o Maven e o Ant pra Java, o Gradle ou o clássico Make. Mas o Grunt é diferente. Foi feito em JavaScript e com grande foco em automatizar tarefas de front-end.

Se você, por exemplo, for seguir as boas práticas de performance para sites, já deve se preocupar com minificar CSS e JavaScript ou ainda juntar arquivos pra diminuir o número de requests e até fazer CSS sprites. Ou talvez você esteja usando algum pré-processador de CSS como o LESS, SASS ou Stylus.

A questão é: você vai precisar rodar um minificador, um concatenador de arquivos, um pré-processador e provavelmente muitas outras pequenas ferramentas. Rodar tudo isso individualmente é insano e queremos automatizar todo esse processo. É aí que entra o Grunt.js.

O Grunt.js

É uma ferramenta automação de tarefas de build feita totalmente em JavaScript. Ela roda no Node.js, que é um interpretador JavaScript que você pode instalar no seu computador. No final do artigo mostro o processo de instalação pra quando for rodar a primeira vez.

O central no Grunt é um arquivo que descreve as tarefas a serem executadas no build do projeto. E esse mesmo arquivo é escrito em JavaScript, então nada de XML ou sintaxes estranhas como em outras ferramentas. Esse arquivo é o Gruntfile.js que você cria na raiz do seu projeto.

A estrutura básica dele é essa:

module.exports = function(grunt) {
  grunt.initConfig({
     // configurações das tasks
  });

  // carrega plugins
  grunt.loadNpmTasks('nome-do-plugin');
};

Repare que é uma função JS que chama outras configurações. A initConfig é onde vamos colocar as regras das tarefas que queremos executar (onde indicamos, por exemplo, quais arquivos minificar). Repare que ele recebe um objeto JS, como num JSON. No final, chamamos a loadNpmTasks pra registrar um plugin do Grunt que vai trazer alguma funcionalidade.

Minficando JS com Uglify

Vamos configurar a minificação de JavaScript usando o UglifyJS. Registramos o plugin — chamado grunt-contrib-uglify usando grunt.loadNpmTasks('grunt-contrib-uglify');.

A configuração em si é bem simples: basta listar os arquivos a serem minficados (origem e destino):

module.exports = function(grunt) {
  grunt.initConfig({
     uglify: {
        'build/home.js': 'src/home.js',
        'build/main.js': 'src/main.js'   
     }
  });

  // carrega plugins
  grunt.loadNpmTasks('grunt-contrib-uglify');
};

No exemplo, eu supus que você cria seus arquivos numa pasta src/ e quer jogar as versões finais numa pasta build/ (claro que você pode usar outros nomes). Daria também pra minificar o próprio arquivo sem copiá-lo pra uma pasta diferente, mas dificilmente você vai querer minificar seu próprio arquivo fonte.

Por fim, pra executar essa tarefa, basta rodar grunt uglify no terminal.

Pré-processando CSS

Agora é muito fácil adicionar outros plugins e executar outras tarefas. Por exemplo, usando o grunt-contrib-less, podemos compilar um arquivo LESS pra CSS:

less: {
  'build/estilo.css': 'src/estilo.less'
}

Pra rodar, basta executar grunt less no terminal. Pra compilar SASS ou Stylus, é praticamente a mesma coisa, só muda o nome do plugin.

Mais: se quiser concatenar os arquivos CSS num só, além de compilar todos os LESS, dá pra fazer isso listando os arquivos:

less: {
  'build/estilo.css': ['src/header.less', 'src/main.less', 'src/footer.less']
}

Ou usar padrões nos nomes dos arquivos pra ficar mais fácil ainda:

less: {
  'build/estilo.css': ['src/*.less']
}

E isso vale, claro, pras outras tarefas também, como a do uglify que vimos antes. E estamos só vendo o início do Grunt. Dá pra fazer muito mais coisas nessas configurações, pra facilitar tudo mais ainda.

Aliás, um recurso que podemos fazer é simplificar a execução das tarefas pra não precisarmos chamar uma por uma na hora de rodar o comando. Podemos definir novas tarefas com grunt.registerTask(). Passamos o nome da nova task e uma lista de tasks a serem executadas:

grunt.registerTask('default', ['uglify', 'less']);

A nova task default pode ser executada na linha de comando com grunt default e já vai rodar tanto o less quanto o uglify pra gente. Melhor ainda, esse nome default é especial então podemos executar tudo só rodando grunt no terminal.

O código final do exemplo está aqui.

Mais tarefas

Há muitos outros plugins úteis no grunt. Pra compiladores de CSS, temos o LESS, Stylus e SASS. Pra JS, temos também CoffeeScript. Pra minificar, temos o uglify, o cssmin e o htmlmin. Temos ainda tarefas básicas como copiar arquivos (copy), concatenação simples (concat) e clean. E ainda o watch com livereload para seu navegador atualizar automaticamente quando um arquivo for mudado.

Isso só falando de alguns dos plugins oficiais. Há uma lista imensa de plugins da comunidade pra fazer as mais variadas tarefas. Como o poderoso grunticon que gera uma sprite de arquivos SVG com fallback para PNGs.

A instalação do Grunt.js

O Grunt é baseado no Node.js então você deve primeiro instalá-lo. No site já há um botão de download logo de cara ou você pode usar o instalador de pacotes do seu sistema operacional (apt-get no Linux, homebrew no Mac etc).

Depois que você instalou o Node, pode instalar as ferramentas de linha de comando do Grunt apenas executando no terminal: npm install -g grunt-cli

Próximo passo é configurar nosso projeto como um artefato do node para que possamos instalar os plugins e outras dependências. É bem fácil. Crie um arquivo package.json na raiz do seu projeto onde colocaremos configurações do projeto — o mínimo é o nome do projeto e um número de versão:

{
  "name": "grunt-demo",
  "version": "0.0.1"
}

Agora, a instalação do Grunt é feita de acordo com o projeto fazendo: npm install grunt --save-dev.

Cada plugin do grunt que você for usar, vai instalar da mesma forma:

npm install grunt-contrib-uglify --save-dev
npm install grunt-contrib-less --save-dev

Aí é só usar esses plugins no seu Gruntfile.js como vimos antes.

Mais

Vimos uma introdução do grunt, suas ideias e alguns poucos recursos. O site oficial deles tem muito mais documentação. Em português, há os excelentes artigos do Zeno Rocha e do Felipe Fialho.

O Grunt é uma ferramenta poderosa para automatizar tarefas de build. Tem bastante foco em tarefas de front-end, mas pode ser usado pra todo tipo de build. Aqui na Caelum mesmo, usamos para buildar a parte front-end de um projeto maior com Java no backend.

28 Comentários

  1. Vitor Mattos 25/06/2013 at 21:27 #

    Pensei hoje em escrever um artigo sobre Grunt haha
    Artigo muito bom!
    Grunt é sensacional

  2. Vítor Nogueira 26/06/2013 at 00:07 #

    Ótimo artigo Sérgio! Apenas para acrescentar, também tem esse ótimo artigo do Fernando Daciuk: http://www.voltsdigital.com.br/labs/gruntjs-por-onde-comecar/

  3. Cândido 26/06/2013 at 17:06 #

    Sérgio,

    Muito bom o post =D … Também havia criado um sobre o Grunt: https://candidosalesg.wordpress.com/2013/06/14/rapidez-no-seu-fluxo-de-trabalho-com-grunt-js/

  4. Edinei 02/07/2013 at 09:26 #

    Muito bom o post!!

    Fiquei curioso quando disse que usa o Grunt para buildar uma parte do front-end de uma aplicação da caelum onde o backend usa-se Java. Como é feito? São duas builds diferentes? Ou uma build Java que chama a build do Grunt para os arquivos front-end? Obrigado!!

  5. Rick Benetti 02/07/2013 at 09:48 #

    Acho muito legal td isso, mas enchergo como uma camada a mais de problemas no meu caso que trabalho numa empresa de magento.

    Até mesmo com WordPress que são nos meus trabalhos pessoais fica complicado, já tenho node instalado pra usar o LESS, instalar mais coisas “pra simplificar”?

  6. Alexandre Cardoso 02/07/2013 at 10:43 #

    Parabéns pelo post, Sérgio. Bem interessante o Grunt.js.

    Acredito que você já conheça o Wro4J (https://code.google.com/p/wro4j/). Tenho utilizado o mesmo em projetos Java, com o VRaptor, e não-Java tb. Funciona muito bem e tem essencialmente as mesmas funções do Grunt.

    Abs

  7. André Machado 02/07/2013 at 11:20 #

    Oi Sérgio, tudo bem?

    Eu trabalho com front e não tenho um grande conhecimento em server, mas o que foi posto aqui nesse tópico faz parte do meu dia a dia e é familiar pra mim.

    Mas eu tenho uma dúvida (abstraia se eu falar alguma grande besteira, como falei não manjo de server): Se eu tenho um projeto que utiliza algum compilador , e eu queira que esse build seja feito no momento do deploy (rodar o compass pra gerar o sprite e os css’s por exemplo, ou mesmo o grunt pra minificar e aglutinar tudo) é possível, certo?

    Mas, se eu tiver um projeto em .net onde seu deploy é feito com o Azure e outro projeto usando o Hudson por exemplo eu preciso configurar esses dois caras separadamente para cumprir essa operação, correto? Não existe uma ponte por exemplo que abstraia esse comando para qualquer linguagem/sistema de deploy?

    Qual é a maneira correta de organizar esse tipo de coisa? Para que esses builds dependam o minimo possível de uma ação “manual” de alguém que não está trabalhando diretamente no desenvolvimento do front, onde ela precise fazer o build, preparar tudo pra aí sim iniciar o processo de deploy.

    Valeu e obrigado pelo post!

  8. Sérgio Lopes 02/07/2013 at 14:10 #

    @Edinei: O projeto aqui usava ANT pra buildar a parte java (compilar etc). Implementamos o Grunt pra parte frontend e o build final é feito por um script que chama as duas coisas

  9. Sérgio Lopes 02/07/2013 at 14:12 #

    @Rick: é mais um ponto do sistema sim, propenso a problemas como todos os outros. Uma vantagem a meu ver com relação a usar os plugins no wordpress é que você vai instalar o Grunt na maquina de desenvolvimento apenas. Nao há complicacao em produção (seu cliente/wordpress não precisa ter plugins instalados pra essas tarefas).

    Eu acho que simplifica pelo fato da aplicação precisar de menos dependencias em producao, e jogar essas tarefas pro build feito pelo desenvolvedor.

  10. Sérgio Lopes 02/07/2013 at 14:16 #

    @Alexandre: Não conhecia não, bem interessante o projeto!

    Acho que a única vantagem do Grunt com relação a concorrentes equivalentes é sua popularidade. Eu mesmo quando comecei com Grunt não gostava tanto, achava meio complicado e preferia soluções mais simples. Acabei me rendendo pois o mercado todo de frontend tá indo em direção ao Grunt. E isso significa trocentos plugins diferentes, suporte da comunidade etc.

  11. Sérgio Lopes 02/07/2013 at 14:19 #

    @André: você pode usar o Grunt nesse cenário também. Você vai configurar seu hudson pra executar o build do Grunt pra você automaticamente, da mesma maneira que você faria na sua máquina.

  12. Fernando 02/07/2013 at 21:29 #

    Parabéns Sergio, ótima introdução ao Grunt. Como leitura complementar recomendo estes post: http://www.newaeonweb.com.br/n3/grunt-js-parte-1-instalando-node-js.html

    Também com uma serie bem legal sobre o Grunt.js.
    Abraço e continue com este grande trabalho.

  13. Caio Ribeiro Pereira 05/07/2013 at 08:59 #

    Parabéns pelo post! Excelente conteúdo sobre Grunt!

    Poderia me recomendar, módulos do grunt que fazem upload para o Amazon S3 e já faz invalidate de cache no Amazon CloudFront?

    Abs!

  14. Sérgio Lopes 05/07/2013 at 15:06 #

    @Caio Não faço ideia 🙂 Se achar algum, posta aqui

  15. Felipe Fialho 25/07/2013 at 13:50 #

    Maravilha Sérgio.

    Estou “catequizando” a galera a para usar, porque é realmente formidável.

    E quanto mais gente usar, mais Plugins vamos ter. 😀

    Da preguiça só de pensar na época em que minificava css, minificava javascript, otimizava imagens e etc… manualmente.

    Abração!

  16. Michel 07/11/2013 at 12:57 #

    @Sérgio qual script vocês usam pra integrar o Grunt com o Ant, pq meu cenário aqui é exatamente o mesmo que o seu. Tenho a parte Java tudo com o Ant e agora quero automatizar o front.

    Parabéns pelo artigo.

  17. Sérgio Lopes 08/11/2013 at 13:17 #

    Aqui usamos um script bash .sh mesmo que chama o ant e o grunt. Nada muito chique 🙂

  18. camilo lopes 27/01/2014 at 00:19 #

    @Sergio realmente excelente o post. Muito bom, bem explicado e objetivo. Gostei. Parabéns.
    abraco,

  19. Jefferson 05/02/2014 at 13:33 #

    Muito bom o post… Me ajudou muito já em meu primeiro projeto utilizando Grunt.JS

    Gostaria de saber se há uma maneira de que quando o arquivo LESS seja compilado o CSS seja transferido para o servidor?

    Valeu.

  20. Breno Alves 26/04/2014 at 01:16 #

    Sérgio! Fantástico esse tutorial, estava há muito tempo querendo começar a usar o Grunt em meus projetos.
    Peguei seu tutorial, fui seguindo as referências e em um dia de estudo já estou praticamente “dominando” todas as ferramentas que eu mais precisava!

    Muito obrigado!

  21. michel 24/09/2014 at 14:08 #

    Alguem sabe como otimizar o concat para ele não compilar todo o projeto novamente quando faço uma atualização em 1 arquivo ?
    Tenho um site bem grande com umas 140 páginas e quando atualizo apenas um arquivo ele compila todo o projeto para depois mostrar a alteração.
    Grato

Deixe uma resposta