Nginx and Apache rewrites to support HTML5 Pushstate in pure Backbone.js (or other JS MV*) Application.
Posted on May 17th, 2012 in Apache, backbone, nginx | 4 Comments »
HTML5 pushstate is awesome. It enables you to change the URL of your site dynamically without refreshing the page (goodbye hashes!). Libraries like Backbone have great support for this. Unfortunately if a user bookmarks or refresh a page on an app that’s using HTML5 pushstate, it makes a request to the server for that deep linked content. Here are the rewrites for Nginx and Apache to internally redirect that call to the same html file. Browser thinks its a unique page but it’s the same.
Apache
In your vhost
<IfModule mod_rewrite.c> RewriteEngine On RewriteBase / RewriteRule ^index\.html$ - [L] RewriteCond %{REQUEST_FILENAME} !-f RewriteCond %{REQUEST_FILENAME} !-d RewriteRule . /index.html [L] </IfModule>
Nginx
rewrite ^(.+)$ /index.html last;
Note that once you have this in place your server no longer reports 400 errors as all requests pull up the index page. To work around this you can create a 404 in a Backbone route:
routes: { // Other routes "*path" : "notFound" }, notFound: function(path) { // Load 404 template, probably of a cute animal. }
4 Responses
If you are using any modern MVC framework, it should be trivial to simply map all requests to the correct controller\action. I’m doing this on a Rails project right now and I like it because it places the logic in the app instead of in the server and leaves less to worry about when deploying.
Great point, Bryan. I guess I didn’t add real context to this post. These kind of Nginx-level rewrites are really for backend-independent JavaScript application frameworks as most the apps I’ve been writing lately have been straight Backbone.js which harness backend as API calls on the same or different server. The Apache version of the rewrites are for local dev environments as most developers are most familiar with that and already have it installed.
Doing it this way enables me to decouple my backend from my front and allows me to put 95% of the entire application compressed and gzipped on the CDN sittin’ cool as a cucumber. The only servers I need to worry about scaling are the API servers, and I don’t require the overhead of loading an entire backend application stack just to load a static html file.
To target those few pages that require SEO (or Facebook sharing), I also use Nginx to serve seo friendly version when those deep links get hit directly (outside of HTML5 pushsate). I use Node Express which I’m working on getting to understand my Backbone routes and templates directly without much extra coding.
How are Ajax requests for dynamic resources handled, won’t they also be redirected to ‘index.html’? Is there a way to ignore requests that are made from Ajax?
Schmulik, I usually put API calls into its own domain served by the same or different web server, for example api.domain.com. I use CORS to support this but also have a work around domain.com/api/ for browsers that don’t support CORS.