I had a quiet afternoon today and while "keeping up with recent developments in my field" or as you might call it "wasting my afternoon googling" I got to thinking what I'd like a Node.js MVC framework should or could contain.
How design shouldn't be done
Firstly, I've been playing with Node.js for about three weeks now and I'm impressed, but I can't seem to find a framework that I'm happy with. Backbone looked good, but I wasted three days on it and it was too much like hard work. Similarly Spine which tried to be less complicated, but eventually failed. Finally I really wanted Brunch to work but it was a release behind backbone (which is a major component of it) and I didn't want to get lost in the mismatching documentation (the Backbone release was pretty major).
I have spent a whole lot of time over the last couple of years using python frameworks, especially Flask and I like their approach of starting with a good foundation (in their case Werkzeug) and adding the bits that are still needed. Could that work with Node? I mean writing a basic HTTP server looks pretty straight forward and there are tons of modules to add the other functionality.
So with this possibly naive starting position I grabbed my pen and scribble down some stuff I thought I'd need. Now bear in mind that I haven't much used any of these modules yet, and I pinched several of them from the bits that go to make up Brunch.
I'd appreciate any feedback, suggestions and so on that those more learned than I might care to offer. Few of you will be less learned I imagine.
I'm teaching myself to use Backbone because after having done quite a lot of JavaScript in work lately, it has become obvious to me that I need a framework.
I'm also learning how to use CoffeeScript, which is close enough to python/ruby for me to understand.
First thing that I noticed is that most of the examples for Backbone out there are in pure JavaScript, so I thought I'd do my bit by providing something in CoffeeScript.
To that end, here is a very simple app which displays a number. You can increase or decrease the count by clicking buttons.
The app.coffee code:
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
At the top, we set up global hashes to store our objects. In a bigger app this would make referencing bits and pieces much easier, although we don't really need it in this example.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Next the controller. This one is almost empty except it has two routes both taking you to the home control which is also part of the controller. The route with no reference (the empty string) and the one for #home tagged on the end of your URL (by way of an example) both call the home function in this case.
The home control just tells the view to render itself.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Next the Counter model which has one attribute called count which defaults to zero. In reality I think you would want to synchronize your models with a database, but we'll do that in another post soon.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
And now for the View. The View is obviously what you are seeing in the browser. In our trivial example we only have one view, but a real app would probably have several. A view lumps together a unit of the app, sometimes nowadays we call these widgets, or blocks or display regions or whatever. You get the idea.
In the initialize function, we just connect the view to the model that backs it. The events connect the button to the functions that they call. The render function draws the result into the #count div; the @ symbol at the end is shorthand for this. In CoffeeScript (like Ruby) the last line of a function gets returned even if you don't specifically say "return". So in other words it means "return this". This is handy since it lets us chain together functions.
The inc and dec functions increase and decrease the count in the model and then update the display. Please see the update here.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Finally the equivalent of the main() function which instaniates the bits and bobs and then starts the history. I've no idea why they called it history, but basically it starts up all the listeners.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
cd ~
rm -fr node # in case this is a fresh install
sudo apt-get install -y g++ curl libssl-dev apache2-utils git-core
wget http://nodejs.org/dist/node-v0.4.9.tar.gz
tar xfz http://nodejs.org/dist/node-v0.4.9.tar.gz
cd node-v0.4.9 && ./configure
# or the bleeding edge version
# git clone git://github.com/joyent/node.git
# cd node && ./configure
make
sudo make install
and finally you need to add the following to your ~/.bashrc file:
export PATH="$HOME/node/bin:$PATH"
Finally install NPM (Node Package Manager):
source ~/.bashrc
curl http://npmjs.org/install.sh | sudo sh