I'm in the middle of making this choice right now and I don't know what kinds of questions I should be asking. One that I believe is valid:
- Do I need SEO / natively crawlable pages? If so, stick with MVC4.
One question that I'm not sure about is the impact on performance - I think this is valid:
- Is initial load time very important? If so, stick with MVC4 (like stackoverflow).
What are some other questions that should be asked that can help point a developer in the right direction here?
PS - if this question is being asked in a way that doesn't meet quality standards, I'd appreciate any help modifying it so that it does.
I have been asked and had to be a part of decision making groups recently that made this same decision. Here is what was important for us -
- How many of the devs that will be working are familiar with MVC4 vs Javascript?
- How much is performance an issue? (Is single page app really necessary?)
- How big is the data we will be working with? (Remember that extremely large data sets don't work well in a spa)
- Durandal requires using a lot of different libraries - is it ok to have to learn each of the different usages? Each library is important in its own regard and you must know when and why to use each library.
- Angular is very set in its ways and harder for a new javascript dev coming from c# and .net to understand, are you willing to provide time for learning?
- Last, which browsers are you targeting? Ie6+ works great with mvc4 and durandal, angular needs some massaging.
Hope this is helpful!
Why not combine the best of both worlds? SPA and straight MVC!
I was also investigating a lot of time in durandal, sammyjs, angular frameworks. I then decided to go with sammy.js for just the routing. This way I could still make use of the easy MVC 4 razor view engine to generate my views at server side. Even though it would be more performant to generate your html and bindings at client side by using knockout, I felt more secure by doing this at the server side.
But then of course you have to deal with those hashbangs? Therefor I started to investigate more time into the history.js (or HTML 5 history API). And then things got clear to me.
My solution
What is the essential part of a SPA? Well, in fact, that your layout.cshtml is only loaded once right. From then on you you only want to load content from the server and display it in the main content div. Does it need to be json? No, in fact it does not.
By default MVC 4 controllers returns an html string. So what if your < a href="">< /a> tags would be intercepted by a simple jQuery script to get the html string from the controller and load it into a div.
I went even further and wrote my own jQuery engine on top of the HTML 5 history api. I just intercept every link that is clicked and load the content from its href attribute and then place it into the desired div. Further I push the URL with history api pushSate. Another big advantage of this approach is that your application is not broken when javascript is disabled or when HTML 5 is not supported.
My views have the following layout page:
@{
Layout = Request.IsAjaxRequest() ? null : "~/Views/Shared/_Layout.cshtml";
}
This way when javascript is disabled or html 5 is not supported, the view will render inside the _Layout.cshtml.
This also allows for URL linking. The link will hit the address bar and will be routed to the controller. As this is not an ajax request, the view will render with _Layout.cshtml.
But once your _Layout.cshtml and javascript is loaded correctly and once, all < a href="">< /a> will be intercepted, loaded by AJAX (partial with layout = null) into the content div and the url is pushed on the address bar. So it seems that you are at that location, but in fact you are not. It's just an illusion to make things more responsive and efficient. Et voila, SPA in straight MVC.
The minimum routing code would be something like this
Interception of Links
$('.spalink').click(function () {
$.ajax({
url: this.href,
success: function (content) {
$('body>#content').css({ opacity: 0 });
$('body>#content').html(content);
$('body>#content').animate({ opacity: 1 }, 300, 'swing');
history.pushState({ state : 'spa' }, null, this.href);
}
});
return false;
});
BACK and FORWARD event
window.addEventListener("popstate", function (e) {
if (e.state != null) {
$.ajax({
url: location.href,
success: function(content) {
$('body>#content').css({ opacity: 0 });
$('body>#content').html(content);
$('body>#content').animate({ opacity: 1 }, 300, 'swing');
},
cache: false
});
return false;
}
});
return true;
}
PS: if you don't feel like writing your own SPA engine, take a look at history.js (it does the same out of the box)
Ajaxify on top of History.js on top of HTML 5 history API