As I mentioned in an earlier post, there's a new dynamic Javascript framework on the block, Meteor. I've had some time to play with it now, and I've seen a myriad of comments and questions in the #Meteor room on freenode, so I thought I'd share my progress thus far.
There's quite a bit of controversy regarding Meteor at the moment. Node.js purists seem to be complaining that Meteor doesn't leverage NPM, that it uses Node-Fibers, instead of the typical asynchronous style of Node, that it's licensed with GPL, versus a more permissive attribution-style license.
The first two issues are, frankly, over my head. I mean, I can point you at the Meteor docs, where they indicate that "the linear execution model a better fit for the typical server code in a Meteor application", or that the Meteor 'Smart Packages' are far more approachable than NPM, but as I've said, I'm a relative newcomer to Javascript on the server, so my opinion wouldn't be that well formed. As for the license, that is of course for you to determine on your own whether the fit is appropriate.
I could also point out that the Meteor team has some serious street cred, and that despite what appears to be an entire community yelling at how they're doing it all wrong™, one might be willing to put their faith in the technical prowess of the team. If you're an experienced Node developer, you almost certainly have a more informed opinion than mine.
What I can say with certainty though, is that even though this is a very early release of their product, I've been able to do things in Javascript I've never been able to before. In writing the very early parts of Orbvt, I've had a lot of ups and downs in understanding the framework, and some of its incompleteness has bitten me in the ass (it is only at a .3.4 preview status, after all), but the amount of code that I have NOT had to write is what makes it shine.
To start playing with Meteor, you can run the following (on supported operating systems) curl install.meteor.com | sh. On OSX Lion, this ran flawlessly. In the IRC channel, a common issue arose for users already running a Mongo database causing problems. If so, you can override which Mongo instance your app uses with an environment variable. export MONGO_URL=mongodb://user.password@host:port/databasename where host is probably localhost, and port is probably 27017.
To create a new application, meteor create meteor-intro will get you started. cd meteor-intro into your new app folder. To start the app that's there, just run meteor, then open up a browser and visit localhost:3000. You should see a "Hello World!" page with a button. Clicking the button logs an entry into your browser's Javascript console (which you should open to see.)
So far, the hardest part has been reading all my wordy ranting in this blog post. If you wanted, we could now open a new console window (so as not to interrupt our server) for file editing (or use your text editor of choice). Inside our meteor-intro folder, we have three files (and one hidden .meteor folder,) meteor-intro.css, meteor-intro.html and meteor-intro.js.
If we look at the meteor-intro.js file in a text editor, we'll see this:
Probably the first Meteor-specific thing we need to show here are the if (Meteor.is_client) and if (Meteor.is_server) blocks. As we know, Meteor is based on Node, so we're using Javascript as both the front and backend languages. In this one-file paradigm that we've started with, we can have both components be served by the same file.
You might put your database methods, or authorization code on the 'is_server' side, and similarly you would probably not want to render the end user's templates from the client side. Though those of those can possibly be done from either location, we'll try to do what makes sense.
It's worth noting that you could create a "server" folder to store server code in, and a "client" folder to store client code in as well, but you don't necessarily need to for smallish apps. As the application grows larger, we may migrate from the 'one-page' design into something more structured, but Meteor allows for both.
So what's the difference between the 'is_server' block and the server folder? Well, the server methods are protected, or are at least private. Code defined in your server folder will never be sent to the client, but code defined in an 'is_server' block will. Knowing that, it's important to give thought to how you lay your code out, and ask "What happens if a user runs this?" If the answer is 'catastrophe', then it should go into the server folder.
Now that we understand that, the first line of real code is the Template.hello.greeting line. Meteor uses Handlebars Templates, and this line (along with some backend Meteor magic) binds a Template item to a function, and also binds an 'Observer' to that function. We'll get to more about what that means later, but put simply, an Observer watches the function and does something when the result of the function changes. In this case, it will re-render our template, which is pretty magical.
If we take a brief look at the accompanying meteor-intro.html file, we'll see the Template we're talking to:
That's it there. Looking back at our JS, you'll see that the Template.hello.greeting is mapping to a Template, named 'hello', with a 'greeting' variable. The 'greeting' might also have been an object, which would require some more special handling in the Template HTML code, but it's about as straightforward as you'd expect. Not having worked with Handlebars before, this was confusing to me at first, so don't feel horrible if it takes a few tries to 'get it'. (If it takes less, feel free to gloat about how much smarter you are than me. I'm used to it.)
The next bit of code Template.hello.events binds event listeners to the "hello" Template. This is similar to how Backbone handles events, so if you're familiar with that, you should be hip here. If not, it's easily explained, though I don't know what events are supported out of the box:
"click input" means that we're binding the 'click' event on 'input' selectors to the function we define (which, in this case, appends to console.log). If we wanted to bind a link, it would instead be "click a" or "click a.new_link", where 'new_link' is a class name.)
We could, of course, also bind to spans, divs, classes or IDs as well. The events appear to be jQuery events, and should support all jQuery event types, though I haven't tested that. You could bind 'keyup', 'keydown', 'mouseover', etc.
Deploying a Meteor app to Meteor's servers is drop-dead simple, though I will make it just ever so slightly more complicated, for great justice.
meteor deploy appname will get it done. If you're just playing around with an ephemeral app, or one that you aren't concerned with what happens to it, that'll work. If however, you care even a little bit that this project not be destroyed, you need to add the "-P" (uppercase) flag, for password. That will password protect the deployment, and prevent others from being able to deploy over your deployment.
Once deployment finishes (it shouldn't take long), you should see your app at http://appname.meteor.com.
Ours is published at http://meteor-intro.meteor.com/, and the source code for this example will be published at https://github.com/bmelton/Meteor-Intro. It's only the content of the 'meteor create' output not, but watch it for coming changes.
That pretty much sums up the anatomy of the intro project. In our next run, we'll look at inserting and querying the Mongo data store, looping through record sets with the Template, and perhaps even working with Route handlers to create new screens in our application.
If you want to jump ahead, Thomas Lomas has posted an introductory video as well, chronicling his build of a Meteor chat application.
More blog entries