How Can a SPA Website Be SEO-Friendly Without Hashbang Urls?

asked at stackoverflow.com

"What I don't understand is, how would you be search engine friendly without using hashbang?"

My answer:

With my custom javascript/php solution to make the search engines load a static version of every page on their respective visits while allowing for SPA navigation for site visitors, we can achieve the supposedly impossible - seo-friendly SPA navigation without #!.  If you navigate this website, you will notice that pages do not actually load in the traditional sense.  This is obvious when you click on links in the drop down menu Pages above - notice how the menu does not disappear on page load if you keep yor mouse hovered over the menu, yet the uri changes in the address bar, which is generated using the HTML5 pushState() 

history.pushState({page:href}, '', href);

I prepare my a tags with:


function prepareAnchors(){
  var h,s,dhref;
  $('a').each(function(value){
    h = $(this).attr('href');
   if(h){
      s = h.substr(0,4);
      if(s !== 'http'){
        if(s[0] === '/'){//allow use of leading slash in url
          dhref = h.substr(1,150);
        } else {
          dhref = h;
        }
        if(!$(this).hasClass('pop')){
          $(this).addClass('menu').attr('data-href',dhref);
        }
      } else {
        $(this).attr('target','_blank');// autoload other websites in a new tab/window
      }
    }
  });
}

The loadPage() function which has a php counterpart in router.php to load the requested uri statically for Search Engines:


function loadPage($data){
  var seg = $data.split('-'); // for spa page views
  $.ajax({
    url:'/ajax/loadPage/',
    type:'post',
    dataType:'json',
    data:{
      page:$data
    }
  }).success(function(response){
    $('body').scrollTop(0);
    var heading = response.heading;
    var body = response.body;

    $('#main').html('<div id="'+$data+'" class="container white">'+
      '<div class="page-header">'+
      '<h1>'+heading+'</h1>'+
      '</div>'+
      '<div id="'+$data+'-div" class="under-heading">'+body+'</div>'+
      '</div>').show();
    prepareAnchors();// this must come before the following $('a.menu').on("click"...    
    
    $('a.menu').on("click", function(evt) {
      /* exterior links must not get the class 'menu'
       * in fact, no links get the class 'menu' unless they start with a slash
       * so all external links must start with http(s)
       * 
       * this must be located within the success function to work 
       * due to content (links to internal views) 
       * being loaded via ajax here
       * not for the main menu items or external links but
       * no need to repeat this as it works for both here 
       */
      evt.preventDefault();
    });
  });
}

Load spa navigation (clicks on a class="menu")


   $(document).on('click','a.menu',function(){
      href = $(this).attr("data-href");
      history.pushState({page:href}, '', href);// no slashes in url
      loadPage(href);
   });

Now to prevent back and forward brtowser button clicks from reloading the page, but load the history:


   $(window).on('popstate', function(event){
      var state = event.originalEvent.state;
      loadPage(state.page);
   });

Search engines that do not generally understand javascript read and follow the  href:

Since I no longer use any directory delimiters (/) in my urls, the leading slash can be eliminated 

href="how-can-a-spa-website-possibly-be-seo-friendly-without-hashbang-urls"

My visitors enjoy the benefit of ignoring the href (for SPA navigation) with the following bit of code:

$('a.menu').on("click", function(evt) {
    evt.preventDefault();
});

This scenario has the added side effect of being available to those with Javascript truned off, except that they will be unable to submit any forms.

This is customizable for any kind of site.  Hit me up for some custom programming via my contact form