Gerenciamento de rotas na URL em Single Page Apps (SPA)
02 Nov 2013Uma Single Page Application, também conhecida por SPA, possui algumas características bem distintas se a compararmos com outros web apps que estamos acostumados a desenvolver.
Sua principal característica é o fato de ser uma única página que carrega outros conteúdos dinamicamente com chamadas AJAX, enquanto que o mais comum é encontrarmos aplicativos que solicitam páginas inteiras ao servidor, ou seja, com <head>, <body> e os demais elementos que a compõem.
Uma prática que vem se tornando cada vez mais comum é o uso de URLs com hash ("#") para "marcar" o conteúdo que foi carregado na Single Page App. Ao utilizarmos esta prática facilitamos a navegação do usuário, pois possibilitamos que o botão voltar do navegador funcione, além de deixarmos a app funcionando como se fosse um site comum. Para quem quer um exemplo, vale gastar alguns minutos navegando no Grooveshark e prestar atenção nas URLs com "#!" (hashbang). Vale dizer também que apesar do uso da "#" ser uma prática comum ela não é obrigatória, ou seja, você também pode fazer sua SPA com rotas normais (/rota, por exemplo).
Neste post, pretendo mostrar duas libraries em javascript que já utilizei em alguns projetos para o gerenciamento e funcionamento das rotas de uma SPA. No final do post também listei alguns nomes muito bons para ajudar quem está procurando outras alternativas.
Sammy.js
O Sammy.js é, como a própria descrição de seu repo no github diz:
"um framework pequeno construído sobre o jQuery e inspirado no Sinatra do Ruby".
Ele se destaca por ser muito simples e ter diversas funcionalidades muito úteis. Aqui estão algumas delas:
- Criar rotas utilizando regular expression
- Rotas com parâmetros
- Vincular funções específicas para certas rotas
- Carregar e criar templates
- Controle de sessão próprio
Para utilizá-lo é simples, como mostrado no código abaixo, retirado da página de introdução do framework:
// define a new Sammy.Application bound to the #main element selector Sammy('#main', function() { // define a 'get' route that will be triggered at '#/path' this.get('#/path', function() { // this context is a Sammy.EventContext this.$element() // $('#main') .html('A new route!'); }); }).run();
Basta indicarmos em qual container serão carregadas todas as rotas (#main no exemplo acima) e logo depois passarmos uma rota ("#/path") e uma função que será executada sempre que ele reconhecer a rota na URL.
Vocês podem conferir um tutorial muito bom sobre diversas funcionalidades do Sammy.js no site oficial: http://sammyjs.org/docs#tutorials.
Como dica, a inicialização das rotas do Sammy pode ficar um pouco "macarrônico" dependendo da estrutura e complexidade da sua app. Tente sempre manter o funcionamento das rotas o mais simples possível chamando initializers de outras funções para posicionar tudo em sua página.
Pagerjs
O Pagerjs é uma library baseada em jQuery e knockout. Com uma página de demonstração que deixa qualquer um com vontade de usá-la alguma vez na vida, ela possui diversas features que facilitam a vida do desenvolvedor na hora de fazer mapping entre suas view models. Acredito que o pagerjs seja a melhor escolha para quem já utiliza o knockout (confiram o repo do github aqui).
Vamos analisar juntos o código abaixo, retirado de alguns trechos da página de demonstração:
<html> <body> <div class="container" style="padding-top: 30px;"> <!-- #!/first-page --> <div data-bind="page: {id: 'first-page'}"> <!-- #!/first-page/details --> <div data-bind="page: {id: 'details'}"> </div> </div> <!-- #!/another-page --> <div data-bind="page: {id: 'another-page'}"> </div> </div> </body> </html>
// use #!/ instead of the default # pager.Href.hash = '#!/'; // extend your view-model with pager.js specific data pager.extendWithPage(viewModel); // apply the view-model using KnockoutJS as normal ko.applyBindings(viewModel); // start pager.js pager.start();
Basicamente, o Pagerjs se junta à sua view model (através do extendWithPage) e cria algumas propriedades dele. Desta forma, você consegue fazer o bind via knockout das rotas para containers da sua página.
São tantas as funcionalidades do Pagerjs que fica difícil escrever um pouco sobre todas elas. Convido os interessados a explorar melhor a página de demonstração e sentir na pele a facilidade que os bindings trazem.
A diferença básica do pagerjs para o sammy.js é que o sammy mapeia a sua rota para funções que tem o trabalho de carregar as views, enquanto que com o pagerjs, suas rotas estão ligadas com bindings ao seu HTML. Não podemos esquecer que o Pagerjs foi criado para ser uma extensão do uso normal do knockout. Caso você estiver lidando com projetos pequenos, mantenha tudo simples e não crie dependências de frameworks inteiros apenas para ter a flexibilidade das rotas. Para isso existem outras libraries que não dependem de frameworks.
Outras opções
Para quem está procurando gerenciar suas rotas, aqui estão mais algumas boas alternativas:
- Crossroads.js - criada pelo brasileiro Miller Medeiros é uma ótima escolha para qualquer projeto, já que não depende de nenhum framework. Sua única dependência é do JS-Signals, também desenvolvido por ele.
- pathjs - extremamente pequena, também não depende de nenhum framework. Já não é atualizada no github há algum tempo.
- Davis.js - muito parecida com o sammy.js, já que também é baseada no Sinatra. Depende do jQuery para que tudo funcione.
Abraços!
Wilson Tayar