So you’ve got a new project you want to build and you’re going to pick a front-end javascript framework. First make sure you absolutely need the single page application. Chances are you can do without it. However, let’s say you want to do a lot of javascript client-side intensive stuff, then how should you decide what framework to use? I’ve been in this same scenario myself multiple times, so I decided to blog about it. I have a love-hate relationship with all 3 of these frameworks because I have used all of them on work and personal projects. I only focus on client side frameworks here, not server side, e.g. meteor, sailsjs, express. I only included the frameworks I have the most experience with.
Angular
If I’ve already got a server side page built and I just want to fancy up the UX with some dynamic features, e.g. - adding a new text box when I push a button, this is super simple with ng bindings.
Two way data-binding is pretty awesome. If we couple this with $resource
or $http
then we have simple model-view layer with persistence with very little effort.
Dependency injection keeps the code nice and clean but it sucks that you end up having to attach a bunch of extra strings to your controllers just so you can minify code and not break things.
Creating a custom directive for an existing jquery plugin. I can go download a jquery plugin like jquery.colorwheel.js and have this thing up and running in minutes. But not if I have to go write an angular directive for it - I already deal with too many 3rd party plugins as it is without having to write my own angular interfaces for them.
Routing in angular is a pain to me. I don’t like the ngRoute service and I have to go study the docs just for routes. Angular seems to work better for me when I let the server-side tackle routing.
Obtrusive javascript is somewhat of a code smell to me. Sure it is easy to use but it still couples the presentation layer (html page) with logic. If you think about it, <button ng-click="foobar">
and <button onclick="foobar">
are both still obtrusive.
Ember
How easy it is to get going. For me, Ember comes the closest to behaving like a server-side MVC framework. You have routes, controllers, views, models, etc.
Naming conventions are very nice. If you follow the standard naming conventions which are very similar to Rails, then it makes coding with Ember so much easier.
Handlebar templating is what I primarily use. However what if I wanted to switch this to a different templating language? I hear HTMLbars will solve a lot of problems with Handlebars.
Chrome dev tools integration is very very awesome. It helps me speed up troubleshooting and I have a clear picture of what is going on inside my application just be inspecting chrome tools. Angular has one of these tools as well, but I haven’t used it all that much.
Tom Dale and Yehuda Katz are programming heroes of mine. We all have developers that we listen closely to what they have to say. These guys are very opinionated about their development styles
Testing in ember is not an after-thought. The guys have documentation and examples. I have played with karma, jasmine and phantomjs and a framework that promotes BDD or TDD is pretty awesome in my opinion. The guys at angular use testacular so they get + points for that.
Ember community in IRC (irc.freenode.net #emberjs) is very helpful. I have found that #emberjs has more activity than #angular and #documentcloud and these guys are pretty helpful.
Ember is very promising. To me this framework seems to be the most promising. It still has a lot of things to figure out and is still a bit unstable but with HTMLbars on the rise and the level of awareness this framework has gotten in the past year, I know Ember is just going to keep getting better and better.
My biggest complaint is how difficult it is to bring in a jquery plugin. This probably needs some explanation. Let’s use jquery.chosen plugin as an example.
First, checkout this jsbin example I made using chosen plugin.
Like many other jquery plugins, the chosen plugin manipulates the DOM which ultimately means that we can’t call $('element').chosen()
until after
- the models have been fetched
- and the handlebar template rendered into DOM
So at what stage do you call the chosen plugin in Ember? In Marionette, this is trivial as we have this nifty little hook called onRender
where we can setup a jquery plugin once a view has rendered.
Scourging through documentation and stackoverflow pages and pestering people on IRC, I finally find there is a function called didInsertElement
along with
Ember.run.scheduleOnce('afterRender',this, this.onRender)
which seem to work great - except if you don’t change routes this never executes! This is all very confusing to me.
After some searching I find some options from some random blog on the internet. On top of this, because Ember junks up your DOM with <script> tags then it later pollutes the DOM so you have to modify the chosen.js source code to ignore that. Now I decide I want the ability to bring in custom tags so I need to switch to select2.js and I am in the same boat again. Lots of frustration here just to bring in a simple jquery plugin.
Lastly, I could just pray that some poor unforunately soul has had this same exact frustration has me and created a special handlebars helper or something (which sure enough one exists).
Having a simple process like onRender
that is called anytime a view and using an unobtrustive templating engine like HTMLbars will be a game changer for me. We have to remember that single page applications are very likely to have lots of 3rd party plugins in them.
If you have a jquery plugin that messes with the DOM (which most do), then chances are you are going to bang your head against the wall at least once trying to get Ember to work with it.
Putting logic in handlebars views makes things difficult. This isn’t really Ember’s fault but it is pretty easy to create some crazy wicked nested views full of #if #else and eventually you find yourself tracing through handlebar templates and cursing it simultaneously.
Emberscript pre-compliation is a custom fork of coffeescript and can be buggy. Writing annotations just to save several lines of code and then running through several stages of pre-compliation is not my ideal workflow for writing javascript applications. I prefer a generator over annotations any day because:
I prefer 20 lines of simple, readable code over 5 lines of complex code.
Marionette
Composite style architecture can scale. You can write 100k line of code applications with Marionette. Modules which can be dynamically included/excluded, a lot like operating system. Derick Bailey is another one of my programming heroes and knows the importance of architecture.
Marionette stays out of my way. It is probably the easiest framework for me to bring in other 3rd party plugins because it doesn’t make me adhere to a scope like angular and I have complete control over when views are rendered.
Focused by design. What does this even mean? It means that I don’t have to shift through pages of documentation to understand what Marionette and Backbone can do. The docs are all on a single github page and can be read front-to-back in probably less than an hour.
So what does Marionette do? I’ve made a list.
- Organize your views into either
Regions
,Layouts
,ItemViews
,CompositeViews
orCollectionViews
. - Organize your application so you can bubble up events from
views -> controllers -> application
. - Organize event handling with Backbone.wreqr for application-wide message bus
Simple right? Marionette has no opinion about your model/persistence later and relies completely on Backbone for this. There are a lot of things in Marionette you will have to go find elsewhere, like how to handle promises, routing and persistence. You won’t find things like two-way data-binding or computed properties out of the box with Marionette.
Fortunately, there are Backbone plugins out there for these types of features. Heck I even wrote one myself.
Brian Mann’s videos show you how to make an enterprise worthy application. When I was first learning Marionette I was confused. I didn’t know how it should be used, and then I saw these videos and it improved not only my Marionette skills but my overall performance as a developer in Laravel and other frameworks.
Composite style architecture is complex. There is a reason people like MVC frameworks. They know to find their models, they can view app/models
. To find controllers, app/controllers
. Marionette has no structure except for that you give it. Creating a new Marionette single page application can be a daunting task to start with just because you have to organize your code with intent. You don’t just drop a file in models/users.js but instead face the challenge of how to broadcast the users entity?
Routing as an afterthought is something Derick Bailey and Brian Mann evangelize. I can’t say I agree 100% because routing is an essential part of single page applications. The reason why this bothers me is that when you rely solely on events to do your routing then it takes a lot more time.
For example, if you have route to #users and write a link <a href="#users">Users</a>
in your navigation then you are done. Simple right? But in Marionette the preffered thinking seems to be that we should
- listen to an event on
<a class="js-clicked">Users</a>
DOM element inside of the users’Item
/Collection
/Composite
View - bubble the event up using a trigger to parent controller.
- parent controller listens for triggers on child views.
- the controller would handle a trigger from child view in a function and take necessary action, which would to be call some event like
App.vent.trigger('!route:to:users')
If none of that makes sense to you then you aren’t alone. Basically, it is a lot of work for something as simple as routing.
Testing in Marionette can be wearisome. Unlike Ember, which has the Chrome dev tools integration, in order to test I have to set breakpoints and follow execution and that can prove to be difficult since there are many events flying around everywhere. Often times I find myself just doing console.log
. Also I have tried using karma/mocha with Marionette and because the Marionette.Application
is a singleton it is hard to test in isolation.
So which one should I use?
Depending on the application I am trying to build I would pick one of these three.
When to use Angular? If I’m just trying to add a simple UX feature that I want some two-way data binding then I might bring in angularjs. But I wouldn’t want to do a lot of routing and client-side templating with it. Another thing I wouldn’t want to do is create custom directive. This might work well for teams that are strictly dedicated to Angular, but our team definitely does not fit that bill.
When to use Ember? If I want to create a more MVC looking front-end client with lots of routing then Ember would be my choice. Ember is great to start prototyping with. It is really fast to get started with but as the application grows, if you are not careful, then it will become increasingly more difficult to work with. Also be prepared to read a lot of docs, blog posts, stack overflows and watch a lot of videos because Ember is the richest (feature-wise) of these 3 frameworks and will take a while for you to become comfortable with. An example of this is Ember model (DS data store). You can define your has many/belongs to relationships on the client side if you wanted to. I’ve not found a good reason to do this yet though. Also instead of following RESTful standards it does something called side-loading so be prepared to write your own Adapter for Ember or handle data in a custom way on the server-side. Honestly, I have not done much with Ember model as you can just use plain ol’ javascript objects with Ember too. You can even use Backbone.Model
with it.
When to use Marionette? You might be curious to see how the composite design pattern will work on your application but I would only pick Marionette if you (and your team) are very comfortable with javascript. If you use Marionette you should be ready to use lots of additional plugins and watch Brian Mann’s videos on a good way to organize your marionette application. You can easily bring in lots of jquery plugins without having to worry about the DOM being messed and you will know you are in complete control of your DOM because there is not a whole lot of magic going on behind the scenes with Marionette since you are having to wire up the different types of views yourself.
Above all else, no matter the framework you choose, test your code. A feature rich client side architecture will need tests just like a server side architecture. This is one area Marionette seems to lack guidance. I have seen many more tutorials for Ember and Angular on testing than Marionette. But it is still possible using jasmine or mocha to crank out a test suite in all 3 of these client side frameworks. Good luck, amigos.