Currently, my application runs on Backbone.js.
The application works fine with the #
fragments but it is not crawlable by Google bots because of the #
in the URL.
So, I decided to remove the #
to make it more SEO friendly. I enabled the History pushState API and added code to prevent the default action. Here is the code snippet that I have while I initialize my router instance.
Backbone.history.start({pushState: true});
$(document).on("click", "a", function(e)
{
var href = $(e.currentTarget).attr('href');
var res = Backbone.history.navigate(href,true);
//if we have an internal route don't call the server
if(res)
e.preventDefault();
});
Also, I modified my Apache config to enable mod_rewrite in order to process stateless requests like refreshing the page or opening the page into a new browser window. Here is my Apache config snippet:
<IfModule mod_rewrite.c>
RewriteEngine on
RewriteRule ^/([a-zA-Z0-9]+)[/]?$ /index.html?pathtyped=$1 [QSA,L]
</IfModule>
The problem that I’m facing is that the Application works just fine with short url fragments but they do not work with large fragments. Meaning the follwoing urls work:
http:server_name/#view1
-> http:server_name/view1
http:server_name/#view2
-> http:server_name/view2
http:server_name/#view3
-> http:server_name/view3
But the url with long fragments do not work. (The following don’t work):
http:server_name/#view1/option1
-> http:server_name/view1/option1
http:server_name/#view2/option1/option2
-> http:server_name/view2/option1/option2
Any suggestions to solve the problem are highly appreciated. Thanks you!
3
Answers
Hm…maybe this is helpful (based on phantomJS) : http://traviswimer.com/blog/backbone-seo
I did a bit of Googling and eventually stumbled onto this gist. I tested it out with a minimal Backbone.js app and it seems to support infinitely long stateless entrance into the app:
I had to do a bit of reading to fully understand the
RewriteCond
statements, specifically what!-f
,-d
, and!index
are doing. Everything but the!index
makes sense.Give it a shot and let me know if it works for you.
Edit: I actually found the above to only work on my Homebrew-installed version of Apache2 on my Mac and not on Debian. Some more Googling yielded this alternative form:
I also put together a fully-worked example of a modern Backbone.js app with pushState and stateless entry here.
I’m guessing that the application works in a single URL component scenario like
http://server_name/viewX
because theBackbone.Router
you have defined matches the URL and successfully and makes the callback defined to renderviewX
(without the#
for modern browsers and web crawlers, and with it for older browsers). So, when it doesn’t work, I would imagine that the defined route patterns are not matching the nested URL components as expected, and the rendering callback is not fired.You might have a look at your
Backbone.Router.routes
hash and be sure your patterns are matching the expected URL components at each depth. Have a look at the Backbone documentation on routes, particularly the example on optional and nested URL components, and check that your matching pattern is correct. For instance, a routes hash containing:should match URLs starting with
view
(or#view
) and optionally containing one or two sub parameters, like:view/1
view/1/a
#view/1
#view/1/a
and in the above examples,
option1
would be assigned1
, andoption2
would be assigneda
, and would be passed to the callback.With a route hash like:
everything beyond the first
/
would match and be assigned tooption1
, like:view/1/a
#view/1/a
In both cases above,
option1
would be assigned the string1/a
, and would be passed to the callback.