Веб-сайти JS та SEO


128

В даний час існує безліч класних інструментів для створення потужних веб-сайтів JavaScript на одній сторінці. На мою думку, це робиться правильно, дозволяючи серверу діяти в якості API (і нічого більше) і дозволяти клієнту обробляти всі матеріали покоління HTML. Проблема з цією «схемою» - відсутність підтримки пошукової системи. Я можу придумати два рішення:

  1. Коли користувач переходить на веб-сайт, дозвольте серверу відображати сторінку саме так, як клієнт під час навігації. Тож якщо я перейду http://example.com/my_pathбезпосередньо до сервера, він зробить те саме, що і клієнт, якщо я перейду /my_pathчерез pushState.
  2. Нехай сервер надає спеціальний веб-сайт лише для ботів пошукової системи. Якщо звичайний користувач відвідує http://example.com/my_pathсервер, він повинен надати йому важку версію веб-сайту JavaScript. Але якщо бот Google відвідує, сервер повинен дати йому мінімальний HTML із вмістом, який я хочу, щоб Google проіндексував.

Перше рішення далі обговорюється тут . Я працюю над веб-сайтом, роблячи це, і це не дуже приємний досвід. Це НЕ СУХО, і в моєму випадку мені довелося використовувати два різних двигуна шаблону для клієнта та сервера.

Я думаю, що я бачив друге рішення для деяких хороших веб-сайтів Flash. Мені подобається такий підхід набагато більше, ніж перший, і з правильним інструментом на сервері це можна було зробити досить безболісно.

Тож мені дуже цікаво таке:

  • Чи можете ви придумати якесь краще рішення?
  • Які недоліки у другого рішення? Якщо Google якимось чином дізнається, що я не подаю абсолютно той самий вміст для бота Google, як звичайний користувач, я був би покараний у результатах пошуку?

Відповіді:


44

Хоча номер 2 може бути "простішим" для вас як розробника, він забезпечує лише сканування пошукової системи. І так, якщо Google дізнається, що ви пропонуєте інший вміст, ви можете бути покарані (я не експерт з цього питання, але я чув, що це відбувається).

Як SEO, так і доступність (не тільки для людей з обмеженими можливостями, але й доступність через мобільні пристрої, пристрої з сенсорним екраном та інші нестандартні платформи для обчислень / Інтернету) обидва мають схожу основу філософії: семантично багата розмітка, яка є "доступною" (тобто може отримати доступ, переглядати, читати, обробляти або використовувати іншим чином) до всіх цих різних браузерів. Зчитувач екрана, сканер пошукової системи або користувач з увімкненим JavaScript, повинні без проблем використовувати / індексувати / розуміти основну функціональність вашого сайту.

pushStateне додає цього тягаря, на мій досвід. Це лише виводить те, що раніше було задумливим, і "якщо у нас буде час" на перший план у веб-розробці.

Те, що ви описуєте у варіанті №1, як правило, найкращий шлях - але, як і інші проблеми з доступністю та SEO, виконання цього завдання pushStateу важкому додатку JavaScript вимагає попереднього планування, або це стане значним тягарем. Це має бути зафіксовано на сторінці та архітектурі додатків із самого початку - оновлення болісне і призведе до більше дублювання, ніж потрібно.

pushStateНещодавно я працював із SEO і працював над декількома різними програмами, і я виявив, що, на мою думку, хороший підхід. Це в основному відповідає вашому пункту №1, але не враховує дублювання html / шаблонів.

Більшість інформації можна знайти в цих двох публікаціях блогу:

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

і

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

Суть у тому, що я використовую шаблони ERB або HAML (запуск Ruby on Rails, Sinatra тощо) для візуалізації на стороні сервера та для створення шаблонів на стороні клієнта, якими може користуватися Backbone, а також для моїх специфікацій Jasmine JavaScript. Це виключає дублювання розмітки між стороною сервера та клієнтом.

Звідти вам потрібно зробити кілька додаткових кроків, щоб ваш JavaScript працював з HTML, який надає сервер - справжнє прогресивне вдосконалення; прийняття отриманої смислової розмітки та покращення її за допомогою JavaScript.

Наприклад, я будую додаток із галереї зображень із pushState. Якщо ви запитаєте /images/1від сервера, він візуалізує всю галерею зображень на сервері та надішле весь HTML, CSS та JavaScript до вашого браузера. Якщо у вас відключений JavaScript, він буде працювати чудово. Кожна дія, яку ви зробите, вимагатиме отримання різної URL-адреси від сервера, і сервер відображатиме всю розмітку для вашого браузера. Якщо у вас увімкнено JavaScript, JavaScript підбере вже відредагований HTML разом із кількома змінними, згенерованими сервером, і перейме звідти.

Ось приклад:

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

Після того, як сервер надає це, JavaScript підбере його (використовуючи перегляд 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")
  });
});

Це дуже простий приклад, але я думаю, що це зрозуміло.

Коли я створюю подання після завантаження сторінки, я надаю існуючий вміст форми, наданої сервером, екземпляру перегляду як elперегляду. Я не викликаю візуалізацію або перегляд, який створює elдля мене, коли завантажується перший погляд. У мене доступний метод візуалізації після запуску перегляду, і ця сторінка - це JavaScript. Це дозволяє мені переглядати подання пізніше, якщо мені потрібно.

Якщо натиснути кнопку "Скажи моє ім'я" з увімкненим JavaScript, це призведе до вікна сповіщення. Без JavaScript він буде розміщений назад на сервері, і сервер міг би десь надати ім'я елементу html.

Редагувати

Розглянемо більш складний приклад, де у вас є список, який потрібно долучити (з коментарів нижче цього)

Скажімо, у вас є список користувачів у <ul>тезі. Цей список був наданий сервером, коли браузер зробив запит, і результат виглядає приблизно так:

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

Тепер вам потрібно переглядати цей список і приєднати перегляд та модель опорних кісток до кожного з <li>елементів. За допомогою data-idатрибута ви можете легко знайти модель, з якої походить кожен тег. Тоді вам знадобиться представлення колекції та вигляд предмета, який є досить розумним, щоб приєднатися до цього 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();

У цьому прикладі UserListViewбуде проведено перегляд всіх <li>тегів та додавання об’єкта перегляду з правильною моделлю для кожного. він встановлює обробник подій для події зміни імені моделі та оновлює відображений текст елемента, коли відбувається зміна.


Такий процес - взяти html, який надає сервер, і запустити мій JavaScript, і запустити його - це чудовий спосіб отримати зручні речі для SEO, Доступності та pushStateпідтримки.

Сподіваюся, що це допомагає.


Я розумію, але що цікаво - це те, як здійснюється візуалізація після того, як "ваш JavaScript перейме на себе". У більш складному прикладі, можливо, вам доведеться використовувати некомпільований шаблон на клієнті, перебираючи масив користувачів для складання списку. Перегляд відображається щоразу, коли модель користувача змінюється. Як би ви це зробили, не дублюючи шаблони (і не запитуючи сервер надати перегляд клієнту)?
користувач544941

2 пов'язані мною повідомлення в блозі повинні колективно показати вам, як мати шаблони, які можна використовувати на клієнті та сервері - не потрібно дублювати. сервер повинен буде відтворити всю сторінку, якщо ви хочете, щоб вона була доступною та оптимізованою для SEO. я оновив свою відповідь, щоб включити більш складний приклад приєднання до списку користувачів, наданий сервером
Derick Bailey

22

Я думаю, вам це потрібно: http://code.google.com/web/ajaxcrawling/

Ви також можете встановити спеціальний бекенд, який "візуалізує" вашу сторінку, запустивши javascript на сервері, а потім обслуговує її для google.

Комбінуйте обидві речі, і у вас є рішення без програмування речей двічі. (Поки ваша програма повністю керована за допомогою фрагментів якоря.)


Власне, це не те, що я шукаю. Це кілька варіантів першого рішення, і, як я вже згадував, я не дуже задоволений таким підходом.
користувач544941

2
Ви не прочитали моєї всієї відповіді. Ви також використовуєте спеціальний бекенд, який надає вам javascript - ви не пишете речі двічі.
Аріель

Так, я це прочитав. Але якби я тебе зрозумів, це було б одним пеклом програми, оскільки воно повинно було б імітувати кожну дію, яка запускає pushState. Крім того, я міг би безпосередньо надати дії до цього, але тоді ми вже не такі ДУХІ.
користувач544941

2
Я думаю, що це в основному браузер без фронту. Але, так, ви повинні зробити програму повністю керованою з фрагментів якоря. Вам також потрібно переконатися, що всі посилання містять у них належний фрагмент, а також чи замість них onClicks.
Аріель

17

Отже, здається, що головне питання - це ДУХА

  • Якщо ви використовуєте pushState, ваш сервер надішле той самий точний код для всіх URL-адрес (які не містять розширення файлу для подання зображень тощо) "/ mydir / myfile", "/ myotherdir / myotherfile" або root "/ "- всі запити отримують однаковий точний код. Потрібно мати якийсь механізм перезапису URL-адреси. Ви також можете подати крихітний HTML-код, а решта - з вашого CDN (використовуючи Require.js для управління залежностями - див. Https://stackoverflow.com/a/13813102/1595913 ).
  • (перевірити дійсність посилання, перетворивши посилання на вашу URL-схему та перевіривши наявність вмісту, запитуючи статичне або динамічне джерело. Якщо воно недійсне, надішліть відповідь 404.)
  • Якщо запит не від бота google, ви просто обробляєтесь нормально.
  • Якщо запит від бота google, ви використовуєте phantom.js - безголовий веб-браузер ( "Безголовий браузер - це просто повнофункціональний веб-браузер без візуального інтерфейсу." ) Для надання html та javascript на сервер та відправлення google bot отриманий html. Коли бот розбирає html, він може потрапити на ваші інші посилання "pushState" / деяку сторінку на сервері <a href="https://stackoverflow.com/someotherpage">mylink</a>, сервер переписує URL у файл вашої програми, завантажує його у phantom.js, а отриманий html надсилається боту тощо. ..
  • Для вашого html я припускаю, що ви використовуєте звичайні посилання з певним викраденням (наприклад, з backbone.js https://stackoverflow.com/a/9331734/1595913 )
  • Щоб уникнути плутанини з будь-якими посиланнями, розділіть свій код api, який обслуговує json, на окремий піддомен, наприклад, api.mysite.com
  • Для підвищення продуктивності ви можете попередньо обробити сторінки свого веб-сайту в пошукових системах заздалегідь у неробочий час, створюючи статичні версії сторінок, використовуючи той самий механізм, що і phantom.js, і, отже, обслуговувати статичні сторінки для Google-ботів. Попередню обробку можна виконати за допомогою простого додатка, який може розбирати <a>теги. У цьому випадку обробка 404 простіша, оскільки ви можете просто перевірити наявність статичного файлу з іменем, що містить шлях до URL-адреси.
  • Якщо ви використовуєте #! Синтаксис хеш-бангу для вашого веб-сайту посилається на аналогічний сценарій, за винятком того, що механізм перезапису URL-сервера буде шукати _escaped_fragment_ в URL-адресі та відформатує URL-адресу у вашу URL-схему.
  • Існує пара інтеграцій node.js з phantom.js на github, і ви можете використовувати node.js як веб-сервер для отримання HTML-виводу.

Ось кілька прикладів використання phantom.js для seo:

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

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


4

Якщо ви використовуєте Rails, спробуйте пуаро . Це дорогоцінний камінь, який робить мертвим простим повторне використання вусів або рульових шаблонів на стороні клієнта та сервера.

Створіть файл у своїх поданнях, як _some_thingy.html.mustache.

Сторінка сервера візуалізації:

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

Покладіть шаблон головою для використання клієнта:

<%= template_include_tag 'some_thingy' %>

Rendre сторона клієнта:

html = poirot.someThingy(my_model)

3

Якщо взяти дещо інший кут, ваше друге рішення було б правильним з точки зору доступності ... ви б надавали альтернативний вміст користувачам, які не можуть використовувати javascript (тих, у яких є зчитувачі екранів тощо).

Це автоматично додасть переваги SEO та, на мою думку, Google не сприйматиметься як «неслухняна» техніка.


А хтось довів, що ви помиляєтесь?
Минув

1

Цікаво. Я шукав життєздатні рішення, але це здається досить проблематичним.

Я насправді більше схилявся до вашого другого підходу:

Нехай сервер надає спеціальний веб-сайт лише для ботів пошукової системи. Якщо звичайний користувач відвідує http://example.com/my_path, сервер повинен надати йому важку версію веб-сайту JavaScript. Але якщо бот Google відвідує, сервер повинен дати йому мінімальний HTML із вмістом, який я хочу, щоб Google проіндексував.

Ось мій погляд на вирішення проблеми. Незважаючи на те, що він не підтверджений, він може дати деяку інформацію чи ідею для інших розробників.

Припустимо, що ви використовуєте структуру JS, яка підтримує функцію "push state", а ваш сервер - "Ruby on Rails". У вас простий веб-сайт блогу, і ви хочете, щоб пошукові системи індексували всі ваші статті indexта showсторінки.

Скажімо, у вас такі маршрути налаштовані так:

resources :articles
match "*path", "main#index"

Переконайтесь, що кожен контролер на стороні сервера надає той самий шаблон, який потрібно запускати на вашій стороні клієнта (html / css / javascript / тощо). Якщо жоден з контролерів не відповідає в запиті (у цьому прикладі ми маємо лише RESTful набір дій для ArticlesController), то просто зіставіть що-небудь інше і просто візуалізуйте шаблон і дозвольте на стороні клієнта фреймворк обробляти маршрутизацію. Єдиною різницею між натисканням на контролер та попаданням у відповідність підстановочних кодів було б можливість візуалізувати вміст на основі URL-адреси, яку вимагали пристрої з відключеною JavaScript.

Наскільки я розумію, погана ідея відтворювати вміст, який не видно браузерам. Тож коли Google проіндексує це, люди проходять через Google, щоб відвідати певну сторінку, а вмісту немає, тоді ви, мабуть, будете штрафовані. Що вам спадає на думку, це те, що ви перетворюєте вміст у divвузол, який ви display: noneзнаходитесь у CSS.

Однак я впевнений, що це не має значення, якщо ви просто зробите це:

<div id="no-js">
  <h1><%= @article.title %></h1>
  <p><%= @article.description %></p>
  <p><%= @article.content %></p>
</div>

А потім за допомогою JavaScript, який не запускається, коли пристрій, відключений JavaScript, відкриває сторінку:

$("#no-js").remove() # jQuery

Таким чином, для Google та для всіх, хто має пристрої з відключеною JavaScript, вони побачать сировинний / статичний вміст. Таким чином, вміст є фізично і його можна побачити всім, хто не має JavaScript.

Але, коли користувач відвідує тій же сторінці і на самому справі був включений JavaScript, то #no-jsвузол буде видалений , так що не захаращувати вашу програму. Тоді ваша система клієнта буде обробляти запит через його маршрутизатор і відображати, що повинен бачити користувач, коли ввімкнено JavaScript.

Я думаю, що це може бути дійсною та досить простою технікою. Хоча це може залежати від складності вашого веб-сайту / програми.

Хоча, будь ласка, виправте мене, якщо це не так. Просто думав, що поділюся своїми думками.


1
Ну, якщо ви спочатку відображаєте вміст і трохи пізніше видаляєте його, то, швидше за все, кінцевий користувач може помітити, що вміст блимає / мерехтить у його браузері :) Особливо якщо це повільний браузер, величезний розмір вмісту HTML, який ви намагаєтеся відобразити / видалити, а також деякі затримка до завантаження та виконання вашого коду JS. Що ти думаєш?
Evereq

1

Використовуйте NodeJS на стороні сервера, перегляньте код свого клієнта та прокладіть маршрутизацію кожного http-запиту (за винятком статичних http-ресурсів) через сервер-клієнт, щоб надати першу «завантажувальну картинку» (знімок сторінки, в якій вона знаходиться). Використовуйте щось на зразок jsdom для обробки jquery dom-ops на сервері. Після повернення валянки встановіть підключення до веб-розетки. Можливо, найкраще розмежувати клієнт веб-розетки та клієнт серверної сторони, зробивши якесь обгорткове з'єднання на стороні клієнта (клієнт сервер може безпосередньо спілкуватися з сервером). Я працював над чимось подібним: https://github.com/jvanveen/rnet/


0

Використовуйте шаблон закриття Google для візуалізації сторінок. Вона компілюється у javascript або java, тому легко візуалізувати сторінку на стороні клієнта чи сервера. Під час першої зустрічі з кожним клієнтом виведіть html та додайте javascript як посилання у заголовку. Сканер буде читати тільки HTML, але браузер виконує ваш сценарій. Усі наступні запити браузера можуть бути виконані проти api, щоб мінімізувати трафік.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.