Während # 2 für Sie als Entwickler "einfacher" sein könnte, bietet es nur Suchmaschinen-Crawlen. Und ja, wenn Google herausfindet, dass Sie unterschiedliche Inhalte bereitstellen, werden Sie möglicherweise bestraft (ich bin kein Experte dafür, aber ich habe davon gehört).
Sowohl SEO als auch Barrierefreiheit (nicht nur für behinderte Menschen, sondern auch Barrierefreiheit über mobile Geräte, Touchscreen-Geräte und andere nicht standardmäßige Computer- / internetfähige Plattformen) haben beide eine ähnliche Philosophie: semantisch reichhaltiges Markup, das "zugänglich" ist (dh kann) auf all diese verschiedenen Browser zugegriffen, angezeigt, gelesen, verarbeitet oder anderweitig verwendet werden. Ein Bildschirmleser, ein Suchmaschinen-Crawler oder ein Benutzer mit aktiviertem JavaScript sollte in der Lage sein, die Kernfunktionen Ihrer Website ohne Probleme zu verwenden / zu indizieren / zu verstehen.
pushState
trägt meiner Belastung nach meiner Erfahrung nicht bei. Es bringt nur das, was früher ein nachträglicher Gedanke war und "wenn wir Zeit haben", in den Vordergrund der Webentwicklung.
Was Sie in Option 1 beschreiben, ist normalerweise der beste Weg - aber wie bei anderen Problemen mit der Barrierefreiheit und der Suchmaschinenoptimierung pushState
erfordert dies in einer JavaScript-lastigen App eine Vorausplanung, da dies zu einer erheblichen Belastung wird. Es sollte von Anfang an in die Seiten- und Anwendungsarchitektur integriert werden - das Nachrüsten ist schmerzhaft und führt zu mehr Duplikaten als erforderlich.
Ich habe pushState
kürzlich mit und SEO für ein paar verschiedene Anwendungen gearbeitet und fand, was ich für einen guten Ansatz halte. Es folgt im Wesentlichen Ihrem Artikel Nr. 1, berücksichtigt jedoch, dass HTML / Vorlagen nicht dupliziert werden.
Die meisten Informationen finden Sie in diesen beiden Blog-Beiträgen:
http://lostechies.com/derickbailey/2011/09/06/test-driving-backbone-views-with-jquery-templates-the-jasmine-gem-and-jasmine-jquery/
und
http://lostechies.com/derickbailey/2011/06/22/rendering-a-rails-partial-as-a-jquery-template/
Das Wesentliche dabei ist, dass ich ERB- oder HAML-Vorlagen (mit Ruby on Rails, Sinatra usw.) für mein serverseitiges Rendern und zum Erstellen der clientseitigen Vorlagen verwende, die Backbone verwenden kann, sowie für meine Jasmine-JavaScript-Spezifikationen. Dies verhindert das Duplizieren von Markups zwischen der Serverseite und der Clientseite.
Von dort aus müssen Sie einige zusätzliche Schritte ausführen, damit Ihr JavaScript mit dem vom Server gerenderten HTML funktioniert - echte progressive Verbesserung; Nehmen Sie das gelieferte semantische Markup und erweitern Sie es mit JavaScript.
Zum Beispiel baue ich eine Bildergalerie-Anwendung mit pushState
. Wenn Sie dies /images/1
vom Server anfordern , wird die gesamte Bildergalerie auf dem Server gerendert und der gesamte HTML-, CSS- und JavaScript-Code an Ihren Browser gesendet. Wenn Sie JavaScript deaktiviert haben, funktioniert es einwandfrei. Jede Aktion, die Sie ausführen, fordert eine andere URL vom Server an und der Server rendert das gesamte Markup für Ihren Browser. Wenn Sie jedoch JavaScript aktiviert haben, nimmt das JavaScript den bereits gerenderten HTML-Code zusammen mit einigen vom Server generierten Variablen auf und übernimmt von dort aus.
Hier ist ein Beispiel:
<form id="foo">
Name: <input id="name"><button id="say">Say My Name!</button>
</form>
Nachdem der Server dies gerendert hat, nimmt das JavaScript es auf (in diesem Beispiel mithilfe der Ansicht Backbone.js).
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")
});
});
Dies ist ein sehr einfaches Beispiel, aber ich denke, es bringt den Punkt auf den Punkt.
Wenn ich die Ansicht nach dem Laden der Seite instanziiere, stelle ich der Ansichtsinstanz den vorhandenen Inhalt des vom Server gerenderten Formulars als el
für die Ansicht bereit. Ich rufe nicht rendern auf oder lasse die Ansicht el
für mich generieren , wenn die erste Ansicht geladen wird. Ich habe eine Rendermethode zur Verfügung, nachdem die Ansicht ausgeführt wurde und die Seite ausschließlich aus JavaScript besteht. Auf diese Weise kann ich die Ansicht später bei Bedarf erneut rendern.
Wenn Sie bei aktiviertem JavaScript auf die Schaltfläche "Sag meinen Namen" klicken, wird ein Warnfeld angezeigt. Ohne JavaScript würde es auf den Server zurückgesendet und der Server könnte den Namen irgendwo in ein HTML-Element rendern.
Bearbeiten
Stellen Sie sich ein komplexeres Beispiel vor, in dem Sie eine Liste haben, die angehängt werden muss (aus den Kommentaren darunter).
Angenommen, Sie haben eine Liste von Benutzern in einem <ul>
Tag. Diese Liste wurde vom Server gerendert, als der Browser eine Anfrage stellte, und das Ergebnis sieht ungefähr so aus:
<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>
Jetzt müssen Sie diese Liste durchlaufen und jedem <li>
Element eine Backbone-Ansicht und ein Backbone-Modell hinzufügen. Mithilfe des data-id
Attributs können Sie leicht das Modell finden, von dem jedes Tag stammt. Sie benötigen dann eine Sammlungsansicht und eine Elementansicht, die intelligent genug sind, um sich an dieses HTML anzuhängen.
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();
In diesem Beispiel UserListView
werden alle <li>
Tags durchlaufen und ein Ansichtsobjekt mit dem richtigen Modell für jedes angehängt. Es richtet einen Ereignishandler für das Ereignis zur Namensänderung des Modells ein und aktualisiert den angezeigten Text des Elements, wenn eine Änderung auftritt.
Diese Art von Prozess, um das vom Server gerenderte HTML zu übernehmen und mein JavaScript übernehmen und ausführen zu lassen, ist eine großartige Möglichkeit, die Dinge für SEO, Barrierefreiheit und pushState
Support ins Rollen zu bringen .
Hoffentlich hilft das.
Ich denke, Sie brauchen dies: http://code.google.com/web/ajaxcrawling/
Sie können auch ein spezielles Backend installieren, das Ihre Seite durch Ausführen von Javascript auf dem Server "rendert" und dieses dann an Google weiterleitet.
Kombinieren Sie beide Dinge und Sie haben eine Lösung, ohne die Dinge zweimal zu programmieren. (Solange Ihre App über Ankerfragmente vollständig steuerbar ist.)
quelle
Es scheint also, dass das Hauptanliegen DRY ist
<a href="https://stackoverflow.com/someotherpage">mylink</a>
, der Server schreibt die URL in Ihre Anwendungsdatei neu, lädt sie in phantom.js und das resultierende HTML wird an den Bot gesendet und so weiter. ..<a>
Tags analysieren kann . In diesem Fall ist die Handhabung von 404 einfacher, da Sie einfach überprüfen können, ob die statische Datei mit einem Namen vorhanden ist, der den URL-Pfad enthält.Hier einige Beispiele für die Verwendung von phantom.js für SEO:
http://backbonetutorials.com/seo-for-single-page-apps/
http://thedigitalself.com/blog/seo-and-javascript-with-phantomjs-server-side-rendering
quelle
Wenn Sie Rails verwenden, versuchen Sie es mit Poirot . Es ist ein Juwel, das es kinderleicht macht, Schnurrbart- oder Lenkervorlagen auf Client- und Serverseite wiederzuverwenden .
Erstellen Sie eine Datei in Ihren Ansichten wie
_some_thingy.html.mustache
.Serverseite rendern:
Legen Sie die Vorlage für die clientseitige Verwendung in Ihren Kopf:
Rendre Client-Seite:
quelle
Um einen etwas anderen Blickwinkel einzunehmen, wäre Ihre zweite Lösung in Bezug auf die Barrierefreiheit die richtige. Sie würden Benutzern, die kein Javascript verwenden können (Benutzer mit Bildschirmleseprogrammen usw.), alternative Inhalte bereitstellen.
Dies würde automatisch die Vorteile von SEO hinzufügen und würde meiner Meinung nach von Google nicht als "ungezogene" Technik angesehen.
quelle
Interessant. Ich habe nach tragfähigen Lösungen gesucht, aber es scheint ziemlich problematisch zu sein.
Ich habe mich tatsächlich mehr auf Ihren zweiten Ansatz konzentriert:
Hier ist meine Einstellung zur Lösung des Problems. Obwohl nicht bestätigt wurde, dass es funktioniert, bietet es möglicherweise einige Einblicke oder Ideen für andere Entwickler.
Angenommen, Sie verwenden ein JS-Framework, das die Push-Status-Funktionalität unterstützt, und Ihr Backend-Framework ist Ruby on Rails. Sie haben eine einfache Blog-Site und möchten, dass Suchmaschinen alle Ihre Artikel
index
undshow
Seiten indizieren .Angenommen, Sie haben Ihre Routen wie folgt eingerichtet:
Stellen Sie sicher, dass jeder serverseitige Controller dieselbe Vorlage rendert, die Ihr clientseitiges Framework zum Ausführen benötigt (html / css / javascript / etc). Wenn keiner der Controller in der Anforderung übereinstimmt (in diesem Beispiel haben wir nur einen RESTful-Satz von Aktionen für den
ArticlesController
), stimmen Sie einfach mit etwas anderem überein und rendern Sie einfach die Vorlage und lassen Sie das clientseitige Framework das Routing übernehmen. Der einzige Unterschied zwischen dem Aufrufen eines Controllers und dem Aufrufen des Platzhalter-Matchers besteht in der Möglichkeit, Inhalte basierend auf der URL zu rendern, die für Geräte mit deaktiviertem JavaScript angefordert wurde.Soweit ich weiß, ist es eine schlechte Idee, Inhalte zu rendern, die für Browser nicht sichtbar sind. Wenn Google es indiziert, gehen die Leute über Google, um eine bestimmte Seite zu besuchen, und es gibt keinen Inhalt. Dann werden Sie wahrscheinlich bestraft. Was Ihnen in den Sinn kommt, ist, dass Sie Inhalte in einem
div
Knoten rendern , den Siedisplay: none
in CSS verwenden.Ich bin mir jedoch ziemlich sicher, dass es keine Rolle spielt, wenn Sie dies einfach tun:
Und dann JavaScript verwenden, das nicht ausgeführt wird, wenn ein Gerät mit deaktiviertem JavaScript die Seite öffnet:
Auf diese Weise wird für Google und für alle Benutzer mit JavaScript-deaktivierten Geräten der rohe / statische Inhalt angezeigt. Der Inhalt ist also physisch vorhanden und für jeden mit JavaScript-deaktivierten Geräten sichtbar.
Aber, wenn ein Nutzer die gleiche Seite und tatsächlich hat JavaScript aktiviert, die
#no-js
den Knoten entfernt werden , damit es nicht Ihre Anwendung verunstalteten ist. Anschließend verarbeitet Ihr clientseitiges Framework die Anforderung über seinen Router und zeigt an, was ein Benutzer sehen sollte, wenn JavaScript aktiviert ist.Ich denke, dies könnte eine gültige und ziemlich einfach zu verwendende Technik sein. Dies kann jedoch von der Komplexität Ihrer Website / Anwendung abhängen.
Bitte korrigieren Sie mich, wenn dies nicht der Fall ist. Ich dachte nur, ich würde meine Gedanken teilen.
quelle
Verwenden Sie NodeJS auf der Serverseite, durchsuchen Sie Ihren clientseitigen Code und leiten Sie die URL jeder http-Anforderung (mit Ausnahme statischer http-Ressourcen) durch einen serverseitigen Client, um den ersten "Bootsnap" (eine Momentaufnahme der Seite, auf der sich der Status befindet) bereitzustellen. Verwenden Sie so etwas wie jsdom, um jquery dom-ops auf dem Server zu verarbeiten. Richten Sie nach der Rückkehr des Bootsnaps die Websocket-Verbindung ein. Am besten unterscheiden Sie wahrscheinlich zwischen einem Websocket-Client und einem serverseitigen Client, indem Sie eine Art Wrapper-Verbindung auf der Clientseite herstellen (der serverseitige Client kann direkt mit dem Server kommunizieren). Ich habe an so etwas gearbeitet: https://github.com/jvanveen/rnet/
quelle
Verwenden Sie die Google Closure-Vorlage , um Seiten zu rendern. Es wird in Javascript oder Java kompiliert, sodass es einfach ist, die Seite entweder auf der Client- oder der Serverseite zu rendern. Rendern Sie bei der ersten Begegnung mit jedem Client das HTML und fügen Sie Javascript als Link in den Header ein. Crawler liest nur das HTML, aber der Browser führt Ihr Skript aus. Alle nachfolgenden Anfragen vom Browser könnten gegen die API erfolgen, um den Datenverkehr zu minimieren.
quelle