Having little knowledge about client-side routing in JavaScript, I decided to compare two frameworks: Sammy.js and Flatiron Director.
Scope
I’ll do the comparison on a very simple application (loosely based on a sample from Flatiron). The features I’d like to use are:
- Routing: Routing based on hash URLs like
app#/author
. - Routing with params: Getting parameters from URLs like ?15? from
app#/books/15
. - Multiple bindings: Performing more than one action for a route (in a real app it could be routing and loading some data).
- Default routes: Plugging in a ?default? route for all unmatched paths.
- Listeners: Plugging in a listener – some special action to execute in addition to routing on all paths.
Code
Flatiron Director
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Flatiron Director Sample</title> <script src="https://raw.github.com/flatiron/director/master/build/director-1.1.6.min.js"></script> <script> var author = function () { console.log("author"); }; var books = function () { console.log("books"); }; var viewBook = function(bookId) { console.log("viewBook: bookId is populated: " + bookId); }; var wildcard = function(route) { console.log("Wildcard at: " + route); }; var listener = function() { console.log("Listener at: " + window.location); }; var routes = { '/author': author, '/books': [books, function() { console.log("An inline route handler."); }], '/books/view/:bookId': viewBook, '/:def': wildcard }; var router = Router(routes); router.configure({ on: listener }); router.init(); </script> </head> <body> <ul> <li><a href="#/author">#/author</a></li> <li><a href="#/books">#/books</a></li> <li><a href="#/books/view/1">#/books/view/1</a></li> <li><a href="#/other">#/other</a></li> </ul> </body> </html>
Sammy.js
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title>Sammy Sample</title> <script src="http://code.jquery.com/jquery-1.8.3.min.js"></script> <script src="https://raw.github.com/quirkey/sammy/master/lib/min/sammy-latest.min.js"></script> <script> $(function() { var author = function () { console.log("author"); }; var books = function () { console.log("books"); }; var viewBook = function(bookId) { console.log("viewBook: bookId is populated: " + bookId); }; var wildcard = function() { console.log("Wildcard at: " + this.params['route']); }; var listener = function() { console.log("Listener at: " + this.params['path']); }; $.sammy("#main", function() { this.get('#author', author); this.get('#books', books); this.get('#books/view/:id', function() { viewBook(this.params['id']); console.log("An inline route handler."); }); this.get('#:route', wildcard); this.bind('run-route', listener); }).run('#'); }); </script> </head> <body id="main"> <ul> <li><a href="#author">#author</a></li> <li><a href="#books">#books</a></li> <li><a href="#books/view/1">#books/view/1</a></li> <li><a href="#other">#other</a></li> </ul> </body> </html>
Notes
So what do I think about them?
Director seems to be fairly lightweight and simple. It has no dependencies and weighs 3.7 kB. It?s almost functional programming (except for the moment when you turn it on) – you can immediately see what?s going on and what the options are.
In comparison, Sammy.js is much heavier. It depends on jQuery (32.7 kB) and it weighs 6.5 kB. It makes more assumptions: Your code needs to run after page is loaded (that?s why it?s wrapped in $.ready
here). It makes you write OO code – functions have no arguments, but you get more information exposed on this
.
Director supports plugging in multiple handlers to a route out of the box (you can pass an array of functions). In Sammy apparently you need to wrap them in another function.
For some reason Director seems to require URLs to have a slash, like app#/books
– never app#books
. Sammy does not care.
The rest you can see for yourself in the code above.
Verdict
Sammy makes me download more code, all the time I need to read documentation (“So what parameters are available here?”, “What does this object hide?”), and in the end it even makes me write more code. Look at the parameterized viewBook
handler: With Director, I can add the parameter to handler function and it just works. With Sammy I need to get it from this
.
At this point I have strong preference for the Director. It’s smaller and much easier to use. I like that even more because I can directly use it from ClojureScript with minimal friction. It would take quite an effort to integrate Sammy.
Thank you, Konrad. I’m in the midst of splicing together a large hybrid app that leverages Knockout.js and D3js extensively. And then there’s my Sammy routes that misbehave for reasons that just have me pounding my head on my desk at the moment. I’m going to try this… What I’m encoding the the #/ path is so damn complicated that effectively I need to hand off to custom parser anyway so the thinner the routing library the better IMO.