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.
Programação, Mobile, Front-end, Design & UX, Infraestrutura e Business
Pensei hoje em escrever um artigo sobre Grunt haha
Artigo muito bom!
Grunt é sensacional
Ó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/
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/
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!!
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”?
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
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!
@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
@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.
@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.
@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.
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.
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!
@Caio Não faço ideia 🙂 Se achar algum, posta aqui
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!
@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.
Aqui usamos um script bash .sh mesmo que chama o ant e o grunt. Nada muito chique 🙂
@Sergio realmente excelente o post. Muito bom, bem explicado e objetivo. Gostei. Parabéns.
abraco,
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.
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!
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