127 votes

Sites web JS "Single-page" et référencement

Il y a beaucoup de cool outils pour faire de la puissante "une seule page" JavaScript des sites web de nos jours. À mon avis, il est fait droit en laissant le serveur agir comme une API (et rien de plus) et de laisser le client de gérer l'ensemble de la génération HTML choses. Le problème avec ce "pattern" est l'absence de moteur de recherche, de soutien. Je pense à deux solutions:

  1. Lorsque l'utilisateur accède au site web, laissez le serveur de rendu de la page exactement comme le client lors de la navigation. Donc, si je vais à l' http://example.com/my_path directement le serveur aurait rendu la même chose que le client serait, si je vais à l' /my_path par pushState.
  2. Laissez le serveur d'un site web uniquement pour les robots des moteurs de recherche. Si un utilisateur normal visites http://example.com/my_path le serveur doit lui donner une JavaScript version lourde du site web. Mais si le bot de Google de visites, le serveur doit donner un minimum de HTML avec le contenu que je veux à Google d'indexer.

La première solution est abordée plus en détail ici. Je travaille sur un site web, le faire et ce n'est pas une expérience très agréable. Il n'est pas SEC et dans mon cas, j'ai dû utiliser deux différents moteurs de template pour le client et le serveur.

Je pense que j'ai vu la deuxième solution pour quelque chose de bon ol' sites web en Flash. J'aime cette approche beaucoup plus que le premier et avec le bon outil sur le serveur, il pourrait être tout à fait sans douleur.

Donc, ce que je demandais est la suivante:

  • Pouvez-vous penser à une meilleure solution?
  • Quels sont les inconvénients à la seconde solution? Si Google en quelque sorte découvre que je ne suis pas servir exactement le même contenu pour le bot de Google en tant qu'utilisateur normal, ce que je puis être sanctionné dans les résultats de recherche?

44voto

Derick Bailey Points 37859

Alors que #2 pourrait être "plus facile" pour vous en tant que développeur, il ne fournit moteur de recherche, de l'analyse. Et oui, si Google trouve votre fournir un contenu différent, vous pourriez être pénalisé (je ne suis pas un expert, mais j'ai entendu dire que cela ce produit).

Les deux RÉFÉRENCEMENTS et de l'accessibilité (et pas seulement pour la personne handicapée, mais l'accessibilité via des appareils mobiles, des appareils à écran tactile, et d'autres non-standard de l'informatique / l'internet a permis à ces plates-formes), les deux ont une semblable philosophie sous-jacente: sémantiquement riche de balisage qui est "accessible" (c'est à dire qui peuvent être consultées, lire, traitée ou utilisée d'une autre manière) via ces différents navigateurs. Un lecteur d'écran, un moteur de recherche, de robot ou d'un utilisateur avec JavaScript activé, il devrait être en mesure d'utiliser/index/comprendre de votre site sur les fonctionnalités de base sans problème.

pushState n'est pas à ajouter à ce fardeau, selon mon expérience. Il apporte seulement une réflexion après coup, et "si nous avons le temps" qui est à l'avant-garde du développement web.

Ce que vous décrivez dans l'option #1 est généralement la meilleure façon de faire - mais, comme d'autres l'accessibilité et le référencement SEO de questions, le faire avec pushState dans un JavaScript-lourds application requiert une planification à l'avance ou il deviendra un fardeau important. Il doit être cuit à la page et de l'architecture de l'application de la start - mise en conformité est douloureux et causer plus de duplication que ce qui est nécessaire.

J'ai travaillé avec pushState SEO, et récemment pour un couple de différentes applications, et j'ai trouvé ce que je pense est une bonne approche. Il suit globalement votre point #1, mais ne représente pas la duplication de code html / modèles.

Plus d'informations peuvent être trouvées dans ces deux billets de blog:

http://lostechies.com/derickbailey/2011/09/06/test-driving-backbone-views-with-jquery-templates-the-jasmine-gem-and-jasmine-jquery/

et

http://lostechies.com/derickbailey/2011/06/22/rendering-a-rails-partial-as-a-jquery-template/

L'essentiel, c'est que j'utilise ERB ou HAML modèles (l'exécution de Ruby on Rails, Sinatra, etc) de mon côté serveur de rendu et de créer le côté client de modèles que l'épine Dorsale pouvez utiliser, ainsi que pour mon Jasmin JavaScript specs. Cela permet de réduire la duplication de balisage entre le côté serveur et côté client.

À partir de là, vous avez besoin de prendre quelques mesures supplémentaires afin d'avoir l'option JavaScript de votre travail avec le HTML qui est affiché par le serveur véritable amélioration progressive; en prenant le balisage sémantique qui les a livrés et de le renforcer avec du JavaScript.

Par exemple, je suis en train de construire une image de la galerie de l'application avec pushState. Si vous demandez /images/1 à partir du serveur, il va rendre l'ensemble de la galerie d'image sur le serveur et d'envoyer le tout le code HTML, CSS et JavaScript en bas de votre navigateur. Si vous avez désactivé JavaScript, il fonctionne parfaitement bien. Chaque action que vous prenez va demander une URL différente à partir du serveur, et le serveur à rendre l'ensemble de la marge pour votre navigateur. Si vous avez activé JavaScript, cependant, le JavaScript va chercher le déjà rendu HTML avec un peu de variables générées par le serveur à partir de là.

Voici un exemple:

<form id="foo">
  Name: <input id="name"><button id="say">Say My Name!</button>
</form>

Une fois que le serveur rend cela, le JavaScript, le ramasser (à l'aide d'un Backbone.js vue dans cet exemple)

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")
  });
});

C'est un exemple très simple, mais je pense qu'il obtient le point à travers.

Quand je instante la vue après le chargement de la page, je suis fournissant le contenu existant de la forme qui a été rendu par le serveur, à l'instance de vue que l' el pour la vue. Je suis pas d'appel de rendu ou d'avoir le point de vue de générer un el pour moi, lorsque le premier point de vue est chargé. J'ai une méthode de rendu disponibles pour une fois que la vue est en place et en cours d'exécution et que la page est tout au JavaScript. Cela me permet de re-rendre la vue plus tard si j'en ai besoin.

En cliquant sur le "Say My Name" bouton avec JavaScript activé va provoquer une boîte d'alerte. Sans JavaScript, il serait de publier sur le serveur et que le serveur pourrait rendre le nom d'un élément html, quelque part.

Modifier

Considérons un exemple plus complexe, où vous avez une liste qui doit être relié (d'après les commentaires ci-dessous)

Disons que vous avez une liste d'utilisateurs dans un <ul> balise. Cette liste a été rendue par le serveur lorsque le navigateur fait une demande, et le résultat ressemble à quelque chose comme:

<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>

Maintenant, vous avez besoin d'une boucle sur cette liste et joindre une épine Dorsale modèle et de la vue à chacune de l' <li> articles. Avec l'utilisation de l' data-id d'attribut, vous pouvez trouver le modèle que chaque balise vient facilement. Vous aurez alors besoin d'une collecte de vue et le point de vue qui est assez intelligent pour s'attacher à ce 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();

Dans cet exemple, l' UserListView , passe en boucle sur tous les de la <li> balises et attacher un objet de vue avec le bon modèle pour chacun. il met en place un gestionnaire d'événement pour le modèle de changement de nom de l'événement et met à jour l'affichage du texte de l'élément lorsqu'un changement se produit.


Ce type de processus, de prendre le code html que le serveur de rendu et d'avoir mon JavaScript prendre le dessus et de le lancer, il est un excellent moyen de bouger les choses pour le RÉFÉRENCEMENT, l'Accessibilité et l' pushState de soutien.

Espérons que cela aide.

22voto

Ariel Points 12944

Je pense que vous avez besoin de ceci: http://code.google.com/web/ajaxcrawling/

Vous pouvez également installer un backend spécial qui "rend" votre page en exécutant javascript sur le serveur, puis le diffusera sur google.

Combinez les deux et vous avez une solution sans programmer deux fois. (Tant que votre application est entièrement contrôlable via des fragments d'ancrage.)

17voto

Leonidaz Points 196

Donc, il semble que la principale préoccupation est d'être à SEC

  • Si vous utilisez pushState votre serveur d'envoyer exactement le même code pour toutes les url (qui ne contiennent pas une extension de fichier pour servir des images, etc.) "/mydir/monfichier", "/myotherdir/myotherfile" ou de la racine "/" -- toutes les demandes de recevoir exactement le même code. Vous avez besoin d'avoir une sorte de réécriture d'url du moteur. Vous pouvez aussi servir un tout petit peu de html et le reste peut venir de votre CA (à l'aide de require.js pour gérer les dépendances -- voir http://stackoverflow.com/a/13813102/1595913).
  • (test le lien de la validité de la conversion le lien de votre schéma d'url et d'essai contre l'existence d'un contenu par l'interrogation d'une statique ou dynamique de la source. si il n'est pas valide envoyer une réponse 404.)
  • Lorsque la demande n'est pas un bot de google, vous avez juste normalement.
  • Si la demande émane d'un bot de google, vous utilisez phantom.js -- sans tête navigateur webkit ("Un headless browser est simplement un navigateur de web complet sans interface visuelle.") pour afficher le code html et javascript sur le serveur et envoyer le bot de google le html résultant. Comme le bot analyse le code html, cela peut frapper vos autres "pushState" liens /somepage sur le serveur <a href="http://stackoverflow.com/someotherpage">mylink</a>, le serveur réécrit l'url de votre fichier d'application, la charge en phantom.js et le html résultant est envoyé au bot, et ainsi de suite...
  • Pour le html, je suis en supposant que vous êtes en utilisant les liens normaux avec une sorte de détournement (par exemple, avec l'aide de backbone.js http://stackoverflow.com/a/9331734/1595913)
  • Pour éviter la confusion avec tous les liens de séparer votre code api qui sert json dans un sous-domaine, par exemple api.mysite.com
  • Pour améliorer les performances, vous pouvez pré-processus de pages de votre site pour les moteurs de recherche à l'avance de l'heure pendant les heures creuses en créant des versions statiques des pages en utilisant le même mécanisme avec phantom.js et, par conséquent, servir les pages statiques pour les robots de google. Le prétraitement peut être fait avec une simple application qui permet de parser <a> tags. Dans ce cas, la manipulation 404 est plus facile puisque vous pouvez simplement vérifier l'existence du fichier statique avec un nom qui contient le chemin d'accès d'url.
  • Si vous utilisez #! hachage bang syntaxe des liens de votre site un scénario similaire s'applique, sauf que la réécriture d'url du serveur de moteur de regarder dehors pour _escaped_fragment_ dans l'url et serait le format de l'url de votre schéma d'url.
  • Il ya un couple de intégrations de node.js avec phantom.js sur github et vous pouvez les utiliser node.js comme le serveur web pour générer du code html de sortie.

Voici quelques exemples d'utilisation de phantom.js pour le référencement:

http://backbonetutorials.com/seo-for-single-page-apps/

http://thedigitalself.com/blog/seo-and-javascript-with-phantomjs-server-side-rendering

4voto

Tim Scott Points 7043

Si vous êtes à l'aide de Rails, essayez de poirot. C'est un petit bijou qui le rend très simple à réutiliser moustache ou guidon modèles de client et côté serveur.

Créer un fichier dans votre point de vue comme _some_thingy.html.mustache.

Le rendu côté serveur:

<%= render :partial => 'some_thingy', object: my_model %>

Mettre le modèle de votre tête pour le côté client utilisation:

<%= template_include_tag 'some_thingy' %>

Rendre côté client:

html = poirot.someThingy(my_model)

3voto

Clive Points 28701

Pour prendre un angle légèrement différent, votre deuxième solution serait la bonne en termes d’ accessibilité … vous fourniriez un contenu alternatif aux utilisateurs qui ne peuvent pas utiliser javascript (ceux avec des lecteurs d’écran, etc.).

Cela ajouterait automatiquement les avantages du SEO et, à mon avis, ne serait pas considéré comme une technique «coquine» par Google.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X