Review do livro “Maintainable JavaScript”

Semana passada (mais especificamente dia 04/05/2014) terminei a leitura do livro “Maintainable JavaScript” escrito por Nicholas C. Zakas. Resolvi então fazer um review com algumas considerações que achei importante em cada capítulo.

O texto ficou um pouco grande (como de costume em meus posts), então se você estiver apenas querendo uma opinião direta sobre o livro, se vale ou não comprar e ler, a minha resposta é: sim, vale a pena.

O que tenho à dizer é que foi uma leitura de “duzentas e poucas” páginas muito interessante. Em apenas um final de semana você pode obter bastante conteúdo de qualidade lendo esse livro.

Sem mais, vamos ao review!

Maintainable-JavaScript

Introduction

Em uma breve introdução, o autor comenta sobre a dificuldade que temos tido ultimamente no ambiente profissional na área de desenvolvimento Web, visto que pessoas que fazem parte de uma equipe grande possuem diferentes backgrounds e formas de resolver problemas no dia a dia.

A importância de se escrever código manutenível fica ainda mais evidente quando nos damos conta de que na realidade, ao invés de sempre criar coisas novas, do zero, gastamos a maior parte de nosso tempo dando manutenção em código já existente.

Acho interessante abrir aqui uma observação, que segundo Roger Pressman, em seu livro sobre Engenharia de Software, 60% do esforço de uma fábrica de software é dedicado à manutenção de sistemas já existentes. Pense por um instante quanto tempo e dinheiro envolve isso!

Com isso em mente, é importante escrever código não como se ele fosse exclusivo para você, mas sim pensando nos desenvolvedores que vão trabalhar com ele depois de você. E fazer parte de uma equipe, não significa tomar decisões que são melhores no seu ponto de vista, mas sim as que são melhores para a sua equipe como um todo.

Part 1: Style Guidelines

Esta parte do livro é focada em padrões de escrita de código, envolve a parte “visual”, a “formatação/aparência” do código. Embora seja um tópico ignorado por muitos, esse é um ponto super importante quando se trabalha em equipe ou ao colaborar em projetos open source. Seguindo padrões no que diz respeito à maneira como se escrever código, faz parecer que o software foi escrito por um único desenvolvedor, mesmo que ele tenha passado pela mão de vários membros da equipe ao longo do projeto, o que elimina problemas de inconsistência e evita desperdicío de tempo. Nesta seção, o autor apresenta também as ferramentas JSLint e JSHint, que são indispensáveis hoje em dia.

Chapter 1: Basic Formatting

Aqui começa-se a definir um guia de estilos, com os padrões que deverão ser seguidos a risca por toda a equipe. Cada tópico apresentado é seguido de um “porque” e exemplos, facilitando bem o entendimento. Entre os assuntos abordados estão: níveis de identação (tab ou espaços?), terminação de instruções (com ou sem ponto-e-vírgula?), tamanho de linha, quebras de linha, nomenclatura de variáveis e funções, uso de valores literais para Strings, Números, Arrays, Objetos, etc.

Chapter 2: Comments

Este capítulo trata sobre padrões ao escrever comentários. Dicas sobre quando comentar o código e de forma correta, utilizando comentários inline ou de multiplas linhas nas ocasiões certas. O capítulo termina com uma passada rápida sobre o uso de comentários para gerar documentação.

Chapter 3: Statements and Expressions

Formatação de estruturas condicionais if, else, laços de repetição e iteração, bem como instrução swtich são os assuntos abordados nesse capítulo. Espaçamentos, alinhamentos, etc., tudo para deixar o código mais legível.

Chapter 4: Variables, Functions, and Operators

Falando sobre variáveis, aqui Zakas nos alerta sobre um comportamento muitas vezes mal entendido, e que prega peças em alguns desenvolvedores: hoisting. Logo após, o assunto são as funções: declaração, invocação e Immediately-Invoked Function Expression (IIFE, tão famosas “função imediatas”). Em seguida, temos algumas dicas sobre o modo estrito e como podemos nos beneficiar por usar esse cara. Por fim, somos alertados sobre o uso de eval() e comparações de igualdade que podem gerar resultados um tanto quanto estranhos.

Part 2: Programming Practices

Nessa segunda seção do livro, são abordados alguns padrões de projetos e dicas de programação. Práticas que resolvem problemas já conhecidos pela comunidade e que podem/devem ser aplicados em nossos projetos também.

Chapter 5: Loose Coupling of UI Layers

Promover o fraco acoplamento é uma boa prática já bem difundida em engenharia de software, e em aplicações JavaScript não é diferente. A própria natureza de aplicativos Web promove essa ideia. HTML, CSS, JavaScript: três camadas com diferentes papéis que juntas entregam uma experiência completa para o usuário, mas que uma não devem invadir o território uma das outras por assim dizer. Neste capítulo temos algumas dicas interessantes, incluindo sobre templates no client-side (ex: Handlebars) e uma temos relatada uma experiência que o próprio Zakas passou ao trabalhar na equipe do Yahoo! em 2005.

Chapter 6: Avoid Globals

No ambiente JavaScript dos browsers, o objeto window atua como uma espécie de objeto global, e qualquer variável ou função declarada em escopo global se torna uma propriedade desse objeto. Por isso, quanto mais variáveis globais você declarar, maiores são as chances de introduzir erros em sua aplicação. Este capítulo apresenta quais são esses erros e também dicas de como evitá-los. Para isso, são explicadas algumas abordagens como “uma única variável global”, “namespaces” e “módulos” (ex: AMD, RequireJS).

Chapter 7: Event Handling

Uma das características mais importantes do JavaScript é o poder que temos para manipular eventos. Mas essa também é uma área problemática quando se trata de compatibilidade entre os diversos browsers e ambientes em que uma aplicação poderá rodar, por isso exige bastante atenção. De forma breve, mas bem explicada, este capítulo mostra algumas abordagens para manter a manutenibilidade ao lidar com eventos.

Chapter 8: Avoid Null Comparisons

Este capítulo mostra algumas armadilhas de se utilizar o operador typeof e como checar valores de forma correta ao comparar valores em validações, tais como o uso do operador instanceof e técnicas para identificar Arrays com a função nativa Array.isArray() introduzida em ECMAScript 5 e um polyfill para uso cross-browser, e por fim o uso do método hasOwnProperty para identificar propriedades em objetos.

Chapter 9: Separate Configuration Data from Code

Uma forma de aumentar a flexibilidade em uma aplicação, é fazer o uso de dados de configuração ao invés de inserir esses dados diretamente no código. Este capítulo vai lhe ajudar a identificar o que são esses “dados de configuração” e como utilizá-los.

Chapter 10: Throw Your Own Errors

Como Zakas diz logo no inicio desse capítulo: “lançar erros é uma arte” e nós como programadores, não devemos ter medo de erros, muito pelo contrário, eles nos ajudam. Em JavaScript temos recursos como o operador throw e instruções try-catch para lançar erros personalizados, além de alguns tipos de erros nativos do browser. Nesse capítulo o autor nos apresenta esses caras, e dá dicas sobre como identificar a hora certa de lançar erros, para que eles facilitem nosso dia a dia.

Chapter 11: Don’t Modify Objects You Don’t Own

Em JavaScript podemos alterar praticamente qualquer objeto que encontrarmos pela frente. Essa é uma das muitas características que tornam JavaScript uma linguagem muito flexível. Mas esse poder também traz alguns perigos, e esse capítulo explica quais são eles, e também como evitá-los. Temos uma visão geral sobre herança, protótipos e um design pattern conhecido como facade. Por fim também são mostrados alguns métodos de ECMAScript 5 que podem ser utilizados para prevenir que objetos sejam alterados indevidamente.

Chapter 12: Browser Detection

Nos primórdios da Web era muito comum fazer uma espécie de “farejamento de browser” para identificar qual navegador o usuário estaria utilizando e servir código específico para ele. Conforme esse capítulo mostra, essa abordagem traz sérios problemas de manutenibilidade e deve ser evitada ao máximo. Aqui também são mostradas quais alternativas podemos utilizar para lidar com essas diferenças entre navegadores sem prejudicar a manutenibilidade do código.

Part 3: Automation

Automação é um ponto chave para desenvolvedores JavaScript modernos. Aplicações de hoje em dia, não raramente possuem milhares de linhas de código JavaScript e são mantidas talvez por dezenas de desenvolvedores diferentes, por isso precisamos de ferramentas para facilitar nossa vida, automatizando processos repetitivos. Essa seção do livro mostra como podemos tirar vantagem de ferramentas de automação no desenvolvimento JavaScript.

Essa pode não ter sido minha seção preferida do livro, pois abrange ferramentas baseadas em Java, e hoje em dia temos as mesmas funcionalidades (diria que até melhores) em ferramentas feitas apenas com JavaScript como Grunt, Gulp entre várias outras. Mas vale a leitura pois os conceitos apresentados podem ser adaptados a qualquer ferramenta de automação que você escolha utilizar.

Chapter 13: File and Directory Structure

Antes de integrar um sistema de automação em sua aplicação, é importante planejar e organizar as coisas. Como você organiza o código do seu projeto? Já chega de código espaguete né? Esse capítulo faz uma análise da estrutura de diretórios e arquivos de alguns projetos grandes como a biblioteca jQuery, Dojo e YUI, onde podemos tirar algumas lições.

Chapter 14: Ant

Após pensar um pouco e estruturar as coisas, agora o capítulo 14 apresenta e mostra como fazer as configurações iniciais no Ant, uma ferramenta originalmente construída para build de projetos Java e com sintaxe XML para configurar suas tasks.

Chapters 15, 16 and 17

Esses capítulos avançam na configuração de tasks do Ant, tais como: validações, concatenação, minificação e compressão arquivos. Sem mais, recomendo fortemente que ao invés disso, utilize o Grunt para esse tipo de coisa.

Chapter 18: Documentation

Todo mundo prefere escrever código do que documentações. Por sorte, também temos ferramentas que nos ajudam com isso. Esse capítulo apresenta ferramentas que podem ser utilizadas para gerar automaticamente documentações para aplicações JavaScript com base em comentários feitos no código. Muito bom, vale a pena conferir e por em prática.

Chapter 19: Automated Testing

Testar código pode ser algo muito doloroso. Testar JavaScript pode ser ainda pior. Já pensou na quantidade de browsers, sistemas operacionais e dispositivos diferentes em que sua aplicação vai ser executada? Agora imagine só ter que testá-la em todas essas variações de forma manual… impossível! Com as dicas desse capítulo, podemos obter uma visão geral de ferramentas para testes automatizados, uma que acho muito interessante é o PhantomJS.

Chapter 20: Putting It Together

Para fechar a última seção do livro, este capítulo fala sobre planejar um workflow de build, com diversos ambientes e um sistema de CI (Continuous Integration), no caso foi apresentado o Jenkins. As vantagens desse tipo de ferramenta são enormes.

Appendix A: JavaScript Style Guide

Após todas as considerações feitas, temos um “Guia de Estilos” com as preferências de estilo de programação do Nicholas Zakas para todos os tópicos abordados em seu livro. Uma boa ideia seria utilizar isso como modelo e documentar suas preferências e passar a adotar um padrão em sua equipe, caso ainda não o façam.

Appendix B: JavaScript Tools

Uma lista de ferramentas para desenvolvedores JavaScript, com links para onde pode encontrá-las. Desde ferramentas de build, geradores de documentação e linting até testes automatizados.

Conclusão

Se você procura escrever JavaScript de forma profissional, acabar com problemas de inconsistência e desperdício de tempo para resolver problemas “bobos” ao trabalhar em equipes grandes ou colaborar em projetos open source, esse livro vai te ajudar muito.

Manipulando classes com classList API

Manipular classes de CSS em elementos HTML é uma tarefa muito útil, e até corriqueira, para quem trabalha com JavaScript. Provavelmente, você já sabe como fazer isso com jQuery. Porém, o que nem todos sabem ainda, é que temos uma API nativa de JavaScript para executar essas tarefas.

Neste artigo vou lhe apresentar a classList API. Essa API é bem simples de ser utilizada, e é extremamente útil para diversas “brincadeiras”.

Se você ainda não a conhece, verá que não é nada complicado manipular elementos dessa forma, mesmo sem utilizar bibliotecas como jQuery. Por outro lado, se você é um desenvolvedor experiente que já utiliza essa API no dia a dia, fique a vontade para deixar críticas e sugestões através dos comentários.

Entendendo a API

Todo objeto Element possui um objeto classList que retorna um DOMTokenList representando seu atributo class definido no documento HTML. O objeto classList possui uma propriedade length e é somente para leitura, porém podemos modificá-lo através de seus métodos, como add e remove. É aí que as coisas ficam interessantes.

Os métodos disponíveis em classList são:

  • add
  • remove
  • toggle
  • contains

Vamos considerar agora cada um desses métodos.

Adicionando classes com classList.add

Para adicionar uma ou mais classes em um elemento HTML, basta selecioná-lo e chamar o método classList.add, passando uma String como argumento. É interessante notar que podemos adicionar multiplas classes de uma só vez. Para isso, informe os nomes das classes que deseja adicionar separados por vírgula. Exemplo:

// Selecionamos um elemento span no DOM:
var mySpan = document.querySelector( 'span' );

// Agora adicionamos a classe highlight para destaca-lo:
mySpan.classList.add( 'highlight' );

// Agora adicionamos mais 3 classes de uma so vez:
mySpan.classList.add( 'feature', 'label', 'label-primary' );

Removendo classes com classList.remove

Além de adicionar novas classes, vez por outra você vai precisar também remover classes já existentes. Para isso, temos o método classList.remove. Vale notar, que assim como o método add, podemos remover multiplas classes de uma só vez. Exemplo:

// Selecionamos um elemento div no DOM:
var myDiv = document.querySelector( 'div' );

// Supondo que esse div tenha a classe 'foo', 'bar' e 'baz',
// vamos remover a classe 'baz':
myDiv.classList.remove( 'baz' );

// Agora vamos remover as classes 'foo' e 'bar' ao mesmo tempo:
myDiv.classList.remove( 'foo', 'bar' );

Alternando classes com classList.toggle

Para dar um comportamento mais dinâmico em nossa interface, pode ser interessante alternar (inserir e remover) uma classe, respondendo a um clique, toque na tela ou outro evento. Com isso, podemos fazer coisas como por exemplo exibir/ocultar um bloco de conteúdo, exibir/ocultar um menu, destacar/remover destaque de um elemento, entre várias outras coisas.

É aí que o método toggle entra em ação. Passamos o nome de uma classe para o método toggle, e ele fica responsável por checar se um elemento tem ou não essa classe. Se já tiver: ele remove, se não tiver: ele adiciona. Tudo “automagicamente” sem precisar escrever instruções if/else, expressões regulares ou coisa do tipo.

Para ver o método toggle funcionando, o ideal é registrarmos uma rotina de tratamento de eventos como comentei acima. No final do artigo, você encontra um exemplo assim. Mas a sintaxe desse método é a seguinte:

// Alterna a classe 'is-visible' no elemento 'myDiv':
myDiv.classList.toggle( 'is-visible' );

Verificando classes com classList.contains

Talvez você precise checar se um elemento possui determinada classe e dependendo do resultado, executar uma ou outra tarefa. Se esse for o caso, utilize o método classList.contains. Exemplo:

if( myDiv.classList.contains( 'is-visible' ) ) {
	// Se o elemento 'myDiv' possui a classe 'is-visible':
	// Faca alguma coisa interessante aqui.
} else {
	// Se nao...
	// Faca alguma outra coisa aqui.
}

Exemplo dinâmico

Para que você possa visualizar melhor as coisas, fiz um exemplo bem simples onde você pode interagir com a classList API clicando nos botões. Ao testar o botão contains, repare a saída gerada no console.

classList API

Compatibilidade nos browsers

Ao aplicarmos a classList API (ou qualquer outro recurso) em nossos projetos, é sempre bom ficar atento em relação a quais browsers suportam ou não tal API ou recurso que queremos implementar, e então tomar as decisões corretas.

Para isso, gosto bastante do site Can I use.

Como podemos ver na tabela abaixo, o suporte à classList API é bem tranquilo em vários navegadores. Para variar um pouco, no IE só funciona a partir da versão 10+. Mas isso não é nenhuma surpresa né? :-P.

Can I Use classList API

Mas fique tranquilo. Qualquer browser moderno aceita essa API, e se você precisa dar suporte aos navegadores mais antigos, pode usar algum polyfill disponível na Internet. Um deles você encontra na documentação da Mozilla Developer Network.

Conclusão

Agora você já sabe como manipular classes em seus documentos HTML de maneira muito fácil e sem depender de bibliotecas de terceiros. O suporte à essa API é muito bom em todos os browsers modernos e podemos utilizar um polyfill para os que não oferecem suporte. API’s nativas podem facilitar bastante nossa vida como desenvolvedores Web, basta conhece-las e colocar em prática.

Referências:

Novo plugin para WordPress lançado: WP Like System

É com grande satisfação que venho através desse post, anunciar mais um novo plugin que desenvolvi para WordPress. O nome desse plugin é WP Like System, e você pode fazer o download aqui no repositório oficial do WordPress.org.

O que esse plugin faz?

O WP Like System adiciona um sistema de ‘curtir’, semelhante ao famoso recurso lançado pelo Facebook. Dessa forma, os usuários podem avaliar seus posts e interagir com seu site/blog, mas sem precisar estar logado na rede social, e não é necessário fazer integração com scripts de terceiros, pois as avaliações dos usuários ficam armazenadas em sua própria base de dados.

Principais recursos

  • Opções “Curtir” e “Desfazer”.
  • Exibe total de pessoas que já curtiram.
  • Fácil de usar: Nada de configurações complicadas e desnecessárias. Basta instalar, colar o snippet do plugin dentro do loop do seu tema, e tudo funciona como o esperado.
  • Fácil de personalizar: marcação HTML limpa e com classes CSS para que você possa estilizar a aparência do plugin da forma que achar melhor, caso ache necessário.
  • Pronto para traduções e já está disponível nos idiomas Português e Inglês.

Como instalar

O processo de instalação é feito como qualquer outro plugin para WordPress.

Após ter instalado, abra o arquivo content.php ou single.php do seu tema e cole o seguinte snippet dentro do loop:

<?php
    if( function_exists( 'has_wpls_show_likes' ) ) {
        has_wpls_show_likes( get_the_ID() );
    }
?>

Qualquer dúvida, fique a vontade para abrir um tópico no fórum de suporte.

Screenshots

Abaixo você pode ver algumas imagens que demonstram como o plugin funciona.

WP-Like-System-1

WP-Like-System-2

WP-Like-System-3

Gostou? Colabore.

Se você não é um programador, pode contribuir com o desenvolvimento do plugin por fazer um review lá no repositório do WordPress.org e deixar uma avaliação com 5 estrelas. Fazer isso não leva mais do que 3 minutos, não lhe custará nada, e irá me ajudar a manter esse plugin, bem como me incentivar a desenvolver outros plugins novos futuramente.

Se você é programador, o código fonte está disponível nesse repositório no Github. Fique a vontade para fazer um fork, e ajudar a melhorar o plugin.

JavaScript: Descobrir Menor e Maior valor em um Array

Neste artigo irei mostrar técnicas para resolver de forma muito simples, um problema que geralmente uma hora ou outra acabamos precisando solucionar (eu por exemplo, já me deparei com esse problema em uma entrevista de emprego). Essas técnicas podem não ser novidade para alguns, mas tenho certeza que poderá ser novidade (e de forte ajuda) para outros.

O problema

Digamos que você tenha um array com alguns números variados:

var random = [2, 3, 1, 4, 6, 5];

Agora você precisa:

  • Encontrar o menor valor dentro do array.
  • Encontrar o maior valor dentro do array.
  • Descobrir o índice de um valor específico.

E então, já sabe como fazer? Veja como é simples.

Menor e maior valor dentro do array

Olhando para o objeto Math nativo da linguagem JavaScript, podemos encontrar vários métodos úteis para realizar operações aritméticas mais complexas. Entre esses, temos os métodos Math.min e Math.max, que como você já deve ter imaginado, encontram respectivamente o menor e o maior valor entre um dado conjunto de números.

Maravilha! Problema resolvido. Será mesmo?

Bom, na verdade se você leu com atenção, deve ter notado que os métodos Math.min e Math.max encontram o menor e o maior valor entre um dado conjunto de números. Mas nós precisamos encontrar o menor e o maior valor de um array.

Vamos testar?

Abra o Chrome DevTools, Firefox Developer Tools, Firebug ou qualquer outra ferramenta que você use para brincar com JavaScript, e digite o código abaixo:

Math.min( [1, 2, 3] ); // Retorna: NaN
Math.max( [1, 2, 3] ); // Retorna: NaN

É, o resultado não foi o esperado. Mas isso pode ser resolvido com uma técnica bem simples.

O segredo da coisa é: podemos pegar funções que recebem um número indeterminado de argumentos (assim como Math.min e Math.max), e adaptá-las para serem utilizadas em um array, através do método .apply(). Não faz parte desse artigo explicar como o método .apply() funciona, mas você pode clicar no link anterior para ler mais sobre o ele.

Sacou a ideia? Ainda não? Após ver o exemplo abaixo tudo ficará mais claro.

// Funcao para retornar o menor valor de um array
Array.min = function(array) {
    return Math.min.apply(Math, array);
};

// Funcao para retornar o maior valor de um array
Array.max = function(array) {
    return Math.max.apply(Math, array);
};

// Agora e so pegar os resultados
var random = [2, 3, 1, 4, 6, 5];  // Nosso array
console.log( Array.min(random) ); // Menor valor
console.log( Array.max(random) ); // Maior valor

Ótimo! Agora sim temos boa parte do nosso problema resolvido.

Bom, em alguns casos você pode também receber um array que possui índices vazios ou que não possuem valores numéricos. Se esse for o seu caso, também é possível utilizar a técnica mostrada acima, basta fazer alguns ajustes para verificar os valores contidos no array antes de passá-lo como argumento para o método .apply(). Fazer essas verificações já foge do escopo desse artigo, mas caso você precise de ajuda para fazer isso, deixe um comentário abaixo.

Bônus: Descobrir o índice (posição) de um valor específico

Para finalizar, precisamos descobrir o índice (posição) de um dado valor específico dentro do nosso array.

Graças ao método nativo .indexOf(), fazer isso é muito, mas muito fácil. Basta digitar o seguinte código:

var random = [2, 3, 1, 4, 6, 5];  // Nosso array
console.log( random.indexOf(1) ); // Retorna a posicaoo do numero 1 no array

Pronto! Agora nosso problema foi resolvido por completo.

Referências

WP Upcoming Releases: meu novo plugin para WordPress

Pouco tempo atrás tive a oportunidade de lançar meu primeiro plugin para WordPress. Publiquei ele no repositório oficial e divulguei discretamente para alguns colegas. Agora gostaria de anunciá-lo aqui no blog para que todos possam conhecê-lo, e caso ache interessante, você poderá fazer o download e utilizá-lo em seu site/blog.

Pra que serve, e pra quem é esse plugin?

O WP Upcoming Releases é um plugin simples, mas que cumpre com seu objetivo: exibir uma lista com “próximos lançamentos” de forma dinâmica e fácil de gerenciar. Evitando um trabalho cansativo de manutenção para atualizar de forma manual o site/blog que necessita desse recurso.

Você pode usar o WP Upcoming Releases em vários tipos de sites/blogs. Tem um site sobre games e gostaria de manter seus visitantes informados sobre quais serão os próximos lançamentos na área? Ou um blog sobre música e quer mostrar os próximos álbuns de um ou mais cantores? Ah, talvez queira exibir os próximos livros que você prentede ler, filmes que assistiu/pretende assistir, que tal? Seja qual for o caso, você pode usar o WP Upcoming Releases para cuidar disso.

Principais recursos

Com ele você pode cadastrar quantos itens desejar com: foto, título, classificação indicativa e data de lançamento. Além disso, você pode organizar seus itens por categorias.

Para exibir seus itens no site, não é necessário ter conhecimento de programação. Basta “arrastar e soltar” o widget de “Próximos lançamentos” em sua barra lateral ou outra área de widgets que tenha disponível em seu tema.

Caso necessite de algo um pouco mais personalizado, basta conhecer um pouco de CSS e você poderá estilizar a exibição dos itens da maneira que lhe agrade melhor. Basta utilizar as classes do plugin no CSS do seu tema.

Vale lembrar também, que até o momento, o plugin está disponível nos idiomas Inglês e Português do Brasil.

Screenshots

Para que você tenha uma visão melhor sobre como o plugin funciona, separei algumas imagens tanto da parte administrativa, como a parte que é exibida para os usuários no site.

screenshot-1

screenshot-2

screenshot-3

screenshot-4

screenshot-5

Contribuindo

Lancei o WP Upcoming Releases com código open source. Logo, você pode fazer o download gratuito para utilizar em seu site/blog, e caso tenha conhecimentos em HTML/CSS/PHP, poderá contribuir com o desenvolvimento dele, seja criando novos recursos ou corrigindo bugs.

O código fonte está disponível em: github.com/HenriqueSilverio/wp-upcoming-releases. Fique a vontade para forkar o repositório e contribuir.

Ah! Se você não é um programador, mas gostou do plugin, você pode contribuir deixando uma avaliação lá na página de download.

Download

Para baixar e instalar o WP Upcoming Releases em seu site, basta acessar essa página.

Espero que goste do plugin e que ele lhe seja útil. Qualquer dúvida, abra um tópico na área de suporte ou deixe um comentário abaixo.

Font Icons para Custom Post Types e Temas ~ WordPress 3.8

Se você conhece o WordPress há um bom tempo e tem acompanhado de perto sua evolução, ao instalar a versão 3.8, sem dúvida deve ter se surpreendido com a grande mudança feita na interface do painel administrativo. O design ficou muito mais limpo e moderno, coisa linda.

Entre as várias mudanças que ocorreram, uma delas é que agora foram adicionados Font Icons (chamados de Dashicons) no lugar das imagens que eram usadas anteriormente. Os ícones seguem um estilo flat, e combinam muito bem com o novo estilo dado à dashboard, e trazem vários benefícios, como por exemplo: são preparados para as poderosas telas de retina.

Bom, após conhecer os novos ícones, é claro que você vai querer utilizá-los ao desenvolver seus plugins e temas. Neste artigo, trago uma dica rápida para você que deseja fazer isso. Veja como é bem tranquilo.

Dashicons para Custom Post Types

Um dos parâmetros que você deve informar ao registrar um post type é o menu_icon. E para inserir o Font Icon (Dashicon) que você desejar, basta informar o nome de sua respectiva classe CSS.

Para descobrir qual é o nome da classe CSS que corresponde ao ícone desejado, você pode acessar o link: melchoyce.github.io/dashicons/. Nessa página você verá uma lista com todos os ícones disponíveis. Basta clicar no ícone para que ele seja selecionado e no topo do site você verá o nome da classe CSS, aí é só copiar esse nome e informá-lo ao parâmetro menu_icon.

Font-Icon-Dashicon-WordPress-3.8

register_post_type( 'lancamentos', array(
	// ...
	'menu_icon' => 'dashicons-list-view',
	// ...
) );

Font-Icons-Painel-WP

Dashicons para Temas no Front-End

Se você deseja utilizar os novos ícones no Front-End de um tema, poderá fazer isso também de forma muito simples. Basta passar o dashicons como uma dependência de sua folha de estilos na chamada da função wp_enqueue_style, como no exemplo abaixo:

function my_theme_enqueue_style() {
	wp_enqueue_style( 
		'my-theme-style', 
		get_stylesheet_uri(), 
		array( 'dashicons' )
	);
} 

add_Action( 'wp_enqueue_scripts', 'my_theme_enqueue_style' );

O código mostrado acima, irá se encarregar de chamar o CSS para os Dashicons sempre junto com o CSS do seu tema. Feito isso, basta voltar ao site do Dashicons, clicar no ícone que deseja utilizar, e depois clicar em “Copy CSS” para obter o código referente ao ícone selecionado, como mostrado na figura abaixo:

Copy-Font-Icon-CSS

Com o código do ícone em mãos, agora basta utilizá-lo em um pseudo-elemento :before ou :after no CSS do seu tema, seguindo o exemplo:

.my-item:before {
	content: "\f163";
	 font-family: "dashicons";
}

Conclusão

Não é de hoje que muitos encaram o WordPress como uma “espécie de framework” completo para desenvolver os mais diferentes tipos de aplicações Web. Neste artigo consideramos um recurso simples, mas que faz uma grande diferença na experiência do usuário, inclusive tornando seu tema ou plugin preparado para dispositivos com telas de alta definição. E vimos como o WordPress lida com isso, tornando o processo de desenvolvimento bem mais tranquilo, mesmo nesses “pequenos detalhes”.

Espero que essas informações lhe sejam úteis. Qualquer dúvida, crítica ou sugestão, é só deixar um comentário abaixo.

JavaScript para iniciantes: O que são Objetos?

Escrevi este artigo com o objetivo de ajudar quem está começando estudar JavaScript. Como futuro programador JavaScript, é fundamental que você entenda o que são, e como funcionam os objetos nessa poderosa linguagem. É claro que existem muitos outros detalhes sobre Objetos em JavaScript, mas espero que esse artigo lhe sirva de ajuda como um ponto de partida em suas pesquisas.

Let’s go! O que são Objetos?

Objetos são como uma espécie de “super variáveis” que armazenam uma “coleção de valores” referenciados por nome, e que podem ser recuperados para serem utilizados em diversas outras partes de um programa. Em JavaScript praticamente qualquer tipo de dado é um objeto.

Cada item dessa “coleção de valores”, é chamado de propriedade. Cada propriedade é composta por um par de “nome: valor”. Quando uma propriedade armazena uma função, ela se torna o que chamamos de método.

Criando objetos

Agora que já sabemos o que são objetos, vamos ver um pouco sobre como trabalhar com eles. Primeiramente vamos conhecer duas maneiras de se criar objetos.

Notação literal

A maneira mais simples (e recomendável) de se criar objetos em JavaScript é usando o que chamamos de notação literal. Um objeto literal é composto por um par de chaves “{ }“, que envolve uma ou mais propriedades. Cada propriedade segue o formato “nome: valor” e devem ser separadas por vírgula.

Para entender bem, nada melhor que um exemplo. Imagine que você vai criar um programa para organizar álbuns de vários cantores e bandas. Aqui vamos criar um objeto para armazenar informações sobre um álbum da banda Metallica, depois você pode praticar criando objetos com suas bandas favoritas. Então, mãos a obra!

var album = {
    title: "Metallica (Black Album)",
    released: 1991,
    showInfo: function() {
        alert("Titulo do album: " + this.title + "Lancado em: " + this.released);
    }
};

Conseguiu entender o que o código acima faz? Veja, é bem simples: primeiro criamos uma variável chamada “album”. Depois criamos um objeto – note a abertura e fechamento das chaves: { e }. Então adicionamos duas propriedades e um método ao nosso objeto, que são: “title”, “released” e “showInfo”. Nas propriedades nós armazenamos o título e ano de lançamento do álbum, e no método temos uma função que irá exibir as informações sobre o álbum em uma “caixa de alerta” para o usuário. Mais fácil do que parece, não é mesmo?

Função construtora

Outra maneira de criar objetos em JavaScript é utilizando uma função construtora. Se quisermos criar o mesmo objeto que criamos anteriormente, só que usando uma função construtora para isso, basta escrever o seguinte código:

var album = new Object();
    album.title = "Metallica (Black Album)";
    album.released = 1991;
    album.showInfo = function() {
    alert("Titulo do album: " + this.title + "Lancado em: " + this.released);
};

Como você pôde notar, a sintaxe ficou um pouco diferente. Aqui devemos utilizar a palavra-chave new seguida pela função construtora Object() ao invés de abrir e fechar chaves. Depois nós adicionamos as propriedades e métodos utilizando album.title, album.released e album.showInfo e atribuimos os valores à elas ao invés de colocar os pares de “nome: valor”.

Acessando propriedades e métodos

Após ter criado um objeto, você vai precisar acessar os valores que ele armazena. Podemos acessar (ou se preferir: “recuperar”) os valores guardados em um objeto, de duas maneiras: utilizando notação de ponto ou notação de colchetes. Veja um exemplo:

// notacao de ponto
album.title // Retorna: Metallica (Black Album)

// notacaoo de colchetes
album["title"] // Retorna: Metallica (Black Album)

Repare que no código acima, acessamos a mesma propriedade de duas maneiras diferentes. Geralmente é recomendável que você utilize a notação de ponto – album.title – por ser mais simples de ler e escrever.

Como os métodos são funções, você deve adicionar um par de parênteses – () – quando for acessá-los. Fora isso, nada de diferente. Veja no exemplo abaixo:

// notacao de ponto
album.showInfo() // Exibe alerta:
 // Titulo do album: Metallica (Black Album) Lancado em: 1991

// notacao de colchetes
album["showInfo"]() // Exibe alerta:
 // Titulo do album: Metallica (Black Album) Lancado em: 1991

Alterando e adicionando propriedades

Alterando

Vez por outra vamos precisar alterar os valores armazenados nas propriedades de nossos objetos. Fazer isso também é bem tranquilo. Basta acessar a propriedade que deseja alterar, utilizando a notação de ponto que acabamos de conhecer, e atribuir o novo valor à ela. Quer um exemplo?

album.title = "Powerslave";
album.released = 1984;

O que aconteceu no código acima? Isso mesmo. Alteramos o título do álbum e o ano de lançamento. Agora nosso objeto armazena informações sobre um outro álbum de outra banda.

Para fixar, antes de prosseguir a leitura (supondo que você esteja lendo e digitando os códigos para treinar), altere os valores de title e released para Metallica (Black Album) e 1991 novamente.

Adicionando

Bom, agora que o título do nosso álbum voltou a ser “Metallica (Black Album)”, que tal adicionar uma lista com os títulos das faixas do álbum? Sim, nós podemos adicionar novas propriedades e métodos aos nossos objetos mesmo após ter criado eles. A sintaxe é a mesma utilizada para alterar valores, que nós acabamos de ver.

Objetos podem armazenar qualquer tipo de dado válido em JavaScript, então, para criar uma lista com os títulos das faixas de nosso álbum, basta seguir o exemplo abaixo:

// Aqui adicionamos um array com os nomes de algumas faixas do album.
// Para praticar voce pode adicionar todas as 12 faixas.
album.tracks = ["Enter Sandman", "Sad but True", "Holier Than Thou", "The Unforgiven"];

Deletando propriedades

Você pode deletar uma propriedade ou método de um objeto utilizando o operador delete seguido pelo nome da propriedade. Vamos testar?

typeof album.showInfo // "function"

delete album.showInfo // deleta o metodo showInfo

typeof album.showInfo // "undefined"

Leitura adicional

Agora você já sabe o básico sobre objetos em JavaScript. Para uma abordagem mais profunda sobre o assunto, consultar bons livros pode ser de grande ajuda. Seguem algumas recomendações:

  • “O Melhor do JavaScript”, por Douglas Crockford. Capítulo 4, Página 26.
  • “JavaScript – O Guia Definitivo” – 6ª Edição, por David Flanagan. Capítulo 6, Página 112.

<dialog>: Janela modal nativa com HTML5

Um recurso bastante utilizado em diversos tipos de aplicações são as famosas “janelas modais”. Provavelmente você já deve ter utilizado esse recurso em algum de seus projetos. Caso já tenha utilizado, como você desenvolveu essa feature? Adicionou elementos extras no DOM e aplicou algumas técnicas de CSS? JavaScript “puro” ou talvez um plugin jQuery, certo?

A verdade é que existem “milhares” de técnicas para implementar uma janela modal. Mas em breve poderemos utilizar um elemento nativo do HTML5 para criar caixas de diálogo e janelas modais. Uma especificação do grupo WHATWG está saindo do forno, e nos traz o novo elemento dialog. Nesse artigo, irei apresentar como ele funciona.

Com vocês, o novo elemento dialog!

O elemento dialog representa uma parte da aplicação onde o usuário interage com a execução de uma tarefa, por exemplo uma caixa de diálogo ou uma janela modal. Esse elemento existe no DOM, e pode ser estilizado com CSS, assim como qualquer outro elemento de bloco.

Junto com este novo elemento, temos algumas APIs de JavaScript para manipular seus comportamentos, como por exemplo os métodos .show(), .close(), .showModal() e também o atributo .returnValue. E para personalizar a experiência de utilização temos o pseudo-elemento ::backdrop, além de que a caixa/janela pode ser estilizada por CSS como já comentado.

Vamos criar então o nosso dialog:

<dialog>
	<h3>Caixa de dialogo simples</h3>
	<p>Lorem ipsum dolor sit amet consectetur.</p>
	<button>Fechar</button>
</dialog>
<button>Abrir modal</button>

Compatibilidade

O elemento dialog ainda está em processo de desenvolvimento e por enquanto não foi especificado como um padrão nos browsers. Em breve os navegadores modernos deverão passar a implementá-lo, mas até que isso aconteça, para testar essa feature, você pode usar o Chrome Canary, acessando chrome://flags e ativando os “recursos experimentais da plataforma Web”.

ativar-flag-experimental-web-platform

Para os demais navegadores já existe também um fallback/polyfill criado pela equipe do Google Chrome. Você pode ver mais detalhes sobre como implementar esse fallback acessando o repositório do projeto no Github.

API .show(), .close() e .returnValue

Para que nossa “caixa de diálogo” ou “janela modal” funcione, basta utilizarmos as novas APIs de JavcaScript. Um exemplo básico é feito utilizando os métodos .show() e .close().

Como é de se esperar, quando o método .show() é chamado, ele checa se o elemento dialog já está sendo exibido, se já estiver, então nada acontece, caso contrário, ele adiciona um atributo open em nosso elemento dialog e exibe o mesmo para o usuário. É interessante notar que quando exibimos a “janela modal” através desse método .show(), o usuário ainda pode selecionar textos e interagir com os elementos da página que ficarão por trás dela.

E o método .close()? Se você adivinhar ganha um doce! Tá você não vai ganhar um doce, mas sim, o método .close() faz exatamente oque o nome sugere. Após chamar esse método, a nossa “janela modal” é fechada. Esse método também aceita um parâmetro opcional, que se for passado, é usado como valor de retorno e será gravado na propriedade .returnValue.

O código ficaria mais ou menos assim:

var dialog = document.getElementById('my-dialog'),
	btOpen = document.getElementById('btn-open'),
	btClose = document.getElementById('btn-close');

btOpen.addEventListener('click' function() {
	dialog.show();
}, false);

btClose.addEventListener('click' function() {
	dialog.close();
}, false);

API .showModal() e pseudo-elemento ::backdrop

Em alguns casos pode ser necessário “bloquear” o restante da página enquanto a “janela modal” estiver sendo exibida na tela. Para este efeito existe o método .showModal(). Basta chamar .showModal() ao invés de .show() para que a “janela modal” seja exibida na tela e o usuário não possa interagir com o restante do conteúdo enquanto não fechá-la.

/* ... */

btOpen.addEventListener('click' function() {
	dialog.showModal();
}, false);

/* ... */

Muito legal não é mesmo? Mas ainda tem mais. Outra feature muito comum, é “escurecer” a página por trás da “janela modal”, aplicando um background com um pouco de “transparência”. Fazer isso é muito fácil: basta utilizar o pseudo-elemento ::backdrop no CSS.

dialog::backdrop {
  position: fixed;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.6);
}

Demonstração

Para finalizar, você pode acessar a demonstração que preparei. Não esqueça de abrir o link no Chrome Canary e ativar a flag “recursos experimentais da plataforma Web” em chrome://flags. Espero que tenha gostado do artigo. Deixe suas opiniões nos comentários. =]

Como utilizar API de Geolocalização HTML5

Nesse artigo irei mostrar como utilizar geolocalização com HTML5. O uso dessa API é muito simples, e as possibilidades de aplicações que ela nos traz são fantásticas, sendo assim um recurso muito bacana para sites e aplicações web modernas.

html5-geolocation-api

Geolo… quê?

Entre as diversas novas API’s que chegaram com o HTML5, está a Geolocation API. O que essa API faz? Simples. Com ela nós podemos descobrir onde o usuário está localizado de maneira bem precisa, e capturar alguns dados como suas coordenadas de latitude e longitude.

Com esses dados em “mãos” por exemplo, você pode usar a Google Maps API para exibir um mapa mostrando onde o usuário está, traçar uma rota para ajudá-lo a chegar em determinado local, exibir locais úteis como restaurantes, lojas, etc. que estão por perto do usuário e podem interessá-lo, enfim, o limite será sua criatividade. O legal é explorar as possibilidades e não ficar apenas no “creme de papaia de sempre“.

Que browsers suportam a API de Geolocalização?

O suporte à API de Geolocalização é bem amplo, funciona na grande maioria dos browsers, com exceção apenas o IEca8- e o Opera Mini 5.0 – 7.0. Você pode conferir esses dados na tabela abaixo, retirada do Can I Use:

Geolocation-HTML5-Support

Para verificar se o browser suporta a API de geolocalização HTML5, podemos utilizar a biblioteca Modernizr ou fazer uma checagem simples com JavaScript “puro”:

if( ! "geolocation" in navigator ) {
	// Nao suporta Geolocation HTML5...
} else {
	// Suporta Geolocation HTML5. Vamos em frente!
}

Mergulhando mais a fundo

Agora vamos realmente entender como as coisas funcionam nessa API. Se você abrir o console Firebug ou outra ferramenta de inspeção em seu browser favorito, verá que o objeto geolocation é composto por três métodos, que são: clearWatch(), getCurrentPosition() e watchPosition(). Veremos como trabalhar com cada um desses métodos.

HTML5-Geolocation-Firebug

O método getCurrentPosition()

Para fins didáticos, vamos começar analisando o método getCurrentPosition(). Esse método pode receber três argumentos que são:

  • successCallback: Uma função que será executada caso a posição do usuário seja localizada com sucesso;
  • errorCallback: Uma função que será utilizada para tratar eventuais erros ao se tentar obter a localização do usuário. Esse parâmetro é opcional;
  • PositionOptions: Um objeto com propriedades de configurações adicionais. Esse parâmetro também é opcional.

getCurrentPosition() é chamado da seguinte forma:

navigator.geolocation.getCurrentPosition( geoSuccess );

Quando esse método é chamado, ele exibe uma notificação solicitando permissão do usuário para detectar sua posição, e caso o usuário concorde (não, você não pode acessar a localização do usuário sem que ele permita), ele executa uma requisição assíncrona para detectar sua posição atual e chama um callback para tratar os dados retornados. Por isso você sempre deve especificar o primeiro argumento de getCurrentPosition().

A função callback de sucesso, recebe um único argumento e retorna um objeto com duas propriedades: coords e timestamp. A propriedade timestamp serve apenas para armazenar a data e o horário de quando a localização foi calculada. E a propriedade coords é um objeto com propriedades interessantes como latitude e longitude.

Após implementar a função callback geoSuccess() nosso código ficou assim:

function geoSuccess( pos ) {
	// armazena as coordenadas de latitude e longitude
	var lat = pos.coords.latitude,
		lng = pos.coords.longitude;
	
	// crie qualquer coisa legal usando as coordenadas
};

navigator.geolocation.getCurrentPosition( geoSuccess );

Tratando erros

Durante o ciclo de uso da geolocalização alguns erros podem ocorrer, e a API nos fornece recursos para tratar esses possíveis erros de maneira bem simples. Para isso, basta usar o segundo parâmetro que é uma função callback para tratar erros, conforme já citado anteriormente. Cada erro retornado é referenciado por um código. Os erros que podem ser retornados e seus respectivos códigos são:

  • 1 – PERMISSION_DENIED: O usuário não aceitou compartilhar sua posição. O ideal nesse caso é não incomodar o usuário com mensagens de erro.
  • 2 – POSITION_UNAVAILABLE: O usuário está desconectado, não foi possível alcancar os satélites de GPS ou algo do tipo.
  • 3 – TIMEOUT: A requisição demorou demais para retornar a posição do usuário. Você pode determinar qual é o tempo limite máximo, veremos como fazer isso.
  • 0 – UNKNOWN_ERROR: Ocorreu um erro desconhecido.
function geoSuccess( pos ) {
	// armazena as coordenadas de latitude e longitude
	var lat = pos.coords.latitude,
		lng = pos.coords.longitude;
	
	// crie qualquer coisa legal usando as coordenadas
};

function geoError( err ) {
	switch( err.code ) {
		case 1:
			// permissao negada pelo usuario
			break;

		case 2:
			// nao foi possivel alcancar os satelites GPS
			break;

		case 3:
			// a requisicao demorou demais para retornar
			break;

		case 0:
			// ocorreu um erro desconhecido...
			break;
	}	
};

navigator.geolocation.getCurrentPosition( geoSuccess, geoError );

Configurações adicionais

Agora que já temos uma função para capturar a posição do usuário e outra para tratar os possíveis erros, podemos também opicionalmente utilizar um terceiro parâmetro, que é o objeto PositionOptions. Esse objeto possui três proriedades que são:

  • enableHighAccuracy: Um valor boolean, por padrão false. Se definir como true, e o dispositivo do usuário suportar tal funcionalidade, irá tentar utilizar GPS para aumentar a precisão da localização, por exemplo.
  • timeout: Aqui definimos o tempo máximo em milisegundos que a requisição poderá demorar antes de disparar um erro TIMEOUT que vimos acima.
  • maximumAge: O tempo máximo em milisegundos que o dispositivo pode fazer um cache da localização do usuário.
function geoSuccess( pos ) {
	// armazena as coordenadas de latitude e longitude
	var lat = pos.coords.latitude,
		lng = pos.coords.longitude;
	
	// crie qualquer coisa legal usando as coordenadas
};

function geoError( err ) {
	switch( err.code ) {
		case 1:
			// permissao negada pelo usuario
			break;

		case 2:
			// nao foi possivel alcancar os satelites GPS
			break;

		case 3:
			// a requisicao demorou demais para retornar
			break;

		case 0:
			// ocorreu um erro desconhecido...
			break;
	}	
};

var geoOptions = {
	enableHighAccuracy: true,
	timeout: 30000,
	maximumAge: 3000
};

navigator.geolocation.getCurrentPosition( geoSuccess, geoError, geoOptions );

watchPosition() e clearWatch()

Ao invés de apenas pegar a localização do usuário, nós podemos também acompanhar continuamente sua posição, atualizando as coordenadas sempre que o usuário se mover. Para isso nós utilizamos o método watchPosition(). Esse método funciona da mesma forma que o getCurrentPosition(), a única diferença é que a função geoSuccess() do nosso exemplo será chamada toda vez que o usuário se locomover, e o método watchPosition() retorna um número, para que possamos parar de rastrear a posição do usuário quando desejarmos.

Para parar de rastrear a posição do usuário, basta utilizarmos o método clearWatch() passando à ele como argumento o número retornado pelo método watchPosition(). Veja agora um exemplo:

// callback para tratar posicao do usuario
function geoSuccess( pos ) {
	// armazena as coordenadas de latitude e longitude
	var lat = pos.coords.latitude,
		lng = pos.coords.longitude;
	
	// crie qualquer coisa legal usando as coordenadas
};

// callback para tratar erros
function geoError( err ) {
	switch( err.code ) {
		case 1:
			// permissao negada pelo usuario
			break;

		case 2:
			// nao foi possivel alcancar os satelites GPS
			break;

		case 3:
			// a requisicao demorou demais para retornar
			break;

		case 0:
			// ocorreu um erro desconhecido...
			break;
	}	
};

// objeto de configuracoes adicionais
var geoOptions = {
	enableHighAccuracy: true,
	timeout: 30000,
	maximumAge: 3000
};

	// um botao "stop"
var btnStop = document.getElementById( "btn-stop" ),

	// rastreia posicao do usuario continuamente
	watch = navigator.geolocation.watchPosition( geoSuccess, geoError, geoOptions );

// para de rastrear posicao do usuario ao clicar no botao "stop"
btnStop.addEventListener( "click", function() {
	navigator.geolocation.clearWatch( watch );
}, false );

Finalizando

Neste artigo você conheceu a API de Geolocalização HTML5 e viu alguns exemplos de código para se trabalhar com ela. Essa API sem dúvida será de grande ajuda para tornar suas aplicações mais ricas e interativas. Conforme já mencionado no artigo, você pode integrar o uso dessa API com outros serviços, API’s sociais etc., para criar coisas muito legais.

Você já usou a API de Geolocalização HTML5 em algum projeto? Gostou do artigo e pretende fazer algum experimento? Não gostou do artigo ou tem dúvidas? Fique a vontade para compartilhar suas experiências nos comentários.

Referências:

Grunt JS: Automatize tarefas e otimize o seu workflow

GruntJS-JavaScript-Task-Runner

Desenvolver um site ou aplicativo web moderno, é algo que está se tornando cada vez mais complexo. Por esse e outros motivos, todo bom desenvolvedor está sempre procurando novas maneiras de otimizar seu workflow visando tornar as coisas mais divertidas e aumentar sua produtividade sem perder a qualidade de seu trabalho.

Neste artigo irei apresentar o Grunt JS, uma excelente ferramenta criada por Ben Alman. Mostrarei  também um exemplo prático de uso, e espero que após lê-lo, você se sinta mais confortável com o Grunt JS e passe a adiciona-lo na “mistura” de seus próximos projetos.

Grunt JS… o que é isso, afinal?

O Grunt JS é um poderoso task runner (automatizador de tarefas), que roda no terminal, e é gerenciado pelo NPM, o gerenciador de pacotes para Node.js.

Legal, mas… por que eu devo aprender sobre Grunt JS?

Pelo “simples” fato da automatização de tarefas.

Já parou para pensar quanto tempo você perde toda vez que vai lançar um projeto em produção por exemplo? Você concatena e minifica (ou pelo menos deveria) seus arquivos de CSS e JavaScript, executa testes unitários e linting nos arquivos de JavaScript, otimiza imagens com ferramentas como Smush.it, JPEGMini, TinyPNG etc., separa os arquivos gerados e finalmente faz deploy da aplicação. E que dizer se você estiver usando um pré-processador de CSS como Sass? Mais uma tarefa na lista: Compilar arquivos .scss ou .sass.

Quanto menos tempo você perder executando tarefas repetitivas como essas citadas, mais fácil e produtivo se torna o seu trabalho. É aí que um task runner como o Grunt JS entra em ação. Uma vez configurado, o Grunt JS fará todo o “trabalho sujo” para você e/ou sua equipe, com praticamente nenhum esforço extra.

Primeiros passos

Como você já deve ter percebido, para usar o Grunt JS é necessário ter o Node.js com o NPM instalados em sua máquina. Caso você ainda não tenha, o processo de instalação é muito simples. Acesse http://nodejs.org/, clique no botão “Install” para fazer o download e execute o instalador. Feito isso você já terá o Node.js + NPM funcionando.

Agora abra seu console/terminal e vamos intalar o Grunt CLI (Grunt Command Line Interface). Se você trabalha em ambiente Windows, recomendo que utilize o Windows PowerShell, rodando como administrador. Em Mac ou sistemas Unix, talvez você precise usar o sudo.

npm install -g grunt-cli

O comando acima irá instalar o Grunt CLI globalmente, e agora você pode usar o comando grunt em seu terminal. O Grunt CLI permite que você rode versões diferentes do Grunt em uma mesma máquina simultaneamente.

Configurando um novo projeto com o Grunt

Todo projeto Grunt precisa de dois arquivos básicos: package.json e o Gruntfile.js. O package.json é um arquivo utilizado para guardar metadados de projetos que são publicados como módulos para o NPM, e o Gruntfile é um arquivo JavaScript ou CoffeeScript, utilizado para configurar tarefas e carregar os plugins do Grunt. Esses dois arquivos devem ser criados dentro da raiz de seu projeto, e devem sempre estar juntos no mesmo diretório.

Aprendendo na prática

Para começar nosso exemplo prático, vamos criar um diretório chamado grunt-project e dentro dele iremos criar um subdiretório chamado src, que é onde iremos salvar o package.json e o Gruntfile.js. Nosso package.json terá um estrutura mais ou menos assim:

{
	"name": "project-name",
	"version": "0.1.0",
	"description": "Project description"
}

Você pode iniciar seguindo o modelo acima e edita-lo conforme suas necessidades. Para maiores informações sobre quais propriedades você pode usar, consulte a documentação. Você pode também dar uma olhada nesse guia interativo, e conhecer diversas propriedades interessantes para acrescentar em sua configuração.

Com o package.json configurado, agora crie um novo arquivo de JavaScript e salve-o dentro do mesmo diretório src, ao lado de seu package.json, com o nome de Gruntfile.js.

O Gruntfile.js é composto por uma função que engloba todo o código, as configurações das tarefas do projeto, carregamento dos “grunt plugins” instalados (Veremos mais sobre como instalar plugins do grunt daqui a pouco) e o(s) registro(s) de sua(s) tarefas personalizadas.

Um Gruntfile.js básico pode ser feito seguindo essa estrutura:

"use strict";

module.exports = function( grunt ) {

	grunt.initConfig({

		// configuracoes das tarefas

	});

	// carregando plugins
	grunt.loadNpmTasks( 'plugin-name' );

	// registrando tarefas
	grunt.registerTask( 'default', [ 'watch' ] );

};

Dentro da função que engloba todo nosso código, temos alguns métodos sendo chamados, como: initConfig(), loadNpmTasks() e registerTask(). Vamos entendê-las melhor.

O método initConfig(), recebe um objeto JSON que será responsável por armazenar as configurações das tarefas de nosso projeto.

O loadNpmTaks() carrega um grunt plugin e permite que você use-o em seu Gruntfile. Você deve chamar esse método para todos os plugins que for utilizar. Carregar plugins vai se tornar algo muito chato conforme você for utiliando o Grunt com mais frequência, por isso mostrarei como você pode automatizar essa tarefa também.

E por fim o registerTask(), recebe dois argumentos: uma string e um array com o nome de uma ou mais tarefas que devem ser realizadas ao executar esse comando. Em nosso exemplo, ao rodar o comando grunt no terminal, ele irá chamar a tarefa default, executando as configurações definidas para o plugin watch.

Instalando o Grunt e plugins úteis

Antes de fazermos nossas configurações, vamos instalar o Grunt e os plugins que iremos utilizar. Para instalar o Grunt, e marcá-lo como uma das dependências de seu projeto é simples:

npm install grunt --save-dev

Após rodar esse comando, você verá que um diretório node_modules foi criado, e visto que usamos ––save-dev, também foi adicionada uma propriedade devDependencies dentro do package.json. Isso é muito importante, pois assim, caso esteja trabalhando com controle de versões, você não precisará incluir o diretório node_modules em seus commits, basta rodar o comando npm install e todas as dependências do projeto serão instaladas.

O processo de instalação de plugins é o mesmo. Geralmente existe um plugin específico para qualquer tarefa que você queira realizar. Literalmente são milhares de plugins que já foram criados para o Grunt. Você pode consultar essa lista extensa de plugins.

Vamos agora instalar os plugins que iremos utilizar:

npm install matchdep --save-dev
npm install grunt-contrib-watch --save-dev
npm install grunt-contrib-compass --save-dev
npm install grunt-contrib-uglify --save-dev
npm install grunt-ftp-deploy --save-dev

Com o Grunt e os plugins que precisaremos instalados, agora vamos configurar nossas tasks e finalmente ver a “mágica” funcionando. Explicarei as configurações uma a uma dos plugins instalados acima, e no final você poderá consultar o código fonte completo.

Carregando todas as taks do Grunt automaticamente

O primeiro plugin que iremos configurar é o matchdep.

Conforme comentei anteriormente, cada vez que você for usar um novo plugin, será necessário adicionar uma chamada ao método loadNpmTasks(). Isso traz um trabalho chato e demanda manutenção desnecessária sempre que for adicionar ou remover um plugin.

Felizmente com o plugin matchdep nós cortamos esse problema pela raiz. O que esse plugin faz é o seguinte: Ele extrai informações gravadas em seu package.json, e chama o método loadNpmTasks() para cada plugin instalado.

require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);

Pronto. Você nunca mais precisará adicionar ou remover chamadas ao método loadNpmTasks() manualmente de novo.

Executando tarefas após alterar arquivos

Com o plugin grunt-contribu-watch, criamos uma task chamada “watch”. Ao rodar essa tarefa, o Grunt irá “observar” os arquivos do nosso projeto, e quando fizermos qualquer alteração em um dos arquivos especificados, ele irá executar outras tarefas que foram atreladas a ela automaticamente. Isso é fantástico, pois dessa forma você pode executar várias tarefas automaticamente com apenas um único comando.

// Watch
watch: {
	css: {
		files: [ '../assets/scss/**/*' ],
		tasks: [ 'compass' ]
	},
	js: {
		files: '../assets/js/**/*',
		tasks: [ 'uglify' ]
	}
},

Nesse exemplo, sempre que algum arquivo dentro do diretório ‘assets/scss’ for alterado, o Grunt irá executar a tarefa ‘compass’ para compilar o código Sass. E sempre que editarmos um arquivo dentro do diretório ‘assets/js’ o Grunt irá executar a tarefa ‘uglify’ para concatenar e minificar os arquivos JavaScript.

Veremos como configurar essas tarefas logo abaixo.

Compilar Sass usando Compass

Se você trabalha com Sass + Compass, compilar seu código para CSS é muito simples usando o plugin grunt-contrib-compass. Em nosso exemplo, definimos a propriedade force como true, para permitir que o Compass sobrescreva arquivos, indicamos o caminho para um arquivo config.rb que contém as demais configurações do Sass e determinamos que o código compilado sairá minificado.

Se você não está familiarizado com o arquivo config.rb que foi citado, leia a documentação para obter maiores informações. Então criamos nosso arquivo config.rb e adicionamos o seguinte código em nosso Gruntfile.js:

// Compile scss
compass: {
	dist: {
		options: {
			force: true,
			config: 'config.rb',
			outputStyle: 'compressed'
		}
	}
},

Concatenando e minificando JavaScript

Para concatenar e minificar nossos arquivos de JavaScript, vamos utilizar o plugin grunt-contrib-uglify. As configurações dessa task também são muito simples. Na propriedade files, passamos um objeto com local onde o arquivo minificado será gravado, que recebe um array de arquivos a serem concatenados e minificados:

// Concat and minify javascripts
uglify: {
	options: {
		mangle: false
	},
	dist: {
		files: {
			'../build/js/app.min.js': [
				'../assets/js/app.js'
			]
		}
	}
},

Fazendo deploy do projeto

Conforme comentei no inicio do artigo, o Grunt também pode ajudar você na hora de fazer deploy de seus projetos em um servidor. Se o seu host lhe dá acesso via SSH, você pode utilizar o plugin grunt-rsync para isso.

Mas em alguns casos você terá acesso apenas via FTP. Não se preocupe, para isso iremos utilizar o plugin grunt-ftp-deploy.

Para que o grunt-ftp-deploy funcione, vamos precisar adicionar um arquivo chamado .ftppass dentro do diretório src do nosso projeto, junto com Gruntfile.js, package.json e o config.rb. Este arquivo é um objeto JSON que armazena os dados de login do seu FTP. Tome cuidado com esse arquivo quando estiver usando Git ou outro sistema de versionamento de arquivos. O .ftppass segue essa estrutura:

{
	"key1": {
		"username": "your-ftp-user",
		"password": "your-ftp-pass"
	}
}

Agora que já temos nosso nome de usuário e senha guardados no arquivo .ftppass, vamos voltar ao nosso Gruntfile.js e configurar a task para fazer o deploy em nosso servidor.

Basta trocar o valor da propriedade ‘host’ para o host do seu site e o valor de ‘dest’ para o caminho onde você irá upar seus arquivos. Em ‘exclusions’ você pode especificar que arquivos e diretórios não devem ser enviados para o servidor junto com sua aplicação.

// FTP deployment
'ftp-deploy': {
	build: {
		auth: {
			host: 'ftp.yoursite.com',
			port: 21,
			authKey: 'key1'
		},
		src: '../',
		dest: '/www/my-app/',
		exclusions: [
			'../**/.DS_Store',
			'../**/Thumbs.db',
			'../.git',
			'../.gitignore',
			'../README.md',
			'../src',
			'../assets'
		]
	}
}

Juntando tudo e testando

Se você está acompanhando o artigo com atenção, nesse ponto você já terá todas as tarefas do Grunt configuradas. Vamos adicionar as duas últimas linhas de código em nosso Gruntfile.js para registrar duas tarefas personalizadas: watch e deploy.

// registrando tarefa default
grunt.registerTask( 'default', [ 'watch' ] );

// registrando tarefa para deploy
grunt.registerTask( 'deploy', [ 'ftp-deploy' ] );

Registrando essas tarefas, agora quando usarmos o comando “grunt” no terminal, será executada a task “watch” conforme já foi explicado anteriormente, e quando usarmos o comando “deploy”, irá rodar nossa task que fará deploy para o servidor.

Então a versão final do nosso Gruntfile.js ficou assim:

"use strict";

module.exports = function( grunt ) {

	// Load all tasks
	require("matchdep").filterDev("grunt-*").forEach(grunt.loadNpmTasks);

	grunt.initConfig({

		// Watch
		watch: {
			css: {
				files: [ '../assets/scss/**/*' ],
				tasks: [ 'compass' ]
			},
			js: {
				files: '../assets/js/**/*',
				tasks: [ 'uglify' ]
			}
		},

		// Compile scss
		compass: {
			dist: {
				options: {
					force: true,
					config: 'config.rb',
					outputStyle: 'compressed'
				}
			}
		},

		// Concat and minify javascripts
		uglify: {
			options: {
				mangle: false
			},
			dist: {
				files: {
					'../build/js/app.min.js': [
						'../assets/js/app.js'
					]
				}
			}
		},

		// FTP deployment
		'ftp-deploy': {
			build: {
				auth: {
					host: 'ftp.yoursite.com',
					port: 21,
					authKey: 'key1'
				},
				src: '../',
				dest: '/www/my-app/',
				exclusions: [
					'../**/.DS_Store',
					'../**/Thumbs.db',
					'../.git',
					'../.gitignore',
					'../README.md',
					'../src',
					'../assets'
				]
			}
		}

	});

	// registrando tarefa default
	grunt.registerTask( 'default', [ 'watch' ] );

	// registrando tarefa para deploy
	grunt.registerTask( 'deploy', [ 'ftp-deploy' ] );

};

Em seu terminal acesse o diretório src e rode o comando:

grunt

Altere um arquivo do diretório assets/scss e assets/js e você verá que será gerado o diretório build com os arquivos minificados prontos para deploy.

Volte ao terminal e pressione CTRL + C para encerrar a task watch.

Agora para fazer o deploy, rode o comando abaixo e aguarde os arquivos serem enviados para seu servidor conforme especificado em suas configurações:

grunt deploy

Muito bem! Se você acompanhou tudo com atenção, com apenas um único comando você compilou arquivos scss, concatenou e minificou arquivos de JavaScript e gerou uma build do seu projeto. E com apenas mais um simples comando, você fez o deploy dessa build.

Eu disse… parece mágica não é mesmo? =D

Conclusão

Ferramentas como o Grunt JS só nos trazem grandes beneficios e estão aí disponíveis para quem quiser usar. Além das opções ensinadas nesse artigo, existem muitas outras coisas que o Grunt pode fazer, e você deve pesquisar sobre elas.

Espero que você tenha se interessado e pesquise mais para adaptar o Grunt as suas necessidades. Sem dúvida você não irá se arrepender se tirar um tempo para estudar e integrar esse tipo de ferramenta em seu workflow.

O código fonte do projeto desenvolvido nesse artigo está disponível no Github. Você pode clonar o repositório e personaliza-lo para seus projetos. Sinta-se a vontade para enviar sugestões e tirar suas dúvidas nos comentários.

Outros links sobre Grunt: