Embora o número 2 possa ser "mais fácil" para você como desenvolvedor, ele fornece apenas o rastreamento do mecanismo de pesquisa. E sim, se o Google descobrir que você exibe conteúdo diferente, você poderá ser penalizado (não sou especialista nisso, mas já ouvi falar disso).
Tanto o SEO quanto a acessibilidade (não apenas para pessoas com deficiência, mas a acessibilidade por meio de dispositivos móveis, dispositivos com tela sensível ao toque e outras plataformas não padronizadas para computação / Internet) têm uma filosofia subjacente semelhante: marcação semanticamente rica que é "acessível" (ou seja, pode acessados, visualizados, lidos, processados ou usados) em todos esses navegadores diferentes. Um leitor de tela, um rastreador de mecanismo de pesquisa ou um usuário com JavaScript habilitado devem ser capazes de usar / indexar / entender a funcionalidade principal do seu site sem problemas.
pushState
não aumenta esse fardo, na minha experiência. Ele apenas traz o que costumava ser uma reflexão tardia e "se tivermos tempo" para a vanguarda do desenvolvimento da web.
O que você descreve na opção nº 1 geralmente é o melhor caminho a percorrer - mas, como outros problemas de acessibilidade e SEO, fazer isso pushState
em um aplicativo pesado em JavaScript requer planejamento antecipado ou isso se tornará um fardo significativo. Ele deve ser inserido na arquitetura da página e do aplicativo desde o início - a atualização é dolorosa e causará mais duplicação do que o necessário.
Eu tenho trabalhado pushState
recentemente com o SEO em algumas aplicações diferentes e achei o que considero uma boa abordagem. Ele segue basicamente o item nº 1, mas é responsável por não duplicar html / templates.
A maioria das informações pode ser encontrada nessas duas postagens no blog:
http://lostechies.com/derickbailey/2011/09/06/test-driving-backbone-views-with-jquery-templates-the-jasmine-gem-and-jasmine-jquery/
e
http://lostechies.com/derickbailey/2011/06/22/rendering-a-rails-partial-as-a-jquery-template/
O essencial disso é que eu uso modelos ERB ou HAML (executando Ruby on Rails, Sinatra etc.) para renderizar no lado do servidor e criar os modelos do lado do cliente que o Backbone pode usar, bem como para minhas especificações JavaScript do Jasmine. Isso elimina a duplicação da marcação entre o lado do servidor e o lado do cliente.
A partir daí, é necessário executar algumas etapas adicionais para que seu JavaScript funcione com o HTML renderizado pelo servidor - verdadeiro aprimoramento progressivo; pegando a marcação semântica que foi entregue e aprimorando-a com JavaScript.
Por exemplo, estou criando um aplicativo de galeria de imagens com pushState
. Se você solicitar /images/1
do servidor, ele renderizará toda a galeria de imagens no servidor e enviará todo o HTML, CSS e JavaScript para o seu navegador. Se você tiver o JavaScript desativado, ele funcionará perfeitamente. Todas as ações que você executar solicitarão um URL diferente do servidor e o servidor renderizará toda a marcação para o seu navegador. Se você tiver o JavaScript ativado, ele pegará o HTML já renderizado junto com algumas variáveis geradas pelo servidor e assumirá o controle a partir daí.
Aqui está um exemplo:
<form id="foo">
Name: <input id="name"><button id="say">Say My Name!</button>
</form>
Depois que o servidor renderiza isso, o JavaScript o seleciona (usando uma visualização Backbone.js neste exemplo)
FooView = Backbone.View.extend({
events: {
"change #name": "setName",
"click #say": "sayName"
},
setName: function(e){
var name = $(e.currentTarget).val();
this.model.set({name: name});
},
sayName: function(e){
e.preventDefault();
var name = this.model.get("name");
alert("Hello " + name);
},
render: function(){
// do some rendering here, for when this is just running JavaScript
}
});
$(function(){
var model = new MyModel();
var view = new FooView({
model: model,
el: $("#foo")
});
});
Este é um exemplo muito simples, mas acho que é o ponto principal.
Quando instante a exibição após o carregamento da página, estou fornecendo o conteúdo existente do formulário que foi renderizado pelo servidor para a instância da exibição como el
a exibição. Estou não chamar prestar ou ter a visão de gerar uma el
para mim, quando a primeira vista é carregado. Eu tenho um método de renderização disponível para depois que a exibição estiver em execução e a página estiver toda em JavaScript. Isso me permite renderizar novamente a exibição mais tarde, se necessário.
Clicar no botão "Diga meu nome" com o JavaScript ativado fará com que uma caixa de alerta. Sem JavaScript, ele seria postado de volta no servidor e o servidor poderia renderizar o nome para um elemento html em algum lugar.
Editar
Considere um exemplo mais complexo, em que você tem uma lista que precisa ser anexada (dos comentários abaixo)
Digamos que você tenha uma lista de usuários em uma <ul>
tag. Essa lista foi renderizada pelo servidor quando o navegador fez uma solicitação e o resultado se parece com:
<ul id="user-list">
<li data-id="1">Bob
<li data-id="2">Mary
<li data-id="3">Frank
<li data-id="4">Jane
</ul>
Agora você precisa percorrer esta lista e anexar uma visualização e modelo de Backbone a cada um dos <li>
itens. Com o uso do data-id
atributo, você pode encontrar o modelo de onde cada tag vem facilmente. Você precisará de uma visualização de coleção e de itens que seja inteligente o suficiente para se conectar a esse html.
UserListView = Backbone.View.extend({
attach: function(){
this.el = $("#user-list");
this.$("li").each(function(index){
var userEl = $(this);
var id = userEl.attr("data-id");
var user = this.collection.get(id);
new UserView({
model: user,
el: userEl
});
});
}
});
UserView = Backbone.View.extend({
initialize: function(){
this.model.bind("change:name", this.updateName, this);
},
updateName: function(model, val){
this.el.text(val);
}
});
var userData = {...};
var userList = new UserCollection(userData);
var userListView = new UserListView({collection: userList});
userListView.attach();
Neste exemplo, o UserListView
loop percorrerá todas as <li>
tags e anexará um objeto de visualização com o modelo correto para cada uma. ele configura um manipulador de eventos para o evento de alteração de nome do modelo e atualiza o texto exibido do elemento quando ocorre uma alteração.
Esse tipo de processo, para pegar o html que o servidor renderizou e fazer com que meu JavaScript o controle e execute, é uma ótima maneira de fazer as coisas rolarem para SEO, acessibilidade e pushState
suporte.
Espero que ajude.