it-swarm.asia

"صفحة واحدة" JS المواقع وكبار المسئولين الاقتصاديين

هناك الكثير من الأدوات الرائعة لإنشاء مواقع ويب جافا سكريبت قوية ذات الصفحة الواحدة هذه الأيام. في رأيي ، يتم ذلك بشكل صحيح من خلال السماح للخادم بالعمل كواجهة برمجة تطبيقات (وليس أكثر من ذلك) والسماح للعميل بمعالجة جميع مواد إنشاء HTML. المشكلة في هذا "النمط" هي قلة دعم محرك البحث. يمكنني التفكير في حلين:

  1. عندما يدخل المستخدم إلى موقع الويب ، اسمح للخادم بعرض الصفحة تمامًا كما يفعل العميل عند التنقل. لذلك إذا ذهبت إلى http://example.com/my_path مباشرةً ، فسيظهر الخادم نفس الشيء الذي سيظهره العميل إذا انتقلت إلى /my_path عبر pushState.
  2. اسمح للخادم بتوفير موقع ويب خاص فقط لروبوتات محرك البحث. إذا قام مستخدم عادي بزيارة http://example.com/my_path ، فيجب أن يقدم له الخادم نسخة جافا سكريبت الثقيلة من موقع الويب. ولكن في حالة زيارة برنامج Google bot ، يجب على الخادم تزويده ببعض الحد الأدنى من HTML مع المحتوى الذي أرغب في فهرسة Google له.

الحل الأول هو مزيد من المناقشة هنا . لقد كنت أعمل على موقع على شبكة الإنترنت أفعل ذلك ، وهي ليست تجربة رائعة جدًا. إنه ليس DRY وفي حالتي ، كان علي استخدام محركي قوالب مختلفين للعميل والخادم.

أعتقد أنني رأيت الحل الثاني لبعض المواقع الإلكترونية الجيدة لـ ol. تعجبني هذه الطريقة أكثر من الطريقة الأولى ، وباستخدام الأداة المناسبة على الخادم ، يمكن القيام بذلك دون أي ألم.

إذن ما أتساءل حقاً هو ما يلي:

  • هل يمكنك التفكير في أي حل أفضل؟
  • ما هي عيوب الحل الثاني؟ إذا اكتشفت Google بطريقة أو بأخرى أنني لا أخدم نفس المحتوى المحدد لبوت الروبوت كمستخدم عادي ، فهل سأعاقب في نتائج البحث؟
128
user544941

في حين أن # 2 قد يكون "أسهل" بالنسبة لك كمطور ، إلا أنه يوفر الزحف إلى محرك البحث فقط. ونعم ، إذا اكتشفت Google تقديم المحتوى المختلف الخاص بك ، فقد تتم معاقبتك (لست خبيرًا في ذلك ، لكنني سمعت بحدوث ذلك).

تتمتع كل من مُحسنات محركات البحث (SEO) وإمكانية الوصول (ليس فقط للأشخاص ذوي الإعاقة ، ولكن إمكانية الوصول عبر الأجهزة المحمولة وأجهزة الشاشات التي تعمل باللمس وغيرها من الأنظمة الأساسية غير المعتمدة للحوسبة/الإنترنت) بفلسفة أساسية متشابهة: ترميز غني بشكل كبير "يمكن الوصول إليه" (أي يمكن يمكن الوصول إليها أو عرضها أو قراءتها أو معالجتها أو استخدامها بطريقة أخرى) لجميع هذه المتصفحات المختلفة. يجب أن يكون كل من قارئ الشاشة ، أو متتبع ارتباطات محرك بحث أو مستخدمًا به JavaScript ممكناً ، قادرًا على استخدام/فهرسة/فهم الوظائف الأساسية لموقعك دون مشكلة.

pushState لا يضيف إلى هذا العبء ، في تجربتي. إنه يجلب فقط ما اعتاد أن يكون فكرة لاحقة و "إذا كان لدينا وقت" في طليعة تطوير الويب.

ما تصفه في الخيار رقم 1 هو عادةً أفضل طريقة للذهاب - ولكن ، مثل مشكلات الوصول وكبار المسئولين الاقتصاديين الأخرى ، فإن القيام بذلك باستخدام pushState في تطبيق جافا سكريبت الثقيل يتطلب تخطيطًا مقدمًا أو سيصبح عبئًا كبيرًا. يجب إدخاله في بنية التطبيق والتطبيق من البداية - التعديل التحديثي مؤلم وسيؤدي إلى تكرار أكثر مما هو ضروري.

لقد كنت أعمل مع 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 الخاصة بي. هذا يقلل من الازدواجية في العلامات بين جانب الخادم وجانب العميل.

من هناك ، تحتاج إلى اتخاذ بعض الخطوات الإضافية لجعل جافا سكريبت لديك يعمل مع HTML الذي يتم تقديمه بواسطة الخادم - تحسين تدريجي حقيقي ؛ أخذ العلامات الدلالية التي تم تسليمها وتحسينها باستخدام جافا سكريبت.

على سبيل المثال ، أقوم بإنشاء تطبيق لمعرض الصور باستخدام pushState. إذا طلبت /images/1 من الخادم ، فستعرض معرض الصور بأكمله على الخادم وترسل كل HTML و CSS و JavaScript إلى متصفحك. إذا تم تعطيل جافا سكريبت ، فسوف يعمل بشكل جيد. سيطلب كل إجراء تقوم به عنوان URL مختلفًا عن الخادم وسيعرض الخادم كل الترميز لمتصفحك. إذا قمت بتمكين جافا سكريبت ، على الرغم من ذلك ، ستقوم JavaScript بالتقاط HTML المقدم بالفعل مع بعض المتغيرات التي تم إنشاؤها بواسطة الخادم وتتولى من هناك.

إليك مثال:

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

بعد أن يعرض الخادم هذا ، فإن جافا سكريبت ستلتقطه (باستخدام طريقة عرض 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> وإرفاق كائن عرض مع النموذج الصحيح لكل منها. يقوم بإعداد معالج حدث لحدث تغيير اسم النموذج وتحديث النص المعروض للعنصر عند حدوث تغيير.


هذا النوع من العمليات ، لأخذ أتش تي أم أل الذي قدمه الخادم وتفعيل جافا سكريبت وتشغيله ، هو طريقة رائعة لجعل الأمور تتدفق من أجل تحسين محركات البحث (SEO) وإمكانية الوصول ودعم pushState.

امل ان يساعد.

44
Derick Bailey

أعتقد أنك بحاجة إلى هذا: http://code.google.com/web/ajaxcrawling/

يمكنك أيضًا تثبيت خلفية خاصة "تعرض" صفحتك عن طريق تشغيل javascript على الخادم ، ثم تخدم ذلك في google.

اجمع بين الأمرين ولديك حل دون برمجة الأشياء مرتين. (طالما أن التطبيق الخاص بك يمكن التحكم فيه تمامًا عبر أجزاء التثبيت).

22
Ariel

لذلك ، يبدو أن الشاغل الرئيسي هو جفاف

  • إذا كنت تستخدم pushState ، فاطلب من الخادم الخاص بك إرسال نفس الرمز الدقيق لجميع عناوين url (التي لا تحتوي على امتداد ملف لخدمة الصور ، وما إلى ذلك) "/ mydir/myfile" ، "/ myotherdir/myotherfile" أو الجذر "/ "- تتلقى جميع الطلبات نفس الرمز الدقيق. تحتاج إلى أن يكون لديك نوع إعادة كتابة محرك url. يمكنك أيضًا تقديم جزء صغير جدًا من html ويمكن أن يأتي الباقي من CDN (باستخدام require.js لإدارة التبعيات - راجع https://stackoverflow.com/a/13813102/1595913 ).
  • (اختبر صلاحية الرابط من خلال تحويل الرابط إلى نظام url الخاص بك والاختبار مقابل وجود محتوى عن طريق الاستعلام عن مصدر ثابت أو حيوي. إذا لم يكن صحيحًا ، فأرسل استجابة 404.)
  • عندما لا يكون الطلب من google bot ، فأنت فقط تعالج بشكل طبيعي.
  • إذا كان الطلب من برنامج google bot ، فأنت تستخدم phantom.js - متصفح الويب بدون رأس ( "متصفح مقطوع الرأس هو ببساطة متصفح ويب كامل المواصفات بدون واجهة مرئية." ) لتقديم html و javascript على الخادم وإرسال جوجل بوت أتش تي أم أل الناتجة. نظرًا لأن البوت يوزع لغة تأشير النص الفائق html ، فإنه يمكن أن يصل إلى روابط/صفحة "pushState" الأخرى على الخادم <a href="/someotherpage">mylink</a> ، يعيد الخادم كتابة عنوان url إلى ملف التطبيق الخاص بك ، ويقوم بتحميله في phantom.js ، ويتم إرسال html الناتج إلى bot ، وهكذا ...
  • بالنسبة إلى html الخاص بك ، أفترض أنك تستخدم روابط عادية مع نوع من عمليات الاختطاف (على سبيل المثال استخدام مع backbone.js https://stackoverflow.com/a/9331734/1595913 )
  • لتجنب الالتباس مع أي روابط ، قم بفصل شفرة api التي تخدم json في نطاق فرعي منفصل ، على سبيل المثال api.mysite.com
  • لتحسين الأداء ، يمكنك معالجة صفحات موقعك مسبقًا لمحركات البحث مسبقًا قبل ساعات العمل عن طريق إنشاء إصدارات ثابتة للصفحات باستخدام نفس الآلية مع phantom.js ومن ثم تقديم الصفحات الثابتة إلى برامج google. يمكن إجراء المعالجة المسبقة باستخدام بعض التطبيقات البسيطة التي يمكنها تحليل علامات <a>. في هذه الحالة ، يكون التعامل مع 404 أسهل نظرًا لأنه يمكنك ببساطة التحقق من وجود الملف الثابت باسم يحتوي على مسار url.
  • إذا كنت تستخدم #! يطبق بناء جملة has bang لموقعك سيناريو مشابهًا ، فيما عدا أن محرك خادم 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

17
Leonidaz

إذا كنت تستخدم Rails ، فحاول poirot . إنها جوهرة تجعل من السهل إعادة استخدام الشارب أو المقاود العميل والقوالب جانب الخادم.

قم بإنشاء ملف في طرق العرض الخاصة بك مثل _some_thingy.html.mustache.

تقديم جانب الخادم:

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

ضع القالب الخاص بك للاستخدام من جانب العميل:

<%= template_include_tag 'some_thingy' %>

جانب العميل Rendre:

html = poirot.someThingy(my_model)
4
Tim Scott

لاتخاذ زاوية مختلفة قليلاً ، سيكون الحل الثاني هو الحل الصحيح من حيث إمكانية الوصول ... ستوفر محتوى بديلاً للمستخدمين الذين لا يمكنهم استخدام javascript (أولئك الذين لديهم قارئات شاشة ، إلخ).

سيؤدي هذا تلقائيًا إلى إضافة فوائد مُحسّنات محرّكات البحث ، وفي رأيي ، لن يُنظر إلى Google على أنها تقنية "غير مطيع".

3
Clive

مثير للإعجاب. لقد كنت أبحث في جميع أنحاء عن حلول قابلة للحياة ولكن يبدو أن مشكلة كبيرة.

كنت أميل فعلاً نحو نهجك الثاني:

اسمح للخادم بتوفير موقع ويب خاص فقط لروبوتات محرك البحث. إذا قام مستخدم عادي بزيارة http://example.com/my_path يجب أن يعطيه الخادم نسخة جافا سكريبت الثقيلة من موقع الويب. ولكن في حالة زيارة برنامج Google bot ، يجب على الخادم تزويده ببعض الحد الأدنى من HTML مع المحتوى الذي أرغب في فهرسة Google له.

إليكم حل المشكلة. على الرغم من عدم تأكيد العمل ، إلا أنه قد يوفر بعض الأفكار أو الأفكار للمطورين الآخرين.

افترض أنك تستخدم إطار عمل JS يدعم وظيفة "حالة الدفع" ، وأن إطار عمل الواجهة الخلفية لديك هو Ruby on Rails. لديك موقع مدونة بسيط وتريد أن تقوم محركات البحث بفهرسة جميع صفحات مقالاتك index و show.

دعنا نقول أن لديك طرقك مثل هذا:

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

تأكد من أن كل وحدة تحكم من جانب الخادم تعرض نفس القالب الذي يتطلبه إطار جانب العميل لتشغيله (html/css/javascript/etc). إذا لم تتم مطابقة أي من وحدات التحكم في الطلب (في هذا المثال ، لدينا فقط مجموعة من الإجراءات المناسبة لـ 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.

ولكن ، عندما يزور المستخدم الصفحة نفسها ويمكّن has جافا سكريبت JavaScript ، ستتم إزالة العقدة #no-js حتى لا تشوش تطبيقك. بعد ذلك ، سيقوم إطار جانب العميل بمعالجة الطلب من خلال جهاز التوجيه الخاص به ويعرض ما يجب على المستخدم رؤيته عند تمكين JavaScript.

أعتقد أن هذا قد يكون وسيلة صالحة وسهلة الاستخدام إلى حد ما. على الرغم من أن هذا قد يعتمد على تعقيد موقع الويب الخاص بك/التطبيق.

رغم ذلك ، يرجى تصحيح لي إذا لم يكن كذلك. فقط أعتقد أنني سوف أشارك أفكاري.

1
Michael van Rooijen

استخدم NodeJS على جانب الخادم ، وتصفح رمز عميلك وقم بتوجيه uri لكل طلب http (باستثناء موارد http الثابتة) من خلال عميل جانب الخادم لتوفير أول "bootnap" (لقطة من الصفحة التي تظهر حالتها). استخدم شيءًا مثل jsdom للتعامل مع jquery dom-ops على الخادم. بعد إرجاع bootsnap ، قم بإعداد اتصال websocket. ربما يكون من الأفضل التمييز بين عميل websocket والعميل serveride عن طريق إجراء نوع من اتصال مجمّع على clientide (يمكن العميل serveride التواصل مباشرة مع الخادم). كنت أعمل على شيء مثل هذا: https://github.com/jvanveen/rnet/

1
Phrearch

استخدم قالب إغلاق Google لعرض الصفحات. يتم تجميعها إلى جافا سكريبت أو جافا ، لذلك من السهل تقديم الصفحة إما على العميل أو الخادم. في أول مواجهة مع كل عميل ، قم بتقديم html وإضافة javascript كارتباط في الرأس. سيقوم برنامج الزاحف بقراءة ملف html فقط ، لكن المتصفح سينفذ البرنامج النصي. يمكن إجراء جميع الطلبات اللاحقة من المستعرض مقابل api لتقليل حركة المرور.

0
Aleš Kotnik